Merge "WindowInsetsAnimationController: Add additional assertions for new APIs" into rvc-dev
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index ae8976a..9f98f8e 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -55,6 +55,10 @@
  * using the {@link JobInfo.Builder}.
  * The goal here is to provide the scheduler with high-level semantics about the work you want to
  * accomplish.
+ * <p> Prior to Android version {@link Build.VERSION_CODES#Q}, you had to specify at least one
+ * constraint on the JobInfo object that you are creating. Otherwise, the builder would throw an
+ * exception when building. From Android version {@link Build.VERSION_CODES#Q} and onwards, it is
+ * valid to schedule jobs with no constraints.
  */
 public class JobInfo implements Parcelable {
     private static String TAG = "JobInfo";
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 819f253..07a9908 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -746,7 +746,13 @@
     final Constants mConstants;
     final ConstantsObserver mConstantsObserver;
 
-    static final Comparator<JobStatus> mEnqueueTimeComparator = (o1, o2) -> {
+    private static final Comparator<JobStatus> sPendingJobComparator = (o1, o2) -> {
+        // Jobs with an override state set (via adb) should be put first as tests/developers
+        // expect the jobs to run immediately.
+        if (o1.overrideState != o2.overrideState) {
+            // Higher override state (OVERRIDE_FULL) should be before lower state (OVERRIDE_SOFT)
+            return o2.overrideState - o1.overrideState;
+        }
         if (o1.enqueueTime < o2.enqueueTime) {
             return -1;
         }
@@ -1097,7 +1103,7 @@
                 // This is a new job, we can just immediately put it on the pending
                 // list and try to run it.
                 mJobPackageTracker.notePending(jobStatus);
-                addOrderedItem(mPendingJobs, jobStatus, mEnqueueTimeComparator);
+                addOrderedItem(mPendingJobs, jobStatus, sPendingJobComparator);
                 maybeRunPendingJobsLocked();
             } else {
                 evaluateControllerStatesLocked(jobStatus);
@@ -1858,7 +1864,7 @@
                         // state is such that all ready jobs should be run immediately.
                         if (runNow != null && isReadyToBeExecutedLocked(runNow)) {
                             mJobPackageTracker.notePending(runNow);
-                            addOrderedItem(mPendingJobs, runNow, mEnqueueTimeComparator);
+                            addOrderedItem(mPendingJobs, runNow, sPendingJobComparator);
                         } else {
                             queueReadyJobsForExecutionLocked();
                         }
@@ -2030,7 +2036,7 @@
             noteJobsPending(newReadyJobs);
             mPendingJobs.addAll(newReadyJobs);
             if (mPendingJobs.size() > 1) {
-                mPendingJobs.sort(mEnqueueTimeComparator);
+                mPendingJobs.sort(sPendingJobComparator);
             }
 
             newReadyJobs.clear();
@@ -2107,7 +2113,7 @@
                 noteJobsPending(runnableJobs);
                 mPendingJobs.addAll(runnableJobs);
                 if (mPendingJobs.size() > 1) {
-                    mPendingJobs.sort(mEnqueueTimeComparator);
+                    mPendingJobs.sort(sPendingJobComparator);
                 }
             } else {
                 if (DEBUG) {
@@ -2813,11 +2819,9 @@
     }
 
     // Shell command infrastructure: run the given job immediately
-    int executeRunCommand(String pkgName, int userId, int jobId, boolean force) {
-        if (DEBUG) {
-            Slog.v(TAG, "executeRunCommand(): " + pkgName + "/" + userId
-                    + " " + jobId + " f=" + force);
-        }
+    int executeRunCommand(String pkgName, int userId, int jobId, boolean satisfied, boolean force) {
+        Slog.d(TAG, "executeRunCommand(): " + pkgName + "/" + userId
+                + " " + jobId + " s=" + satisfied + " f=" + force);
 
         try {
             final int uid = AppGlobals.getPackageManager().getPackageUid(pkgName, 0,
@@ -2832,7 +2836,8 @@
                     return JobSchedulerShellCommand.CMD_ERR_NO_JOB;
                 }
 
-                js.overrideState = (force) ? JobStatus.OVERRIDE_FULL : JobStatus.OVERRIDE_SOFT;
+                js.overrideState = (force) ? JobStatus.OVERRIDE_FULL
+                        : (satisfied ? JobStatus.OVERRIDE_SORTING : JobStatus.OVERRIDE_SOFT);
 
                 // Re-evaluate constraints after the override is set in case one of the overridden
                 // constraints was preventing another constraint from thinking it needed to update.
@@ -2841,7 +2846,7 @@
                 }
 
                 if (!js.isConstraintsSatisfied()) {
-                    js.overrideState = 0;
+                    js.overrideState = JobStatus.OVERRIDE_NONE;
                     return JobSchedulerShellCommand.CMD_ERR_CONSTRAINTS;
                 }
 
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
index 9571708..1e72062 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
@@ -136,6 +136,7 @@
         checkPermission("force scheduled jobs");
 
         boolean force = false;
+        boolean satisfied = false;
         int userId = UserHandle.USER_SYSTEM;
 
         String opt;
@@ -146,6 +147,11 @@
                     force = true;
                     break;
 
+                case "-s":
+                case "--satisfied":
+                    satisfied = true;
+                    break;
+
                 case "-u":
                 case "--user":
                     userId = Integer.parseInt(getNextArgRequired());
@@ -157,12 +163,17 @@
             }
         }
 
+        if (force && satisfied) {
+            pw.println("Cannot specify both --force and --satisfied");
+            return -1;
+        }
+
         final String pkgName = getNextArgRequired();
         final int jobId = Integer.parseInt(getNextArgRequired());
 
         final long ident = Binder.clearCallingIdentity();
         try {
-            int ret = mInternal.executeRunCommand(pkgName, userId, jobId, force);
+            int ret = mInternal.executeRunCommand(pkgName, userId, jobId, satisfied, force);
             if (printError(ret, pkgName, userId, jobId)) {
                 return ret;
             }
@@ -424,11 +435,18 @@
         pw.println("Job scheduler (jobscheduler) commands:");
         pw.println("  help");
         pw.println("    Print this help text.");
-        pw.println("  run [-f | --force] [-u | --user USER_ID] PACKAGE JOB_ID");
-        pw.println("    Trigger immediate execution of a specific scheduled job.");
+        pw.println("  run [-f | --force] [-s | --satisfied] [-u | --user USER_ID] PACKAGE JOB_ID");
+        pw.println("    Trigger immediate execution of a specific scheduled job. For historical");
+        pw.println("    reasons, some constraints, such as battery, are ignored when this");
+        pw.println("    command is called. If you don't want any constraints to be ignored,");
+        pw.println("    include the -s flag.");
         pw.println("    Options:");
         pw.println("      -f or --force: run the job even if technical constraints such as");
-        pw.println("         connectivity are not currently met");
+        pw.println("         connectivity are not currently met. This is incompatible with -f ");
+        pw.println("         and so an error will be reported if both are given.");
+        pw.println("      -s or --satisfied: run the job only if all constraints are met.");
+        pw.println("         This is incompatible with -f and so an error will be reported");
+        pw.println("         if both are given.");
         pw.println("      -u or --user: specify which user's job is to be run; the default is");
         pw.println("         the primary or system user");
         pw.println("  timeout [-u | --user USER_ID] [PACKAGE] [JOB_ID]");
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index 81dbc87..d7c6ddb 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -131,10 +131,14 @@
     // TODO(b/129954980)
     private static final boolean STATS_LOG_ENABLED = false;
 
+    // No override.
+    public static final int OVERRIDE_NONE = 0;
+    // Override to improve sorting order. Does not affect constraint evaluation.
+    public static final int OVERRIDE_SORTING = 1;
     // Soft override: ignore constraints like time that don't affect API availability
-    public static final int OVERRIDE_SOFT = 1;
+    public static final int OVERRIDE_SOFT = 2;
     // Full override: ignore all constraints including API-affecting like connectivity
-    public static final int OVERRIDE_FULL = 2;
+    public static final int OVERRIDE_FULL = 3;
 
     /** If not specified, trigger update delay is 10 seconds. */
     public static final long DEFAULT_TRIGGER_UPDATE_DELAY = 10*1000;
@@ -304,7 +308,7 @@
     public int nextPendingWorkId = 1;
 
     // Used by shell commands
-    public int overrideState = 0;
+    public int overrideState = JobStatus.OVERRIDE_NONE;
 
     // When this job was enqueued, for ordering.  (in elapsedRealtimeMillis)
     public long enqueueTime;
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index 0ff55da..bb3f4e9 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -104,12 +104,12 @@
  *     private int bytesWrittenCount = 0;
  *
  *     &#64;Override
- *     public void onSeekMap(int i, &#64;NonNull MediaFormat mediaFormat) {
+ *     public void onSeekMapFound(int i, &#64;NonNull MediaFormat mediaFormat) {
  *       // Do nothing.
  *     }
  *
  *     &#64;Override
- *     public void onTrackData(int i, &#64;NonNull TrackData trackData) {
+ *     public void onTrackDataFound(int i, &#64;NonNull TrackData trackData) {
  *       MediaFormat mediaFormat = trackData.mediaFormat;
  *       if (videoTrackIndex == -1 &&
  *           mediaFormat
@@ -120,7 +120,7 @@
  *     }
  *
  *     &#64;Override
- *     public void onSampleData(int trackIndex, &#64;NonNull InputReader inputReader)
+ *     public void onSampleDataFound(int trackIndex, &#64;NonNull InputReader inputReader)
  *         throws IOException {
  *       int numberOfBytesToRead = (int) inputReader.getLength();
  *       if (videoTrackIndex != trackIndex) {
@@ -387,9 +387,9 @@
          * @param flags Flags associated with the sample. See {@link MediaCodec
          *     MediaCodec.BUFFER_FLAG_*}.
          * @param size The size of the sample data, in bytes.
-         * @param offset The number of bytes that have been consumed by {@code onSampleData(int,
-         *     MediaParser.InputReader)} for the specified track, since the last byte belonging to
-         *     the sample whose metadata is being passed.
+         * @param offset The number of bytes that have been consumed by {@code
+         *     onSampleDataFound(int, MediaParser.InputReader)} for the specified track, since the
+         *     last byte belonging to the sample whose metadata is being passed.
          * @param cryptoData Encryption data required to decrypt the sample. May be null for
          *     unencrypted samples.
          */
diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp
index 986682e..8185bb0 100644
--- a/apex/statsd/framework/Android.bp
+++ b/apex/statsd/framework/Android.bp
@@ -166,8 +166,10 @@
 
 android_test {
     name: "FrameworkStatsdTest",
-    sdk_version: "module_current",
+    platform_apis: true,
     srcs: [
+        // TODO(b/147705194): Use framework-statsd as a lib dependency instead.
+        ":framework-statsd-sources",
         "test/**/*.java",
     ],
     manifest: "test/AndroidManifest.xml",
@@ -178,7 +180,6 @@
     libs: [
         "android.test.runner.stubs",
         "android.test.base.stubs",
-        "framework-statsd",
     ],
     test_suites: [
         "device-tests",
diff --git a/api/current.txt b/api/current.txt
index 3327167..baad02c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -288,9 +288,9 @@
     field public static final int alignmentMode = 16843642; // 0x101037a
     field public static final int allContactsName = 16843468; // 0x10102cc
     field public static final int allowAudioPlaybackCapture = 16844289; // 0x1010601
+    field public static final int allowAutoRevokePermissionsExemption = 16844309; // 0x1010615
     field public static final int allowBackup = 16843392; // 0x1010280
     field public static final int allowClearUserData = 16842757; // 0x1010005
-    field public static final int allowDontAutoRevokePermissions = 16844309; // 0x1010615
     field public static final int allowEmbedded = 16843765; // 0x10103f5
     field public static final int allowNativeHeapPointerTagging = 16844307; // 0x1010613
     field public static final int allowParallelSyncs = 16843570; // 0x1010332
@@ -1140,7 +1140,7 @@
     field public static final int reqKeyboardType = 16843304; // 0x1010228
     field public static final int reqNavigation = 16843306; // 0x101022a
     field public static final int reqTouchScreen = 16843303; // 0x1010227
-    field public static final int requestDontAutoRevokePermissions = 16844308; // 0x1010614
+    field public static final int requestAutoRevokePermissionsExemption = 16844308; // 0x1010614
     field public static final int requestLegacyExternalStorage = 16844291; // 0x1010603
     field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
     field public static final int required = 16843406; // 0x101028e
@@ -4049,6 +4049,7 @@
     method @RequiresPermission(android.Manifest.permission.REORDER_TASKS) public void moveTaskToFront(int, int);
     method @RequiresPermission(android.Manifest.permission.REORDER_TASKS) public void moveTaskToFront(int, int, android.os.Bundle);
     method @Deprecated public void restartPackage(String);
+    method public void setProcessStateSummary(@Nullable byte[]);
     method public static void setVrThread(int);
     method public void setWatchHeapLimit(long);
     field public static final String ACTION_REPORT_HEAP_LIMIT = "android.app.action.REPORT_HEAP_LIMIT";
@@ -4561,12 +4562,14 @@
     method public int getPackageUid();
     method public int getPid();
     method @NonNull public String getProcessName();
+    method @Nullable public byte[] getProcessStateSummary();
     method public long getPss();
     method public int getRealUid();
     method public int getReason();
     method public long getRss();
     method public int getStatus();
     method public long getTimestamp();
+    method @Nullable public java.io.InputStream getTraceInputStream() throws java.io.IOException;
     method @NonNull public android.os.UserHandle getUserHandle();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.ApplicationExitInfo> CREATOR;
@@ -6942,7 +6945,7 @@
     method public boolean isApplicationHidden(@NonNull android.content.ComponentName, String);
     method public boolean isBackupServiceEnabled(@NonNull android.content.ComponentName);
     method @Deprecated public boolean isCallerApplicationRestrictionsManagingPackage();
-    method public boolean isCommonCriteriaModeEnabled(@NonNull android.content.ComponentName);
+    method public boolean isCommonCriteriaModeEnabled(@Nullable android.content.ComponentName);
     method public boolean isDeviceIdAttestationSupported();
     method public boolean isDeviceOwnerApp(String);
     method public boolean isEphemeralUser(@NonNull android.content.ComponentName);
@@ -10202,7 +10205,6 @@
     field public static final String MEDIA_ROUTER_SERVICE = "media_router";
     field public static final String MEDIA_SESSION_SERVICE = "media_session";
     field public static final String MIDI_SERVICE = "midi";
-    field public static final String MMS_SERVICE = "mms";
     field public static final int MODE_APPEND = 32768; // 0x8000
     field public static final int MODE_ENABLE_WRITE_AHEAD_LOGGING = 8; // 0x8
     field @Deprecated public static final int MODE_MULTI_PROCESS = 4; // 0x4
@@ -23601,13 +23603,13 @@
     method @FloatRange(from=0, to=63) public double getCn0DbHz();
     method @NonNull public String getCodeType();
     method public int getConstellationType();
+    method public double getFullInterSignalBiasNanos();
+    method @FloatRange(from=0.0) public double getFullInterSignalBiasUncertaintyNanos();
     method public int getMultipathIndicator();
     method public double getPseudorangeRateMetersPerSecond();
     method public double getPseudorangeRateUncertaintyMetersPerSecond();
     method public long getReceivedSvTimeNanos();
     method public long getReceivedSvTimeUncertaintyNanos();
-    method public double getReceiverInterSignalBiasNanos();
-    method @FloatRange(from=0.0) public double getReceiverInterSignalBiasUncertaintyNanos();
     method public double getSatelliteInterSignalBiasNanos();
     method @FloatRange(from=0.0) public double getSatelliteInterSignalBiasUncertaintyNanos();
     method public double getSnrInDb();
@@ -23621,8 +23623,8 @@
     method @Deprecated public boolean hasCarrierPhase();
     method @Deprecated public boolean hasCarrierPhaseUncertainty();
     method public boolean hasCodeType();
-    method public boolean hasReceiverInterSignalBiasNanos();
-    method public boolean hasReceiverInterSignalBiasUncertaintyNanos();
+    method public boolean hasFullInterSignalBiasNanos();
+    method public boolean hasFullInterSignalBiasUncertaintyNanos();
     method public boolean hasSatelliteInterSignalBiasNanos();
     method public boolean hasSatelliteInterSignalBiasUncertaintyNanos();
     method public boolean hasSnrInDb();
@@ -43121,7 +43123,6 @@
   public static final class FillResponse.Builder {
     ctor public FillResponse.Builder();
     method @NonNull public android.service.autofill.FillResponse.Builder addDataset(@Nullable android.service.autofill.Dataset);
-    method @NonNull public android.service.autofill.FillResponse.Builder addInlineAction(@NonNull android.service.autofill.InlineAction);
     method @NonNull public android.service.autofill.FillResponse build();
     method @NonNull public android.service.autofill.FillResponse.Builder disableAutofill(long);
     method @NonNull public android.service.autofill.FillResponse.Builder setAuthentication(@NonNull android.view.autofill.AutofillId[], @Nullable android.content.IntentSender, @Nullable android.widget.RemoteViews);
@@ -43151,15 +43152,6 @@
     method public android.service.autofill.ImageTransformation build();
   }
 
-  public final class InlineAction implements android.os.Parcelable {
-    ctor public InlineAction(@NonNull android.service.autofill.InlinePresentation, @NonNull android.content.IntentSender);
-    method public int describeContents();
-    method @NonNull public android.content.IntentSender getAction();
-    method @NonNull public android.service.autofill.InlinePresentation getInlinePresentation();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.service.autofill.InlineAction> CREATOR;
-  }
-
   public final class InlinePresentation implements android.os.Parcelable {
     ctor public InlinePresentation(@NonNull android.app.slice.Slice, @NonNull android.view.inline.InlinePresentationSpec, boolean);
     method public int describeContents();
@@ -47545,11 +47537,6 @@
     method @Nullable public android.telephony.mbms.StreamingService startStreaming(android.telephony.mbms.StreamingServiceInfo, @NonNull java.util.concurrent.Executor, android.telephony.mbms.StreamingServiceCallback);
   }
 
-  public class MmsManager {
-    method public void downloadMultimediaMessage(int, @NonNull String, @NonNull android.net.Uri, @Nullable android.os.Bundle, @Nullable android.app.PendingIntent, long);
-    method public void sendMultimediaMessage(int, @NonNull android.net.Uri, @Nullable String, @Nullable android.os.Bundle, @Nullable android.app.PendingIntent, long);
-  }
-
   @Deprecated public class NeighboringCellInfo implements android.os.Parcelable {
     ctor @Deprecated public NeighboringCellInfo();
     ctor @Deprecated public NeighboringCellInfo(int, int);
@@ -48110,7 +48097,7 @@
     method public long getDataLimitBytes();
     method public long getDataUsageBytes();
     method public long getDataUsageTime();
-    method @Nullable public int[] getNetworkTypes();
+    method @NonNull public int[] getNetworkTypes();
     method @Nullable public CharSequence getSummary();
     method @Nullable public CharSequence getTitle();
     method public void writeToParcel(android.os.Parcel, int);
@@ -48130,7 +48117,7 @@
     method public static android.telephony.SubscriptionPlan.Builder createRecurring(java.time.ZonedDateTime, java.time.Period);
     method public android.telephony.SubscriptionPlan.Builder setDataLimit(long, int);
     method public android.telephony.SubscriptionPlan.Builder setDataUsage(long, long);
-    method @NonNull public android.telephony.SubscriptionPlan.Builder setNetworkTypes(@Nullable int[]);
+    method @NonNull public android.telephony.SubscriptionPlan.Builder setNetworkTypes(@NonNull int[]);
     method public android.telephony.SubscriptionPlan.Builder setSummary(@Nullable CharSequence);
     method public android.telephony.SubscriptionPlan.Builder setTitle(@Nullable CharSequence);
   }
@@ -53619,6 +53606,7 @@
 
   public static final class SurfaceControlViewHost.SurfacePackage implements android.os.Parcelable {
     method public int describeContents();
+    method public void release();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.view.SurfaceControlViewHost.SurfacePackage> CREATOR;
   }
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index ee997f1..cfb9b83 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -72,19 +72,20 @@
     field public static final int TETHERING_WIFI = 0; // 0x0
     field public static final int TETHERING_WIFI_P2P = 3; // 0x3
     field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc
-    field public static final int TETHER_ERROR_DISABLE_NAT_ERROR = 9; // 0x9
-    field public static final int TETHER_ERROR_ENABLE_NAT_ERROR = 8; // 0x8
+    field public static final int TETHER_ERROR_DISABLE_FORWARDING_ERROR = 9; // 0x9
+    field public static final int TETHER_ERROR_ENABLE_FORWARDING_ERROR = 8; // 0x8
     field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd
     field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa
-    field public static final int TETHER_ERROR_MASTER_ERROR = 5; // 0x5
+    field public static final int TETHER_ERROR_INTERNAL_ERROR = 5; // 0x5
     field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf
     field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe
     field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
-    field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
+    field public static final int TETHER_ERROR_PROVISIONING_FAILED = 11; // 0xb
     field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2
     field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6
     field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4
     field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
+    field public static final int TETHER_ERROR_UNKNOWN_TYPE = 16; // 0x10
     field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
     field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
     field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2
@@ -96,29 +97,26 @@
     method public void onTetheringEntitlementResult(int);
   }
 
-  public abstract static class TetheringManager.StartTetheringCallback {
-    ctor public TetheringManager.StartTetheringCallback();
-    method public void onTetheringFailed(int);
-    method public void onTetheringStarted();
+  public static interface TetheringManager.StartTetheringCallback {
+    method public default void onTetheringFailed(int);
+    method public default void onTetheringStarted();
   }
 
-  public abstract static class TetheringManager.TetheringEventCallback {
-    ctor public TetheringManager.TetheringEventCallback();
-    method public void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
-    method public void onError(@NonNull String, int);
-    method public void onOffloadStatusChanged(int);
-    method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
-    method public void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
-    method public void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
-    method public void onTetheringSupported(boolean);
-    method public void onUpstreamChanged(@Nullable android.net.Network);
+  public static interface TetheringManager.TetheringEventCallback {
+    method public default void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
+    method public default void onError(@NonNull String, int);
+    method public default void onOffloadStatusChanged(int);
+    method public default void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
+    method public default void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
+    method public default void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
+    method public default void onTetheringSupported(boolean);
+    method public default void onUpstreamChanged(@Nullable android.net.Network);
   }
 
-  @Deprecated public static class TetheringManager.TetheringInterfaceRegexps {
-    ctor @Deprecated public TetheringManager.TetheringInterfaceRegexps(@NonNull String[], @NonNull String[], @NonNull String[]);
-    method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableBluetoothRegexs();
-    method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableUsbRegexs();
-    method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
+  public static class TetheringManager.TetheringInterfaceRegexps {
+    method @NonNull public java.util.List<java.lang.String> getTetherableBluetoothRegexs();
+    method @NonNull public java.util.List<java.lang.String> getTetherableUsbRegexs();
+    method @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
   }
 
   public static class TetheringManager.TetheringRequest {
@@ -127,9 +125,14 @@
   public static class TetheringManager.TetheringRequest.Builder {
     ctor public TetheringManager.TetheringRequest.Builder(int);
     method @NonNull public android.net.TetheringManager.TetheringRequest build();
+    method @Nullable public android.net.LinkAddress getClientStaticIpv4Address();
+    method @Nullable public android.net.LinkAddress getLocalIpv4Address();
+    method public boolean getShouldShowEntitlementUi();
+    method public int getTetheringType();
+    method public boolean isExemptFromEntitlementCheck();
     method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean);
-    method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setSilentProvisioning(boolean);
-    method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder useStaticIpv4Addresses(@NonNull android.net.LinkAddress);
+    method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setShouldShowEntitlementUi(boolean);
+    method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setStaticIpv4Addresses(@NonNull android.net.LinkAddress, @NonNull android.net.LinkAddress);
   }
 
 }
diff --git a/api/system-current.txt b/api/system-current.txt
index 0fb80a2..f8cb6c9 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -387,6 +387,7 @@
     field public static final String OPSTR_AUDIO_NOTIFICATION_VOLUME = "android:audio_notification_volume";
     field public static final String OPSTR_AUDIO_RING_VOLUME = "android:audio_ring_volume";
     field public static final String OPSTR_AUDIO_VOICE_VOLUME = "android:audio_voice_volume";
+    field public static final String OPSTR_AUTO_REVOKE_MANAGED_BY_INSTALLER = "android:auto_revoke_managed_by_installer";
     field public static final String OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED = "android:auto_revoke_permissions_if_unused";
     field public static final String OPSTR_BIND_ACCESSIBILITY_SERVICE = "android:bind_accessibility_service";
     field public static final String OPSTR_CHANGE_WIFI_STATE = "android:change_wifi_state";
@@ -1806,7 +1807,6 @@
     field public static final String NETD_SERVICE = "netd";
     field public static final String NETWORK_POLICY_SERVICE = "netpolicy";
     field public static final String NETWORK_SCORE_SERVICE = "network_score";
-    field public static final String NETWORK_STACK_SERVICE = "network_stack";
     field public static final String OEM_LOCK_SERVICE = "oem_lock";
     field public static final String PERMISSION_SERVICE = "permission";
     field public static final String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block";
@@ -1870,7 +1870,6 @@
     field public static final String ACTION_UPGRADE_SETUP = "android.intent.action.UPGRADE_SETUP";
     field public static final String ACTION_USER_ADDED = "android.intent.action.USER_ADDED";
     field public static final String ACTION_USER_REMOVED = "android.intent.action.USER_REMOVED";
-    field @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public static final String ACTION_USER_SWITCHED = "android.intent.action.USER_SWITCHED";
     field public static final String ACTION_VOICE_ASSIST = "android.intent.action.VOICE_ASSIST";
     field public static final String CATEGORY_LEANBACK_SETTINGS = "android.intent.category.LEANBACK_SETTINGS";
     field public static final String EXTRA_CALLING_PACKAGE = "android.intent.extra.CALLING_PACKAGE";
@@ -2313,7 +2312,6 @@
     field public static final int PROTECTION_FLAG_OEM = 16384; // 0x4000
     field public static final int PROTECTION_FLAG_RETAIL_DEMO = 16777216; // 0x1000000
     field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
-    field public static final int PROTECTION_FLAG_TELEPHONY = 4194304; // 0x400000
     field public static final int PROTECTION_FLAG_WELLBEING = 131072; // 0x20000
     field @Nullable public final String backgroundPermission;
     field @StringRes public int requestRes;
@@ -4828,11 +4826,11 @@
   }
 
   public class Lnb implements java.lang.AutoCloseable {
-    method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public void close();
-    method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int sendDiseqcMessage(@NonNull byte[]);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int setSatellitePosition(int);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int setTone(int);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int setVoltage(int);
+    method public void close();
+    method public int sendDiseqcMessage(@NonNull byte[]);
+    method public int setSatellitePosition(int);
+    method public int setTone(int);
+    method public int setVoltage(int);
     field public static final int EVENT_TYPE_DISEQC_RX_OVERFLOW = 0; // 0x0
     field public static final int EVENT_TYPE_DISEQC_RX_PARITY_ERROR = 2; // 0x2
     field public static final int EVENT_TYPE_DISEQC_RX_TIMEOUT = 1; // 0x1
@@ -4860,32 +4858,32 @@
 
   public class Tuner implements java.lang.AutoCloseable {
     ctor @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public Tuner(@NonNull android.content.Context, @Nullable String, int);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int cancelScanning();
-    method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int cancelTuning();
-    method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public void clearOnTuneEventListener();
-    method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public void clearResourceLostListener();
-    method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public void close();
-    method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int connectCiCam(int);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int disconnectCiCam();
-    method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int getAvSyncHwId(@NonNull android.media.tv.tuner.filter.Filter);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public long getAvSyncTime(int);
-    method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.DemuxCapabilities getDemuxCapabilities(@NonNull android.content.Context);
-    method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public android.media.tv.tuner.frontend.FrontendInfo getFrontendInfo();
+    method public int cancelScanning();
+    method public int cancelTuning();
+    method public void clearOnTuneEventListener();
+    method public void clearResourceLostListener();
+    method public void close();
+    method public int connectCiCam(int);
+    method public int disconnectCiCam();
+    method public int getAvSyncHwId(@NonNull android.media.tv.tuner.filter.Filter);
+    method public long getAvSyncTime(int);
+    method @Nullable public android.media.tv.tuner.DemuxCapabilities getDemuxCapabilities();
+    method @Nullable public android.media.tv.tuner.frontend.FrontendInfo getFrontendInfo();
     method @Nullable public android.media.tv.tuner.frontend.FrontendStatus getFrontendStatus(@NonNull int[]);
     method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_DESCRAMBLER) public android.media.tv.tuner.Descrambler openDescrambler();
-    method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public android.media.tv.tuner.dvr.DvrPlayback openDvrPlayback(long, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.dvr.OnPlaybackStatusChangedListener);
-    method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public android.media.tv.tuner.dvr.DvrRecorder openDvrRecorder(long, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.dvr.OnRecordStatusChangedListener);
-    method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public android.media.tv.tuner.filter.Filter openFilter(int, int, long, @Nullable java.util.concurrent.Executor, @Nullable android.media.tv.tuner.filter.FilterCallback);
-    method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public android.media.tv.tuner.Lnb openLnb(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.LnbCallback);
-    method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public android.media.tv.tuner.Lnb openLnbByName(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.LnbCallback);
+    method @Nullable public android.media.tv.tuner.dvr.DvrPlayback openDvrPlayback(long, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.dvr.OnPlaybackStatusChangedListener);
+    method @Nullable public android.media.tv.tuner.dvr.DvrRecorder openDvrRecorder(long, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.dvr.OnRecordStatusChangedListener);
+    method @Nullable public android.media.tv.tuner.filter.Filter openFilter(int, int, long, @Nullable java.util.concurrent.Executor, @Nullable android.media.tv.tuner.filter.FilterCallback);
+    method @Nullable public android.media.tv.tuner.Lnb openLnb(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.LnbCallback);
+    method @Nullable public android.media.tv.tuner.Lnb openLnbByName(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.LnbCallback);
     method @Nullable public android.media.tv.tuner.filter.TimeFilter openTimeFilter();
-    method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int scan(@NonNull android.media.tv.tuner.frontend.FrontendSettings, int, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.frontend.ScanCallback);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int setLnaEnabled(boolean);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public void setOnTuneEventListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.frontend.OnTuneEventListener);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public void setResourceLostListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.Tuner.OnResourceLostListener);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public void shareFrontendFromTuner(@NonNull android.media.tv.tuner.Tuner);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int tune(@NonNull android.media.tv.tuner.frontend.FrontendSettings);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public void updateResourcePriority(int, int);
+    method public int scan(@NonNull android.media.tv.tuner.frontend.FrontendSettings, int, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.frontend.ScanCallback);
+    method public int setLnaEnabled(boolean);
+    method public void setOnTuneEventListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.frontend.OnTuneEventListener);
+    method public void setResourceLostListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.Tuner.OnResourceLostListener);
+    method public void shareFrontendFromTuner(@NonNull android.media.tv.tuner.Tuner);
+    method public int tune(@NonNull android.media.tv.tuner.frontend.FrontendSettings);
+    method public void updateResourcePriority(int, int);
     field public static final int INVALID_AV_SYNC_ID = -1; // 0xffffffff
     field public static final int INVALID_FILTER_ID = -1; // 0xffffffff
     field public static final int INVALID_STREAM_ID = 65535; // 0xffff
@@ -6219,6 +6217,7 @@
 
   public final class LinkProperties implements android.os.Parcelable {
     ctor public LinkProperties(@Nullable android.net.LinkProperties);
+    ctor public LinkProperties(@Nullable android.net.LinkProperties, boolean);
     method public boolean addDnsServer(@NonNull java.net.InetAddress);
     method public boolean addLinkAddress(@NonNull android.net.LinkAddress);
     method public boolean addPcscfServer(@NonNull java.net.InetAddress);
@@ -6241,7 +6240,6 @@
     method public boolean isIpv6Provisioned();
     method public boolean isProvisioned();
     method public boolean isReachable(@NonNull java.net.InetAddress);
-    method @NonNull public android.net.LinkProperties makeSensitiveFieldsParcelingCopy();
     method public boolean removeDnsServer(@NonNull java.net.InetAddress);
     method public boolean removeLinkAddress(@NonNull android.net.LinkAddress);
     method public boolean removeRoute(@NonNull android.net.RouteInfo);
@@ -6320,11 +6318,11 @@
   }
 
   public final class NetworkCapabilities implements android.os.Parcelable {
-    method @NonNull public java.util.List<java.lang.Integer> getAdministratorUids();
+    method @NonNull public int[] getAdministratorUids();
     method @Nullable public String getSSID();
     method @NonNull public int[] getTransportTypes();
     method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
-    method @NonNull public android.net.NetworkCapabilities setAdministratorUids(@NonNull java.util.List<java.lang.Integer>);
+    method @NonNull public android.net.NetworkCapabilities setAdministratorUids(@NonNull int[]);
     method @NonNull public android.net.NetworkCapabilities setRequestorPackageName(@NonNull String);
     method @NonNull public android.net.NetworkCapabilities setRequestorUid(int);
     method @NonNull public android.net.NetworkCapabilities setSSID(@Nullable String);
@@ -6402,6 +6400,7 @@
   }
 
   public class NetworkStack {
+    method @Nullable public static android.os.IBinder getService();
     field public static final String PERMISSION_MAINLINE_NETWORK_STACK = "android.permission.MAINLINE_NETWORK_STACK";
   }
 
@@ -6543,19 +6542,20 @@
     field public static final int TETHERING_WIFI = 0; // 0x0
     field public static final int TETHERING_WIFI_P2P = 3; // 0x3
     field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc
-    field public static final int TETHER_ERROR_DISABLE_NAT_ERROR = 9; // 0x9
-    field public static final int TETHER_ERROR_ENABLE_NAT_ERROR = 8; // 0x8
+    field public static final int TETHER_ERROR_DISABLE_FORWARDING_ERROR = 9; // 0x9
+    field public static final int TETHER_ERROR_ENABLE_FORWARDING_ERROR = 8; // 0x8
     field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd
     field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa
-    field public static final int TETHER_ERROR_MASTER_ERROR = 5; // 0x5
+    field public static final int TETHER_ERROR_INTERNAL_ERROR = 5; // 0x5
     field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf
     field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe
     field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
-    field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
+    field public static final int TETHER_ERROR_PROVISIONING_FAILED = 11; // 0xb
     field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2
     field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6
     field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4
     field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
+    field public static final int TETHER_ERROR_UNKNOWN_TYPE = 16; // 0x10
     field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
     field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
     field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2
@@ -6567,29 +6567,19 @@
     method public void onTetheringEntitlementResult(int);
   }
 
-  public abstract static class TetheringManager.StartTetheringCallback {
-    ctor public TetheringManager.StartTetheringCallback();
-    method public void onTetheringFailed(int);
-    method public void onTetheringStarted();
+  public static interface TetheringManager.StartTetheringCallback {
+    method public default void onTetheringFailed(int);
+    method public default void onTetheringStarted();
   }
 
-  public abstract static class TetheringManager.TetheringEventCallback {
-    ctor public TetheringManager.TetheringEventCallback();
-    method public void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
-    method public void onError(@NonNull String, int);
-    method public void onOffloadStatusChanged(int);
-    method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
-    method public void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
-    method public void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
-    method public void onTetheringSupported(boolean);
-    method public void onUpstreamChanged(@Nullable android.net.Network);
-  }
-
-  @Deprecated public static class TetheringManager.TetheringInterfaceRegexps {
-    ctor @Deprecated public TetheringManager.TetheringInterfaceRegexps(@NonNull String[], @NonNull String[], @NonNull String[]);
-    method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableBluetoothRegexs();
-    method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableUsbRegexs();
-    method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
+  public static interface TetheringManager.TetheringEventCallback {
+    method public default void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
+    method public default void onError(@NonNull String, int);
+    method public default void onOffloadStatusChanged(int);
+    method public default void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
+    method public default void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
+    method public default void onTetheringSupported(boolean);
+    method public default void onUpstreamChanged(@Nullable android.net.Network);
   }
 
   public static class TetheringManager.TetheringRequest {
@@ -6598,9 +6588,14 @@
   public static class TetheringManager.TetheringRequest.Builder {
     ctor public TetheringManager.TetheringRequest.Builder(int);
     method @NonNull public android.net.TetheringManager.TetheringRequest build();
+    method @Nullable public android.net.LinkAddress getClientStaticIpv4Address();
+    method @Nullable public android.net.LinkAddress getLocalIpv4Address();
+    method public boolean getShouldShowEntitlementUi();
+    method public int getTetheringType();
+    method public boolean isExemptFromEntitlementCheck();
     method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean);
-    method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setSilentProvisioning(boolean);
-    method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder useStaticIpv4Addresses(@NonNull android.net.LinkAddress);
+    method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setShouldShowEntitlementUi(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setStaticIpv4Addresses(@NonNull android.net.LinkAddress, @NonNull android.net.LinkAddress);
   }
 
   public class TrafficStats {
@@ -8893,6 +8888,7 @@
     method @BinderThread public abstract void onRevokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull String, @NonNull java.util.function.Consumer<java.util.Map<java.lang.String,java.util.List<java.lang.String>>>);
     method @BinderThread public abstract void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull String, @NonNull String, int, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @BinderThread public void onStageAndApplyRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
+    method @BinderThread public void onUpdateUserSensitivePermissionFlags(int, @NonNull java.util.concurrent.Executor, @NonNull Runnable);
     method @BinderThread public void onUpdateUserSensitivePermissionFlags(int, @NonNull Runnable);
     field public static final String SERVICE_INTERFACE = "android.permission.PermissionControllerService";
   }
@@ -9289,7 +9285,6 @@
     field public static final String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages";
     field public static final String CARRIER_APP_NAMES = "carrier_app_names";
     field public static final String CARRIER_APP_WHITELIST = "carrier_app_whitelist";
-    field public static final String COMMON_CRITERIA_MODE = "common_criteria_mode";
     field public static final String DEFAULT_SM_DP_PLUS = "default_sm_dp_plus";
     field public static final String DEVICE_DEMO_MODE = "device_demo_mode";
     field public static final String DEVICE_PROVISIONING_MOBILE_DATA_ENABLED = "device_provisioning_mobile_data";
@@ -9773,7 +9768,6 @@
     method @NonNull public android.service.autofill.augmented.FillResponse build();
     method @NonNull public android.service.autofill.augmented.FillResponse.Builder setClientState(@NonNull android.os.Bundle);
     method @NonNull public android.service.autofill.augmented.FillResponse.Builder setFillWindow(@NonNull android.service.autofill.augmented.FillWindow);
-    method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineActions(@NonNull java.util.List<android.service.autofill.InlineAction>);
     method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineSuggestions(@NonNull java.util.List<android.service.autofill.Dataset>);
   }
 
@@ -11568,14 +11562,10 @@
     field public static final String ACTION_EMERGENCY_CALLBACK_MODE_CHANGED = "android.intent.action.EMERGENCY_CALLBACK_MODE_CHANGED";
     field public static final String ACTION_EMERGENCY_CALL_STATE_CHANGED = "android.intent.action.EMERGENCY_CALL_STATE_CHANGED";
     field public static final String ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE = "com.android.omadm.service.CONFIGURATION_UPDATE";
-    field public static final String ACTION_SERVICE_PROVIDERS_UPDATED = "android.telephony.action.SERVICE_PROVIDERS_UPDATED";
     field public static final String ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS = "android.telephony.action.SHOW_NOTICE_ECM_BLOCK_OTHERS";
     field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED";
     field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED";
     field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED";
-    field public static final int CARD_POWER_DOWN = 0; // 0x0
-    field public static final int CARD_POWER_UP = 1; // 0x1
-    field public static final int CARD_POWER_UP_PASS_THROUGH = 2; // 0x2
     field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe
     field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
     field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
@@ -11586,7 +11576,6 @@
     field public static final String EXTRA_APN_PROTOCOL_INT = "apnProtoInt";
     field @Deprecated public static final String EXTRA_APN_TYPE = "apnType";
     field public static final String EXTRA_APN_TYPE_INT = "apnTypeInt";
-    field public static final String EXTRA_DATA_SPN = "android.telephony.extra.DATA_SPN";
     field public static final String EXTRA_DEFAULT_NETWORK_AVAILABLE = "defaultNetworkAvailable";
     field public static final String EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE = "android.telephony.extra.DEFAULT_SUBSCRIPTION_SELECT_TYPE";
     field public static final int EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_ALL = 4; // 0x4
@@ -11599,16 +11588,12 @@
     field public static final String EXTRA_PCO_VALUE = "pcoValue";
     field public static final String EXTRA_PHONE_IN_ECM_STATE = "android.telephony.extra.PHONE_IN_ECM_STATE";
     field public static final String EXTRA_PHONE_IN_EMERGENCY_CALL = "android.telephony.extra.PHONE_IN_EMERGENCY_CALL";
-    field public static final String EXTRA_PLMN = "android.telephony.extra.PLMN";
     field public static final String EXTRA_REDIRECTION_URL = "redirectionUrl";
-    field public static final String EXTRA_SHOW_PLMN = "android.telephony.extra.SHOW_PLMN";
-    field public static final String EXTRA_SHOW_SPN = "android.telephony.extra.SHOW_SPN";
     field public static final String EXTRA_SIM_COMBINATION_NAMES = "android.telephony.extra.SIM_COMBINATION_NAMES";
     field public static final String EXTRA_SIM_COMBINATION_WARNING_TYPE = "android.telephony.extra.SIM_COMBINATION_WARNING_TYPE";
     field public static final int EXTRA_SIM_COMBINATION_WARNING_TYPE_DUAL_CDMA = 1; // 0x1
     field public static final int EXTRA_SIM_COMBINATION_WARNING_TYPE_NONE = 0; // 0x0
     field public static final String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE";
-    field public static final String EXTRA_SPN = "android.telephony.extra.SPN";
     field public static final String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL";
     field public static final String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING";
     field public static final int INVALID_EMERGENCY_NUMBER_DB_VERSION = -1; // 0xffffffff
diff --git a/api/test-current.txt b/api/test-current.txt
index 5bd1f89..632afdf6 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -111,6 +111,7 @@
     method public void setLaunchActivityType(int);
     method public void setLaunchTaskId(int);
     method public void setLaunchWindowingMode(int);
+    method public void setTaskAlwaysOnTop(boolean);
     method public void setTaskOverlay(boolean, boolean);
   }
 
@@ -829,7 +830,6 @@
     field public static final String DEVICE_IDLE_CONTROLLER = "deviceidle";
     field public static final String DREAM_SERVICE = "dream";
     field public static final String ETHERNET_SERVICE = "ethernet";
-    field public static final String NETWORK_STACK_SERVICE = "network_stack";
     field public static final String PERMISSION_SERVICE = "permission";
     field public static final String POWER_WHITELIST_MANAGER = "power_whitelist";
     field public static final String ROLLBACK_SERVICE = "rollback";
@@ -964,7 +964,6 @@
     method @NonNull public abstract String getServicesSystemSharedLibraryPackageName();
     method @NonNull public abstract String getSharedSystemSharedLibraryPackageName();
     method @Nullable public String getSystemTextClassifierPackageName();
-    method @Nullable public String[] getTelephonyPackageNames();
     method @Nullable public String getWellbeingPackageName();
     method @RequiresPermission("android.permission.GRANT_RUNTIME_PERMISSIONS") public abstract void grantRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
     method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void removeOnPermissionsChangeListener(@NonNull android.content.pm.PackageManager.OnPermissionsChangedListener);
@@ -1007,7 +1006,6 @@
     field public static final int PROTECTION_FLAG_OEM = 16384; // 0x4000
     field public static final int PROTECTION_FLAG_RETAIL_DEMO = 16777216; // 0x1000000
     field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
-    field public static final int PROTECTION_FLAG_TELEPHONY = 4194304; // 0x400000
     field public static final int PROTECTION_FLAG_VENDOR_PRIVILEGED = 32768; // 0x8000
     field public static final int PROTECTION_FLAG_WELLBEING = 131072; // 0x20000
     field @Nullable public final String backgroundPermission;
@@ -1355,8 +1353,8 @@
     method @Deprecated public void resetCarrierPhase();
     method @Deprecated public void resetCarrierPhaseUncertainty();
     method public void resetCodeType();
-    method public void resetReceiverInterSignalBiasNanos();
-    method public void resetReceiverInterSignalBiasUncertaintyNanos();
+    method public void resetFullInterSignalBiasNanos();
+    method public void resetFullInterSignalBiasUncertaintyNanos();
     method public void resetSatelliteInterSignalBiasNanos();
     method public void resetSatelliteInterSignalBiasUncertaintyNanos();
     method public void resetSnrInDb();
@@ -1373,13 +1371,13 @@
     method public void setCn0DbHz(double);
     method public void setCodeType(@NonNull String);
     method public void setConstellationType(int);
+    method public void setFullInterSignalBiasNanos(double);
+    method public void setFullInterSignalBiasUncertaintyNanos(@FloatRange(from=0.0) double);
     method public void setMultipathIndicator(int);
     method public void setPseudorangeRateMetersPerSecond(double);
     method public void setPseudorangeRateUncertaintyMetersPerSecond(double);
     method public void setReceivedSvTimeNanos(long);
     method public void setReceivedSvTimeUncertaintyNanos(long);
-    method public void setReceiverInterSignalBiasNanos(double);
-    method public void setReceiverInterSignalBiasUncertaintyNanos(@FloatRange(from=0.0) double);
     method public void setSatelliteInterSignalBiasNanos(double);
     method public void setSatelliteInterSignalBiasUncertaintyNanos(@FloatRange(from=0.0) double);
     method public void setSnrInDb(double);
@@ -1792,6 +1790,7 @@
 
   public final class LinkProperties implements android.os.Parcelable {
     ctor public LinkProperties(@Nullable android.net.LinkProperties);
+    ctor public LinkProperties(@Nullable android.net.LinkProperties, boolean);
     method public boolean addDnsServer(@NonNull java.net.InetAddress);
     method public boolean addLinkAddress(@NonNull android.net.LinkAddress);
     method @Nullable public android.net.Uri getCaptivePortalApiUrl();
@@ -1806,7 +1805,6 @@
     method public boolean isIpv6Provisioned();
     method public boolean isProvisioned();
     method public boolean isReachable(@NonNull java.net.InetAddress);
-    method @NonNull public android.net.LinkProperties makeSensitiveFieldsParcelingCopy();
     method public boolean removeDnsServer(@NonNull java.net.InetAddress);
     method public boolean removeLinkAddress(@NonNull android.net.LinkAddress);
     method public boolean removeRoute(@NonNull android.net.RouteInfo);
@@ -1832,6 +1830,7 @@
   }
 
   public class NetworkStack {
+    method @Nullable public static android.os.IBinder getService();
     field public static final String PERMISSION_MAINLINE_NETWORK_STACK = "android.permission.MAINLINE_NETWORK_STACK";
   }
 
@@ -1922,19 +1921,20 @@
     field public static final int TETHERING_WIFI = 0; // 0x0
     field public static final int TETHERING_WIFI_P2P = 3; // 0x3
     field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc
-    field public static final int TETHER_ERROR_DISABLE_NAT_ERROR = 9; // 0x9
-    field public static final int TETHER_ERROR_ENABLE_NAT_ERROR = 8; // 0x8
+    field public static final int TETHER_ERROR_DISABLE_FORWARDING_ERROR = 9; // 0x9
+    field public static final int TETHER_ERROR_ENABLE_FORWARDING_ERROR = 8; // 0x8
     field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd
     field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa
-    field public static final int TETHER_ERROR_MASTER_ERROR = 5; // 0x5
+    field public static final int TETHER_ERROR_INTERNAL_ERROR = 5; // 0x5
     field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf
     field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe
     field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
-    field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
+    field public static final int TETHER_ERROR_PROVISIONING_FAILED = 11; // 0xb
     field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2
     field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6
     field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4
     field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
+    field public static final int TETHER_ERROR_UNKNOWN_TYPE = 16; // 0x10
     field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
     field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
     field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2
@@ -1946,29 +1946,19 @@
     method public void onTetheringEntitlementResult(int);
   }
 
-  public abstract static class TetheringManager.StartTetheringCallback {
-    ctor public TetheringManager.StartTetheringCallback();
-    method public void onTetheringFailed(int);
-    method public void onTetheringStarted();
+  public static interface TetheringManager.StartTetheringCallback {
+    method public default void onTetheringFailed(int);
+    method public default void onTetheringStarted();
   }
 
-  public abstract static class TetheringManager.TetheringEventCallback {
-    ctor public TetheringManager.TetheringEventCallback();
-    method public void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
-    method public void onError(@NonNull String, int);
-    method public void onOffloadStatusChanged(int);
-    method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
-    method public void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
-    method public void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
-    method public void onTetheringSupported(boolean);
-    method public void onUpstreamChanged(@Nullable android.net.Network);
-  }
-
-  @Deprecated public static class TetheringManager.TetheringInterfaceRegexps {
-    ctor @Deprecated public TetheringManager.TetheringInterfaceRegexps(@NonNull String[], @NonNull String[], @NonNull String[]);
-    method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableBluetoothRegexs();
-    method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableUsbRegexs();
-    method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
+  public static interface TetheringManager.TetheringEventCallback {
+    method public default void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
+    method public default void onError(@NonNull String, int);
+    method public default void onOffloadStatusChanged(int);
+    method public default void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
+    method public default void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
+    method public default void onTetheringSupported(boolean);
+    method public default void onUpstreamChanged(@Nullable android.net.Network);
   }
 
   public static class TetheringManager.TetheringRequest {
@@ -1977,9 +1967,14 @@
   public static class TetheringManager.TetheringRequest.Builder {
     ctor public TetheringManager.TetheringRequest.Builder(int);
     method @NonNull public android.net.TetheringManager.TetheringRequest build();
+    method @Nullable public android.net.LinkAddress getClientStaticIpv4Address();
+    method @Nullable public android.net.LinkAddress getLocalIpv4Address();
+    method public boolean getShouldShowEntitlementUi();
+    method public int getTetheringType();
+    method public boolean isExemptFromEntitlementCheck();
     method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean);
-    method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setSilentProvisioning(boolean);
-    method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder useStaticIpv4Addresses(@NonNull android.net.LinkAddress);
+    method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setShouldShowEntitlementUi(boolean);
+    method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setStaticIpv4Addresses(@NonNull android.net.LinkAddress, @NonNull android.net.LinkAddress);
   }
 
   public class TrafficStats {
@@ -3262,7 +3257,6 @@
     method @NonNull public android.service.autofill.augmented.FillResponse build();
     method @NonNull public android.service.autofill.augmented.FillResponse.Builder setClientState(@NonNull android.os.Bundle);
     method @NonNull public android.service.autofill.augmented.FillResponse.Builder setFillWindow(@NonNull android.service.autofill.augmented.FillWindow);
-    method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineActions(@NonNull java.util.List<android.service.autofill.InlineAction>);
     method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineSuggestions(@NonNull java.util.List<android.service.autofill.Dataset>);
   }
 
diff --git a/api/test-lint-baseline.txt b/api/test-lint-baseline.txt
index 94db346..caf8fdb 100644
--- a/api/test-lint-baseline.txt
+++ b/api/test-lint-baseline.txt
@@ -421,9 +421,9 @@
     
 GetterSetterNames: android.location.GnssMeasurement#setCodeType(String):
 
-GetterSetterNames: android.location.GnssMeasurement#setReceiverInterSignalBiasNanos(double):
+GetterSetterNames: android.location.GnssMeasurement#setFullInterSignalBiasNanos(double):
 
-GetterSetterNames: android.location.GnssMeasurement#setReceiverInterSignalBiasUncertaintyNanos(double):
+GetterSetterNames: android.location.GnssMeasurement#setFullInterSignalBiasUncertaintyNanos(double):
 
 GetterSetterNames: android.location.GnssMeasurement#setSatelliteInterSignalBiasNanos(double):
 
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index d79123b..60d1ac7 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -267,28 +267,29 @@
     bool workerDone = false;
     FdBuffer buffer;
 
-    // Create shared data and pipe
-    WorkerThreadData data(this);
-    if (!data.pipe.init()) {
+    // Create shared data and pipe. Don't put data on the stack since this thread may exit early.
+    sp<WorkerThreadData> data = new WorkerThreadData(this);
+    if (!data->pipe.init()) {
         return -errno;
     }
-
-    std::thread([&]() {
+    data->incStrong(this);
+    std::thread([data, this]() {
         // Don't crash the service if writing to a closed pipe (may happen if dumping times out)
         signal(SIGPIPE, sigpipe_handler);
-        status_t err = data.section->BlockingCall(data.pipe.writeFd());
+        status_t err = data->section->BlockingCall(data->pipe.writeFd());
         {
-            std::unique_lock<std::mutex> lock(data.lock);
-            data.workerDone = true;
-            data.workerError = err;
+            std::scoped_lock<std::mutex> lock(data->lock);
+            data->workerDone = true;
+            data->workerError = err;
             // unique_fd is not thread safe. If we don't lock it, reset() may pause half way while
             // the other thread executes to the end, calling ~Fpipe, which is a race condition.
-            data.pipe.writeFd().reset();
+            data->pipe.writeFd().reset();
         }
+        data->decStrong(this);
     }).detach();
 
     // Loop reading until either the timeout or the worker side is done (i.e. eof).
-    err = buffer.read(data.pipe.readFd().get(), this->timeoutMs);
+    err = buffer.read(data->pipe.readFd().get(), this->timeoutMs);
     if (err != NO_ERROR) {
         ALOGE("[%s] reader failed with error '%s'", this->name.string(), strerror(-err));
     }
@@ -296,13 +297,13 @@
     // If the worker side is finished, then return its error (which may overwrite
     // our possible error -- but it's more interesting anyway). If not, then we timed out.
     {
-        std::unique_lock<std::mutex> lock(data.lock);
-        data.pipe.close();
-        if (data.workerError != NO_ERROR) {
-            err = data.workerError;
+        std::scoped_lock<std::mutex> lock(data->lock);
+        data->pipe.close();
+        if (data->workerError != NO_ERROR) {
+            err = data->workerError;
             ALOGE("[%s] worker failed with error '%s'", this->name.string(), strerror(-err));
         }
-        workerDone = data.workerDone;
+        workerDone = data->workerDone;
     }
 
     writer->setSectionStats(buffer);
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 33bfe51..4529dff 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -189,6 +189,34 @@
     ],
 }
 
+genrule {
+    name: "statslog_statsdtest.h",
+    tools: ["stats-log-api-gen"],
+    cmd: "$(location stats-log-api-gen) --header $(genDir)/statslog_statsdtest.h --module statsdtest --namespace android,os,statsd,util",
+    out: [
+        "statslog_statsdtest.h",
+    ],
+}
+
+genrule {
+    name: "statslog_statsdtest.cpp",
+    tools: ["stats-log-api-gen"],
+    cmd: "$(location stats-log-api-gen) --cpp $(genDir)/statslog_statsdtest.cpp --module statsdtest --namespace android,os,statsd,util --importHeader statslog_statsdtest.h",
+    out: [
+        "statslog_statsdtest.cpp",
+    ],
+}
+
+cc_library_static {
+    name: "libstatslog_statsdtest",
+    generated_sources: ["statslog_statsdtest.cpp"],
+    generated_headers: ["statslog_statsdtest.h"],
+    export_generated_headers: ["statslog_statsdtest.h"],
+    shared_libs: [
+        "libstatssocket",
+    ]
+}
+
 cc_library_static {
     name: "libstatslog_statsd",
     generated_sources: ["statslog_statsd.cpp"],
@@ -331,7 +359,7 @@
     static_libs: [
         "libgmock",
         "libplatformprotos",
-        "libstatslog", //TODO(b/150976524): remove this when the tests no longer hardcode atoms.
+        "libstatslog_statsdtest",
         "libstatssocket_private",
     ],
 
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 1cbe150..f0a5b51 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -81,12 +81,16 @@
         BleScanStateChanged ble_scan_state_changed = 2 [(module) = "bluetooth"];
         ProcessStateChanged process_state_changed = 3 [(module) = "framework"];
         BleScanResultReceived ble_scan_result_received = 4 [(module) = "bluetooth"];
-        SensorStateChanged sensor_state_changed = 5 [(module) = "framework"];
+        SensorStateChanged sensor_state_changed =
+                5 [(module) = "framework", (module) = "statsdtest"];
         GpsScanStateChanged gps_scan_state_changed = 6 [(module) = "framework"];
-        SyncStateChanged sync_state_changed = 7 [(module) = "framework"];
-        ScheduledJobStateChanged scheduled_job_state_changed = 8 [(module) = "framework"];
-        ScreenBrightnessChanged screen_brightness_changed = 9 [(module) = "framework"];
-        WakelockStateChanged wakelock_state_changed = 10 [(module) = "framework"];
+        SyncStateChanged sync_state_changed = 7 [(module) = "framework", (module) = "statsdtest"];
+        ScheduledJobStateChanged scheduled_job_state_changed =
+                8 [(module) = "framework", (module) = "statsdtest"];
+        ScreenBrightnessChanged screen_brightness_changed =
+                9 [(module) = "framework", (module) = "statsdtest"];
+        WakelockStateChanged wakelock_state_changed =
+                10 [(module) = "framework", (module) = "statsdtest"];
         LongPartialWakelockStateChanged long_partial_wakelock_state_changed =
                 11 [(module) = "framework"];
         MobileRadioPowerStateChanged mobile_radio_power_state_changed = 12 [(module) = "framework"];
@@ -98,17 +102,22 @@
         CachedKillReported cached_kill_reported = 17 [(module) = "framework"];
         ProcessMemoryStatReported process_memory_stat_reported = 18 [(module) = "framework"];
         LauncherUIChanged launcher_event = 19 [(module) = "sysui"];
-        BatterySaverModeStateChanged battery_saver_mode_state_changed = 20 [(module) = "framework"];
+        BatterySaverModeStateChanged battery_saver_mode_state_changed =
+                20 [(module) = "framework", (module) = "statsdtest"];
         DeviceIdleModeStateChanged device_idle_mode_state_changed = 21 [(module) = "framework"];
         DeviceIdlingModeStateChanged device_idling_mode_state_changed = 22 [(module) = "framework"];
         AudioStateChanged audio_state_changed = 23 [(module) = "framework"];
         MediaCodecStateChanged media_codec_state_changed = 24 [(module) = "framework"];
         CameraStateChanged camera_state_changed = 25 [(module) = "framework"];
         FlashlightStateChanged flashlight_state_changed = 26 [(module) = "framework"];
-        UidProcessStateChanged uid_process_state_changed = 27 [(module) = "framework"];
-        ProcessLifeCycleStateChanged process_life_cycle_state_changed = 28 [(module) = "framework"];
-        ScreenStateChanged screen_state_changed = 29 [(module) = "framework"];
-        BatteryLevelChanged battery_level_changed = 30 [(module) = "framework"];
+        UidProcessStateChanged uid_process_state_changed =
+                27 [(module) = "framework", (module) = "statsdtest"];
+        ProcessLifeCycleStateChanged process_life_cycle_state_changed =
+                28 [(module) = "framework", (module) = "statsdtest"];
+        ScreenStateChanged screen_state_changed =
+                29 [(module) = "framework", (module) = "statsdtest"];
+        BatteryLevelChanged battery_level_changed =
+                30 [(module) = "framework", (module) = "statsdtest"];
         ChargingStateChanged charging_state_changed = 31 [(module) = "framework"];
         PluggedStateChanged plugged_state_changed = 32 [(module) = "framework"];
         InteractiveStateChanged interactive_state_changed = 33 [(module) = "framework"];
@@ -121,14 +130,15 @@
         PhoneSignalStrengthChanged phone_signal_strength_changed = 40 [(module) = "framework"];
         SettingChanged setting_changed = 41 [(module) = "framework"];
         ActivityForegroundStateChanged activity_foreground_state_changed =
-                42 [(module) = "framework"];
-        IsolatedUidChanged isolated_uid_changed = 43 [(module) = "framework", (module) = "statsd"];
+                42 [(module) = "framework", (module) = "statsdtest"];
+        IsolatedUidChanged isolated_uid_changed =
+                43 [(module) = "framework", (module) = "statsd", (module) = "statsdtest"];
         PacketWakeupOccurred packet_wakeup_occurred = 44 [(module) = "framework"];
         WallClockTimeShifted wall_clock_time_shifted = 45 [(module) = "framework"];
         AnomalyDetected anomaly_detected = 46 [(module) = "statsd"];
         AppBreadcrumbReported app_breadcrumb_reported =
                 47 [(allow_from_any_uid) = true, (module) = "statsd"];
-        AppStartOccurred app_start_occurred = 48 [(module) = "framework"];
+        AppStartOccurred app_start_occurred = 48 [(module) = "framework", (module) = "statsdtest"];
         AppStartCanceled app_start_canceled = 49 [(module) = "framework"];
         AppStartFullyDrawn app_start_fully_drawn = 50 [(module) = "framework"];
         LmkKillOccurred lmk_kill_occurred = 51 [(module) = "lmkd"];
@@ -139,7 +149,8 @@
         ShutdownSequenceReported shutdown_sequence_reported = 56 [(module) = "framework"];
         BootSequenceReported boot_sequence_reported = 57;
         DaveyOccurred davey_occurred = 58 [(allow_from_any_uid) = true, (module) = "statsd"];
-        OverlayStateChanged overlay_state_changed = 59 [(module) = "framework"];
+        OverlayStateChanged overlay_state_changed =
+                59 [(module) = "framework", (module) = "statsdtest"];
         ForegroundServiceStateChanged foreground_service_state_changed
                 = 60 [(module) = "framework"];
         CallStateChanged call_state_changed = 61 [(module) = "telecom"];
@@ -160,7 +171,7 @@
         MobileConnectionStateChanged mobile_connection_state_changed = 75 [(module) = "telephony"];
         MobileRadioTechnologyChanged mobile_radio_technology_changed = 76 [(module) = "telephony"];
         UsbDeviceAttached usb_device_attached = 77 [(module) = "framework"];
-        AppCrashOccurred app_crash_occurred = 78 [(module) = "framework"];
+        AppCrashOccurred app_crash_occurred = 78 [(module) = "framework", (module) = "statsdtest"];
         ANROccurred anr_occurred = 79 [(module) = "framework"];
         WTFOccurred wtf_occurred = 80 [(module) = "framework"];
         LowMemReported low_mem_reported = 81 [(module) = "framework"];
@@ -412,9 +423,9 @@
         MobileBytesTransferByFgBg mobile_bytes_transfer_by_fg_bg = 10003 [(module) = "framework"];
         BluetoothBytesTransfer bluetooth_bytes_transfer = 10006 [(module) = "framework"];
         KernelWakelock kernel_wakelock = 10004 [(module) = "framework"];
-        SubsystemSleepState subsystem_sleep_state = 10005;
+        SubsystemSleepState subsystem_sleep_state = 10005 [(module) = "statsdtest"];
         CpuTimePerFreq cpu_time_per_freq = 10008 [(module) = "framework"];
-        CpuTimePerUid cpu_time_per_uid = 10009 [(module) = "framework"];
+        CpuTimePerUid cpu_time_per_uid = 10009 [(module) = "framework", (module) = "statsdtest"];
         CpuTimePerUidFreq cpu_time_per_uid_freq =
                 10010 [(module) = "framework", (module) = "statsd"];
         WifiActivityInfo wifi_activity_info = 10011 [(module) = "framework"];
@@ -422,13 +433,13 @@
         BluetoothActivityInfo bluetooth_activity_info = 10007 [(module) = "framework"];
         ProcessMemoryState process_memory_state = 10013 [(module) = "framework"];
         SystemElapsedRealtime system_elapsed_realtime = 10014 [(module) = "framework"];
-        SystemUptime system_uptime = 10015 [(module) = "framework"];
+        SystemUptime system_uptime = 10015 [(module) = "framework", (module) = "statsdtest"];
         CpuActiveTime cpu_active_time = 10016 [(module) = "framework"];
-        CpuClusterTime cpu_cluster_time = 10017 [(module) = "framework"];
-        DiskSpace disk_space = 10018 [deprecated=true];
+        CpuClusterTime cpu_cluster_time = 10017 [(module) = "framework", (module) = "statsdtest"];
+        DiskSpace disk_space = 10018 [deprecated=true, (module) = "statsdtest"];
         RemainingBatteryCapacity remaining_battery_capacity = 10019 [(module) = "framework"];
         FullBatteryCapacity full_battery_capacity = 10020 [(module) = "framework"];
-        Temperature temperature = 10021 [(module) = "framework"];
+        Temperature temperature = 10021 [(module) = "framework", (module) = "statsdtest"];
         BinderCalls binder_calls = 10022 [(module) = "framework", (module) = "statsd"];
         BinderCallsExceptions binder_calls_exceptions = 10023 [(module) = "framework"];
         LooperStats looper_stats = 10024 [(module) = "framework", (module) = "statsd"];
diff --git a/cmds/statsd/src/state/StateTracker.h b/cmds/statsd/src/state/StateTracker.h
index aeca2a5..154750e 100644
--- a/cmds/statsd/src/state/StateTracker.h
+++ b/cmds/statsd/src/state/StateTracker.h
@@ -30,7 +30,7 @@
 
 class StateTracker : public virtual RefBase {
 public:
-    StateTracker(const int32_t atomId, const util::StateAtomFieldOptions& stateAtomInfo);
+    StateTracker(const int32_t atomId, const android::util::StateAtomFieldOptions& stateAtomInfo);
 
     virtual ~StateTracker(){};
 
diff --git a/cmds/statsd/src/stats_log_util.h b/cmds/statsd/src/stats_log_util.h
index aec0956..ade25d6 100644
--- a/cmds/statsd/src/stats_log_util.h
+++ b/cmds/statsd/src/stats_log_util.h
@@ -23,24 +23,26 @@
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 #include "guardrail/StatsdStats.h"
 
+using android::util::ProtoOutputStream;
+
 namespace android {
 namespace os {
 namespace statsd {
 
 void writeFieldValueTreeToStream(int tagId, const std::vector<FieldValue>& values,
-                                 util::ProtoOutputStream* protoOutput);
+                                 ProtoOutputStream* protoOutput);
 void writeDimensionToProto(const HashableDimensionKey& dimension, std::set<string> *str_set,
-                           util::ProtoOutputStream* protoOutput);
+                           ProtoOutputStream* protoOutput);
 
 void writeDimensionLeafNodesToProto(const HashableDimensionKey& dimension,
                                     const int dimensionLeafFieldId,
                                     std::set<string> *str_set,
-                                    util::ProtoOutputStream* protoOutput);
+                                    ProtoOutputStream* protoOutput);
 
 void writeDimensionPathToProto(const std::vector<Matcher>& fieldMatchers,
-                               util::ProtoOutputStream* protoOutput);
+                               ProtoOutputStream* protoOutput);
 
-void writeStateToProto(const FieldValue& state, util::ProtoOutputStream* protoOutput);
+void writeStateToProto(const FieldValue& state, ProtoOutputStream* protoOutput);
 
 // Convert the TimeUnit enum to the bucket size in millis with a guardrail on
 // bucket size.
@@ -73,14 +75,14 @@
 
 // Helper function to write PulledAtomStats to ProtoOutputStream
 void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats>& pair,
-                              util::ProtoOutputStream* protoOutput);
+                              ProtoOutputStream* protoOutput);
 
 // Helper function to write AtomMetricStats to ProtoOutputStream
 void writeAtomMetricStatsToStream(const std::pair<int64_t, StatsdStats::AtomMetricStats> &pair,
-                                  util::ProtoOutputStream *protoOutput);
+                                  ProtoOutputStream *protoOutput);
 
 template<class T>
-bool parseProtoOutputStream(util::ProtoOutputStream& protoOutput, T* message) {
+bool parseProtoOutputStream(ProtoOutputStream& protoOutput, T* message) {
     std::string pbBytes;
     sp<android::util::ProtoReader> reader = protoOutput.data();
     while (reader->readBuffer() != NULL) {
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index 81d6f72..d6498f4 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -21,7 +21,7 @@
 #include "logd/LogEvent.h"
 #include "packages/UidMap.h"
 #include "storage/StorageManager.h"
-#include "statslog.h"
+#include "statslog_statsdtest.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index af6de06..a49c18f 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -18,7 +18,7 @@
 #include "guardrail/StatsdStats.h"
 #include "logd/LogEvent.h"
 #include "hash.h"
-#include "statslog.h"
+#include "statslog_statsdtest.h"
 #include "statsd_test_util.h"
 
 #include <android/util/ProtoOutputStream.h>
@@ -49,7 +49,7 @@
 //    StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
 //                        [](const ConfigKey& key) { return true; },
 //                        [](const int&, const vector<int64_t>&) {return true;});
-//    LogEvent addEvent(android::util::ISOLATED_UID_CHANGED, 1);
+//    LogEvent addEvent(util::ISOLATED_UID_CHANGED, 1);
 //    addEvent.write(100);  // parent UID
 //    addEvent.write(101);  // isolated UID
 //    addEvent.write(1);    // Indicates creation.
@@ -60,7 +60,7 @@
 //    p.OnLogEvent(&addEvent);
 //    EXPECT_EQ(100, m->getHostUidOrSelf(101));
 //
-//    LogEvent removeEvent(android::util::ISOLATED_UID_CHANGED, 1);
+//    LogEvent removeEvent(util::ISOLATED_UID_CHANGED, 1);
 //    removeEvent.write(100);  // parent UID
 //    removeEvent.write(101);  // isolated UID
 //    removeEvent.write(0);    // Indicates removal.
diff --git a/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp b/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
index e0eebef..9c6965d 100644
--- a/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
@@ -39,7 +39,7 @@
     countMetric->set_id(123456);
     countMetric->set_what(wakelockAcquireMatcher.id());
     *countMetric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
-            android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+            util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
     countMetric->set_bucket(FIVE_MINUTES);
 
     auto alert = config.add_alert();
@@ -83,12 +83,12 @@
     std::vector<int> attributionUids5 = {222};
     std::vector<string> attributionTags5 = {"GMSCoreModule1"};
 
-    FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+    FieldValue fieldValue1(Field(util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
                            Value((int32_t)111));
     HashableDimensionKey whatKey1({fieldValue1});
     MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
 
-    FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+    FieldValue fieldValue2(Field(util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
                            Value((int32_t)222));
     HashableDimensionKey whatKey2({fieldValue2});
     MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY);
@@ -194,7 +194,7 @@
     std::vector<int> attributionUids2 = {111, 222};
     std::vector<string> attributionTags2 = {"App1", "GMSCoreModule1"};
 
-    FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+    FieldValue fieldValue1(Field(util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
                            Value((int32_t)111));
     HashableDimensionKey whatKey1({fieldValue1});
     MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
diff --git a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
index fe45b55..4f9f315 100644
--- a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
@@ -45,7 +45,7 @@
 
     auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
     FieldMatcher dimensions = CreateAttributionUidDimensions(
-            android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+            util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
     dimensions.add_child()->set_field(3);  // The wakelock tag is set in field 3 of the wakelock.
     *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions;
     holdingWakelockPredicate.mutable_simple_predicate()->set_count_nesting(nesting);
@@ -57,7 +57,7 @@
     durationMetric->set_condition(screenIsOffPredicate.id());
     durationMetric->set_aggregation_type(aggregationType);
     *durationMetric->mutable_dimensions_in_what() =
-        CreateAttributionUidDimensions(android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+        CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
     durationMetric->set_bucket(FIVE_MINUTES);
 
     auto alert = config.add_alert();
@@ -79,13 +79,13 @@
 std::vector<string> attributionTags3 = {"GMSCoreModule1"};
 
 MetricDimensionKey dimensionKey1(
-        HashableDimensionKey({FieldValue(Field(android::util::WAKELOCK_STATE_CHANGED,
+        HashableDimensionKey({FieldValue(Field(util::WAKELOCK_STATE_CHANGED,
                                                (int32_t)0x02010101),
                                          Value((int32_t)111))}),
         DEFAULT_DIMENSION_KEY);
 
 MetricDimensionKey dimensionKey2(
-    HashableDimensionKey({FieldValue(Field(android::util::WAKELOCK_STATE_CHANGED,
+    HashableDimensionKey({FieldValue(Field(util::WAKELOCK_STATE_CHANGED,
                                            (int32_t)0x02010101), Value((int32_t)222))}),
     DEFAULT_DIMENSION_KEY);
 
diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
index 9e743f7..52229e2 100644
--- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
@@ -48,7 +48,7 @@
     countMetric->set_what(wakelockAcquireMatcher.id());
     *countMetric->mutable_dimensions_in_what() =
         CreateAttributionUidAndTagDimensions(
-            android::util::WAKELOCK_STATE_CHANGED, {position});
+            util::WAKELOCK_STATE_CHANGED, {position});
     countMetric->set_bucket(FIVE_MINUTES);
     return config;
 }
@@ -164,7 +164,7 @@
 
     auto data = countMetrics.data(0);
     ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
-                                          android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
+                                          util::WAKELOCK_STATE_CHANGED, 111, "App1");
     EXPECT_EQ(data.bucket_info_size(), 2);
     EXPECT_EQ(data.bucket_info(0).count(), 2);
     EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
@@ -176,7 +176,7 @@
 
     data = countMetrics.data(1);
     ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
-                                          android::util::WAKELOCK_STATE_CHANGED, 222,
+                                          util::WAKELOCK_STATE_CHANGED, 222,
                                           "GMSCoreModule1");
     EXPECT_EQ(data.bucket_info_size(), 2);
     EXPECT_EQ(data.bucket_info(0).count(), 1);
@@ -188,7 +188,7 @@
 
     data = countMetrics.data(2);
     ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
-                                          android::util::WAKELOCK_STATE_CHANGED, 222,
+                                          util::WAKELOCK_STATE_CHANGED, 222,
                                           "GMSCoreModule3");
     EXPECT_EQ(data.bucket_info_size(), 1);
     EXPECT_EQ(data.bucket_info(0).count(), 1);
@@ -198,7 +198,7 @@
 
     data = countMetrics.data(3);
     ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
-                                          android::util::WAKELOCK_STATE_CHANGED, 444,
+                                          util::WAKELOCK_STATE_CHANGED, 444,
                                           "GMSCoreModule2");
     EXPECT_EQ(data.bucket_info_size(), 1);
     EXPECT_EQ(data.bucket_info(0).count(), 1);
@@ -277,7 +277,7 @@
 
     auto data = countMetrics.data(0);
     ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
-                                          android::util::WAKELOCK_STATE_CHANGED, 222,
+                                          util::WAKELOCK_STATE_CHANGED, 222,
                                           "GMSCoreModule1");
     EXPECT_EQ(2, data.bucket_info_size());
     EXPECT_EQ(1, data.bucket_info(0).count());
@@ -289,26 +289,26 @@
     EXPECT_EQ(bucketStartTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(1);
-    ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 222);
+    ValidateUidDimension(data.dimensions_in_what(), 0, util::WAKELOCK_STATE_CHANGED, 222);
     ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
-                                          android::util::WAKELOCK_STATE_CHANGED, 222,
+                                          util::WAKELOCK_STATE_CHANGED, 222,
                                           "GMSCoreModule1");
-    ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333);
+    ValidateUidDimension(data.dimensions_in_what(), 1, util::WAKELOCK_STATE_CHANGED, 333);
     ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
-                                          android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
+                                          util::WAKELOCK_STATE_CHANGED, 333, "App3");
     EXPECT_EQ(data.bucket_info_size(), 1);
     EXPECT_EQ(data.bucket_info(0).count(), 1);
     EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
     EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
 
     data = countMetrics.data(2);
-    ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 444);
+    ValidateUidDimension(data.dimensions_in_what(), 0, util::WAKELOCK_STATE_CHANGED, 444);
     ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
-                                          android::util::WAKELOCK_STATE_CHANGED, 444,
+                                          util::WAKELOCK_STATE_CHANGED, 444,
                                           "GMSCoreModule2");
-    ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222);
+    ValidateUidDimension(data.dimensions_in_what(), 1, util::WAKELOCK_STATE_CHANGED, 222);
     ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
-                                          android::util::WAKELOCK_STATE_CHANGED, 222,
+                                          util::WAKELOCK_STATE_CHANGED, 222,
                                           "GMSCoreModule1");
     EXPECT_EQ(data.bucket_info_size(), 1);
     EXPECT_EQ(data.bucket_info(0).count(), 1);
@@ -317,31 +317,31 @@
     EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(3);
-    ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
+    ValidateUidDimension(data.dimensions_in_what(), 0, util::WAKELOCK_STATE_CHANGED, 111);
     ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
-                                          android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
-    ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222);
+                                          util::WAKELOCK_STATE_CHANGED, 111, "App1");
+    ValidateUidDimension(data.dimensions_in_what(), 1, util::WAKELOCK_STATE_CHANGED, 222);
     ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
-                                          android::util::WAKELOCK_STATE_CHANGED, 222,
+                                          util::WAKELOCK_STATE_CHANGED, 222,
                                           "GMSCoreModule1");
-    ValidateUidDimension(data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333);
+    ValidateUidDimension(data.dimensions_in_what(), 2, util::WAKELOCK_STATE_CHANGED, 333);
     ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 2,
-                                          android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
+                                          util::WAKELOCK_STATE_CHANGED, 333, "App3");
     EXPECT_EQ(data.bucket_info_size(), 1);
     EXPECT_EQ(data.bucket_info(0).count(), 1);
     EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(4);
-    ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
+    ValidateUidDimension(data.dimensions_in_what(), 0, util::WAKELOCK_STATE_CHANGED, 111);
     ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
-                                          android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
-    ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333);
+                                          util::WAKELOCK_STATE_CHANGED, 111, "App1");
+    ValidateUidDimension(data.dimensions_in_what(), 1, util::WAKELOCK_STATE_CHANGED, 333);
     ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
-                                          android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
-    ValidateUidDimension(data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 222);
+                                          util::WAKELOCK_STATE_CHANGED, 333, "App3");
+    ValidateUidDimension(data.dimensions_in_what(), 2, util::WAKELOCK_STATE_CHANGED, 222);
     ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 2,
-                                          android::util::WAKELOCK_STATE_CHANGED, 222,
+                                          util::WAKELOCK_STATE_CHANGED, 222,
                                           "GMSCoreModule1");
     EXPECT_EQ(data.bucket_info_size(), 1);
     EXPECT_EQ(data.bucket_info(0).count(), 1);
@@ -349,16 +349,16 @@
     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(5);
-    ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
+    ValidateUidDimension(data.dimensions_in_what(), 0, util::WAKELOCK_STATE_CHANGED, 111);
     ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
-                                          android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
-    ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 444);
+                                          util::WAKELOCK_STATE_CHANGED, 111, "App1");
+    ValidateUidDimension(data.dimensions_in_what(), 1, util::WAKELOCK_STATE_CHANGED, 444);
     ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
-                                          android::util::WAKELOCK_STATE_CHANGED, 444,
+                                          util::WAKELOCK_STATE_CHANGED, 444,
                                           "GMSCoreModule2");
-    ValidateUidDimension(data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333);
+    ValidateUidDimension(data.dimensions_in_what(), 2, util::WAKELOCK_STATE_CHANGED, 333);
     ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 2,
-                                          android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
+                                          util::WAKELOCK_STATE_CHANGED, 333, "App3");
     EXPECT_EQ(data.bucket_info_size(), 1);
     EXPECT_EQ(data.bucket_info(0).count(), 1);
     EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
diff --git a/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp b/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
index 102bb1e..16adbdd 100644
--- a/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
@@ -39,7 +39,7 @@
     countMetric->set_id(123456);
     countMetric->set_what(wakelockAcquireMatcher.id());
     *countMetric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
-            android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+            util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
     countMetric->set_bucket(FIVE_MINUTES);
 
     auto alert = config.add_alert();
@@ -74,12 +74,12 @@
     std::vector<int> attributionUids1 = {111};
     std::vector<string> attributionTags1 = {"App1"};
 
-    FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+    FieldValue fieldValue1(Field(util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
                            Value((int32_t)111));
     HashableDimensionKey whatKey1({fieldValue1});
     MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
 
-    FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+    FieldValue fieldValue2(Field(util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
                            Value((int32_t)222));
     HashableDimensionKey whatKey2({fieldValue2});
     MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY);
diff --git a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
index 2cd7854..69326cb 100644
--- a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
@@ -365,7 +365,7 @@
     config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
 
     auto appCrashMatcher =
-            CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", android::util::APP_CRASH_OCCURRED);
+            CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", util::APP_CRASH_OCCURRED);
     *config.add_atom_matcher() = appCrashMatcher;
 
     auto state = CreateUidProcessState();
@@ -381,7 +381,7 @@
     MetricStateLink* stateLink = countMetric->add_state_link();
     stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
     auto fieldsInWhat = stateLink->mutable_fields_in_what();
-    *fieldsInWhat = CreateDimensions(android::util::APP_CRASH_OCCURRED, {1 /*uid*/});
+    *fieldsInWhat = CreateDimensions(util::APP_CRASH_OCCURRED, {1 /*uid*/});
     auto fieldsInState = stateLink->mutable_fields_in_state();
     *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /*uid*/});
 
@@ -551,7 +551,7 @@
     config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
 
     auto appCrashMatcher =
-            CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", android::util::APP_CRASH_OCCURRED);
+            CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", util::APP_CRASH_OCCURRED);
     *config.add_atom_matcher() = appCrashMatcher;
 
     auto state1 = CreateScreenStateWithOnOffMap();
@@ -571,7 +571,7 @@
     MetricStateLink* stateLink = countMetric->add_state_link();
     stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
     auto fieldsInWhat = stateLink->mutable_fields_in_what();
-    *fieldsInWhat = CreateDimensions(android::util::APP_CRASH_OCCURRED, {1 /*uid*/});
+    *fieldsInWhat = CreateDimensions(util::APP_CRASH_OCCURRED, {1 /*uid*/});
     auto fieldsInState = stateLink->mutable_fields_in_state();
     *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /*uid*/});
 
diff --git a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
index b586b06..ae2a0f5 100644
--- a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
@@ -456,14 +456,14 @@
 
     auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
     // The predicate is dimensioning by first attribution node by uid.
-    FieldMatcher dimensions = CreateAttributionUidDimensions(android::util::WAKELOCK_STATE_CHANGED,
+    FieldMatcher dimensions = CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED,
                                                              {Position::FIRST});
     *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions;
     *config.add_predicate() = holdingWakelockPredicate;
 
     auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
     *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
-            CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
+            CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
     *config.add_predicate() = isInBackgroundPredicate;
 
     auto durationMetric = config.add_duration_metric();
@@ -473,17 +473,17 @@
     durationMetric->set_aggregation_type(DurationMetric::SUM);
     // The metric is dimensioning by first attribution node and only by uid.
     *durationMetric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
-            android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+            util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
     durationMetric->set_bucket(FIVE_MINUTES);
 
     // Links between wakelock state atom and condition of app is in background.
     auto links = durationMetric->add_links();
     links->set_condition(isInBackgroundPredicate.id());
     auto dimensionWhat = links->mutable_fields_in_what();
-    dimensionWhat->set_field(android::util::WAKELOCK_STATE_CHANGED);
+    dimensionWhat->set_field(util::WAKELOCK_STATE_CHANGED);
     dimensionWhat->add_child()->set_field(1);  // uid field.
     *links->mutable_fields_in_condition() = CreateAttributionUidDimensions(
-            android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
+            util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
 
     ConfigKey cfgKey;
     uint64_t bucketStartTimeNs = 10000000000;
@@ -536,7 +536,7 @@
     auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
     // Validate dimension value.
     ValidateAttributionUidDimension(data.dimensions_in_what(),
-                                    android::util::WAKELOCK_STATE_CHANGED, appUid);
+                                    util::WAKELOCK_STATE_CHANGED, appUid);
     // Validate bucket info.
     EXPECT_EQ(1, data.bucket_info_size());
 
@@ -558,14 +558,14 @@
 
     auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
     // The predicate is dimensioning by first attribution node by uid.
-    FieldMatcher dimensions = CreateAttributionUidDimensions(android::util::WAKELOCK_STATE_CHANGED,
+    FieldMatcher dimensions = CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED,
                                                              {Position::FIRST});
     *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions;
     *config.add_predicate() = holdingWakelockPredicate;
 
     auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
     *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
-            CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
+            CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
     *config.add_predicate() = isInBackgroundPredicate;
 
     auto durationMetric = config.add_duration_metric();
@@ -575,17 +575,17 @@
     durationMetric->set_aggregation_type(DurationMetric::SUM);
     // The metric is dimensioning by first attribution node and only by uid.
     *durationMetric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
-            android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+            util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
     durationMetric->set_bucket(FIVE_MINUTES);
 
     // Links between wakelock state atom and condition of app is in background.
     auto links = durationMetric->add_links();
     links->set_condition(isInBackgroundPredicate.id());
     auto dimensionWhat = links->mutable_fields_in_what();
-    dimensionWhat->set_field(android::util::WAKELOCK_STATE_CHANGED);
+    dimensionWhat->set_field(util::WAKELOCK_STATE_CHANGED);
     dimensionWhat->add_child()->set_field(1);  // uid field.
     *links->mutable_fields_in_condition() = CreateAttributionUidDimensions(
-            android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
+            util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
 
     auto metric_activation1 = config.add_metric_activation();
     metric_activation1->set_metric_id(durationMetric->id());
@@ -694,7 +694,7 @@
     auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
     // Validate dimension value.
     ValidateAttributionUidDimension(data.dimensions_in_what(),
-                                    android::util::WAKELOCK_STATE_CHANGED, appUid);
+                                    util::WAKELOCK_STATE_CHANGED, appUid);
     // Validate bucket info.
     EXPECT_EQ(2, data.bucket_info_size());
 
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
index 594c1e6..ca4de6d 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
@@ -32,7 +32,7 @@
 namespace {
 
 const int64_t metricId = 123456;
-const int32_t ATOM_TAG = android::util::SUBSYSTEM_SLEEP_STATE;
+const int32_t ATOM_TAG = util::SUBSYSTEM_SLEEP_STATE;
 
 StatsdConfig CreateStatsdConfig(const GaugeMetric::SamplingType sampling_type,
                                 bool useCondition = true) {
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
index 6e3d93a..81e1c05 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
@@ -35,12 +35,12 @@
     *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
     *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
 
-    auto atomMatcher = CreateSimpleAtomMatcher("", android::util::APP_START_OCCURRED);
+    auto atomMatcher = CreateSimpleAtomMatcher("", util::APP_START_OCCURRED);
     *config.add_atom_matcher() = atomMatcher;
 
     auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
     *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
-        CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */ });
+        CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */ });
     *config.add_predicate() = isInBackgroundPredicate;
 
     auto gaugeMetric = config.add_gauge_metric();
@@ -50,21 +50,21 @@
     gaugeMetric->mutable_gauge_fields_filter()->set_include_all(false);
     gaugeMetric->set_sampling_type(sampling_type);
     auto fieldMatcher = gaugeMetric->mutable_gauge_fields_filter()->mutable_fields();
-    fieldMatcher->set_field(android::util::APP_START_OCCURRED);
+    fieldMatcher->set_field(util::APP_START_OCCURRED);
     fieldMatcher->add_child()->set_field(3);  // type (enum)
     fieldMatcher->add_child()->set_field(4);  // activity_name(str)
     fieldMatcher->add_child()->set_field(7);  // activity_start_msec(int64)
     *gaugeMetric->mutable_dimensions_in_what() =
-        CreateDimensions(android::util::APP_START_OCCURRED, {1 /* uid field */ });
+        CreateDimensions(util::APP_START_OCCURRED, {1 /* uid field */ });
     gaugeMetric->set_bucket(FIVE_MINUTES);
 
     auto links = gaugeMetric->add_links();
     links->set_condition(isInBackgroundPredicate.id());
     auto dimensionWhat = links->mutable_fields_in_what();
-    dimensionWhat->set_field(android::util::APP_START_OCCURRED);
+    dimensionWhat->set_field(util::APP_START_OCCURRED);
     dimensionWhat->add_child()->set_field(1);  // uid field.
     auto dimensionCondition = links->mutable_fields_in_condition();
-    dimensionCondition->set_field(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED);
+    dimensionCondition->set_field(util::ACTIVITY_FOREGROUND_STATE_CHANGED);
     dimensionCondition->add_child()->set_field(1);  // uid field.
     return config;
 }
@@ -74,7 +74,7 @@
         AppStartOccurred::TransitionType type, const string& activity_name,
         const string& calling_pkg_name, const bool is_instant_app, int64_t activity_start_msec) {
     AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, android::util::APP_START_OCCURRED);
+    AStatsEvent_setAtomId(statsEvent, util::APP_START_OCCURRED);
     AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
 
     AStatsEvent_writeInt32(statsEvent, uid);
@@ -173,7 +173,7 @@
         EXPECT_EQ(2, gaugeMetrics.data_size());
 
         auto data = gaugeMetrics.data(0);
-        EXPECT_EQ(android::util::APP_START_OCCURRED, data.dimensions_in_what().field());
+        EXPECT_EQ(util::APP_START_OCCURRED, data.dimensions_in_what().field());
         EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
         EXPECT_EQ(1 /* uid field */,
                   data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -272,7 +272,7 @@
 
         data = gaugeMetrics.data(1);
 
-        EXPECT_EQ(data.dimensions_in_what().field(), android::util::APP_START_OCCURRED);
+        EXPECT_EQ(data.dimensions_in_what().field(), util::APP_START_OCCURRED);
         EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
         EXPECT_EQ(1 /* uid field */,
                   data.dimensions_in_what().value_tuple().dimensions_value(0).field());
diff --git a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
index 1dd90e2..f1e2744 100644
--- a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
@@ -45,7 +45,7 @@
     countMetric->set_what(crashMatcher.id());
     countMetric->set_bucket(FIVE_MINUTES);
     countMetric->mutable_dimensions_in_what()->set_field(
-        android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
+        util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
     countMetric->mutable_dimensions_in_what()->add_child()->set_field(1);  // uid field
 
     auto metric_activation1 = config.add_metric_activation();
@@ -79,7 +79,7 @@
     countMetric->set_what(crashMatcher.id());
     countMetric->set_bucket(FIVE_MINUTES);
     countMetric->mutable_dimensions_in_what()->set_field(
-        android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
+        util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
     countMetric->mutable_dimensions_in_what()->add_child()->set_field(1);  // uid field
 
     auto metric_activation1 = config.add_metric_activation();
@@ -117,7 +117,7 @@
     countMetric->set_what(crashMatcher.id());
     countMetric->set_bucket(FIVE_MINUTES);
     countMetric->mutable_dimensions_in_what()->set_field(
-        android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
+        util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
     countMetric->mutable_dimensions_in_what()->add_child()->set_field(1);  // uid field
 
     auto metric_activation1 = config.add_metric_activation();
@@ -153,7 +153,7 @@
     countMetric->set_what(crashMatcher.id());
     countMetric->set_bucket(FIVE_MINUTES);
     countMetric->mutable_dimensions_in_what()->set_field(
-        android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
+        util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
     countMetric->mutable_dimensions_in_what()->add_child()->set_field(1);  // uid field
 
     auto metric_activation1 = config.add_metric_activation();
@@ -194,7 +194,7 @@
     countMetric->set_what(crashMatcher.id());
     countMetric->set_bucket(FIVE_MINUTES);
     countMetric->mutable_dimensions_in_what()->set_field(
-        android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
+        util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
     countMetric->mutable_dimensions_in_what()->add_child()->set_field(1);  // uid field
 
     int64_t metricId2 = 234567;
@@ -203,7 +203,7 @@
     countMetric->set_what(foregroundMatcher.id());
     countMetric->set_bucket(FIVE_MINUTES);
     countMetric->mutable_dimensions_in_what()->set_field(
-        android::util::ACTIVITY_FOREGROUND_STATE_CHANGED);
+        util::ACTIVITY_FOREGROUND_STATE_CHANGED);
     countMetric->mutable_dimensions_in_what()->add_child()->set_field(1);  // uid field
 
     auto metric_activation1 = config.add_metric_activation();
@@ -398,7 +398,7 @@
     EXPECT_EQ(4, countMetrics.data_size());
 
     auto data = countMetrics.data(0);
-    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -409,7 +409,7 @@
     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(1);
-    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -420,7 +420,7 @@
     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(2);
-    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -433,7 +433,7 @@
               data.bucket_info(0).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(3);
-    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -706,7 +706,7 @@
     EXPECT_EQ(5, countMetrics.data_size());
 
     auto data = countMetrics.data(0);
-    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -717,7 +717,7 @@
     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(1);
-    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -728,7 +728,7 @@
     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(2);
-    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -741,7 +741,7 @@
               data.bucket_info(0).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(3);
-    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -754,7 +754,7 @@
               data.bucket_info(0).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(4);
-    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -1040,7 +1040,7 @@
     EXPECT_EQ(5, countMetrics.data_size());
 
     auto data = countMetrics.data(0);
-    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -1051,7 +1051,7 @@
     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(1);
-    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -1062,7 +1062,7 @@
     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(2);
-    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -1075,7 +1075,7 @@
               data.bucket_info(0).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(3);
-    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -1088,7 +1088,7 @@
               data.bucket_info(0).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(4);
-    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -1264,7 +1264,7 @@
     EXPECT_EQ(3, countMetrics.data_size());
 
     auto data = countMetrics.data(0);
-    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -1275,7 +1275,7 @@
     EXPECT_EQ(firstDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(1);
-    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -1286,7 +1286,7 @@
     EXPECT_EQ(firstDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(2);
-    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -1704,7 +1704,7 @@
     EXPECT_EQ(5, countMetrics.data_size());
 
     auto data = countMetrics.data(0);
-    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -1715,7 +1715,7 @@
     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(1);
-    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -1726,7 +1726,7 @@
     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(2);
-    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -1739,7 +1739,7 @@
               data.bucket_info(0).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(3);
-    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -1752,7 +1752,7 @@
               data.bucket_info(0).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(4);
-    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -1769,7 +1769,7 @@
     EXPECT_EQ(5, countMetrics.data_size());
 
     data = countMetrics.data(0);
-    EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -1780,7 +1780,7 @@
     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(1);
-    EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -1791,7 +1791,7 @@
     EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(2);
-    EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -1804,7 +1804,7 @@
               data.bucket_info(0).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(3);
-    EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -1817,7 +1817,7 @@
               data.bucket_info(0).end_bucket_elapsed_nanos());
 
     data = countMetrics.data(4);
-    EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* uid field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
index e8fb523..f0df2c6 100644
--- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
@@ -48,12 +48,12 @@
     auto isSyncingPredicate = CreateIsSyncingPredicate();
     auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
     *syncDimension = CreateAttributionUidDimensions(
-        android::util::SYNC_STATE_CHANGED, {Position::FIRST});
+        util::SYNC_STATE_CHANGED, {Position::FIRST});
     syncDimension->add_child()->set_field(2 /* name field*/);
 
     auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
     *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
-        CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */ });
+        CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */ });
 
     *config.add_predicate() = screenIsOffPredicate;
     *config.add_predicate() = isSyncingPredicate;
@@ -72,26 +72,26 @@
     countMetric->set_condition(combinationPredicate->id());
     // The metric is dimensioning by uid only.
     *countMetric->mutable_dimensions_in_what() =
-        CreateDimensions(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, {1});
+        CreateDimensions(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, {1});
     countMetric->set_bucket(FIVE_MINUTES);
 
     // Links between crash atom and condition of app is in syncing.
     auto links = countMetric->add_links();
     links->set_condition(isSyncingPredicate.id());
     auto dimensionWhat = links->mutable_fields_in_what();
-    dimensionWhat->set_field(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
+    dimensionWhat->set_field(util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
     dimensionWhat->add_child()->set_field(1);  // uid field.
     *links->mutable_fields_in_condition() = CreateAttributionUidDimensions(
-            android::util::SYNC_STATE_CHANGED, {Position::FIRST});
+            util::SYNC_STATE_CHANGED, {Position::FIRST});
 
     // Links between crash atom and condition of app is in background.
     links = countMetric->add_links();
     links->set_condition(isInBackgroundPredicate.id());
     dimensionWhat = links->mutable_fields_in_what();
-    dimensionWhat->set_field(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
+    dimensionWhat->set_field(util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
     dimensionWhat->add_child()->set_field(1);  // uid field.
     auto dimensionCondition = links->mutable_fields_in_condition();
-    dimensionCondition->set_field(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED);
+    dimensionCondition->set_field(util::ACTIVITY_FOREGROUND_STATE_CHANGED);
     dimensionCondition->add_child()->set_field(1);  // uid field.
     return config;
 }
@@ -211,7 +211,7 @@
     EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
     auto data = reports.reports(0).metrics(0).count_metrics().data(0);
     // Validate dimension value.
-    EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
+    EXPECT_EQ(data.dimensions_in_what().field(), util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
     // Uid field.
     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
@@ -332,7 +332,7 @@
     EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(1).count(), 3);
     auto data = reports.reports(0).metrics(0).count_metrics().data(0);
     // Validate dimension value.
-    EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
+    EXPECT_EQ(data.dimensions_in_what().field(), util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
     // Uid field.
     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
index b975907..371a346 100644
--- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -73,7 +73,7 @@
     config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
 
     auto pulledAtomMatcher =
-            CreateSimpleAtomMatcher("TestMatcher", android::util::SUBSYSTEM_SLEEP_STATE);
+            CreateSimpleAtomMatcher("TestMatcher", util::SUBSYSTEM_SLEEP_STATE);
     *config.add_atom_matcher() = pulledAtomMatcher;
     *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
     *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
@@ -82,9 +82,9 @@
     valueMetric->set_id(123456);
     valueMetric->set_what(pulledAtomMatcher.id());
     *valueMetric->mutable_value_field() =
-            CreateDimensions(android::util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
+            CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
     *valueMetric->mutable_dimensions_in_what() =
-            CreateDimensions(android::util::SUBSYSTEM_SLEEP_STATE, {1 /* subsystem name */});
+            CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {1 /* subsystem name */});
     valueMetric->set_bucket(FIVE_MINUTES);
     valueMetric->set_min_bucket_size_nanos(minTime);
     valueMetric->set_use_absolute_value_on_reset(true);
@@ -96,7 +96,7 @@
     config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
 
     auto pulledAtomMatcher =
-                CreateSimpleAtomMatcher("TestMatcher", android::util::SUBSYSTEM_SLEEP_STATE);
+                CreateSimpleAtomMatcher("TestMatcher", util::SUBSYSTEM_SLEEP_STATE);
     *config.add_atom_matcher() = pulledAtomMatcher;
     *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
     *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
@@ -106,7 +106,7 @@
     gaugeMetric->set_what(pulledAtomMatcher.id());
     gaugeMetric->mutable_gauge_fields_filter()->set_include_all(true);
     *gaugeMetric->mutable_dimensions_in_what() =
-            CreateDimensions(android::util::SUBSYSTEM_SLEEP_STATE, {1 /* subsystem name */});
+            CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {1 /* subsystem name */});
     gaugeMetric->set_bucket(FIVE_MINUTES);
     gaugeMetric->set_min_bucket_size_nanos(minTime);
     return config;
@@ -218,7 +218,7 @@
 TEST(PartialBucketE2eTest, TestValueMetricWithoutMinPartialBucket) {
     shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
     service->mPullerManager->RegisterPullAtomCallback(
-            /*uid=*/0, android::util::SUBSYSTEM_SLEEP_STATE, NS_PER_SEC, NS_PER_SEC * 10, {},
+            /*uid=*/0, util::SUBSYSTEM_SLEEP_STATE, NS_PER_SEC, NS_PER_SEC * 10, {},
             SharedRefBase::make<FakeSubsystemSleepCallback>());
     // Partial buckets don't occur when app is first installed.
     service->mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
@@ -239,7 +239,7 @@
 TEST(PartialBucketE2eTest, TestValueMetricWithMinPartialBucket) {
     shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
     service->mPullerManager->RegisterPullAtomCallback(
-            /*uid=*/0, android::util::SUBSYSTEM_SLEEP_STATE, NS_PER_SEC, NS_PER_SEC * 10, {},
+            /*uid=*/0, util::SUBSYSTEM_SLEEP_STATE, NS_PER_SEC, NS_PER_SEC * 10, {},
             SharedRefBase::make<FakeSubsystemSleepCallback>());
     // Partial buckets don't occur when app is first installed.
     service->mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
index a87bb71..a5ef733 100644
--- a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
@@ -37,7 +37,7 @@
     StatsdConfig config;
     config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
     auto pulledAtomMatcher =
-            CreateSimpleAtomMatcher("TestMatcher", android::util::SUBSYSTEM_SLEEP_STATE);
+            CreateSimpleAtomMatcher("TestMatcher", util::SUBSYSTEM_SLEEP_STATE);
     *config.add_atom_matcher() = pulledAtomMatcher;
     *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
     *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
@@ -52,9 +52,9 @@
         valueMetric->set_condition(screenIsOffPredicate.id());
     }
     *valueMetric->mutable_value_field() =
-            CreateDimensions(android::util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
+            CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
     *valueMetric->mutable_dimensions_in_what() =
-            CreateDimensions(android::util::SUBSYSTEM_SLEEP_STATE, {1 /* subsystem name */});
+            CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {1 /* subsystem name */});
     valueMetric->set_bucket(FIVE_MINUTES);
     valueMetric->set_use_absolute_value_on_reset(true);
     valueMetric->set_skip_zero_diff_output(false);
@@ -73,7 +73,7 @@
     ConfigKey cfgKey;
     auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
                                              SharedRefBase::make<FakeSubsystemSleepCallback>(),
-                                             android::util::SUBSYSTEM_SLEEP_STATE);
+                                             util::SUBSYSTEM_SLEEP_STATE);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
     processor->mPullerManager->ForceClearPullerCache();
@@ -142,7 +142,7 @@
     EXPECT_GT((int)valueMetrics.data_size(), 1);
 
     auto data = valueMetrics.data(0);
-    EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
+    EXPECT_EQ(util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* subsystem name field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -177,7 +177,7 @@
     ConfigKey cfgKey;
     auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
                                              SharedRefBase::make<FakeSubsystemSleepCallback>(),
-                                             android::util::SUBSYSTEM_SLEEP_STATE);
+                                             util::SUBSYSTEM_SLEEP_STATE);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
     processor->mPullerManager->ForceClearPullerCache();
@@ -250,7 +250,7 @@
     EXPECT_GT((int)valueMetrics.data_size(), 1);
 
     auto data = valueMetrics.data(0);
-    EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
+    EXPECT_EQ(util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* subsystem name field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -289,7 +289,7 @@
     ConfigKey cfgKey;
     auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
                                              SharedRefBase::make<FakeSubsystemSleepCallback>(),
-                                             android::util::SUBSYSTEM_SLEEP_STATE);
+                                             util::SUBSYSTEM_SLEEP_STATE);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
     processor->mPullerManager->ForceClearPullerCache();
@@ -353,7 +353,7 @@
     EXPECT_GT((int)valueMetrics.data_size(), 0);
 
     auto data = valueMetrics.data(0);
-    EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
+    EXPECT_EQ(util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
     EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
     EXPECT_EQ(1 /* subsystem name field */,
               data.dimensions_in_what().value_tuple().dimensions_value(0).field());
@@ -383,7 +383,7 @@
     config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
 
     auto pulledAtomMatcher =
-            CreateSimpleAtomMatcher("TestMatcher", android::util::SUBSYSTEM_SLEEP_STATE);
+            CreateSimpleAtomMatcher("TestMatcher", util::SUBSYSTEM_SLEEP_STATE);
     *config.add_atom_matcher() = pulledAtomMatcher;
 
     auto screenState = CreateScreenState();
@@ -396,7 +396,7 @@
     valueMetric->set_bucket(TimeUnit::FIVE_MINUTES);
     valueMetric->set_what(pulledAtomMatcher.id());
     *valueMetric->mutable_value_field() =
-            CreateDimensions(android::util::CPU_TIME_PER_UID, {2 /* user_time_micros */});
+            CreateDimensions(util::CPU_TIME_PER_UID, {2 /* user_time_micros */});
     valueMetric->add_slice_by_state(screenState.id());
     valueMetric->set_max_pull_delay_sec(INT_MAX);
 
@@ -437,7 +437,7 @@
     config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
 
     auto cpuTimePerUidMatcher =
-            CreateSimpleAtomMatcher("CpuTimePerUidMatcher", android::util::CPU_TIME_PER_UID);
+            CreateSimpleAtomMatcher("CpuTimePerUidMatcher", util::CPU_TIME_PER_UID);
     *config.add_atom_matcher() = cpuTimePerUidMatcher;
 
     auto uidProcessState = CreateUidProcessState();
@@ -450,14 +450,14 @@
     valueMetric->set_bucket(TimeUnit::FIVE_MINUTES);
     valueMetric->set_what(cpuTimePerUidMatcher.id());
     *valueMetric->mutable_value_field() =
-            CreateDimensions(android::util::CPU_TIME_PER_UID, {2 /* user_time_micros */});
+            CreateDimensions(util::CPU_TIME_PER_UID, {2 /* user_time_micros */});
     *valueMetric->mutable_dimensions_in_what() =
-            CreateDimensions(android::util::CPU_TIME_PER_UID, {1 /* uid */});
+            CreateDimensions(util::CPU_TIME_PER_UID, {1 /* uid */});
     valueMetric->add_slice_by_state(uidProcessState.id());
     MetricStateLink* stateLink = valueMetric->add_state_link();
     stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
     auto fieldsInWhat = stateLink->mutable_fields_in_what();
-    *fieldsInWhat = CreateDimensions(android::util::CPU_TIME_PER_UID, {1 /* uid */});
+    *fieldsInWhat = CreateDimensions(util::CPU_TIME_PER_UID, {1 /* uid */});
     auto fieldsInState = stateLink->mutable_fields_in_state();
     *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
     valueMetric->set_max_pull_delay_sec(INT_MAX);
@@ -497,7 +497,7 @@
     config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
 
     auto cpuTimePerUidMatcher =
-            CreateSimpleAtomMatcher("CpuTimePerUidMatcher", android::util::CPU_TIME_PER_UID);
+            CreateSimpleAtomMatcher("CpuTimePerUidMatcher", util::CPU_TIME_PER_UID);
     *config.add_atom_matcher() = cpuTimePerUidMatcher;
 
     auto uidProcessState = CreateUidProcessState();
@@ -510,12 +510,12 @@
     valueMetric->set_bucket(TimeUnit::FIVE_MINUTES);
     valueMetric->set_what(cpuTimePerUidMatcher.id());
     *valueMetric->mutable_value_field() =
-            CreateDimensions(android::util::CPU_TIME_PER_UID, {2 /* user_time_micros */});
+            CreateDimensions(util::CPU_TIME_PER_UID, {2 /* user_time_micros */});
     valueMetric->add_slice_by_state(uidProcessState.id());
     MetricStateLink* stateLink = valueMetric->add_state_link();
     stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
     auto fieldsInWhat = stateLink->mutable_fields_in_what();
-    *fieldsInWhat = CreateDimensions(android::util::CPU_TIME_PER_UID, {1 /* uid */});
+    *fieldsInWhat = CreateDimensions(util::CPU_TIME_PER_UID, {1 /* uid */});
     auto fieldsInState = stateLink->mutable_fields_in_state();
     *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
     valueMetric->set_max_pull_delay_sec(INT_MAX);
diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
index ddd8f95..80f3c28 100644
--- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
@@ -42,7 +42,7 @@
     auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
     // The predicate is dimensioning by any attribution node and both by uid and tag.
     FieldMatcher dimensions = CreateAttributionUidAndTagDimensions(
-            android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST, Position::LAST});
+            util::WAKELOCK_STATE_CHANGED, {Position::FIRST, Position::LAST});
     // Also slice by the wakelock tag
     dimensions.add_child()->set_field(3);  // The wakelock tag is set in field 3 of the wakelock.
     *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions;
@@ -56,7 +56,7 @@
     // The metric is dimensioning by first attribution node and only by uid.
     *durationMetric->mutable_dimensions_in_what() =
         CreateAttributionUidDimensions(
-            android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+            util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
     durationMetric->set_bucket(FIVE_MINUTES);
     return config;
 }
@@ -142,7 +142,7 @@
     auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
     // Validate dimension value.
     ValidateAttributionUidDimension(data.dimensions_in_what(),
-                                    android::util::WAKELOCK_STATE_CHANGED, 111);
+                                    util::WAKELOCK_STATE_CHANGED, 111);
     // Validate bucket info.
     EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1);
     data = reports.reports(0).metrics(0).duration_metrics().data(0);
@@ -178,7 +178,7 @@
     auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
     // Validate dimension value.
     ValidateAttributionUidDimension(data.dimensions_in_what(),
-                                    android::util::WAKELOCK_STATE_CHANGED, 111);
+                                    util::WAKELOCK_STATE_CHANGED, 111);
     // Two output buckets.
     // The wakelock holding interval in the 1st bucket starts from the screen off event and to
     // the end of the 1st bucket.
@@ -228,7 +228,7 @@
     EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 6);
     auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
     ValidateAttributionUidDimension(data.dimensions_in_what(),
-                                    android::util::WAKELOCK_STATE_CHANGED, 111);
+                                    util::WAKELOCK_STATE_CHANGED, 111);
     // The last wakelock holding spans 4 buckets.
     EXPECT_EQ((unsigned long long)data.bucket_info(2).duration_nanos(), bucketSizeNs - 100);
     EXPECT_EQ((unsigned long long)data.bucket_info(3).duration_nanos(), bucketSizeNs);
@@ -293,7 +293,7 @@
     auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
     // Validate dimension value.
     ValidateAttributionUidDimension(data.dimensions_in_what(),
-                                    android::util::WAKELOCK_STATE_CHANGED, 111);
+                                    util::WAKELOCK_STATE_CHANGED, 111);
     // The max is acquire event for wl1 to screen off start.
     EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), bucketSizeNs + 2 - 200);
 }
@@ -337,7 +337,7 @@
     EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2);
     auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
     ValidateAttributionUidDimension(data.dimensions_in_what(),
-                                    android::util::WAKELOCK_STATE_CHANGED, 111);
+                                    util::WAKELOCK_STATE_CHANGED, 111);
     // The last wakelock holding spans 4 buckets.
     EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 3 * bucketSizeNs);
     EXPECT_EQ((unsigned long long)data.bucket_info(1).start_bucket_elapsed_nanos(),
diff --git a/cmds/statsd/tests/external/puller_util_test.cpp b/cmds/statsd/tests/external/puller_util_test.cpp
index f21954f2..15425d8 100644
--- a/cmds/statsd/tests/external/puller_util_test.cpp
+++ b/cmds/statsd/tests/external/puller_util_test.cpp
@@ -22,7 +22,7 @@
 
 #include "../metrics/metrics_test_helper.h"
 #include "stats_event.h"
-#include "statslog.h"
+#include "statslog_statsdtest.h"
 
 #ifdef __ANDROID__
 
@@ -39,9 +39,9 @@
  * Test merge isolated and host uid
  */
 namespace {
-int uidAtomTagId = android::util::CPU_CLUSTER_TIME;
+int uidAtomTagId = util::CPU_CLUSTER_TIME;
 const vector<int> uidAdditiveFields = {3};
-int nonUidAtomTagId = android::util::SYSTEM_UPTIME;
+int nonUidAtomTagId = util::SYSTEM_UPTIME;
 int timestamp = 1234;
 int isolatedUid = 30;
 int isolatedAdditiveData = 31;
diff --git a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
index 2a43d9b..00e8397 100644
--- a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
+++ b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 #include "src/guardrail/StatsdStats.h"
-#include "statslog.h"
+#include "statslog_statsdtest.h"
 #include "tests/statsd_test_util.h"
 
 #include <gtest/gtest.h>
@@ -222,11 +222,11 @@
     StatsdStats stats;
     time_t now = time(nullptr);
     // old event, we get it from the stats buffer. should be ignored.
-    stats.noteAtomLogged(android::util::SENSOR_STATE_CHANGED, 1000);
+    stats.noteAtomLogged(util::SENSOR_STATE_CHANGED, 1000);
 
-    stats.noteAtomLogged(android::util::SENSOR_STATE_CHANGED, now + 1);
-    stats.noteAtomLogged(android::util::SENSOR_STATE_CHANGED, now + 2);
-    stats.noteAtomLogged(android::util::APP_CRASH_OCCURRED, now + 3);
+    stats.noteAtomLogged(util::SENSOR_STATE_CHANGED, now + 1);
+    stats.noteAtomLogged(util::SENSOR_STATE_CHANGED, now + 2);
+    stats.noteAtomLogged(util::APP_CRASH_OCCURRED, now + 3);
 
     vector<uint8_t> output;
     stats.dumpStats(&output, false);
@@ -239,10 +239,10 @@
     bool dropboxAtomGood = false;
 
     for (const auto& atomStats : report.atom_stats()) {
-        if (atomStats.tag() == android::util::SENSOR_STATE_CHANGED && atomStats.count() == 3) {
+        if (atomStats.tag() == util::SENSOR_STATE_CHANGED && atomStats.count() == 3) {
             sensorAtomGood = true;
         }
-        if (atomStats.tag() == android::util::APP_CRASH_OCCURRED && atomStats.count() == 1) {
+        if (atomStats.tag() == util::APP_CRASH_OCCURRED && atomStats.count() == 1) {
             dropboxAtomGood = true;
         }
     }
@@ -287,21 +287,21 @@
 TEST(StatsdStatsTest, TestPullAtomStats) {
     StatsdStats stats;
 
-    stats.updateMinPullIntervalSec(android::util::DISK_SPACE, 3333L);
-    stats.updateMinPullIntervalSec(android::util::DISK_SPACE, 2222L);
-    stats.updateMinPullIntervalSec(android::util::DISK_SPACE, 4444L);
+    stats.updateMinPullIntervalSec(util::DISK_SPACE, 3333L);
+    stats.updateMinPullIntervalSec(util::DISK_SPACE, 2222L);
+    stats.updateMinPullIntervalSec(util::DISK_SPACE, 4444L);
 
-    stats.notePull(android::util::DISK_SPACE);
-    stats.notePullTime(android::util::DISK_SPACE, 1111L);
-    stats.notePullDelay(android::util::DISK_SPACE, 1111L);
-    stats.notePull(android::util::DISK_SPACE);
-    stats.notePullTime(android::util::DISK_SPACE, 3333L);
-    stats.notePullDelay(android::util::DISK_SPACE, 3335L);
-    stats.notePull(android::util::DISK_SPACE);
-    stats.notePullFromCache(android::util::DISK_SPACE);
-    stats.notePullerCallbackRegistrationChanged(android::util::DISK_SPACE, true);
-    stats.notePullerCallbackRegistrationChanged(android::util::DISK_SPACE, false);
-    stats.notePullerCallbackRegistrationChanged(android::util::DISK_SPACE, true);
+    stats.notePull(util::DISK_SPACE);
+    stats.notePullTime(util::DISK_SPACE, 1111L);
+    stats.notePullDelay(util::DISK_SPACE, 1111L);
+    stats.notePull(util::DISK_SPACE);
+    stats.notePullTime(util::DISK_SPACE, 3333L);
+    stats.notePullDelay(util::DISK_SPACE, 3335L);
+    stats.notePull(util::DISK_SPACE);
+    stats.notePullFromCache(util::DISK_SPACE);
+    stats.notePullerCallbackRegistrationChanged(util::DISK_SPACE, true);
+    stats.notePullerCallbackRegistrationChanged(util::DISK_SPACE, false);
+    stats.notePullerCallbackRegistrationChanged(util::DISK_SPACE, true);
 
 
     vector<uint8_t> output;
@@ -312,7 +312,7 @@
 
     EXPECT_EQ(1, report.pulled_atom_stats_size());
 
-    EXPECT_EQ(android::util::DISK_SPACE, report.pulled_atom_stats(0).atom_id());
+    EXPECT_EQ(util::DISK_SPACE, report.pulled_atom_stats(0).atom_id());
     EXPECT_EQ(3, report.pulled_atom_stats(0).total_pull());
     EXPECT_EQ(1, report.pulled_atom_stats(0).total_pull_from_cache());
     EXPECT_EQ(2222L, report.pulled_atom_stats(0).min_pull_interval_sec());
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 27addc7..fab8e68 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -432,1203 +432,1060 @@
     EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second.back().mConditionTrueNs);
 }
 
-///*
-// * Tests pulled atoms with no conditions and take absolute value after reset
-// */
-// TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) {
-//    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-//    metric.set_use_absolute_value_on_reset(true);
-//
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//    EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(true));
-//    sp<ValueMetricProducer> valueProducer =
-//            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
-//
-//    vector<shared_ptr<LogEvent>> allData;
-//    allData.clear();
-//    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-//    event->write(tagId);
-//    event->write(11);
-//    event->init();
-//    allData.push_back(event);
-//
-//    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-//    ValueMetricProducer::Interval curInterval =
-//    valueProducer->mCurrentSlicedBucket.begin()->second[0]; ValueMetricProducer::BaseInfo
-//    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
-//
-//    EXPECT_EQ(true, curBaseInfo.hasBase);
-//    EXPECT_EQ(11, curBaseInfo.base.long_value);
-//    EXPECT_EQ(false, curInterval.hasValue);
-//    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
-//
-//    allData.clear();
-//    event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
-//    event->write(tagId);
-//    event->write(10);
-//    event->init();
-//    allData.push_back(event);
-//    valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-//    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
-//    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
-//    EXPECT_EQ(true, curBaseInfo.hasBase);
-//    EXPECT_EQ(10, curBaseInfo.base.long_value);
-//    EXPECT_EQ(false, curInterval.hasValue);
-//    EXPECT_EQ(10, curInterval.value.long_value);
-//    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
-//    EXPECT_EQ(10, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
-//    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second.back().mConditionTrueNs);
-//
-//    allData.clear();
-//    event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
-//    event->write(tagId);
-//    event->write(36);
-//    event->init();
-//    allData.push_back(event);
-//    valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
-//    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-//    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
-//    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
-//    EXPECT_EQ(true, curBaseInfo.hasBase);
-//    EXPECT_EQ(36, curBaseInfo.base.long_value);
-//    EXPECT_EQ(false, curInterval.hasValue);
-//    EXPECT_EQ(26, curInterval.value.long_value);
-//    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
-//    EXPECT_EQ(2UL, valueProducer->mPastBuckets.begin()->second.size());
-//    EXPECT_EQ(10, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
-//    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
-//    EXPECT_EQ(26, valueProducer->mPastBuckets.begin()->second[1].values[0].long_value);
-//    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[1].mConditionTrueNs);
-//}
-//
-///*
-// * Tests pulled atoms with no conditions and take zero value after reset
-// */
-// TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) {
-//    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//    EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false));
-//    sp<ValueMetricProducer> valueProducer =
-//            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
-//
-//    vector<shared_ptr<LogEvent>> allData;
-//    allData.clear();
-//    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-//    event->write(tagId);
-//    event->write(11);
-//    event->init();
-//    allData.push_back(event);
-//
-//    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-//    ValueMetricProducer::Interval curInterval =
-//    valueProducer->mCurrentSlicedBucket.begin()->second[0]; ValueMetricProducer::BaseInfo
-//    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
-//
-//    EXPECT_EQ(true, curBaseInfo.hasBase);
-//    EXPECT_EQ(11, curBaseInfo.base.long_value);
-//    EXPECT_EQ(false, curInterval.hasValue);
-//    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
-//
-//    allData.clear();
-//    event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
-//    event->write(tagId);
-//    event->write(10);
-//    event->init();
-//    allData.push_back(event);
-//    valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-//    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
-//    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
-//    EXPECT_EQ(true, curBaseInfo.hasBase);
-//    EXPECT_EQ(10, curBaseInfo.base.long_value);
-//    EXPECT_EQ(false, curInterval.hasValue);
-//    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
-//
-//    allData.clear();
-//    event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
-//    event->write(tagId);
-//    event->write(36);
-//    event->init();
-//    allData.push_back(event);
-//    valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
-//    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-//    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
-//    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
-//    EXPECT_EQ(true, curBaseInfo.hasBase);
-//    EXPECT_EQ(36, curBaseInfo.base.long_value);
-//    EXPECT_EQ(false, curInterval.hasValue);
-//    EXPECT_EQ(26, curInterval.value.long_value);
-//    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
-//    EXPECT_EQ(26, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
-//    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
-//}
-//
-///*
-// * Test pulled event with non sliced condition.
-// */
-// TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
-//    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-//
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//
-//    EXPECT_CALL(*pullerManager, Pull(tagId, _))
-//            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-//                data->clear();
-//                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
-//                event->write(tagId);
-//                event->write(100);
-//                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, bucket2StartTimeNs + 1);
-//                event->write(tagId);
-//                event->write(130);
-//                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, bucket3StartTimeNs + 1);
-//                event->write(tagId);
-//                event->write(180);
-//                event->init();
-//                data->push_back(event);
-//                return true;
-//            }));
-//
-//    sp<ValueMetricProducer> valueProducer =
-//            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager,
-//            metric);
-//
-//    valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
-//
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-//    ValueMetricProducer::Interval curInterval =
-//    valueProducer->mCurrentSlicedBucket.begin()->second[0]; ValueMetricProducer::BaseInfo
-//    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
-//    // startUpdated:false sum:0 start:100
-//    EXPECT_EQ(true, curBaseInfo.hasBase);
-//    EXPECT_EQ(100, curBaseInfo.base.long_value);
-//    EXPECT_EQ(false, curInterval.hasValue);
-//    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
-//
-//    vector<shared_ptr<LogEvent>> allData;
-//    allData.clear();
-//    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-//    event->write(1);
-//    event->write(110);
-//    event->init();
-//    allData.push_back(event);
-//    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-//    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10}, {bucketSizeNs - 8});
-//
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-//    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
-//    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
-//    EXPECT_EQ(true, curBaseInfo.hasBase);
-//    EXPECT_EQ(110, curBaseInfo.base.long_value);
-//    EXPECT_EQ(false, curInterval.hasValue);
-//    EXPECT_EQ(10, curInterval.value.long_value);
-//
-//    valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
-//    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10}, {bucketSizeNs - 8});
-//
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-//    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
-//    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
-//    EXPECT_EQ(true, curInterval.hasValue);
-//    EXPECT_EQ(20, curInterval.value.long_value);
-//    EXPECT_EQ(false, curBaseInfo.hasBase);
-//
-//    valueProducer->onConditionChanged(true, bucket3StartTimeNs + 1);
-//    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10, 20}, {bucketSizeNs - 8, 1});
-//}
-//
-// TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade) {
-//    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-//
-//    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>();
-//    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
-//                                      eventMatcherWizard, -1, bucketStartTimeNs,
-//                                      bucketStartTimeNs, pullerManager);
-//
-//    shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-//    event1->write(1);
-//    event1->write(10);
-//    event1->init();
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
-//    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-//
-//    valueProducer.notifyAppUpgrade(bucketStartTimeNs + 150, "ANY.APP", 1, 1);
-//    EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ(bucketStartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs);
-//
-//    shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 59 *
-//    NS_PER_SEC); event2->write(1); event2->write(10); event2->init();
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
-//    EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ(bucketStartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs);
-//
-//    // Next value should create a new bucket.
-//    shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 65 *
-//    NS_PER_SEC); event3->write(1); event3->write(10); event3->init();
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
-//    EXPECT_EQ(2UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, valueProducer.mCurrentBucketStartTimeNs);
-//}
-//
-// TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade) {
-//    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-//
-//    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, _)).WillOnce(Return());
-//    EXPECT_CALL(*pullerManager, Pull(tagId, _))
-//            .WillOnce(Return(true))
-//            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-//                data->clear();
-//                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs +
-//                149); event->write(tagId); event->write(120); 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(100);
-//    event->init();
-//    allData.push_back(event);
-//
-//    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-//    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-//
-//    valueProducer.notifyAppUpgrade(bucket2StartTimeNs + 150, "ANY.APP", 1, 1);
-//    EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ(bucket2StartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs);
-//    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {20}, {150});
-//
-//    allData.clear();
-//    event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
-//    event->write(tagId);
-//    event->write(150);
-//    event->init();
-//    allData.push_back(event);
-//    valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
-//    EXPECT_EQ(2UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ(bucket3StartTimeNs, valueProducer.mCurrentBucketStartTimeNs);
-//    EXPECT_EQ(20L,
-//              valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].values[0].long_value);
-//    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {20, 30},
-//                                    {150, bucketSizeNs - 150});
-//}
-//
-// TEST(ValueMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
-//    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-//    metric.set_split_bucket_for_app_upgrade(false);
-//
-//    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, _)).WillOnce(Return());
-//    EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(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(100);
-//    event->init();
-//    allData.push_back(event);
-//
-//    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-//    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-//
-//    valueProducer.notifyAppUpgrade(bucket2StartTimeNs + 150, "ANY.APP", 1, 1);
-//    EXPECT_EQ(0UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ(bucket2StartTimeNs, valueProducer.mCurrentBucketStartTimeNs);
-//}
-//
-// TEST(ValueMetricProducerTest, TestPulledValueWithUpgradeWhileConditionFalse) {
-//    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-//
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//    EXPECT_CALL(*pullerManager, Pull(tagId, _))
-//            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-//                data->clear();
-//                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
-//                event->write(tagId);
-//                event->write(100);
-//                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, bucket2StartTimeNs -
-//                100); event->write(tagId); event->write(120); event->init();
-//                data->push_back(event);
-//                return true;
-//            }));
-//    sp<ValueMetricProducer> valueProducer =
-//            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager,
-//            metric);
-//
-//    valueProducer->onConditionChanged(true, bucketStartTimeNs + 1);
-//
-//    valueProducer->onConditionChanged(false, bucket2StartTimeNs-100);
-//    EXPECT_FALSE(valueProducer->mCondition);
-//
-//    valueProducer->notifyAppUpgrade(bucket2StartTimeNs-50, "ANY.APP", 1, 1);
-//    // Expect one full buckets already done and starting a partial bucket.
-//    EXPECT_EQ(bucket2StartTimeNs-50, valueProducer->mCurrentBucketStartTimeNs);
-//    EXPECT_EQ(1UL, valueProducer->mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ(bucketStartTimeNs,
-//              valueProducer->mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
-//    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20},
-//                                    {(bucket2StartTimeNs - 100) - (bucketStartTimeNs + 1)});
-//    EXPECT_FALSE(valueProducer->mCondition);
-//}
-//
-// TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
-//    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-//
-//    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>();
-//
-//    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
-//                                      eventMatcherWizard, -1, bucketStartTimeNs,
-//                                      bucketStartTimeNs, pullerManager);
-//
-//    shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-//    event1->write(1);
-//    event1->write(10);
-//    event1->init();
-//    shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
-//    event2->write(1);
-//    event2->write(20);
-//    event2->init();
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-//    ValueMetricProducer::Interval curInterval =
-//    valueProducer.mCurrentSlicedBucket.begin()->second[0]; ValueMetricProducer::BaseInfo
-//    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(10,
-//    curInterval.value.long_value); EXPECT_EQ(true, curInterval.hasValue);
-//
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
-//
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-//    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-//    EXPECT_EQ(30, curInterval.value.long_value);
-//
-//    valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
-//    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {30}, {bucketSizeNs});
-//}
-//
-// TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
-//    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-//
-//    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>();
-//
-//    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
-//                                      eventMatcherWizard, -1, bucketStartTimeNs,
-//                                      bucketStartTimeNs, pullerManager);
-//    valueProducer.mCondition = ConditionState::kFalse;
-//
-//    shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-//    event1->write(1);
-//    event1->write(10);
-//    event1->init();
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
-//    // has 1 slice
-//    EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
-//
-//    valueProducer.onConditionChangedLocked(true, bucketStartTimeNs + 15);
-//    shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
-//    event2->write(1);
-//    event2->write(20);
-//    event2->init();
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
-//
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-//    ValueMetricProducer::Interval curInterval =
-//            valueProducer.mCurrentSlicedBucket.begin()->second[0];
-//    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-//    EXPECT_EQ(20, curInterval.value.long_value);
-//
-//    shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 30);
-//    event3->write(1);
-//    event3->write(30);
-//    event3->init();
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
-//
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-//    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-//    EXPECT_EQ(50, curInterval.value.long_value);
-//
-//    valueProducer.onConditionChangedLocked(false, bucketStartTimeNs + 35);
-//    shared_ptr<LogEvent> event4 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 40);
-//    event4->write(1);
-//    event4->write(40);
-//    event4->init();
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
-//
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-//    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-//    EXPECT_EQ(50, curInterval.value.long_value);
-//
-//    valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
-//    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {50}, {20});
-//}
-//
-// TEST(ValueMetricProducerTest, TestAnomalyDetection) {
-//    sp<AlarmMonitor> alarmMonitor;
-//    Alert alert;
-//    alert.set_id(101);
-//    alert.set_metric_id(metricId);
-//    alert.set_trigger_if_sum_gt(130);
-//    alert.set_num_buckets(2);
-//    const int32_t refPeriodSec = 3;
-//    alert.set_refractory_period_secs(refPeriodSec);
-//
-//    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-//
-//    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>();
-//    ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-//                                      logEventMatcherIndex, eventMatcherWizard, -1 /*not pulled*/,
-//                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-//
-//    sp<AnomalyTracker> anomalyTracker = valueProducer.addAnomalyTracker(alert, alarmMonitor);
-//
-//
-//    shared_ptr<LogEvent> event1
-//            = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1 * NS_PER_SEC);
-//    event1->write(161);
-//    event1->write(10); // value of interest
-//    event1->init();
-//    shared_ptr<LogEvent> event2
-//            = make_shared<LogEvent>(tagId, bucketStartTimeNs + 2 + NS_PER_SEC);
-//    event2->write(162);
-//    event2->write(20); // value of interest
-//    event2->init();
-//    shared_ptr<LogEvent> event3
-//            = make_shared<LogEvent>(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 1 * NS_PER_SEC);
-//    event3->write(163);
-//    event3->write(130); // value of interest
-//    event3->init();
-//    shared_ptr<LogEvent> event4
-//            = make_shared<LogEvent>(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 1 * NS_PER_SEC);
-//    event4->write(35);
-//    event4->write(1); // value of interest
-//    event4->init();
-//    shared_ptr<LogEvent> event5
-//            = make_shared<LogEvent>(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 2 * NS_PER_SEC);
-//    event5->write(45);
-//    event5->write(150); // value of interest
-//    event5->init();
-//    shared_ptr<LogEvent> event6
-//            = make_shared<LogEvent>(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 10 *
-//            NS_PER_SEC);
-//    event6->write(25);
-//    event6->write(160); // value of interest
-//    event6->init();
-//
-//    // Two events in bucket #0.
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
-//    // Value sum == 30 <= 130.
-//    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
-//
-//    // One event in bucket #2. No alarm as bucket #0 is trashed out.
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
-//    // Value sum == 130 <= 130.
-//    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
-//
-//    // Three events in bucket #3.
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
-//    // Anomaly at event 4 since Value sum == 131 > 130!
-//    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-//            std::ceil(1.0 * event4->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event5);
-//    // Event 5 is within 3 sec refractory period. Thus last alarm timestamp is still event4.
-//    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-//            std::ceil(1.0 * event4->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
-//
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event6);
-//    // Anomaly at event 6 since Value sum == 160 > 130 and after refractory period.
-//    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-//            std::ceil(1.0 * event6->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
-//}
-//
-//// Test value metric no condition, the pull on bucket boundary come in time and too late
-// TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) {
-//    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//    EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(true));
-//    sp<ValueMetricProducer> valueProducer =
-//            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
-//
-//    vector<shared_ptr<LogEvent>> allData;
-//    // pull 1
-//    allData.clear();
-//    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-//    event->write(tagId);
-//    event->write(11);
-//    event->init();
-//    allData.push_back(event);
-//
-//    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-//    ValueMetricProducer::Interval curInterval =
-//            valueProducer->mCurrentSlicedBucket.begin()->second[0];
-//    ValueMetricProducer::BaseInfo curBaseInfo =
-//    valueProducer->mCurrentBaseInfo.begin()->second[0];
-//
-//    // startUpdated:true sum:0 start:11
-//    EXPECT_EQ(true, curBaseInfo.hasBase);
-//    EXPECT_EQ(11, curBaseInfo.base.long_value);
-//    EXPECT_EQ(false, curInterval.hasValue);
-//    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
-//
-//    // pull 2 at correct time
-//    allData.clear();
-//    event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
-//    event->write(tagId);
-//    event->write(23);
-//    event->init();
-//    allData.push_back(event);
-//    valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-//    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
-//    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
-//    // tartUpdated:false sum:12
-//    EXPECT_EQ(true, curBaseInfo.hasBase);
-//    EXPECT_EQ(23, curBaseInfo.base.long_value);
-//    EXPECT_EQ(false, curInterval.hasValue);
-//    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12}, {bucketSizeNs});
-//
-//    // pull 3 come late.
-//    // The previous bucket gets closed with error. (Has start value 23, no ending)
-//    // Another bucket gets closed with error. (No start, but ending with 36)
-//    // The new bucket is back to normal.
-//    allData.clear();
-//    event = make_shared<LogEvent>(tagId, bucket6StartTimeNs + 1);
-//    event->write(tagId);
-//    event->write(36);
-//    event->init();
-//    allData.push_back(event);
-//    valueProducer->onDataPulled(allData, /** succeed */ true, bucket6StartTimeNs);
-//    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-//    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
-//    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
-//    // startUpdated:false sum:12
-//    EXPECT_EQ(true, curBaseInfo.hasBase);
-//    EXPECT_EQ(36, curBaseInfo.base.long_value);
-//    EXPECT_EQ(false, curInterval.hasValue);
-//    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12}, {bucketSizeNs});
-//}
-//
-///*
-// * Test pulled event with non sliced condition. The pull on boundary come late because the alarm
-// * was delivered late.
-// */
-// TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) {
-//    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-//
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//    EXPECT_CALL(*pullerManager, Pull(tagId, _))
-//            // condition becomes true
-//            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-//                data->clear();
-//                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
-//                event->write(tagId);
-//                event->write(100);
-//                event->init();
-//                data->push_back(event);
-//                return true;
-//            }))
-//            // condition becomes false
-//            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-//                data->clear();
-//                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-//                event->write(tagId);
-//                event->write(120);
-//                event->init();
-//                data->push_back(event);
-//                return true;
-//            }));
-//    sp<ValueMetricProducer> valueProducer =
-//            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager,
-//            metric);
-//
-//    valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
-//
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-//    ValueMetricProducer::Interval curInterval =
-//            valueProducer->mCurrentSlicedBucket.begin()->second[0];
-//    ValueMetricProducer::BaseInfo curBaseInfo =
-//    valueProducer->mCurrentBaseInfo.begin()->second[0]; EXPECT_EQ(true, curBaseInfo.hasBase);
-//    EXPECT_EQ(100, curBaseInfo.base.long_value);
-//    EXPECT_EQ(false, curInterval.hasValue);
-//    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
-//
-//    // pull on bucket boundary come late, condition change happens before it
-//    valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
-//    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
-//    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
-//    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
-//    EXPECT_EQ(false, curBaseInfo.hasBase);
-//
-//    // Now the alarm is delivered.
-//    // since the condition turned to off before this pull finish, it has no effect
-//    vector<shared_ptr<LogEvent>> allData;
-//    allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 30, 110));
-//    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-//
-//    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
-//    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
-//    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
-//    EXPECT_EQ(false, curBaseInfo.hasBase);
-//    EXPECT_EQ(false, curInterval.hasValue);
-//}
-//
-///*
-// * Test pulled event with non sliced condition. The pull on boundary come late, after the
-// condition
-// * change to false, and then true again. This is due to alarm delivered late.
-// */
-// TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) {
-//    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-//
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//    EXPECT_CALL(*pullerManager, Pull(tagId, _))
-//            // condition becomes true
-//            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-//                data->clear();
-//                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
-//                event->write(tagId);
-//                event->write(100);
-//                event->init();
-//                data->push_back(event);
-//                return true;
-//            }))
-//            // condition becomes false
-//            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-//                data->clear();
-//                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-//                event->write(tagId);
-//                event->write(120);
-//                event->init();
-//                data->push_back(event);
-//                return true;
-//            }))
-//            // condition becomes true again
-//            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-//                data->clear();
-//                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs +
-//                25); event->write(tagId); event->write(130); event->init();
-//                data->push_back(event);
-//                return true;
-//            }));
-//
-//    sp<ValueMetricProducer> valueProducer =
-//            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager,
-//            metric);
-//
-//    valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
-//
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-//    ValueMetricProducer::Interval curInterval =
-//            valueProducer->mCurrentSlicedBucket.begin()->second[0];
-//    ValueMetricProducer::BaseInfo curBaseInfo =
-//    valueProducer->mCurrentBaseInfo.begin()->second[0];
-//    // startUpdated:false sum:0 start:100
-//    EXPECT_EQ(true, curBaseInfo.hasBase);
-//    EXPECT_EQ(100, curBaseInfo.base.long_value);
-//    EXPECT_EQ(false, curInterval.hasValue);
-//    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
-//
-//    // pull on bucket boundary come late, condition change happens before it
-//    valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
-//    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
-//    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-//    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
-//    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
-//    EXPECT_EQ(false, curBaseInfo.hasBase);
-//    EXPECT_EQ(false, curInterval.hasValue);
-//
-//    // condition changed to true again, before the pull alarm is delivered
-//    valueProducer->onConditionChanged(true, bucket2StartTimeNs + 25);
-//    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
-//    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
-//    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
-//    EXPECT_EQ(true, curBaseInfo.hasBase);
-//    EXPECT_EQ(130, curBaseInfo.base.long_value);
-//    EXPECT_EQ(false, curInterval.hasValue);
-//
-//    // Now the alarm is delivered, but it is considered late, the data will be used
-//    // for the new bucket since it was just pulled.
-//    vector<shared_ptr<LogEvent>> allData;
-//    allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 50, 140));
-//    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 50);
-//
-//    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
-//    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
-//    EXPECT_EQ(true, curBaseInfo.hasBase);
-//    EXPECT_EQ(140, curBaseInfo.base.long_value);
-//    EXPECT_EQ(true, curInterval.hasValue);
-//    EXPECT_EQ(10, curInterval.value.long_value);
-//    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
-//
-//    allData.clear();
-//    allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket3StartTimeNs, 160));
-//    valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
-//    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20, 30},
-//                                    {bucketSizeNs - 8, bucketSizeNs - 24});
-//}
-//
-// TEST(ValueMetricProducerTest, TestPushedAggregateMin) {
-//    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-//    metric.set_aggregation_type(ValueMetric::MIN);
-//
-//    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>();
-//
-//    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
-//                                      eventMatcherWizard, -1, bucketStartTimeNs,
-//                                      bucketStartTimeNs, pullerManager);
-//
-//    shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-//    event1->write(1);
-//    event1->write(10);
-//    event1->init();
-//    shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
-//    event2->write(1);
-//    event2->write(20);
-//    event2->init();
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-//    ValueMetricProducer::Interval curInterval =
-//            valueProducer.mCurrentSlicedBucket.begin()->second[0];
-//    EXPECT_EQ(10, curInterval.value.long_value);
-//    EXPECT_EQ(true, curInterval.hasValue);
-//
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
-//
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-//    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-//    EXPECT_EQ(10, curInterval.value.long_value);
-//
-//    valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
-//    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {10}, {bucketSizeNs});
-//}
-//
-// TEST(ValueMetricProducerTest, TestPushedAggregateMax) {
-//    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-//    metric.set_aggregation_type(ValueMetric::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>();
-//
-//    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
-//                                      eventMatcherWizard, -1, bucketStartTimeNs,
-//                                      bucketStartTimeNs, pullerManager);
-//
-//    shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-//    event1->write(1);
-//    event1->write(10);
-//    event1->init();
-//    shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
-//    event2->write(1);
-//    event2->write(20);
-//    event2->init();
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-//    ValueMetricProducer::Interval curInterval =
-//            valueProducer.mCurrentSlicedBucket.begin()->second[0];
-//    EXPECT_EQ(10, curInterval.value.long_value);
-//    EXPECT_EQ(true, curInterval.hasValue);
-//
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
-//
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-//    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-//    EXPECT_EQ(20, curInterval.value.long_value);
-//
-//    valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
-//    /* EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); */
-//    /* EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); */
-//    /* EXPECT_EQ(20, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value); */
-//}
-//
-// TEST(ValueMetricProducerTest, TestPushedAggregateAvg) {
-//    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-//    metric.set_aggregation_type(ValueMetric::AVG);
-//
-//    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>();
-//
-//    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
-//                                      eventMatcherWizard, -1, bucketStartTimeNs,
-//                                      bucketStartTimeNs, pullerManager);
-//
-//    shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-//    event1->write(1);
-//    event1->write(10);
-//    event1->init();
-//    shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
-//    event2->write(1);
-//    event2->write(15);
-//    event2->init();
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-//    ValueMetricProducer::Interval curInterval;
-//    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-//    EXPECT_EQ(10, curInterval.value.long_value);
-//    EXPECT_EQ(true, curInterval.hasValue);
-//    EXPECT_EQ(1, curInterval.sampleSize);
-//
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
-//
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-//    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-//    EXPECT_EQ(25, curInterval.value.long_value);
-//    EXPECT_EQ(2, curInterval.sampleSize);
-//
-//    valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
-//    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-//    EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
-//
-//    EXPECT_TRUE(std::abs(valueProducer.mPastBuckets.begin()->second.back().values[0].double_value
-//    -
-//                         12.5) < epsilon);
-//}
-//
-// TEST(ValueMetricProducerTest, TestPushedAggregateSum) {
-//    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-//    metric.set_aggregation_type(ValueMetric::SUM);
-//
-//    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>();
-//
-//    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
-//                                      eventMatcherWizard, -1, bucketStartTimeNs,
-//                                      bucketStartTimeNs, pullerManager);
-//
-//    shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-//    event1->write(1);
-//    event1->write(10);
-//    event1->init();
-//    shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
-//    event2->write(1);
-//    event2->write(15);
-//    event2->init();
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-//    ValueMetricProducer::Interval curInterval =
-//            valueProducer.mCurrentSlicedBucket.begin()->second[0];
-//    EXPECT_EQ(10, curInterval.value.long_value);
-//    EXPECT_EQ(true, curInterval.hasValue);
-//
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
-//
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-//    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-//    EXPECT_EQ(25, curInterval.value.long_value);
-//
-//    valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
-//    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {25}, {bucketSizeNs});
-//}
-//
-// TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
-//    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-//    metric.set_aggregation_type(ValueMetric::MIN);
-//    metric.set_use_diff(true);
-//
-//    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>();
-//
-//    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
-//                                      eventMatcherWizard, -1, bucketStartTimeNs,
-//                                      bucketStartTimeNs, pullerManager);
-//
-//    shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-//    event1->write(1);
-//    event1->write(10);
-//    event1->init();
-//    shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 15);
-//    event2->write(1);
-//    event2->write(15);
-//    event2->init();
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-//    ValueMetricProducer::Interval curInterval =
-//            valueProducer.mCurrentSlicedBucket.begin()->second[0];
-//    ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
-//    EXPECT_EQ(true, curBaseInfo.hasBase);
-//    EXPECT_EQ(10, curBaseInfo.base.long_value);
-//    EXPECT_EQ(false, curInterval.hasValue);
-//
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
-//
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-//    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-//    EXPECT_EQ(true, curInterval.hasValue);
-//    EXPECT_EQ(5, curInterval.value.long_value);
-//
-//    // no change in data.
-//    shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10);
-//    event3->write(1);
-//    event3->write(15);
-//    event3->init();
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
-//    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-//    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-//    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
-//    EXPECT_EQ(true, curBaseInfo.hasBase);
-//    EXPECT_EQ(15, curBaseInfo.base.long_value);
-//    EXPECT_EQ(true, curInterval.hasValue);
-//
-//    shared_ptr<LogEvent> event4 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 15);
-//    event4->write(1);
-//    event4->write(15);
-//    event4->init();
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
-//    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-//    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-//    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
-//    EXPECT_EQ(true, curBaseInfo.hasBase);
-//    EXPECT_EQ(15, curBaseInfo.base.long_value);
-//    EXPECT_EQ(true, curInterval.hasValue);
-//
-//    valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
-//    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-//    EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
-//    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {5}, {bucketSizeNs});
-//}
-//
-// TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) {
-//    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-//    metric.mutable_value_field()->add_child()->set_field(3);
-//    metric.set_aggregation_type(ValueMetric::MIN);
-//    metric.set_use_diff(true);
-//
-//    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>();
-//
-//    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
-//                                      eventMatcherWizard, -1, bucketStartTimeNs,
-//                                      bucketStartTimeNs, pullerManager);
-//
-//    shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-//    event1->write(1);
-//    event1->write(10);
-//    event1->write(20);
-//    event1->init();
-//    shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 15);
-//    event2->write(1);
-//    event2->write(15);
-//    event2->write(22);
-//    event2->init();
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-//    ValueMetricProducer::Interval curInterval =
-//            valueProducer.mCurrentSlicedBucket.begin()->second[0];
-//    ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
-//    EXPECT_EQ(true, curBaseInfo.hasBase);
-//    EXPECT_EQ(10, curBaseInfo.base.long_value);
-//    EXPECT_EQ(false, curInterval.hasValue);
-//    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
-//    EXPECT_EQ(true, curBaseInfo.hasBase);
-//    EXPECT_EQ(20, curBaseInfo.base.long_value);
-//    EXPECT_EQ(false, curInterval.hasValue);
-//
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
-//
-//    // has one slice
-//    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-//    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-//    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
-//    EXPECT_EQ(true, curInterval.hasValue);
-//    EXPECT_EQ(5, curInterval.value.long_value);
-//    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1];
-//    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
-//    EXPECT_EQ(true, curInterval.hasValue);
-//    EXPECT_EQ(2, curInterval.value.long_value);
-//
-//    // no change in first value field
-//    shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10);
-//    event3->write(1);
-//    event3->write(15);
-//    event3->write(25);
-//    event3->init();
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
-//    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-//    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-//    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
-//
-//    EXPECT_EQ(true, curBaseInfo.hasBase);
-//    EXPECT_EQ(15, curBaseInfo.base.long_value);
-//    EXPECT_EQ(true, curInterval.hasValue);
-//    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1];
-//    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
-//    EXPECT_EQ(true, curBaseInfo.hasBase);
-//    EXPECT_EQ(25, curBaseInfo.base.long_value);
-//    EXPECT_EQ(true, curInterval.hasValue);
-//
-//    shared_ptr<LogEvent> event4 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 15);
-//    event4->write(1);
-//    event4->write(15);
-//    event4->write(29);
-//    event4->init();
-//    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
-//    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-//    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-//    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
-//    EXPECT_EQ(true, curBaseInfo.hasBase);
-//    EXPECT_EQ(15, curBaseInfo.base.long_value);
-//    EXPECT_EQ(true, curInterval.hasValue);
-//    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1];
-//    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
-//    EXPECT_EQ(true, curBaseInfo.hasBase);
-//    EXPECT_EQ(29, curBaseInfo.base.long_value);
-//    EXPECT_EQ(true, curInterval.hasValue);
-//
-//    valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
-//
-//    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-//    EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
-//    EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second[0].values.size());
-//    EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second[1].values.size());
-//
-//    EXPECT_EQ(bucketSizeNs, valueProducer.mPastBuckets.begin()->second[0].mConditionTrueNs);
-//    EXPECT_EQ(5, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
-//    EXPECT_EQ(0, valueProducer.mPastBuckets.begin()->second[0].valueIndex[0]);
-//    EXPECT_EQ(2, valueProducer.mPastBuckets.begin()->second[0].values[1].long_value);
-//    EXPECT_EQ(1, valueProducer.mPastBuckets.begin()->second[0].valueIndex[1]);
-//
-//    EXPECT_EQ(bucketSizeNs, valueProducer.mPastBuckets.begin()->second[1].mConditionTrueNs);
-//    EXPECT_EQ(3, valueProducer.mPastBuckets.begin()->second[1].values[0].long_value);
-//    EXPECT_EQ(1, valueProducer.mPastBuckets.begin()->second[1].valueIndex[0]);
-//}
-//
+/*
+ * Tests pulled atoms with no conditions and take absolute value after reset
+ */
+TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+    metric.set_use_absolute_value_on_reset(true);
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(true));
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
+
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 11));
+
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval =
+            valueProducer->mCurrentSlicedBucket.begin()->second[0];
+    ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+
+    EXPECT_EQ(true, curBaseInfo.hasBase);
+    EXPECT_EQ(11, curBaseInfo.base.long_value);
+    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+
+    allData.clear();
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 10));
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+    EXPECT_EQ(true, curBaseInfo.hasBase);
+    EXPECT_EQ(10, curBaseInfo.base.long_value);
+    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(10, curInterval.value.long_value);
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+    EXPECT_EQ(10, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
+    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second.back().mConditionTrueNs);
+
+    allData.clear();
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1, 36));
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+    EXPECT_EQ(true, curBaseInfo.hasBase);
+    EXPECT_EQ(36, curBaseInfo.base.long_value);
+    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(26, curInterval.value.long_value);
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+    EXPECT_EQ(2UL, valueProducer->mPastBuckets.begin()->second.size());
+    EXPECT_EQ(10, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
+    EXPECT_EQ(26, valueProducer->mPastBuckets.begin()->second[1].values[0].long_value);
+    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[1].mConditionTrueNs);
+}
+
+/*
+ * Tests pulled atoms with no conditions and take zero value after reset
+ */
+TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false));
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
+
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 11));
+
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval =
+            valueProducer->mCurrentSlicedBucket.begin()->second[0];
+    ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+
+    EXPECT_EQ(true, curBaseInfo.hasBase);
+    EXPECT_EQ(11, curBaseInfo.base.long_value);
+    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+
+    allData.clear();
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 10));
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+    EXPECT_EQ(true, curBaseInfo.hasBase);
+    EXPECT_EQ(10, curBaseInfo.base.long_value);
+    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+
+    allData.clear();
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1, 36));
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+    EXPECT_EQ(true, curBaseInfo.hasBase);
+    EXPECT_EQ(36, curBaseInfo.base.long_value);
+    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(26, curInterval.value.long_value);
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+    EXPECT_EQ(26, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
+}
+
+/*
+ * Test pulled event with non sliced condition.
+ */
+TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
+                return true;
+            }))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 130));
+                return true;
+            }))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 180));
+                return true;
+            }));
+
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
+
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval =
+            valueProducer->mCurrentSlicedBucket.begin()->second[0];
+    ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+    // startUpdated:false sum:0 start:100
+    EXPECT_EQ(true, curBaseInfo.hasBase);
+    EXPECT_EQ(100, curBaseInfo.base.long_value);
+    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1, 110));
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10}, {bucketSizeNs - 8});
+
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+    EXPECT_EQ(true, curBaseInfo.hasBase);
+    EXPECT_EQ(110, curBaseInfo.base.long_value);
+    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(10, curInterval.value.long_value);
+
+    valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10}, {bucketSizeNs - 8});
+
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(20, curInterval.value.long_value);
+    EXPECT_EQ(false, curBaseInfo.hasBase);
+
+    valueProducer->onConditionChanged(true, bucket3StartTimeNs + 1);
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10, 20}, {bucketSizeNs - 8, 1});
+}
+
+TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+
+    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>();
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
+                                      pullerManager);
+
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10);
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+
+    valueProducer.notifyAppUpgrade(bucketStartTimeNs + 150, "ANY.APP", 1, 1);
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(bucketStartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs);
+
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 59 * NS_PER_SEC, 1, 10);
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(bucketStartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs);
+
+    // Next value should create a new bucket.
+    LogEvent event3(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event3, tagId, bucketStartTimeNs + 65 * NS_PER_SEC, 1, 10);
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+    EXPECT_EQ(2UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, valueProducer.mCurrentBucketStartTimeNs);
+}
+
+TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+
+    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, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            .WillOnce(Return(true))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 149, 120));
+                return true;
+            }));
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, tagId, bucketStartTimeNs,
+                                      bucketStartTimeNs, pullerManager);
+
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 100));
+
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+
+    valueProducer.notifyAppUpgrade(bucket2StartTimeNs + 150, "ANY.APP", 1, 1);
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(bucket2StartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs);
+    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {20}, {150});
+
+    allData.clear();
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 150));
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+    EXPECT_EQ(2UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(bucket3StartTimeNs, valueProducer.mCurrentBucketStartTimeNs);
+    EXPECT_EQ(20L,
+              valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].values[0].long_value);
+    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {20, 30},
+                                    {150, bucketSizeNs - 150});
+}
+
+TEST(ValueMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+    metric.set_split_bucket_for_app_upgrade(false);
+
+    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, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(true));
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, tagId, bucketStartTimeNs,
+                                      bucketStartTimeNs, pullerManager);
+
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 100));
+
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+
+    valueProducer.notifyAppUpgrade(bucket2StartTimeNs + 150, "ANY.APP", 1, 1);
+    EXPECT_EQ(0UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(bucket2StartTimeNs, valueProducer.mCurrentBucketStartTimeNs);
+}
+
+TEST(ValueMetricProducerTest, TestPulledValueWithUpgradeWhileConditionFalse) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 100));
+                return true;
+            }))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs - 100, 120));
+                return true;
+            }));
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 1);
+
+    valueProducer->onConditionChanged(false, bucket2StartTimeNs - 100);
+    EXPECT_FALSE(valueProducer->mCondition);
+
+    valueProducer->notifyAppUpgrade(bucket2StartTimeNs - 50, "ANY.APP", 1, 1);
+    // Expect one full buckets already done and starting a partial bucket.
+    EXPECT_EQ(bucket2StartTimeNs - 50, valueProducer->mCurrentBucketStartTimeNs);
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(bucketStartTimeNs,
+              valueProducer->mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20},
+                                    {(bucket2StartTimeNs - 100) - (bucketStartTimeNs + 1)});
+    EXPECT_FALSE(valueProducer->mCondition);
+}
+TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+
+    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>();
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
+                                      pullerManager);
+
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10);
+
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 1, 20);
+
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval =
+            valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+    EXPECT_EQ(10, curInterval.value.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
+
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(30, curInterval.value.long_value);
+
+    valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
+    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {30}, {bucketSizeNs});
+}
+
+TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+
+    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>();
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
+                                      pullerManager);
+    valueProducer.mCondition = ConditionState::kFalse;
+
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10);
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+    // has 1 slice
+    EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
+
+    valueProducer.onConditionChangedLocked(true, bucketStartTimeNs + 15);
+
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 1, 20);
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval =
+            valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(20, curInterval.value.long_value);
+
+    LogEvent event3(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event3, tagId, bucketStartTimeNs + 30, 1, 30);
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(50, curInterval.value.long_value);
+
+    valueProducer.onConditionChangedLocked(false, bucketStartTimeNs + 35);
+
+    LogEvent event4(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event4, tagId, bucketStartTimeNs + 40, 1, 40);
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
+
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(50, curInterval.value.long_value);
+
+    valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
+    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {50}, {20});
+}
+
+TEST(ValueMetricProducerTest, TestAnomalyDetection) {
+    sp<AlarmMonitor> alarmMonitor;
+    Alert alert;
+    alert.set_id(101);
+    alert.set_metric_id(metricId);
+    alert.set_trigger_if_sum_gt(130);
+    alert.set_num_buckets(2);
+    const int32_t refPeriodSec = 3;
+    alert.set_refractory_period_secs(refPeriodSec);
+
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+
+    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>();
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      logEventMatcherIndex, eventMatcherWizard, -1 /*not pulled*/,
+                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+    sp<AnomalyTracker> anomalyTracker = valueProducer.addAnomalyTracker(alert, alarmMonitor);
+
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 1 * NS_PER_SEC, 10);
+
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 2 + NS_PER_SEC, 20);
+
+    LogEvent event3(/*uid=*/0, /*pid=*/0);
+    CreateRepeatedValueLogEvent(&event3, tagId,
+                                bucketStartTimeNs + 2 * bucketSizeNs + 1 * NS_PER_SEC, 130);
+
+    LogEvent event4(/*uid=*/0, /*pid=*/0);
+    CreateRepeatedValueLogEvent(&event4, tagId,
+                                bucketStartTimeNs + 3 * bucketSizeNs + 1 * NS_PER_SEC, 1);
+
+    LogEvent event5(/*uid=*/0, /*pid=*/0);
+    CreateRepeatedValueLogEvent(&event5, tagId,
+                                bucketStartTimeNs + 3 * bucketSizeNs + 2 * NS_PER_SEC, 150);
+
+    LogEvent event6(/*uid=*/0, /*pid=*/0);
+    CreateRepeatedValueLogEvent(&event6, tagId,
+                                bucketStartTimeNs + 3 * bucketSizeNs + 10 * NS_PER_SEC, 160);
+
+    // Two events in bucket #0.
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+    // Value sum == 30 <= 130.
+    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
+
+    // One event in bucket #2. No alarm as bucket #0 is trashed out.
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+    // Value sum == 130 <= 130.
+    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
+
+    // Three events in bucket #3.
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
+    // Anomaly at event 4 since Value sum == 131 > 130!
+    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
+              std::ceil(1.0 * event4.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event5);
+    // Event 5 is within 3 sec refractory period. Thus last alarm timestamp is still event4.
+    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
+              std::ceil(1.0 * event4.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
+
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event6);
+    // Anomaly at event 6 since Value sum == 160 > 130 and after refractory period.
+    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
+              std::ceil(1.0 * event6.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
+}
+
+// Test value metric no condition, the pull on bucket boundary come in time and too late
+TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(true));
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
+
+    vector<shared_ptr<LogEvent>> allData;
+    // pull 1
+    allData.clear();
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 11));
+
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval =
+            valueProducer->mCurrentSlicedBucket.begin()->second[0];
+    ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+
+    // startUpdated:true sum:0 start:11
+    EXPECT_EQ(true, curBaseInfo.hasBase);
+    EXPECT_EQ(11, curBaseInfo.base.long_value);
+    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+
+    // pull 2 at correct time
+    allData.clear();
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 23));
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+    // tartUpdated:false sum:12
+    EXPECT_EQ(true, curBaseInfo.hasBase);
+    EXPECT_EQ(23, curBaseInfo.base.long_value);
+    EXPECT_EQ(false, curInterval.hasValue);
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12}, {bucketSizeNs});
+
+    // pull 3 come late.
+    // The previous bucket gets closed with error. (Has start value 23, no ending)
+    // Another bucket gets closed with error. (No start, but ending with 36)
+    // The new bucket is back to normal.
+    allData.clear();
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket6StartTimeNs + 1, 36));
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket6StartTimeNs);
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+    // startUpdated:false sum:12
+    EXPECT_EQ(true, curBaseInfo.hasBase);
+    EXPECT_EQ(36, curBaseInfo.base.long_value);
+    EXPECT_EQ(false, curInterval.hasValue);
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12}, {bucketSizeNs});
+}
+
+/*
+ * Test pulled event with non sliced condition. The pull on boundary come late because the alarm
+ * was delivered late.
+ */
+TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // condition becomes true
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
+                return true;
+            }))
+            // condition becomes false
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 120));
+                return true;
+            }));
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
+
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval =
+            valueProducer->mCurrentSlicedBucket.begin()->second[0];
+    ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+    EXPECT_EQ(true, curBaseInfo.hasBase);
+    EXPECT_EQ(100, curBaseInfo.base.long_value);
+    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+
+    // pull on bucket boundary come late, condition change happens before it
+    valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
+    EXPECT_EQ(false, curBaseInfo.hasBase);
+
+    // Now the alarm is delivered.
+    // since the condition turned to off before this pull finish, it has no effect
+    vector<shared_ptr<LogEvent>> allData;
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 30, 110));
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+    EXPECT_EQ(false, curBaseInfo.hasBase);
+    EXPECT_EQ(false, curInterval.hasValue);
+}
+
+/*
+* Test pulled event with non sliced condition. The pull on boundary come late, after the
+condition
+* change to false, and then true again. This is due to alarm delivered late.
+*/
+TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // condition becomes true
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
+                return true;
+            }))
+            // condition becomes false
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 120));
+                return true;
+            }))
+            // condition becomes true again
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 25, 130));
+                return true;
+            }));
+
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
+
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval =
+            valueProducer->mCurrentSlicedBucket.begin()->second[0];
+    ValueMetricProducer::BaseInfo curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+    // startUpdated:false sum:0 start:100
+    EXPECT_EQ(true, curBaseInfo.hasBase);
+    EXPECT_EQ(100, curBaseInfo.base.long_value);
+    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
+
+    // pull on bucket boundary come late, condition change happens before it
+    valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+    EXPECT_EQ(false, curBaseInfo.hasBase);
+    EXPECT_EQ(false, curInterval.hasValue);
+
+    // condition changed to true again, before the pull alarm is delivered
+    valueProducer->onConditionChanged(true, bucket2StartTimeNs + 25);
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+    EXPECT_EQ(true, curBaseInfo.hasBase);
+    EXPECT_EQ(130, curBaseInfo.base.long_value);
+    EXPECT_EQ(false, curInterval.hasValue);
+
+    // Now the alarm is delivered, but it is considered late, the data will be used
+    // for the new bucket since it was just pulled.
+    vector<shared_ptr<LogEvent>> allData;
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 50, 140));
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 50);
+
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second[0];
+    EXPECT_EQ(true, curBaseInfo.hasBase);
+    EXPECT_EQ(140, curBaseInfo.base.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(10, curInterval.value.long_value);
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
+
+    allData.clear();
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs, 160));
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20, 30},
+                                    {bucketSizeNs - 8, bucketSizeNs - 24});
+}
+
+TEST(ValueMetricProducerTest, TestPushedAggregateMin) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+    metric.set_aggregation_type(ValueMetric::MIN);
+
+    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>();
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
+                                      pullerManager);
+
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10);
+
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 1, 20);
+
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval =
+            valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(10, curInterval.value.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
+
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(10, curInterval.value.long_value);
+
+    valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
+    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {10}, {bucketSizeNs});
+}
+
+TEST(ValueMetricProducerTest, TestPushedAggregateMax) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+    metric.set_aggregation_type(ValueMetric::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>();
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
+                                      pullerManager);
+
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10);
+
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 1, 20);
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval =
+            valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(10, curInterval.value.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
+
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(20, curInterval.value.long_value);
+
+    valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
+    /* EXPECT_EQ(1UL, valueProducer.mPastBuckets.size()); */
+    /* EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size()); */
+    /* EXPECT_EQ(20, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value); */
+}
+
+TEST(ValueMetricProducerTest, TestPushedAggregateAvg) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+    metric.set_aggregation_type(ValueMetric::AVG);
+
+    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>();
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
+                                      pullerManager);
+
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10);
+
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 1, 15);
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval;
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(10, curInterval.value.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(1, curInterval.sampleSize);
+
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(25, curInterval.value.long_value);
+    EXPECT_EQ(2, curInterval.sampleSize);
+
+    valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
+
+    EXPECT_TRUE(std::abs(valueProducer.mPastBuckets.begin()->second.back().values[0].double_value -
+                         12.5) < epsilon);
+}
+
+TEST(ValueMetricProducerTest, TestPushedAggregateSum) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+    metric.set_aggregation_type(ValueMetric::SUM);
+
+    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>();
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
+                                      pullerManager);
+
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10);
+
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 1, 15);
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval =
+            valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(10, curInterval.value.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
+
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(25, curInterval.value.long_value);
+
+    valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
+    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {25}, {bucketSizeNs});
+}
+
+TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+    metric.set_aggregation_type(ValueMetric::MIN);
+    metric.set_use_diff(true);
+
+    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>();
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
+                                      pullerManager);
+
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10);
+
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 15, 1, 15);
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval =
+            valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+    EXPECT_EQ(true, curBaseInfo.hasBase);
+    EXPECT_EQ(10, curBaseInfo.base.long_value);
+    EXPECT_EQ(false, curInterval.hasValue);
+
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(5, curInterval.value.long_value);
+
+    // no change in data.
+    LogEvent event3(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event3, tagId, bucket2StartTimeNs + 10, 1, 15);
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+    EXPECT_EQ(true, curBaseInfo.hasBase);
+    EXPECT_EQ(15, curBaseInfo.base.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
+
+    LogEvent event4(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event4, tagId, bucket2StartTimeNs + 15, 1, 15);
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+    EXPECT_EQ(true, curBaseInfo.hasBase);
+    EXPECT_EQ(15, curBaseInfo.base.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
+
+    valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
+    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {5}, {bucketSizeNs});
+}
+
+TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+    metric.mutable_value_field()->add_child()->set_field(3);
+    metric.set_aggregation_type(ValueMetric::MIN);
+    metric.set_use_diff(true);
+
+    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>();
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
+                                      pullerManager);
+
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    CreateThreeValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10, 20);
+
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    CreateThreeValueLogEvent(&event2, tagId, bucketStartTimeNs + 15, 1, 15, 22);
+
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval =
+            valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    ValueMetricProducer::BaseInfo curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+    EXPECT_EQ(true, curBaseInfo.hasBase);
+    EXPECT_EQ(10, curBaseInfo.base.long_value);
+    EXPECT_EQ(false, curInterval.hasValue);
+    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
+    EXPECT_EQ(true, curBaseInfo.hasBase);
+    EXPECT_EQ(20, curBaseInfo.base.long_value);
+    EXPECT_EQ(false, curInterval.hasValue);
+
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(5, curInterval.value.long_value);
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1];
+    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
+    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(2, curInterval.value.long_value);
+
+    // no change in first value field
+    LogEvent event3(/*uid=*/0, /*pid=*/0);
+    CreateThreeValueLogEvent(&event3, tagId, bucket2StartTimeNs + 10, 1, 15, 25);
+
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+
+    EXPECT_EQ(true, curBaseInfo.hasBase);
+    EXPECT_EQ(15, curBaseInfo.base.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1];
+    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
+    EXPECT_EQ(true, curBaseInfo.hasBase);
+    EXPECT_EQ(25, curBaseInfo.base.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
+
+    LogEvent event4(/*uid=*/0, /*pid=*/0);
+    CreateThreeValueLogEvent(&event4, tagId, bucket2StartTimeNs + 15, 1, 15, 29);
+
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[0];
+    EXPECT_EQ(true, curBaseInfo.hasBase);
+    EXPECT_EQ(15, curBaseInfo.base.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[1];
+    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second[1];
+    EXPECT_EQ(true, curBaseInfo.hasBase);
+    EXPECT_EQ(29, curBaseInfo.base.long_value);
+    EXPECT_EQ(true, curInterval.hasValue);
+
+    valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
+
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
+    EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second[0].values.size());
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second[1].values.size());
+
+    EXPECT_EQ(bucketSizeNs, valueProducer.mPastBuckets.begin()->second[0].mConditionTrueNs);
+    EXPECT_EQ(5, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
+    EXPECT_EQ(0, valueProducer.mPastBuckets.begin()->second[0].valueIndex[0]);
+    EXPECT_EQ(2, valueProducer.mPastBuckets.begin()->second[0].values[1].long_value);
+    EXPECT_EQ(1, valueProducer.mPastBuckets.begin()->second[0].valueIndex[1]);
+
+    EXPECT_EQ(bucketSizeNs, valueProducer.mPastBuckets.begin()->second[1].mConditionTrueNs);
+    EXPECT_EQ(3, valueProducer.mPastBuckets.begin()->second[1].values[0].long_value);
+    EXPECT_EQ(1, valueProducer.mPastBuckets.begin()->second[1].valueIndex[0]);
+}
+
 ///*
 // * Tests zero default base.
 // */
@@ -3814,7 +3671,7 @@
 //
 //    sp<ValueMetricProducer> valueProducer =
 //            ValueMetricProducerTestHelper::createValueProducerWithState(
-//                    pullerManager, metric, {android::util::SCREEN_STATE_CHANGED}, {});
+//                    pullerManager, metric, {util::SCREEN_STATE_CHANGED}, {});
 //
 //    // Set up StateManager and check that StateTrackers are initialized.
 //    StateManager::getInstance().clear();
@@ -3998,7 +3855,7 @@
 //
 //    sp<ValueMetricProducer> valueProducer =
 //            ValueMetricProducerTestHelper::createValueProducerWithState(
-//                    pullerManager, metric, {android::util::SCREEN_STATE_CHANGED}, stateGroupMap);
+//                    pullerManager, metric, {util::SCREEN_STATE_CHANGED}, stateGroupMap);
 //
 //    // Set up StateManager and check that StateTrackers are initialized.
 //    StateManager::getInstance().clear();
diff --git a/cmds/statsd/tests/state/StateTracker_test.cpp b/cmds/statsd/tests/state/StateTracker_test.cpp
index 36c0f32..b1633c6 100644
--- a/cmds/statsd/tests/state/StateTracker_test.cpp
+++ b/cmds/statsd/tests/state/StateTracker_test.cpp
@@ -61,7 +61,7 @@
 //// State with no primary fields - ScreenStateChanged
 //std::shared_ptr<LogEvent> buildScreenEvent(int state) {
 //    std::shared_ptr<LogEvent> event =
-//            std::make_shared<LogEvent>(android::util::SCREEN_STATE_CHANGED, 1000 /*timestamp*/);
+//            std::make_shared<LogEvent>(util::SCREEN_STATE_CHANGED, 1000 /*timestamp*/);
 //    event->write((int32_t)state);
 //    event->init();
 //    return event;
@@ -70,7 +70,7 @@
 //// State with one primary field - UidProcessStateChanged
 //std::shared_ptr<LogEvent> buildUidProcessEvent(int uid, int state) {
 //    std::shared_ptr<LogEvent> event =
-//            std::make_shared<LogEvent>(android::util::UID_PROCESS_STATE_CHANGED, 1000 /*timestamp*/);
+//            std::make_shared<LogEvent>(util::UID_PROCESS_STATE_CHANGED, 1000 /*timestamp*/);
 //    event->write((int32_t)uid);
 //    event->write((int32_t)state);
 //    event->init();
@@ -85,7 +85,7 @@
 //    attr.set_uid(uid);
 //
 //    std::shared_ptr<LogEvent> event =
-//            std::make_shared<LogEvent>(android::util::WAKELOCK_STATE_CHANGED, 1000 /* timestamp */);
+//            std::make_shared<LogEvent>(util::WAKELOCK_STATE_CHANGED, 1000 /* timestamp */);
 //    event->write(chain);
 //    event->write((int32_t)1);  // PARTIAL_WAKE_LOCK
 //    event->write(tag);
@@ -97,7 +97,7 @@
 //// State with multiple primary fields - OverlayStateChanged
 //std::shared_ptr<LogEvent> buildOverlayEvent(int uid, const std::string& packageName, int state) {
 //    std::shared_ptr<LogEvent> event =
-//            std::make_shared<LogEvent>(android::util::OVERLAY_STATE_CHANGED, 1000 /*timestamp*/);
+//            std::make_shared<LogEvent>(util::OVERLAY_STATE_CHANGED, 1000 /*timestamp*/);
 //    event->write((int32_t)uid);
 //    event->write(packageName);
 //    event->write(true);  // using_alert_window
@@ -109,7 +109,7 @@
 //// Incorrect event - missing fields
 //std::shared_ptr<LogEvent> buildIncorrectOverlayEvent(int uid, const std::string& packageName, int state) {
 //    std::shared_ptr<LogEvent> event =
-//            std::make_shared<LogEvent>(android::util::OVERLAY_STATE_CHANGED, 1000 /*timestamp*/);
+//            std::make_shared<LogEvent>(util::OVERLAY_STATE_CHANGED, 1000 /*timestamp*/);
 //    event->write((int32_t)uid);
 //    event->write(packageName);
 //    event->write((int32_t)state);
@@ -120,7 +120,7 @@
 //// Incorrect event - exclusive state has wrong type
 //std::shared_ptr<LogEvent> buildOverlayEventBadStateType(int uid, const std::string& packageName) {
 //    std::shared_ptr<LogEvent> event =
-//            std::make_shared<LogEvent>(android::util::OVERLAY_STATE_CHANGED, 1000 /*timestamp*/);
+//            std::make_shared<LogEvent>(util::OVERLAY_STATE_CHANGED, 1000 /*timestamp*/);
 //    event->write((int32_t)uid);
 //    event->write(packageName);
 //    event->write(true);
@@ -136,7 +136,7 @@
 //    attr.set_uid(uid);
 //
 //    std::shared_ptr<LogEvent> event =
-//            std::make_shared<LogEvent>(android::util::BLE_SCAN_STATE_CHANGED, 1000);
+//            std::make_shared<LogEvent>(util::BLE_SCAN_STATE_CHANGED, 1000);
 //    event->write(chain);
 //    event->write(reset ? 2 : acquire ? 1 : 0);  // PARTIAL_WAKE_LOCK
 //    event->write(0);                            // filtered
@@ -216,7 +216,7 @@
     StateManager& mgr = StateManager::getInstance();
     mgr.clear();
 
-    mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener1);
+    mgr.registerListener(util::SCREEN_STATE_CHANGED, listener1);
     EXPECT_EQ(1, mgr.getStateTrackersCount());
     EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
 }
@@ -236,22 +236,22 @@
 
     // Register listener to non-existing StateTracker
     EXPECT_EQ(0, mgr.getStateTrackersCount());
-    EXPECT_TRUE(mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener1));
+    EXPECT_TRUE(mgr.registerListener(util::SCREEN_STATE_CHANGED, listener1));
     EXPECT_EQ(1, mgr.getStateTrackersCount());
-    EXPECT_EQ(1, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
+    EXPECT_EQ(1, mgr.getListenersCount(util::SCREEN_STATE_CHANGED));
 
     // Register listener to existing StateTracker
-    EXPECT_TRUE(mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener2));
+    EXPECT_TRUE(mgr.registerListener(util::SCREEN_STATE_CHANGED, listener2));
     EXPECT_EQ(1, mgr.getStateTrackersCount());
-    EXPECT_EQ(2, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
+    EXPECT_EQ(2, mgr.getListenersCount(util::SCREEN_STATE_CHANGED));
 
     // Register already registered listener to existing StateTracker
-    EXPECT_TRUE(mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener2));
+    EXPECT_TRUE(mgr.registerListener(util::SCREEN_STATE_CHANGED, listener2));
     EXPECT_EQ(1, mgr.getStateTrackersCount());
-    EXPECT_EQ(2, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
+    EXPECT_EQ(2, mgr.getListenersCount(util::SCREEN_STATE_CHANGED));
 
     // Register listener to non-state atom
-    EXPECT_FALSE(mgr.registerListener(android::util::BATTERY_LEVEL_CHANGED, listener2));
+    EXPECT_FALSE(mgr.registerListener(util::BATTERY_LEVEL_CHANGED, listener2));
     EXPECT_EQ(1, mgr.getStateTrackersCount());
 }
 
@@ -270,28 +270,28 @@
 
     // Unregister listener from non-existing StateTracker
     EXPECT_EQ(0, mgr.getStateTrackersCount());
-    mgr.unregisterListener(android::util::SCREEN_STATE_CHANGED, listener1);
+    mgr.unregisterListener(util::SCREEN_STATE_CHANGED, listener1);
     EXPECT_EQ(0, mgr.getStateTrackersCount());
-    EXPECT_EQ(-1, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
+    EXPECT_EQ(-1, mgr.getListenersCount(util::SCREEN_STATE_CHANGED));
 
     // Unregister non-registered listener from existing StateTracker
-    mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener1);
+    mgr.registerListener(util::SCREEN_STATE_CHANGED, listener1);
     EXPECT_EQ(1, mgr.getStateTrackersCount());
-    EXPECT_EQ(1, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
-    mgr.unregisterListener(android::util::SCREEN_STATE_CHANGED, listener2);
+    EXPECT_EQ(1, mgr.getListenersCount(util::SCREEN_STATE_CHANGED));
+    mgr.unregisterListener(util::SCREEN_STATE_CHANGED, listener2);
     EXPECT_EQ(1, mgr.getStateTrackersCount());
-    EXPECT_EQ(1, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
+    EXPECT_EQ(1, mgr.getListenersCount(util::SCREEN_STATE_CHANGED));
 
     // Unregister second-to-last listener from StateTracker
-    mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener2);
-    mgr.unregisterListener(android::util::SCREEN_STATE_CHANGED, listener1);
+    mgr.registerListener(util::SCREEN_STATE_CHANGED, listener2);
+    mgr.unregisterListener(util::SCREEN_STATE_CHANGED, listener1);
     EXPECT_EQ(1, mgr.getStateTrackersCount());
-    EXPECT_EQ(1, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
+    EXPECT_EQ(1, mgr.getListenersCount(util::SCREEN_STATE_CHANGED));
 
     // Unregister last listener from StateTracker
-    mgr.unregisterListener(android::util::SCREEN_STATE_CHANGED, listener2);
+    mgr.unregisterListener(util::SCREEN_STATE_CHANGED, listener2);
     EXPECT_EQ(0, mgr.getStateTrackersCount());
-    EXPECT_EQ(-1, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
+    EXPECT_EQ(-1, mgr.getListenersCount(util::SCREEN_STATE_CHANGED));
 }
 // TODO(b/149590301): Update these tests to use new socket schema.
 ///**
@@ -305,7 +305,7 @@
 //TEST(StateTrackerTest, TestStateChangeNested) {
 //    sp<TestStateListener> listener = new TestStateListener();
 //    StateManager mgr;
-//    mgr.registerListener(android::util::WAKELOCK_STATE_CHANGED, listener);
+//    mgr.registerListener(util::WAKELOCK_STATE_CHANGED, listener);
 //
 //    std::shared_ptr<LogEvent> event1 =
 //            buildPartialWakelockEvent(1000 /* uid */, "tag", true /*acquire*/);
@@ -342,7 +342,7 @@
 //TEST(StateTrackerTest, TestStateChangeReset) {
 //    sp<TestStateListener> listener = new TestStateListener();
 //    StateManager mgr;
-//    mgr.registerListener(android::util::BLE_SCAN_STATE_CHANGED, listener);
+//    mgr.registerListener(util::BLE_SCAN_STATE_CHANGED, listener);
 //
 //    std::shared_ptr<LogEvent> event1 =
 //            buildBleScanEvent(1000 /* uid */, true /*acquire*/, false /*reset*/);
@@ -375,7 +375,7 @@
 //TEST(StateTrackerTest, TestStateChangeNoPrimaryFields) {
 //    sp<TestStateListener> listener1 = new TestStateListener();
 //    StateManager mgr;
-//    mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener1);
+//    mgr.registerListener(util::SCREEN_STATE_CHANGED, listener1);
 //
 //    // log event
 //    std::shared_ptr<LogEvent> event =
@@ -390,7 +390,7 @@
 //    // check StateTracker was updated by querying for state
 //    HashableDimensionKey queryKey = DEFAULT_DIMENSION_KEY;
 //    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-//              getStateInt(mgr, android::util::SCREEN_STATE_CHANGED, queryKey));
+//              getStateInt(mgr, util::SCREEN_STATE_CHANGED, queryKey));
 //}
 //
 ///**
@@ -400,7 +400,7 @@
 //TEST(StateTrackerTest, TestStateChangeOnePrimaryField) {
 //    sp<TestStateListener> listener1 = new TestStateListener();
 //    StateManager mgr;
-//    mgr.registerListener(android::util::UID_PROCESS_STATE_CHANGED, listener1);
+//    mgr.registerListener(util::UID_PROCESS_STATE_CHANGED, listener1);
 //
 //    // log event
 //    std::shared_ptr<LogEvent> event =
@@ -416,13 +416,13 @@
 //    HashableDimensionKey queryKey;
 //    getUidProcessKey(1000 /* uid */, &queryKey);
 //    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_TOP,
-//              getStateInt(mgr, android::util::UID_PROCESS_STATE_CHANGED, queryKey));
+//              getStateInt(mgr, util::UID_PROCESS_STATE_CHANGED, queryKey));
 //}
 //
 //TEST(StateTrackerTest, TestStateChangePrimaryFieldAttrChain) {
 //    sp<TestStateListener> listener1 = new TestStateListener();
 //    StateManager mgr;
-//    mgr.registerListener(android::util::WAKELOCK_STATE_CHANGED, listener1);
+//    mgr.registerListener(util::WAKELOCK_STATE_CHANGED, listener1);
 //
 //    // Log event.
 //    std::shared_ptr<LogEvent> event =
@@ -430,7 +430,7 @@
 //    mgr.onLogEvent(*event);
 //
 //    EXPECT_EQ(1, mgr.getStateTrackersCount());
-//    EXPECT_EQ(1, mgr.getListenersCount(android::util::WAKELOCK_STATE_CHANGED));
+//    EXPECT_EQ(1, mgr.getListenersCount(util::WAKELOCK_STATE_CHANGED));
 //
 //    // Check listener was updated.
 //    EXPECT_EQ(1, listener1->updates.size());
@@ -444,19 +444,19 @@
 //    HashableDimensionKey queryKey;
 //    getPartialWakelockKey(1001 /* uid */, "tag1", &queryKey);
 //    EXPECT_EQ(WakelockStateChanged::ACQUIRE,
-//              getStateInt(mgr, android::util::WAKELOCK_STATE_CHANGED, queryKey));
+//              getStateInt(mgr, util::WAKELOCK_STATE_CHANGED, queryKey));
 //
 //    // No state stored for this query key.
 //    HashableDimensionKey queryKey2;
 //    getPartialWakelockKey(1002 /* uid */, "tag1", &queryKey2);
 //    EXPECT_EQ(WakelockStateChanged::RELEASE,
-//              getStateInt(mgr, android::util::WAKELOCK_STATE_CHANGED, queryKey2));
+//              getStateInt(mgr, util::WAKELOCK_STATE_CHANGED, queryKey2));
 //
 //    // Partial query fails.
 //    HashableDimensionKey queryKey3;
 //    getPartialWakelockKey(1001 /* uid */, &queryKey3);
 //    EXPECT_EQ(WakelockStateChanged::RELEASE,
-//              getStateInt(mgr, android::util::WAKELOCK_STATE_CHANGED, queryKey3));
+//              getStateInt(mgr, util::WAKELOCK_STATE_CHANGED, queryKey3));
 //}
 //
 ///**
@@ -466,7 +466,7 @@
 //TEST(StateTrackerTest, TestStateChangeMultiplePrimaryFields) {
 //    sp<TestStateListener> listener1 = new TestStateListener();
 //    StateManager mgr;
-//    mgr.registerListener(android::util::OVERLAY_STATE_CHANGED, listener1);
+//    mgr.registerListener(util::OVERLAY_STATE_CHANGED, listener1);
 //
 //    // log event
 //    std::shared_ptr<LogEvent> event =
@@ -482,7 +482,7 @@
 //    HashableDimensionKey queryKey;
 //    getOverlayKey(1000 /* uid */, "package1", &queryKey);
 //    EXPECT_EQ(OverlayStateChanged::ENTERED,
-//              getStateInt(mgr, android::util::OVERLAY_STATE_CHANGED, queryKey));
+//              getStateInt(mgr, util::OVERLAY_STATE_CHANGED, queryKey));
 //}
 //
 ///**
@@ -493,7 +493,7 @@
 //TEST(StateTrackerTest, TestStateChangeEventError) {
 //    sp<TestStateListener> listener1 = new TestStateListener();
 //    StateManager mgr;
-//    mgr.registerListener(android::util::OVERLAY_STATE_CHANGED, listener1);
+//    mgr.registerListener(util::OVERLAY_STATE_CHANGED, listener1);
 //
 //    // log event
 //    std::shared_ptr<LogEvent> event1 =
@@ -513,10 +513,10 @@
 //    sp<TestStateListener> listener3 = new TestStateListener();
 //    sp<TestStateListener> listener4 = new TestStateListener();
 //    StateManager mgr;
-//    mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener1);
-//    mgr.registerListener(android::util::UID_PROCESS_STATE_CHANGED, listener2);
-//    mgr.registerListener(android::util::OVERLAY_STATE_CHANGED, listener3);
-//    mgr.registerListener(android::util::WAKELOCK_STATE_CHANGED, listener4);
+//    mgr.registerListener(util::SCREEN_STATE_CHANGED, listener1);
+//    mgr.registerListener(util::UID_PROCESS_STATE_CHANGED, listener2);
+//    mgr.registerListener(util::OVERLAY_STATE_CHANGED, listener3);
+//    mgr.registerListener(util::WAKELOCK_STATE_CHANGED, listener4);
 //
 //    std::shared_ptr<LogEvent> event1 = buildUidProcessEvent(
 //            1000,
@@ -554,40 +554,40 @@
 //    HashableDimensionKey queryKey1;
 //    getUidProcessKey(1001, &queryKey1);
 //    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE,
-//              getStateInt(mgr, android::util::UID_PROCESS_STATE_CHANGED, queryKey1));
+//              getStateInt(mgr, util::UID_PROCESS_STATE_CHANGED, queryKey1));
 //
 //    // Query for UidProcessState of uid 1004 - not in state map
 //    HashableDimensionKey queryKey2;
 //    getUidProcessKey(1004, &queryKey2);
-//    EXPECT_EQ(-1, getStateInt(mgr, android::util::UID_PROCESS_STATE_CHANGED,
+//    EXPECT_EQ(-1, getStateInt(mgr, util::UID_PROCESS_STATE_CHANGED,
 //                              queryKey2));  // default state
 //
 //    // Query for UidProcessState of uid 1001 - after change in state
 //    mgr.onLogEvent(*event4);
 //    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_TOP,
-//              getStateInt(mgr, android::util::UID_PROCESS_STATE_CHANGED, queryKey1));
+//              getStateInt(mgr, util::UID_PROCESS_STATE_CHANGED, queryKey1));
 //
 //    // Query for ScreenState
 //    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-//              getStateInt(mgr, android::util::SCREEN_STATE_CHANGED, DEFAULT_DIMENSION_KEY));
+//              getStateInt(mgr, util::SCREEN_STATE_CHANGED, DEFAULT_DIMENSION_KEY));
 //
 //    // Query for OverlayState of uid 1000, package name "package2"
 //    HashableDimensionKey queryKey3;
 //    getOverlayKey(1000, "package2", &queryKey3);
 //    EXPECT_EQ(OverlayStateChanged::EXITED,
-//              getStateInt(mgr, android::util::OVERLAY_STATE_CHANGED, queryKey3));
+//              getStateInt(mgr, util::OVERLAY_STATE_CHANGED, queryKey3));
 //
 //    // Query for WakelockState of uid 1005, tag 2
 //    HashableDimensionKey queryKey4;
 //    getPartialWakelockKey(1005, "tag2", &queryKey4);
 //    EXPECT_EQ(WakelockStateChanged::RELEASE,
-//              getStateInt(mgr, android::util::WAKELOCK_STATE_CHANGED, queryKey4));
+//              getStateInt(mgr, util::WAKELOCK_STATE_CHANGED, queryKey4));
 //
 //    // Query for WakelockState of uid 1005, tag 1
 //    HashableDimensionKey queryKey5;
 //    getPartialWakelockKey(1005, "tag1", &queryKey5);
 //    EXPECT_EQ(WakelockStateChanged::ACQUIRE,
-//              getStateInt(mgr, android::util::WAKELOCK_STATE_CHANGED, queryKey5));
+//              getStateInt(mgr, util::WAKELOCK_STATE_CHANGED, queryKey5));
 //}
 
 }  // namespace statsd
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index 58eeed3..050dbf8 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -51,7 +51,7 @@
 }
 
 AtomMatcher CreateTemperatureAtomMatcher() {
-    return CreateSimpleAtomMatcher("TemperatureMatcher", android::util::TEMPERATURE);
+    return CreateSimpleAtomMatcher("TemperatureMatcher", util::TEMPERATURE);
 }
 
 AtomMatcher CreateScheduledJobStateChangedAtomMatcher(const string& name,
@@ -59,7 +59,7 @@
     AtomMatcher atom_matcher;
     atom_matcher.set_id(StringToId(name));
     auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
-    simple_atom_matcher->set_atom_id(android::util::SCHEDULED_JOB_STATE_CHANGED);
+    simple_atom_matcher->set_atom_id(util::SCHEDULED_JOB_STATE_CHANGED);
     auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
     field_value_matcher->set_field(3);  // State field.
     field_value_matcher->set_eq_int(state);
@@ -80,7 +80,7 @@
     AtomMatcher atom_matcher;
     atom_matcher.set_id(StringToId("ScreenBrightnessChanged"));
     auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
-    simple_atom_matcher->set_atom_id(android::util::SCREEN_BRIGHTNESS_CHANGED);
+    simple_atom_matcher->set_atom_id(util::SCREEN_BRIGHTNESS_CHANGED);
     return atom_matcher;
 }
 
@@ -88,7 +88,7 @@
     AtomMatcher atom_matcher;
     atom_matcher.set_id(StringToId("UidProcessStateChanged"));
     auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
-    simple_atom_matcher->set_atom_id(android::util::UID_PROCESS_STATE_CHANGED);
+    simple_atom_matcher->set_atom_id(util::UID_PROCESS_STATE_CHANGED);
     return atom_matcher;
 }
 
@@ -97,7 +97,7 @@
     AtomMatcher atom_matcher;
     atom_matcher.set_id(StringToId(name));
     auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
-    simple_atom_matcher->set_atom_id(android::util::WAKELOCK_STATE_CHANGED);
+    simple_atom_matcher->set_atom_id(util::WAKELOCK_STATE_CHANGED);
     auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
     field_value_matcher->set_field(4);  // State field.
     field_value_matcher->set_eq_int(state);
@@ -117,7 +117,7 @@
     AtomMatcher atom_matcher;
     atom_matcher.set_id(StringToId(name));
     auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
-    simple_atom_matcher->set_atom_id(android::util::BATTERY_SAVER_MODE_STATE_CHANGED);
+    simple_atom_matcher->set_atom_id(util::BATTERY_SAVER_MODE_STATE_CHANGED);
     auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
     field_value_matcher->set_field(1);  // State field.
     field_value_matcher->set_eq_int(state);
@@ -141,7 +141,7 @@
     AtomMatcher atom_matcher;
     atom_matcher.set_id(StringToId(name));
     auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
-    simple_atom_matcher->set_atom_id(android::util::SCREEN_STATE_CHANGED);
+    simple_atom_matcher->set_atom_id(util::SCREEN_STATE_CHANGED);
     auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
     field_value_matcher->set_field(1);  // State field.
     field_value_matcher->set_eq_int(state);
@@ -164,7 +164,7 @@
     AtomMatcher atom_matcher;
     atom_matcher.set_id(StringToId(name));
     auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
-    simple_atom_matcher->set_atom_id(android::util::SYNC_STATE_CHANGED);
+    simple_atom_matcher->set_atom_id(util::SYNC_STATE_CHANGED);
     auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
     field_value_matcher->set_field(3);  // State field.
     field_value_matcher->set_eq_int(state);
@@ -184,7 +184,7 @@
     AtomMatcher atom_matcher;
     atom_matcher.set_id(StringToId(name));
     auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
-    simple_atom_matcher->set_atom_id(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED);
+    simple_atom_matcher->set_atom_id(util::ACTIVITY_FOREGROUND_STATE_CHANGED);
     auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
     field_value_matcher->set_field(4);  // Activity field.
     field_value_matcher->set_eq_int(state);
@@ -206,7 +206,7 @@
     AtomMatcher atom_matcher;
     atom_matcher.set_id(StringToId(name));
     auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
-    simple_atom_matcher->set_atom_id(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
+    simple_atom_matcher->set_atom_id(util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
     auto field_value_matcher = simple_atom_matcher->add_field_value_matcher();
     field_value_matcher->set_field(3);  // Process state field.
     field_value_matcher->set_eq_int(state);
@@ -277,28 +277,28 @@
 State CreateScreenState() {
     State state;
     state.set_id(StringToId("ScreenState"));
-    state.set_atom_id(android::util::SCREEN_STATE_CHANGED);
+    state.set_atom_id(util::SCREEN_STATE_CHANGED);
     return state;
 }
 
 State CreateUidProcessState() {
     State state;
     state.set_id(StringToId("UidProcessState"));
-    state.set_atom_id(android::util::UID_PROCESS_STATE_CHANGED);
+    state.set_atom_id(util::UID_PROCESS_STATE_CHANGED);
     return state;
 }
 
 State CreateOverlayState() {
     State state;
     state.set_id(StringToId("OverlayState"));
-    state.set_atom_id(android::util::OVERLAY_STATE_CHANGED);
+    state.set_atom_id(util::OVERLAY_STATE_CHANGED);
     return state;
 }
 
 State CreateScreenStateWithOnOffMap() {
     State state;
     state.set_id(StringToId("ScreenStateOnOff"));
-    state.set_atom_id(android::util::SCREEN_STATE_CHANGED);
+    state.set_atom_id(util::SCREEN_STATE_CHANGED);
 
     auto map = CreateScreenStateOnOffMap();
     *state.mutable_map() = map;
@@ -309,7 +309,7 @@
 State CreateScreenStateWithInDozeMap() {
     State state;
     state.set_id(StringToId("ScreenStateInDoze"));
-    state.set_atom_id(android::util::SCREEN_STATE_CHANGED);
+    state.set_atom_id(util::SCREEN_STATE_CHANGED);
 
     auto map = CreateScreenStateInDozeMap();
     *state.mutable_map() = map;
@@ -534,7 +534,7 @@
 std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
         uint64_t timestampNs, const android::view::DisplayStateEnum state) {
     AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, android::util::SCREEN_STATE_CHANGED);
+    AStatsEvent_setAtomId(statsEvent, util::SCREEN_STATE_CHANGED);
     AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
 
     AStatsEvent_writeInt32(statsEvent, state);
@@ -551,7 +551,7 @@
 
 std::unique_ptr<LogEvent> CreateBatterySaverOnEvent(uint64_t timestampNs) {
     AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, android::util::BATTERY_SAVER_MODE_STATE_CHANGED);
+    AStatsEvent_setAtomId(statsEvent, util::BATTERY_SAVER_MODE_STATE_CHANGED);
     AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
 
     AStatsEvent_writeInt32(statsEvent, BatterySaverModeStateChanged::ON);
@@ -568,7 +568,7 @@
 
 std::unique_ptr<LogEvent> CreateBatterySaverOffEvent(uint64_t timestampNs) {
     AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, android::util::BATTERY_SAVER_MODE_STATE_CHANGED);
+    AStatsEvent_setAtomId(statsEvent, util::BATTERY_SAVER_MODE_STATE_CHANGED);
     AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
 
     AStatsEvent_writeInt32(statsEvent, BatterySaverModeStateChanged::OFF);
@@ -585,7 +585,7 @@
 
 std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(uint64_t timestampNs, int level) {
     AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, android::util::SCREEN_BRIGHTNESS_CHANGED);
+    AStatsEvent_setAtomId(statsEvent, util::SCREEN_BRIGHTNESS_CHANGED);
     AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
 
     AStatsEvent_writeInt32(statsEvent, level);
@@ -603,7 +603,7 @@
 //std::unique_ptr<LogEvent> CreateScheduledJobStateChangedEvent(
 //        const std::vector<AttributionNodeInternal>& attributions, const string& jobName,
 //        const ScheduledJobStateChanged::State state, uint64_t timestampNs) {
-//    auto event = std::make_unique<LogEvent>(android::util::SCHEDULED_JOB_STATE_CHANGED, timestampNs);
+//    auto event = std::make_unique<LogEvent>(util::SCHEDULED_JOB_STATE_CHANGED, timestampNs);
 //    event->write(attributions);
 //    event->write(jobName);
 //    event->write(state);
@@ -632,7 +632,7 @@
                                                           const string& wakelockName,
                                                           const WakelockStateChanged::State state) {
     AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, android::util::WAKELOCK_STATE_CHANGED);
+    AStatsEvent_setAtomId(statsEvent, util::WAKELOCK_STATE_CHANGED);
     AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
 
     vector<const char*> cTags(attributionTags.size());
@@ -676,7 +676,7 @@
 std::unique_ptr<LogEvent> CreateActivityForegroundStateChangedEvent(
         uint64_t timestampNs, const int uid, const ActivityForegroundStateChanged::State state) {
     AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, android::util::ACTIVITY_FOREGROUND_STATE_CHANGED);
+    AStatsEvent_setAtomId(statsEvent, util::ACTIVITY_FOREGROUND_STATE_CHANGED);
     AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
 
     AStatsEvent_writeInt32(statsEvent, uid);
@@ -710,7 +710,7 @@
                                                       const string& name,
                                                       const SyncStateChanged::State state) {
     AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, android::util::SYNC_STATE_CHANGED);
+    AStatsEvent_setAtomId(statsEvent, util::SYNC_STATE_CHANGED);
     AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
 
     vector<const char*> cTags(attributionTags.size());
@@ -753,7 +753,7 @@
 std::unique_ptr<LogEvent> CreateProcessLifeCycleStateChangedEvent(
         uint64_t timestampNs, const int uid, const ProcessLifeCycleStateChanged::State state) {
     AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
+    AStatsEvent_setAtomId(statsEvent, util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
     AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
 
     AStatsEvent_writeInt32(statsEvent, uid);
@@ -777,7 +777,7 @@
 
 std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(uint64_t timestampNs, const int uid) {
     AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, android::util::APP_CRASH_OCCURRED);
+    AStatsEvent_setAtomId(statsEvent, util::APP_CRASH_OCCURRED);
     AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
 
     AStatsEvent_writeInt32(statsEvent, uid);
@@ -797,7 +797,7 @@
 std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(uint64_t timestampNs, int hostUid,
                                                         int isolatedUid, bool is_create) {
     AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, android::util::ISOLATED_UID_CHANGED);
+    AStatsEvent_setAtomId(statsEvent, util::ISOLATED_UID_CHANGED);
     AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
 
     AStatsEvent_writeInt32(statsEvent, hostUid);
@@ -817,7 +817,7 @@
 std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent(
         uint64_t timestampNs, int uid, const android::app::ProcessStateEnum state) {
     AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, android::util::UID_PROCESS_STATE_CHANGED);
+    AStatsEvent_setAtomId(statsEvent, util::UID_PROCESS_STATE_CHANGED);
     AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
 
     AStatsEvent_writeInt32(statsEvent, uid);
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index 4c25ca3..ead041c 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -25,7 +25,7 @@
 #include "src/hash.h"
 #include "src/logd/LogEvent.h"
 #include "src/stats_log_util.h"
-#include "statslog.h"
+#include "statslog_statsdtest.h"
 
 namespace android {
 namespace os {
@@ -38,8 +38,8 @@
 using google::protobuf::RepeatedPtrField;
 using Status = ::ndk::ScopedAStatus;
 
-const int SCREEN_STATE_ATOM_ID = android::util::SCREEN_STATE_CHANGED;
-const int UID_PROCESS_STATE_ATOM_ID = android::util::UID_PROCESS_STATE_CHANGED;
+const int SCREEN_STATE_ATOM_ID = util::SCREEN_STATE_CHANGED;
+const int UID_PROCESS_STATE_ATOM_ID = util::UID_PROCESS_STATE_CHANGED;
 
 // Converts a ProtoOutputStream to a StatsLogReport proto.
 StatsLogReport outputStreamToProto(ProtoOutputStream* proto);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index f4ee8fa..b3a0be1 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -3628,11 +3628,40 @@
         }
     }
 
+    /**
+     * Set custom state data for this process. It will be included in the record of
+     * {@link ApplicationExitInfo} on the death of the current calling process; the new process
+     * of the app can retrieve this state data by calling
+     * {@link ApplicationExitInfo#getProcessStateSummary} on the record returned by
+     * {@link #getHistoricalProcessExitReasons}.
+     *
+     * <p> This would be useful for the calling app to save its stateful data: if it's
+     * killed later for any reason, the new process of the app can know what the
+     * previous process of the app was doing. For instance, you could use this to encode
+     * the current level in a game, or a set of features/experiments that were enabled. Later you
+     * could analyze under what circumstances the app tends to crash or use too much memory.
+     * However, it's not suggested to rely on this to restore the applications previous UI state
+     * or so, it's only meant for analyzing application healthy status.</p>
+     *
+     * <p> System might decide to throttle the calls to this API; so call this API in a reasonable
+     * manner, excessive calls to this API could result a {@link java.lang.RuntimeException}.
+     * </p>
+     *
+     * @param state The state data
+     */
+    public void setProcessStateSummary(@Nullable byte[] state) {
+        try {
+            getService().setProcessStateSummary(state);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /*
      * @return Whether or not the low memory kill will be reported in
      * {@link #getHistoricalProcessExitReasons}.
      *
-     * @see {@link ApplicationExitInfo#REASON_LOW_MEMORY}
+     * @see ApplicationExitInfo#REASON_LOW_MEMORY
      */
     public static boolean isLowMemoryKillReportSupported() {
         return SystemProperties.getBoolean("persist.sys.lmk.reportkills", false);
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 489a0de..f926075 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -248,7 +248,8 @@
 
     /**
      * Returns whether the given user requires credential entry at this time. This is used to
-     * intercept activity launches for work apps when the Work Challenge is present.
+     * intercept activity launches for locked work apps due to work challenge being triggered or
+     * when the profile user is yet to be unlocked.
      */
     public abstract boolean shouldConfirmCredentials(@UserIdInt int userId);
 
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 4aacf48..7fd02112 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -209,6 +209,12 @@
             "android.activity.pendingIntentLaunchFlags";
 
     /**
+     * See {@link #setTaskAlwaysOnTop}.
+     * @hide
+     */
+    private static final String KEY_TASK_ALWAYS_ON_TOP = "android.activity.alwaysOnTop";
+
+    /**
      * See {@link #setTaskOverlay}.
      * @hide
      */
@@ -337,6 +343,7 @@
     private int mSplitScreenCreateMode = SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
     private boolean mLockTaskMode = false;
     private boolean mDisallowEnterPictureInPictureWhileLaunching;
+    private boolean mTaskAlwaysOnTop;
     private boolean mTaskOverlay;
     private boolean mTaskOverlayCanResume;
     private boolean mAvoidMoveToFront;
@@ -971,6 +978,7 @@
         mLaunchActivityType = opts.getInt(KEY_LAUNCH_ACTIVITY_TYPE, ACTIVITY_TYPE_UNDEFINED);
         mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1);
         mPendingIntentLaunchFlags = opts.getInt(KEY_PENDING_INTENT_LAUNCH_FLAGS, 0);
+        mTaskAlwaysOnTop = opts.getBoolean(KEY_TASK_ALWAYS_ON_TOP, false);
         mTaskOverlay = opts.getBoolean(KEY_TASK_OVERLAY, false);
         mTaskOverlayCanResume = opts.getBoolean(KEY_TASK_OVERLAY_CAN_RESUME, false);
         mAvoidMoveToFront = opts.getBoolean(KEY_AVOID_MOVE_TO_FRONT, false);
@@ -1300,6 +1308,22 @@
     }
 
     /**
+     * Set's whether the task for the activity launched with this option should always be on top.
+     * @hide
+     */
+    @TestApi
+    public void setTaskAlwaysOnTop(boolean alwaysOnTop) {
+        mTaskAlwaysOnTop = alwaysOnTop;
+    }
+
+    /**
+     * @hide
+     */
+    public boolean getTaskAlwaysOnTop() {
+        return mTaskAlwaysOnTop;
+    }
+
+    /**
      * Set's whether the activity launched with this option should be a task overlay. That is the
      * activity will always be the top activity of the task.
      * @param canResume {@code false} if the task will also not be moved to the front of the stack.
@@ -1556,6 +1580,9 @@
         if (mPendingIntentLaunchFlags != 0) {
             b.putInt(KEY_PENDING_INTENT_LAUNCH_FLAGS, mPendingIntentLaunchFlags);
         }
+        if (mTaskAlwaysOnTop) {
+            b.putBoolean(KEY_TASK_ALWAYS_ON_TOP, mTaskAlwaysOnTop);
+        }
         if (mTaskOverlay) {
             b.putBoolean(KEY_TASK_OVERLAY, mTaskOverlay);
         }
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index fa4aa19..9c1a861 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1386,6 +1386,7 @@
             "android:auto_revoke_permissions_if_unused";
 
     /** @hide Auto-revoke app permissions if app is unused for an extended period */
+    @SystemApi
     public static final String OPSTR_AUTO_REVOKE_MANAGED_BY_INSTALLER =
             "android:auto_revoke_managed_by_installer";
 
diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java
index 5df3257..61be01f 100644
--- a/core/java/android/app/ApplicationExitInfo.java
+++ b/core/java/android/app/ApplicationExitInfo.java
@@ -23,7 +23,9 @@
 import android.app.ActivityManager.RunningAppProcessInfo.Importance;
 import android.icu.text.SimpleDateFormat;
 import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.DebugUtils;
@@ -31,12 +33,17 @@
 import android.util.proto.ProtoOutputStream;
 import android.util.proto.WireTypeMismatchException;
 
+import com.android.internal.util.ArrayUtils;
+
+import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Date;
 import java.util.Objects;
+import java.util.zip.GZIPInputStream;
 
 /**
  * Describes the information of an application process's death.
@@ -321,85 +328,105 @@
     // be categorized in {@link #REASON_OTHER}, with subreason code starting from 1000.
 
     /**
-     * @see {@link #getPid}
+     * @see #getPid
      */
     private int mPid;
 
     /**
-     * @see {@link #getRealUid}
+     * @see #getRealUid
      */
     private int mRealUid;
 
     /**
-     * @see {@link #getPackageUid}
+     * @see #getPackageUid
      */
     private int mPackageUid;
 
     /**
-     * @see {@link #getDefiningUid}
+     * @see #getDefiningUid
      */
     private int mDefiningUid;
 
     /**
-     * @see {@link #getProcessName}
+     * @see #getProcessName
      */
     private String mProcessName;
 
     /**
-     * @see {@link #getReason}
+     * @see #getReason
      */
     private @Reason int mReason;
 
     /**
-     * @see {@link #getStatus}
+     * @see #getStatus
      */
     private int mStatus;
 
     /**
-     * @see {@link #getImportance}
+     * @see #getImportance
      */
     private @Importance int mImportance;
 
     /**
-     * @see {@link #getPss}
+     * @see #getPss
      */
     private long mPss;
 
     /**
-     * @see {@link #getRss}
+     * @see #getRss
      */
     private long mRss;
 
     /**
-     * @see {@link #getTimestamp}
+     * @see #getTimestamp
      */
     private @CurrentTimeMillisLong long mTimestamp;
 
     /**
-     * @see {@link #getDescription}
+     * @see #getDescription
      */
     private @Nullable String mDescription;
 
     /**
-     * @see {@link #getSubReason}
+     * @see #getSubReason
      */
     private @SubReason int mSubReason;
 
     /**
-     * @see {@link #getConnectionGroup}
+     * @see #getConnectionGroup
      */
     private int mConnectionGroup;
 
     /**
-     * @see {@link #getPackageName}
+     * @see #getPackageName
      */
     private String mPackageName;
 
     /**
-     * @see {@link #getPackageList}
+     * @see #getPackageList
      */
     private String[] mPackageList;
 
+    /**
+     * @see #getProcessStateSummary
+     */
+    private byte[] mState;
+
+    /**
+     * The file to the trace file in the storage;
+     *
+     * for system internal use only, will not retain across processes.
+     *
+     * @see #getTraceInputStream
+     */
+    private File mTraceFile;
+
+    /**
+     * The Binder interface to retrieve the file descriptor to
+     * the trace file from the system.
+     */
+    private IAppTraceRetriever mAppTraceRetriever;
+
     /** @hide */
     @IntDef(prefix = { "REASON_" }, value = {
         REASON_UNKNOWN,
@@ -557,6 +584,54 @@
     }
 
     /**
+     * Return the state data set by calling {@link ActivityManager#setProcessStateSummary}
+     * from the process before its death.
+     *
+     * @return The process-customized data
+     * @see ActivityManager#setProcessStateSummary(byte[])
+     */
+    public @Nullable byte[] getProcessStateSummary() {
+        return mState;
+    }
+
+    /**
+     * Return the InputStream to the traces that was taken by the system
+     * prior to the death of the process; typically it'll be available when
+     * the reason is {@link #REASON_ANR}, though if the process gets an ANR
+     * but recovers, and dies for another reason later, this trace will be included
+     * in the record of {@link ApplicationExitInfo} still.
+     *
+     * @return The input stream to the traces that was taken by the system
+     *         prior to the death of the process.
+     */
+    public @Nullable InputStream getTraceInputStream() throws IOException {
+        if (mAppTraceRetriever == null) {
+            return null;
+        }
+        try {
+            final ParcelFileDescriptor fd = mAppTraceRetriever.getTraceFileDescriptor(
+                    mPackageName, mPackageUid, mPid);
+            if (fd == null) {
+                return null;
+            }
+            return new GZIPInputStream(new ParcelFileDescriptor.AutoCloseInputStream(fd));
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Similar to {@link #getTraceInputStream} but return the File object.
+     *
+     * For internal use only.
+     *
+     * @hide
+     */
+    public @Nullable File getTraceFile() {
+        return mTraceFile;
+    }
+
+    /**
      * A subtype reason in conjunction with {@link #mReason}.
      *
      * For internal use only.
@@ -569,7 +644,7 @@
 
     /**
      * The connection group this process belongs to, if there is any.
-     * @see {@link android.content.Context#updateServiceGroup}.
+     * @see android.content.Context#updateServiceGroup
      *
      * For internal use only.
      *
@@ -582,8 +657,6 @@
     /**
      * Name of first package running in this process;
      *
-     * For system internal use only, will not retain across processes.
-     *
      * @hide
      */
     public String getPackageName() {
@@ -602,7 +675,7 @@
     }
 
     /**
-     * @see {@link #getPid}
+     * @see #getPid
      *
      * @hide
      */
@@ -611,7 +684,7 @@
     }
 
     /**
-     * @see {@link #getRealUid}
+     * @see #getRealUid
      *
      * @hide
      */
@@ -620,7 +693,7 @@
     }
 
     /**
-     * @see {@link #getPackageUid}
+     * @see #getPackageUid
      *
      * @hide
      */
@@ -629,7 +702,7 @@
     }
 
     /**
-     * @see {@link #getDefiningUid}
+     * @see #getDefiningUid
      *
      * @hide
      */
@@ -638,7 +711,7 @@
     }
 
     /**
-     * @see {@link #getProcessName}
+     * @see #getProcessName
      *
      * @hide
      */
@@ -647,7 +720,7 @@
     }
 
     /**
-     * @see {@link #getReason}
+     * @see #getReason
      *
      * @hide
      */
@@ -656,7 +729,7 @@
     }
 
     /**
-     * @see {@link #getStatus}
+     * @see #getStatus
      *
      * @hide
      */
@@ -665,7 +738,7 @@
     }
 
     /**
-     * @see {@link #getImportance}
+     * @see #getImportance
      *
      * @hide
      */
@@ -674,7 +747,7 @@
     }
 
     /**
-     * @see {@link #getPss}
+     * @see #getPss
      *
      * @hide
      */
@@ -683,7 +756,7 @@
     }
 
     /**
-     * @see {@link #getRss}
+     * @see #getRss
      *
      * @hide
      */
@@ -692,7 +765,7 @@
     }
 
     /**
-     * @see {@link #getTimestamp}
+     * @see #getTimestamp
      *
      * @hide
      */
@@ -701,7 +774,7 @@
     }
 
     /**
-     * @see {@link #getDescription}
+     * @see #getDescription
      *
      * @hide
      */
@@ -710,7 +783,7 @@
     }
 
     /**
-     * @see {@link #getSubReason}
+     * @see #getSubReason
      *
      * @hide
      */
@@ -719,7 +792,7 @@
     }
 
     /**
-     * @see {@link #getConnectionGroup}
+     * @see #getConnectionGroup
      *
      * @hide
      */
@@ -728,7 +801,7 @@
     }
 
     /**
-     * @see {@link #getPackageName}
+     * @see #getPackageName
      *
      * @hide
      */
@@ -737,7 +810,7 @@
     }
 
     /**
-     * @see {@link #getPackageList}
+     * @see #getPackageList
      *
      * @hide
      */
@@ -745,6 +818,33 @@
         mPackageList = packageList;
     }
 
+    /**
+     * @see #getProcessStateSummary
+     *
+     * @hide
+     */
+    public void setProcessStateSummary(final byte[] state) {
+        mState = state;
+    }
+
+    /**
+     * @see #getTraceFile
+     *
+     * @hide
+     */
+    public void setTraceFile(final File traceFile) {
+        mTraceFile = traceFile;
+    }
+
+    /**
+     * @see #mAppTraceRetriever
+     *
+     * @hide
+     */
+    public void setAppTraceRetriever(final IAppTraceRetriever retriever) {
+        mAppTraceRetriever = retriever;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -757,6 +857,7 @@
         dest.writeInt(mPackageUid);
         dest.writeInt(mDefiningUid);
         dest.writeString(mProcessName);
+        dest.writeString(mPackageName);
         dest.writeInt(mConnectionGroup);
         dest.writeInt(mReason);
         dest.writeInt(mSubReason);
@@ -766,6 +867,13 @@
         dest.writeLong(mRss);
         dest.writeLong(mTimestamp);
         dest.writeString(mDescription);
+        dest.writeByteArray(mState);
+        if (mAppTraceRetriever != null) {
+            dest.writeInt(1);
+            dest.writeStrongBinder(mAppTraceRetriever.asBinder());
+        } else {
+            dest.writeInt(0);
+        }
     }
 
     /** @hide */
@@ -779,6 +887,7 @@
         mPackageUid = other.mPackageUid;
         mDefiningUid = other.mDefiningUid;
         mProcessName = other.mProcessName;
+        mPackageName = other.mPackageName;
         mConnectionGroup = other.mConnectionGroup;
         mReason = other.mReason;
         mStatus = other.mStatus;
@@ -790,6 +899,9 @@
         mDescription = other.mDescription;
         mPackageName = other.mPackageName;
         mPackageList = other.mPackageList;
+        mState = other.mState;
+        mTraceFile = other.mTraceFile;
+        mAppTraceRetriever = other.mAppTraceRetriever;
     }
 
     private ApplicationExitInfo(@NonNull Parcel in) {
@@ -798,6 +910,7 @@
         mPackageUid = in.readInt();
         mDefiningUid = in.readInt();
         mProcessName = in.readString();
+        mPackageName = in.readString();
         mConnectionGroup = in.readInt();
         mReason = in.readInt();
         mSubReason = in.readInt();
@@ -807,6 +920,10 @@
         mRss = in.readLong();
         mTimestamp = in.readLong();
         mDescription = in.readString();
+        mState = in.createByteArray();
+        if (in.readInt() == 1) {
+            mAppTraceRetriever = IAppTraceRetriever.Stub.asInterface(in.readStrongBinder());
+        }
     }
 
     public @NonNull static final Creator<ApplicationExitInfo> CREATOR =
@@ -839,6 +956,9 @@
         pw.print(prefix + "  pss="); DebugUtils.printSizeValue(pw, mPss << 10); pw.println();
         pw.print(prefix + "  rss="); DebugUtils.printSizeValue(pw, mRss << 10); pw.println();
         pw.println(prefix + "  description=" + mDescription);
+        pw.println(prefix + "  state=" + (ArrayUtils.isEmpty(mState)
+                ? "empty" : Integer.toString(mState.length) + " bytes"));
+        pw.println(prefix + "  trace=" + mTraceFile);
     }
 
     @Override
@@ -859,6 +979,9 @@
         sb.append(" pss="); DebugUtils.sizeValueToString(mPss << 10, sb);
         sb.append(" rss="); DebugUtils.sizeValueToString(mRss << 10, sb);
         sb.append(" description=").append(mDescription);
+        sb.append(" state=").append(ArrayUtils.isEmpty(mState)
+                ? "empty" : Integer.toString(mState.length) + " bytes");
+        sb.append(" trace=").append(mTraceFile);
         return sb.toString();
     }
 
@@ -961,6 +1084,9 @@
         proto.write(ApplicationExitInfoProto.RSS, mRss);
         proto.write(ApplicationExitInfoProto.TIMESTAMP, mTimestamp);
         proto.write(ApplicationExitInfoProto.DESCRIPTION, mDescription);
+        proto.write(ApplicationExitInfoProto.STATE, mState);
+        proto.write(ApplicationExitInfoProto.TRACE_FILE,
+                mTraceFile == null ? null : mTraceFile.getAbsolutePath());
         proto.end(token);
     }
 
@@ -1019,6 +1145,15 @@
                 case (int) ApplicationExitInfoProto.DESCRIPTION:
                     mDescription = proto.readString(ApplicationExitInfoProto.DESCRIPTION);
                     break;
+                case (int) ApplicationExitInfoProto.STATE:
+                    mState = proto.readBytes(ApplicationExitInfoProto.STATE);
+                    break;
+                case (int) ApplicationExitInfoProto.TRACE_FILE:
+                    final String path = proto.readString(ApplicationExitInfoProto.TRACE_FILE);
+                    if (!TextUtils.isEmpty(path)) {
+                        mTraceFile = new File(path);
+                    }
+                    break;
             }
         }
         proto.end(token);
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 18df401..0b0a803 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -3297,15 +3297,6 @@
     }
 
     @Override
-    public String[] getTelephonyPackageNames() {
-        try {
-            return mPM.getTelephonyPackageNames();
-        } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
-        }
-    }
-
-    @Override
     public String getSystemCaptionsServicePackageName() {
         try {
             return mPM.getSystemCaptionsServicePackageName();
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 6f0611e..b8221b4 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -652,4 +652,27 @@
      */
     void setActivityLocusContext(in ComponentName activity, in LocusId locusId,
             in IBinder appToken);
+
+    /**
+     * Set custom state data for this process. It will be included in the record of
+     * {@link ApplicationExitInfo} on the death of the current calling process; the new process
+     * of the app can retrieve this state data by calling
+     * {@link ApplicationExitInfo#getProcessStateSummary} on the record returned by
+     * {@link #getHistoricalProcessExitReasons}.
+     *
+     * <p> This would be useful for the calling app to save its stateful data: if it's
+     * killed later for any reason, the new process of the app can know what the
+     * previous process of the app was doing. For instance, you could use this to encode
+     * the current level in a game, or a set of features/experiments that were enabled. Later you
+     * could analyze under what circumstances the app tends to crash or use too much memory.
+     * However, it's not suggested to rely on this to restore the applications previous UI state
+     * or so, it's only meant for analyzing application healthy status.</p>
+     *
+     * <p> System might decide to throttle the calls to this API; so call this API in a reasonable
+     * manner, excessive calls to this API could result a {@link java.lang.RuntimeException}.
+     * </p>
+     *
+     * @param state The customized state data
+     */
+    void setProcessStateSummary(in byte[] state);
 }
diff --git a/core/java/android/app/IAppTraceRetriever.aidl b/core/java/android/app/IAppTraceRetriever.aidl
new file mode 100644
index 0000000..1463da7
--- /dev/null
+++ b/core/java/android/app/IAppTraceRetriever.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.os.ParcelFileDescriptor;
+
+/**
+ * An interface that's to be used by {@link ApplicationExitInfo#getTraceFile()}
+ * to retrieve the actual file descriptor to its trace file.
+ *
+ * @hide
+ */
+interface IAppTraceRetriever {
+    /**
+     * Retrieve the trace file with given packageName/uid/pid.
+     *
+     * @param packagename The target package name of the trace
+     * @param uid The target UID of the trace
+     * @param pid The target PID of the trace
+     * @return The file descriptor to the trace file, or null if it's not found.
+     */
+    ParcelFileDescriptor getTraceFileDescriptor(in String packageName,
+            int uid, int pid);
+}
diff --git a/core/java/android/app/ITaskOrganizerController.aidl b/core/java/android/app/ITaskOrganizerController.aidl
index 9d6c3d6..a448e13 100644
--- a/core/java/android/app/ITaskOrganizerController.aidl
+++ b/core/java/android/app/ITaskOrganizerController.aidl
@@ -32,6 +32,11 @@
     void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode);
 
     /**
+     * Unregisters a previously registered task organizer.
+     */
+    void unregisterTaskOrganizer(ITaskOrganizer organizer);
+
+    /**
      * Apply multiple WindowContainer operations at once.
      * @param organizer If non-null this transaction will use the synchronization
      *        scheme described in BLASTSyncEngine.java. The SurfaceControl transaction
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index e8f30df..1aabd24 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -359,14 +359,6 @@
             }
         });
 
-        registerService(Context.NETWORK_STACK_SERVICE, IBinder.class,
-                new StaticServiceFetcher<IBinder>() {
-                    @Override
-                    public IBinder createService() {
-                        return ServiceManager.getService(Context.NETWORK_STACK_SERVICE);
-                    }
-                });
-
         registerService(Context.TETHERING_SERVICE, TetheringManager.class,
                 new CachedServiceFetcher<TetheringManager>() {
             @Override
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 5b8ee71..37f1a65 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -6832,6 +6832,10 @@
      * package will no longer be suspended. The admin can block this by using
      * {@link #setUninstallBlocked}.
      *
+     * <p>Some apps cannot be suspended, such as device admins, the active launcher, the required
+     * package installer, the required package uninstaller, the required package verifier, the
+     * default dialer, and the permission controller.
+     *
      * @param admin The name of the admin component to check, or {@code null} if the caller is a
      *            package access delegate.
      * @param packageNames The package names to suspend or unsuspend.
@@ -11919,13 +11923,17 @@
     }
 
     /**
-     * Called by device owner or profile owner of an organization-owned managed profile to return
-     * whether Common Criteria mode is currently enabled for the device.
+     * Returns whether Common Criteria mode is currently enabled. Device owner and profile owner of
+     * an organization-owned managed profile can query its own Common Criteria mode setting by
+     * calling this method with its admin {@link ComponentName}. Any caller can obtain the
+     * aggregated device-wide Common Criteria mode state by passing {@code null} as the
+     * {@code admin} argument.
      *
-     * @param admin which {@link DeviceAdminReceiver} this request is associated with.
+     * @param admin which {@link DeviceAdminReceiver} this request is associated with, or
+     *     {@code null} if the caller is not a device admin.
      * @return {@code true} if Common Criteria mode is enabled, {@code false} otherwise.
      */
-    public boolean isCommonCriteriaModeEnabled(@NonNull ComponentName admin) {
+    public boolean isCommonCriteriaModeEnabled(@Nullable ComponentName admin) {
         throwIfParentInstance("isCommonCriteriaModeEnabled");
         if (mService != null) {
             try {
diff --git a/core/java/android/app/timezonedetector/ManualTimeZoneSuggestion.java b/core/java/android/app/timezonedetector/ManualTimeZoneSuggestion.java
index 3a9adc7..22e2efb 100644
--- a/core/java/android/app/timezonedetector/ManualTimeZoneSuggestion.java
+++ b/core/java/android/app/timezonedetector/ManualTimeZoneSuggestion.java
@@ -20,7 +20,9 @@
 import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.ShellCommand;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -127,4 +129,32 @@
                 + ", mDebugInfo=" + mDebugInfo
                 + '}';
     }
+
+    /** @hide */
+    public static ManualTimeZoneSuggestion parseCommandLineArg(@NonNull ShellCommand cmd) {
+        String zoneId = null;
+        String opt;
+        while ((opt = cmd.getNextArg()) != null) {
+            switch (opt) {
+                case "--zone_id": {
+                    zoneId = cmd.getNextArgRequired();
+                    break;
+                }
+                default: {
+                    throw new IllegalArgumentException("Unknown option: " + opt);
+                }
+            }
+        }
+        ManualTimeZoneSuggestion suggestion = new ManualTimeZoneSuggestion(zoneId);
+        suggestion.addDebugInfo("Command line injection");
+        return suggestion;
+    }
+
+    /** @hide */
+    public static void printCommandLineOpts(@NonNull PrintWriter pw) {
+        pw.println("Manual suggestion options:");
+        pw.println("  --zone_id <Olson ID>");
+        pw.println();
+        pw.println("See " + ManualTimeZoneSuggestion.class.getName() + " for more information");
+    }
 }
diff --git a/core/java/android/app/timezonedetector/TelephonyTimeZoneSuggestion.java b/core/java/android/app/timezonedetector/TelephonyTimeZoneSuggestion.java
index 150c01d..430462b 100644
--- a/core/java/android/app/timezonedetector/TelephonyTimeZoneSuggestion.java
+++ b/core/java/android/app/timezonedetector/TelephonyTimeZoneSuggestion.java
@@ -21,7 +21,10 @@
 import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.ShellCommand;
+import android.text.TextUtils;
 
+import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
@@ -392,4 +395,96 @@
             return new TelephonyTimeZoneSuggestion(this);
         }
     }
+
+    /** @hide */
+    public static TelephonyTimeZoneSuggestion parseCommandLineArg(@NonNull ShellCommand cmd)
+            throws IllegalArgumentException {
+        Integer slotIndex = null;
+        String zoneId = null;
+        Integer quality = null;
+        Integer matchType = null;
+        String opt;
+        while ((opt = cmd.getNextArg()) != null) {
+            switch (opt) {
+                case "--slot_index": {
+                    slotIndex = Integer.parseInt(cmd.getNextArgRequired());
+                    break;
+                }
+                case "--zone_id": {
+                    zoneId = cmd.getNextArgRequired();
+                    break;
+                }
+                case "--quality": {
+                    quality = parseQualityCommandLineArg(cmd.getNextArgRequired());
+                    break;
+                }
+                case "--match_type": {
+                    matchType = parseMatchTypeCommandLineArg(cmd.getNextArgRequired());
+                    break;
+                }
+                default: {
+                    throw new IllegalArgumentException("Unknown option: " + opt);
+                }
+            }
+        }
+
+        if (slotIndex == null) {
+            throw new IllegalArgumentException("No slotIndex specified.");
+        }
+
+        Builder builder = new Builder(slotIndex);
+        if (!(TextUtils.isEmpty(zoneId) || "_".equals(zoneId))) {
+            builder.setZoneId(zoneId);
+        }
+        if (quality != null) {
+            builder.setQuality(quality);
+        }
+        if (matchType != null) {
+            builder.setMatchType(matchType);
+        }
+        builder.addDebugInfo("Command line injection");
+        return builder.build();
+    }
+
+    private static int parseQualityCommandLineArg(@NonNull String arg) {
+        switch (arg) {
+            case "single":
+                return QUALITY_SINGLE_ZONE;
+            case "multiple_same":
+                return QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
+            case "multiple_different":
+                return QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
+            default:
+                throw new IllegalArgumentException("Unrecognized quality: " + arg);
+        }
+    }
+
+    private static int parseMatchTypeCommandLineArg(@NonNull String arg) {
+        switch (arg) {
+            case "emulator":
+                return MATCH_TYPE_EMULATOR_ZONE_ID;
+            case "country_with_offset":
+                return MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET;
+            case "country":
+                return MATCH_TYPE_NETWORK_COUNTRY_ONLY;
+            case "test_network":
+                return MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY;
+            default:
+                throw new IllegalArgumentException("Unrecognized match_type: " + arg);
+        }
+    }
+
+    /** @hide */
+    public static void printCommandLineOpts(@NonNull PrintWriter pw) {
+        pw.println("Telephony suggestion options:");
+        pw.println("  --slot_index <number>");
+        pw.println("  To withdraw a previous suggestion:");
+        pw.println("    [--zone_id \"_\"]");
+        pw.println("  To make a new suggestion:");
+        pw.println("    --zone_id <Olson ID>");
+        pw.println("    --quality <single|multiple_same|multiple_different>");
+        pw.println("    --match_type <emulator|country_with_offset|country|test_network>");
+        pw.println();
+        pw.println("See " + TelephonyTimeZoneSuggestion.class.getName() + " for more information");
+    }
 }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 318ae11..6f46066 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3430,7 +3430,7 @@
             TELEPHONY_SUBSCRIPTION_SERVICE,
             CARRIER_CONFIG_SERVICE,
             EUICC_SERVICE,
-            MMS_SERVICE,
+            //@hide: MMS_SERVICE,
             TELECOM_SERVICE,
             CLIPBOARD_SERVICE,
             INPUT_METHOD_SERVICE,
@@ -3984,8 +3984,6 @@
      * @hide
      * @see NetworkStackClient
      */
-    @SystemApi
-    @TestApi
     public static final String NETWORK_STACK_SERVICE = "network_stack";
 
     /**
@@ -4344,6 +4342,7 @@
      *
      * @see #getSystemService(String)
      * @see android.telephony.MmsManager
+     * @hide
      */
     public static final String MMS_SERVICE = "mms";
 
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 38c1890..95385ee 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3675,9 +3675,7 @@
      * {@link android.Manifest.permission#MANAGE_USERS} to receive this broadcast.
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    @SystemApi
+    @UnsupportedAppUsage
     public static final String ACTION_USER_SWITCHED =
             "android.intent.action.USER_SWITCHED";
 
diff --git a/core/java/android/content/pm/IDataLoader.aidl b/core/java/android/content/pm/IDataLoader.aidl
index 6a2658d..5ec6341 100644
--- a/core/java/android/content/pm/IDataLoader.aidl
+++ b/core/java/android/content/pm/IDataLoader.aidl
@@ -29,9 +29,9 @@
    void create(int id, in DataLoaderParamsParcel params,
            in FileSystemControlParcel control,
            IDataLoaderStatusListener listener);
-   void start();
-   void stop();
-   void destroy();
+   void start(int id);
+   void stop(int id);
+   void destroy(int id);
 
-   void prepareImage(in InstallationFileParcel[] addedFiles, in @utf8InCpp String[] removedFiles);
+   void prepareImage(int id, in InstallationFileParcel[] addedFiles, in @utf8InCpp String[] removedFiles);
 }
diff --git a/core/java/android/content/pm/IDataLoaderStatusListener.aidl b/core/java/android/content/pm/IDataLoaderStatusListener.aidl
index 5011faa..9819b5d 100644
--- a/core/java/android/content/pm/IDataLoaderStatusListener.aidl
+++ b/core/java/android/content/pm/IDataLoaderStatusListener.aidl
@@ -31,9 +31,7 @@
     const int DATA_LOADER_IMAGE_READY = 4;
     const int DATA_LOADER_IMAGE_NOT_READY = 5;
 
-    const int DATA_LOADER_SLOW_CONNECTION = 6;
-    const int DATA_LOADER_NO_CONNECTION = 7;
-    const int DATA_LOADER_CONNECTION_OK = 8;
+    const int DATA_LOADER_UNRECOVERABLE = 6;
 
     /** Data loader status callback */
     void onStatusChanged(in int dataLoaderId, in int status);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 0311120..b52034f 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -680,8 +680,6 @@
 
     String getWellbeingPackageName();
 
-    String[] getTelephonyPackageNames();
-
     String getAppPredictionServicePackageName();
 
     String getSystemCaptionsServicePackageName();
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 05ff830..84eabdb 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -7796,18 +7796,6 @@
     }
 
     /**
-     * @return the system defined telephony package names, or null if there's none.
-     *
-     * @hide
-     */
-    @Nullable
-    @TestApi
-    public String[] getTelephonyPackageNames() {
-        throw new UnsupportedOperationException(
-                "getTelephonyPackageNames not implemented in subclass");
-    }
-
-    /**
      * @return the system defined content capture service package name, or null if there's none.
      *
      * @hide
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 3aa1a6d..c6c2882 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -239,17 +239,6 @@
 
     /**
      * Additional flag for {@link #protectionLevel}, corresponding
-     * to the <code>telephony</code> value of
-     * {@link android.R.attr#protectionLevel}.
-     *
-     * @hide
-     */
-    @SystemApi
-    @TestApi
-    public static final int PROTECTION_FLAG_TELEPHONY = 0x400000;
-
-    /**
-     * Additional flag for {@link #protectionLevel}, corresponding
      * to the <code>companion</code> value of
      * {@link android.R.attr#protectionLevel}.
      *
@@ -291,7 +280,6 @@
             PROTECTION_FLAG_CONFIGURATOR,
             PROTECTION_FLAG_INCIDENT_REPORT_APPROVER,
             PROTECTION_FLAG_APP_PREDICTOR,
-            PROTECTION_FLAG_TELEPHONY,
             PROTECTION_FLAG_COMPANION,
             PROTECTION_FLAG_RETAIL_DEMO,
     })
@@ -537,9 +525,6 @@
         if ((level & PermissionInfo.PROTECTION_FLAG_APP_PREDICTOR) != 0) {
             protLevel += "|appPredictor";
         }
-        if ((level & PermissionInfo.PROTECTION_FLAG_TELEPHONY) != 0) {
-            protLevel += "|telephony";
-        }
         if ((level & PermissionInfo.PROTECTION_FLAG_RETAIL_DEMO) != 0) {
             protLevel += "|retailDemo";
         }
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index e41ed85..6f8acb6 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -1820,8 +1820,8 @@
                 .setUseEmbeddedDex(bool(false, R.styleable.AndroidManifestApplication_useEmbeddedDex, sa))
                 .setUsesNonSdkApi(bool(false, R.styleable.AndroidManifestApplication_usesNonSdkApi, sa))
                 .setVmSafeMode(bool(false, R.styleable.AndroidManifestApplication_vmSafeMode, sa))
-                .setDontAutoRevokePermissions(bool(false, R.styleable.AndroidManifestApplication_requestDontAutoRevokePermissions, sa))
-                .setAllowDontAutoRevokePermissions(bool(false, R.styleable.AndroidManifestApplication_allowDontAutoRevokePermissions, sa))
+                .setDontAutoRevokePermissions(bool(false, R.styleable.AndroidManifestApplication_requestAutoRevokePermissionsExemption, sa))
+                .setAllowDontAutoRevokePermissions(bool(false, R.styleable.AndroidManifestApplication_allowAutoRevokePermissionsExemption, sa))
                 // targetSdkVersion gated
                 .setAllowAudioPlaybackCapture(bool(targetSdk >= Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture, sa))
                 .setBaseHardwareAccelerated(bool(targetSdk >= Build.VERSION_CODES.ICE_CREAM_SANDWICH, R.styleable.AndroidManifestApplication_hardwareAccelerated, sa))
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 7e72b73d..737fe60 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -2860,6 +2860,29 @@
             new Key<android.hardware.camera2.params.MandatoryStreamCombination[]>("android.scaler.mandatoryStreamCombinations", android.hardware.camera2.params.MandatoryStreamCombination[].class);
 
     /**
+     * <p>An array of mandatory concurrent stream combinations.
+     * This is an app-readable conversion of the concurrent mandatory stream combination
+     * {@link android.hardware.camera2.CameraDevice#createCaptureSession tables}.</p>
+     * <p>The array of
+     * {@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
+     * generated according to the documented
+     * {@link android.hardware.camera2.CameraDevice#createCaptureSession guideline} for each
+     * device which has its Id present in the set returned by
+     * {@link android.hardware.camera2.CameraManager#getConcurrentCameraIds }.
+     * Clients can use the array as a quick reference to find an appropriate camera stream
+     * combination.
+     * The mandatory stream combination array will be {@code null} in case the device is not a
+     * part of at least one set of combinations returned by
+     * {@link android.hardware.camera2.CameraManager#getConcurrentCameraIds }.</p>
+     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+     */
+    @PublicKey
+    @NonNull
+    @SyntheticKey
+    public static final Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS =
+            new Key<android.hardware.camera2.params.MandatoryStreamCombination[]>("android.scaler.mandatoryConcurrentStreamCombinations", android.hardware.camera2.params.MandatoryStreamCombination[].class);
+
+    /**
      * <p>List of rotate-and-crop modes for {@link CaptureRequest#SCALER_ROTATE_AND_CROP android.scaler.rotateAndCrop} that are supported by this camera device.</p>
      * <p>This entry lists the valid modes for {@link CaptureRequest#SCALER_ROTATE_AND_CROP android.scaler.rotateAndCrop} for this camera device.</p>
      * <p>Starting with API level 30, all devices will list at least <code>ROTATE_AND_CROP_NONE</code>.
@@ -2875,28 +2898,7 @@
     @NonNull
     public static final Key<int[]> SCALER_AVAILABLE_ROTATE_AND_CROP_MODES =
             new Key<int[]>("android.scaler.availableRotateAndCropModes", int[].class);
-    /**
-     * <p>An array of mandatory concurrent stream combinations.
-     * This is an app-readable conversion of the concurrent mandatory stream combination
-     * {@link android.hardware.camera2.CameraDevice#createCaptureSession tables}.</p>
-     * <p>The array of
-     * {@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
-     * generated according to the documented
-     * {@link android.hardware.camera2.CameraDevice#createCaptureSession guideline} for each device
-     * which has its Id present in the set returned by
-     * {@link android.hardware.camera2.CameraManager#getConcurrentCameraIds}.
-     * Clients can use the array as a quick reference to find an appropriate camera stream
-     * combination.
-     * The mandatory stream combination array will be {@code null} in case the device is not a part
-     * of at least one set of combinations returned by
-     * {@link android.hardware.camera2.CameraManager#getConcurrentCameraIds}.</p>
-     * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
-     */
-    @PublicKey
-    @NonNull
-    @SyntheticKey
-    public static final Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS =
-            new Key<android.hardware.camera2.params.MandatoryStreamCombination[]>("android.scaler.mandatoryConcurrentStreamCombinations", android.hardware.camera2.params.MandatoryStreamCombination[].class);
+
     /**
      * <p>The area of the image sensor which corresponds to active pixels after any geometric
      * distortion correction has been applied.</p>
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 8f3cb93..45d6fed 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1066,8 +1066,9 @@
      * <li>One Jpeg ImageReader, any resolution: the camera device is
      *    allowed to slow down JPEG output speed by 50% if there is any ongoing offline
      *    session.</li>
-     * <li>One ImageWriter surface of private format, any resolution if the device supports
-     *    PRIVATE_REPROCESSING capability</li>
+     * <li>If the device supports PRIVATE_REPROCESSING, one pair of ImageWriter/ImageReader
+     *    surfaces of private format, with the same resolution that is larger or equal to
+     *    the JPEG ImageReader resolution above.</li>
      * </ol>
      * </li>
      * <li>Alternatively, the active camera session above can be replaced by an legacy
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 81735ac..2418014 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -145,16 +145,6 @@
     public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
 
     /**
-     * A temporary hack until SUPL system can get off the legacy APIS.
-     * They do too many network requests and the long list of apps listening
-     * and waking due to the CONNECTIVITY_ACTION broadcast makes it expensive.
-     * Use this broadcast intent instead for SUPL requests.
-     * @hide
-     */
-    public static final String CONNECTIVITY_ACTION_SUPL =
-            "android.net.conn.CONNECTIVITY_CHANGE_SUPL";
-
-    /**
      * The device has connected to a network that has presented a captive
      * portal, which is blocking Internet connectivity. The user was presented
      * with a notification that network sign in is required,
@@ -1517,84 +1507,6 @@
         return null;
     }
 
-    /**
-     * Guess what the network request was trying to say so that the resulting
-     * network is accessible via the legacy (deprecated) API such as
-     * requestRouteToHost.
-     *
-     * This means we should try to be fairly precise about transport and
-     * capability but ignore things such as networkSpecifier.
-     * If the request has more than one transport or capability it doesn't
-     * match the old legacy requests (they selected only single transport/capability)
-     * so this function cannot map the request to a single legacy type and
-     * the resulting network will not be available to the legacy APIs.
-     *
-     * This code is only called from the requestNetwork API (L and above).
-     *
-     * Setting a legacy type causes CONNECTIVITY_ACTION broadcasts, which are expensive
-     * because they wake up lots of apps - see http://b/23350688 . So we currently only
-     * do this for SUPL requests, which are the only ones that we know need it. If
-     * omitting these broadcasts causes unacceptable app breakage, then for backwards
-     * compatibility we can send them:
-     *
-     * if (targetSdkVersion < Build.VERSION_CODES.M) &&        // legacy API unsupported >= M
-     *     targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP))  // requestNetwork not present < L
-     *
-     * TODO - This should be removed when the legacy APIs are removed.
-     */
-    private int inferLegacyTypeForNetworkCapabilities(NetworkCapabilities netCap) {
-        if (netCap == null) {
-            return TYPE_NONE;
-        }
-
-        if (!netCap.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
-            return TYPE_NONE;
-        }
-
-        // Do this only for SUPL, until GnssLocationProvider is fixed. http://b/25876485 .
-        if (!netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) {
-            // NOTE: if this causes app breakage, we should not just comment out this early return;
-            // instead, we should make this early return conditional on the requesting app's target
-            // SDK version, as described in the comment above.
-            return TYPE_NONE;
-        }
-
-        String type = null;
-        int result = TYPE_NONE;
-
-        if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) {
-            type = "enableCBS";
-            result = TYPE_MOBILE_CBS;
-        } else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)) {
-            type = "enableIMS";
-            result = TYPE_MOBILE_IMS;
-        } else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOTA)) {
-            type = "enableFOTA";
-            result = TYPE_MOBILE_FOTA;
-        } else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)) {
-            type = "enableDUN";
-            result = TYPE_MOBILE_DUN;
-        } else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) {
-            type = "enableSUPL";
-            result = TYPE_MOBILE_SUPL;
-        // back out this hack for mms as they no longer need this and it's causing
-        // device slowdowns - b/23350688 (note, supl still needs this)
-        //} else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) {
-        //    type = "enableMMS";
-        //    result = TYPE_MOBILE_MMS;
-        } else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
-            type = "enableHIPRI";
-            result = TYPE_MOBILE_HIPRI;
-        }
-        if (type != null) {
-            NetworkCapabilities testCap = networkCapabilitiesForFeature(TYPE_MOBILE, type);
-            if (testCap.equalsNetCapabilities(netCap) && testCap.equalsTransportTypes(netCap)) {
-                return result;
-            }
-        }
-        return TYPE_NONE;
-    }
-
     private int legacyTypeForNetworkCapabilities(NetworkCapabilities netCap) {
         if (netCap == null) return TYPE_NONE;
         if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) {
@@ -2575,13 +2487,13 @@
             }
 
             @Override
-            public void onTetheringFailed(final int resultCode) {
+            public void onTetheringFailed(final int error) {
                 callback.onTetheringFailed();
             }
         };
 
         final TetheringRequest request = new TetheringRequest.Builder(type)
-                .setSilentProvisioning(!showProvisioningUi).build();
+                .setShouldShowEntitlementUi(showProvisioningUi).build();
 
         mTetheringManager.startTethering(request, executor, tetheringCallback);
     }
@@ -2801,11 +2713,12 @@
     public static final int TETHER_ERROR_UNAVAIL_IFACE =
             TetheringManager.TETHER_ERROR_UNAVAIL_IFACE;
     /**
-     * @deprecated Use {@link TetheringManager#TETHER_ERROR_MASTER_ERROR}.
+     * @deprecated Use {@link TetheringManager#TETHER_ERROR_INTERNAL_ERROR}.
      * {@hide}
      */
     @Deprecated
-    public static final int TETHER_ERROR_MASTER_ERROR = TetheringManager.TETHER_ERROR_MASTER_ERROR;
+    public static final int TETHER_ERROR_MASTER_ERROR =
+            TetheringManager.TETHER_ERROR_INTERNAL_ERROR;
     /**
      * @deprecated Use {@link TetheringManager#TETHER_ERROR_TETHER_IFACE_ERROR}.
      * {@hide}
@@ -2821,19 +2734,19 @@
     public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR =
             TetheringManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
     /**
-     * @deprecated Use {@link TetheringManager#TETHER_ERROR_ENABLE_NAT_ERROR}.
+     * @deprecated Use {@link TetheringManager#TETHER_ERROR_ENABLE_FORWARDING_ERROR}.
      * {@hide}
      */
     @Deprecated
     public static final int TETHER_ERROR_ENABLE_NAT_ERROR =
-            TetheringManager.TETHER_ERROR_ENABLE_NAT_ERROR;
+            TetheringManager.TETHER_ERROR_ENABLE_FORWARDING_ERROR;
     /**
-     * @deprecated Use {@link TetheringManager#TETHER_ERROR_DISABLE_NAT_ERROR}.
+     * @deprecated Use {@link TetheringManager#TETHER_ERROR_DISABLE_FORWARDING_ERROR}.
      * {@hide}
      */
     @Deprecated
     public static final int TETHER_ERROR_DISABLE_NAT_ERROR =
-            TetheringManager.TETHER_ERROR_DISABLE_NAT_ERROR;
+            TetheringManager.TETHER_ERROR_DISABLE_FORWARDING_ERROR;
     /**
      * @deprecated Use {@link TetheringManager#TETHER_ERROR_IFACE_CFG_ERROR}.
      * {@hide}
@@ -2842,13 +2755,13 @@
     public static final int TETHER_ERROR_IFACE_CFG_ERROR =
             TetheringManager.TETHER_ERROR_IFACE_CFG_ERROR;
     /**
-     * @deprecated Use {@link TetheringManager#TETHER_ERROR_PROVISION_FAILED}.
+     * @deprecated Use {@link TetheringManager#TETHER_ERROR_PROVISIONING_FAILED}.
      * {@hide}
      */
     @SystemApi
     @Deprecated
     public static final int TETHER_ERROR_PROVISION_FAILED =
-            TetheringManager.TETHER_ERROR_PROVISION_FAILED;
+            TetheringManager.TETHER_ERROR_PROVISIONING_FAILED;
     /**
      * @deprecated Use {@link TetheringManager#TETHER_ERROR_DHCPSERVER_ERROR}.
      * {@hide}
@@ -2880,7 +2793,14 @@
     @UnsupportedAppUsage
     @Deprecated
     public int getLastTetherError(String iface) {
-        return mTetheringManager.getLastTetherError(iface);
+        int error = mTetheringManager.getLastTetherError(iface);
+        if (error == TetheringManager.TETHER_ERROR_UNKNOWN_TYPE) {
+            // TETHER_ERROR_UNKNOWN_TYPE was introduced with TetheringManager and has never been
+            // returned by ConnectivityManager. Convert it to the legacy TETHER_ERROR_UNKNOWN_IFACE
+            // instead.
+            error = TetheringManager.TETHER_ERROR_UNKNOWN_IFACE;
+        }
+        return error;
     }
 
     /** @hide */
@@ -3893,9 +3813,8 @@
      */
     public void requestNetwork(@NonNull NetworkRequest request,
             @NonNull NetworkCallback networkCallback, @NonNull Handler handler) {
-        int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
         CallbackHandler cbHandler = new CallbackHandler(handler);
-        requestNetwork(request, networkCallback, 0, legacyType, cbHandler);
+        requestNetwork(request, networkCallback, 0, TYPE_NONE, cbHandler);
     }
 
     /**
@@ -3928,8 +3847,7 @@
     public void requestNetwork(@NonNull NetworkRequest request,
             @NonNull NetworkCallback networkCallback, int timeoutMs) {
         checkTimeout(timeoutMs);
-        int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
-        requestNetwork(request, networkCallback, timeoutMs, legacyType, getDefaultHandler());
+        requestNetwork(request, networkCallback, timeoutMs, TYPE_NONE, getDefaultHandler());
     }
 
     /**
@@ -3954,9 +3872,8 @@
     public void requestNetwork(@NonNull NetworkRequest request,
             @NonNull NetworkCallback networkCallback, @NonNull Handler handler, int timeoutMs) {
         checkTimeout(timeoutMs);
-        int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
         CallbackHandler cbHandler = new CallbackHandler(handler);
-        requestNetwork(request, networkCallback, timeoutMs, legacyType, cbHandler);
+        requestNetwork(request, networkCallback, timeoutMs, TYPE_NONE, cbHandler);
     }
 
     /**
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 732ceb5..2c356e4 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -167,7 +167,19 @@
         this(source, false /* parcelSensitiveFields */);
     }
 
-    private LinkProperties(@Nullable LinkProperties source, boolean parcelSensitiveFields) {
+    /**
+     * Create a copy of a {@link LinkProperties} that may preserve fields that were set
+     * based on the permissions of the process that originally received it.
+     *
+     * <p>By default {@link LinkProperties} does not preserve such fields during parceling, as
+     * they should not be shared outside of the process that receives them without appropriate
+     * checks.
+     * @param parcelSensitiveFields Whether the sensitive fields should be kept when parceling
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public LinkProperties(@Nullable LinkProperties source, boolean parcelSensitiveFields) {
         mParcelSensitiveFields = parcelSensitiveFields;
         if (source == null) return;
         mIfaceName = source.mIfaceName;
@@ -674,17 +686,29 @@
             route.getDestination(),
             route.getGateway(),
             mIfaceName,
-            route.getType());
+            route.getType(),
+            route.getMtu());
+    }
+
+    private int findRouteIndexByDestination(RouteInfo route) {
+        for (int i = 0; i < mRoutes.size(); i++) {
+            if (mRoutes.get(i).isSameDestinationAs(route)) {
+                return i;
+            }
+        }
+        return -1;
     }
 
     /**
-     * Adds a {@link RouteInfo} to this {@code LinkProperties}, if not present. If the
-     * {@link RouteInfo} had an interface name set and that differs from the interface set for this
-     * {@code LinkProperties} an {@link IllegalArgumentException} will be thrown.  The proper
+     * Adds a {@link RouteInfo} to this {@code LinkProperties}, if a {@link RouteInfo}
+     * with the same destination exists with different properties (e.g., different MTU),
+     * it will be updated. If the {@link RouteInfo} had an interface name set and
+     * that differs from the interface set for this {@code LinkProperties} an
+     * {@link IllegalArgumentException} will be thrown.  The proper
      * course is to add either un-named or properly named {@link RouteInfo}.
      *
      * @param route A {@link RouteInfo} to add to this object.
-     * @return {@code false} if the route was already present, {@code true} if it was added.
+     * @return {@code true} was added or updated, false otherwise.
      */
     public boolean addRoute(@NonNull RouteInfo route) {
         String routeIface = route.getInterface();
@@ -694,11 +718,20 @@
                             + " vs. " + mIfaceName);
         }
         route = routeWithInterface(route);
-        if (!mRoutes.contains(route)) {
+
+        int i = findRouteIndexByDestination(route);
+        if (i == -1) {
+            // Route was not present. Add it.
             mRoutes.add(route);
             return true;
+        } else if (mRoutes.get(i).equals(route)) {
+            // Route was present and has same properties. Do nothing.
+            return false;
+        } else {
+            // Route was present and has different properties. Update it.
+            mRoutes.set(i, route);
+            return true;
         }
-        return false;
     }
 
     /**
@@ -706,6 +739,7 @@
      * specify an interface and the interface must match the interface of this
      * {@code LinkProperties}, or it will not be removed.
      *
+     * @param route A {@link RouteInfo} specifying the route to remove.
      * @return {@code true} if the route was removed, {@code false} if it was not present.
      *
      * @hide
@@ -1561,22 +1595,6 @@
     }
 
     /**
-     * Create a copy of this {@link LinkProperties} that will preserve fields that were set
-     * based on the permissions of the process that received this {@link LinkProperties}.
-     *
-     * <p>By default {@link LinkProperties} does not preserve such fields during parceling, as
-     * they should not be shared outside of the process that receives them without appropriate
-     * checks.
-     * @hide
-     */
-    @SystemApi
-    @TestApi
-    @NonNull
-    public LinkProperties makeSensitiveFieldsParcelingCopy() {
-        return new LinkProperties(this, true /* parcelSensitiveFields */);
-    }
-
-    /**
      * Compares this {@code LinkProperties} instance against the target
      * LinkProperties in {@code obj}. Two LinkPropertieses are equal if
      * all their fields are equal in values.
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 116e343..7d8df6a 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -37,9 +37,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
+import java.util.Arrays;
 import java.util.Objects;
 import java.util.Set;
 import java.util.StringJoiner;
@@ -96,7 +94,7 @@
         mTransportInfo = null;
         mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
         mUids = null;
-        mAdministratorUids.clear();
+        mAdministratorUids = new int[0];
         mOwnerUid = Process.INVALID_UID;
         mSSID = null;
         mPrivateDnsBroken = false;
@@ -884,10 +882,10 @@
      * empty unless the destination is 1) the System Server, or 2) Telephony. In either case, the
      * receiving entity must have the ACCESS_FINE_LOCATION permission and target R+.
      */
-    private final List<Integer> mAdministratorUids = new ArrayList<>();
+    private int[] mAdministratorUids = new int[0];
 
     /**
-     * Sets the list of UIDs that are administrators of this network.
+     * Sets the int[] of UIDs that are administrators of this network.
      *
      * <p>UIDs included in administratorUids gain administrator privileges over this Network.
      * Examples of UIDs that should be included in administratorUids are:
@@ -907,23 +905,21 @@
      */
     @NonNull
     @SystemApi
-    public NetworkCapabilities setAdministratorUids(
-            @NonNull final List<Integer> administratorUids) {
-        mAdministratorUids.clear();
-        mAdministratorUids.addAll(administratorUids);
+    public NetworkCapabilities setAdministratorUids(@NonNull final int[] administratorUids) {
+        mAdministratorUids = Arrays.copyOf(administratorUids, administratorUids.length);
         return this;
     }
 
     /**
-     * Retrieves the list of UIDs that are administrators of this Network.
+     * Retrieves the UIDs that are administrators of this Network.
      *
-     * @return the List of UIDs that are administrators of this Network
+     * @return the int[] of UIDs that are administrators of this Network
      * @hide
      */
     @NonNull
     @SystemApi
-    public List<Integer> getAdministratorUids() {
-        return Collections.unmodifiableList(mAdministratorUids);
+    public int[] getAdministratorUids() {
+        return Arrays.copyOf(mAdministratorUids, mAdministratorUids.length);
     }
 
     /**
@@ -1584,7 +1580,7 @@
         dest.writeArraySet(mUids);
         dest.writeString(mSSID);
         dest.writeBoolean(mPrivateDnsBroken);
-        dest.writeList(mAdministratorUids);
+        dest.writeIntArray(mAdministratorUids);
         dest.writeInt(mOwnerUid);
         dest.writeInt(mRequestorUid);
         dest.writeString(mRequestorPackageName);
@@ -1608,7 +1604,7 @@
                         null /* ClassLoader, null for default */);
                 netCap.mSSID = in.readString();
                 netCap.mPrivateDnsBroken = in.readBoolean();
-                netCap.setAdministratorUids(in.readArrayList(null));
+                netCap.setAdministratorUids(in.createIntArray());
                 netCap.mOwnerUid = in.readInt();
                 netCap.mRequestorUid = in.readInt();
                 netCap.mRequestorPackageName = in.readString();
@@ -1665,8 +1661,8 @@
             sb.append(" OwnerUid: ").append(mOwnerUid);
         }
 
-        if (!mAdministratorUids.isEmpty()) {
-            sb.append(" AdministratorUids: ").append(mAdministratorUids);
+        if (mAdministratorUids.length == 0) {
+            sb.append(" AdministratorUids: ").append(Arrays.toString(mAdministratorUids));
         }
 
         if (null != mSSID) {
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index c1198aa..0948a4da 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -25,6 +25,7 @@
 import android.net.wifi.WifiManager;
 import android.os.Build;
 import android.service.NetworkIdentityProto;
+import android.telephony.Annotation.NetworkType;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
@@ -39,16 +40,6 @@
 public class NetworkIdentity implements Comparable<NetworkIdentity> {
     private static final String TAG = "NetworkIdentity";
 
-    /**
-     * When enabled, combine all {@link #mSubType} together under
-     * {@link #SUBTYPE_COMBINED}.
-     *
-     * @deprecated we no longer offer to collect statistics on a per-subtype
-     *             basis; this is always disabled.
-     */
-    @Deprecated
-    public static final boolean COMBINE_SUBTYPE_ENABLED = true;
-
     public static final int SUBTYPE_COMBINED = -1;
 
     final int mType;
@@ -63,7 +54,7 @@
             int type, int subType, String subscriberId, String networkId, boolean roaming,
             boolean metered, boolean defaultNetwork) {
         mType = type;
-        mSubType = COMBINE_SUBTYPE_ENABLED ? SUBTYPE_COMBINED : subType;
+        mSubType = subType;
         mSubscriberId = subscriberId;
         mNetworkId = networkId;
         mRoaming = roaming;
@@ -95,7 +86,7 @@
         final StringBuilder builder = new StringBuilder("{");
         builder.append("type=").append(getNetworkTypeName(mType));
         builder.append(", subType=");
-        if (COMBINE_SUBTYPE_ENABLED) {
+        if (mSubType == SUBTYPE_COMBINED) {
             builder.append("COMBINED");
         } else {
             builder.append(mSubType);
@@ -187,13 +178,14 @@
     }
 
     /**
-     * Build a {@link NetworkIdentity} from the given {@link NetworkState},
-     * assuming that any mobile networks are using the current IMSI.
+     * Build a {@link NetworkIdentity} from the given {@link NetworkState} and {@code subType},
+     * assuming that any mobile networks are using the current IMSI. The subType if applicable,
+     * should be set as one of the TelephonyManager.NETWORK_TYPE_* constants, or
+     * {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not.
      */
     public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state,
-            boolean defaultNetwork) {
+            boolean defaultNetwork, @NetworkType int subType) {
         final int type = state.networkInfo.getType();
-        final int subType = state.networkInfo.getSubtype();
 
         String subscriberId = null;
         String networkId = null;
diff --git a/core/java/android/net/NetworkStack.java b/core/java/android/net/NetworkStack.java
index a46c410..a6d52d1 100644
--- a/core/java/android/net/NetworkStack.java
+++ b/core/java/android/net/NetworkStack.java
@@ -19,15 +19,17 @@
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.content.Context;
+import android.os.IBinder;
+import android.os.ServiceManager;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 /**
- *
- * Constants for client code communicating with the network stack service.
+ * Constants and utilities for client code communicating with the network stack service.
  * @hide
  */
 @SystemApi
@@ -43,6 +45,17 @@
     public static final String PERMISSION_MAINLINE_NETWORK_STACK =
             "android.permission.MAINLINE_NETWORK_STACK";
 
+    /**
+     * Get an {@link IBinder} representing the NetworkStack stable AIDL Interface, if registered.
+     * @hide
+     */
+    @Nullable
+    @SystemApi
+    @TestApi
+    public static IBinder getService() {
+        return ServiceManager.getService(Context.NETWORK_STACK_SERVICE);
+    }
+
     private NetworkStack() {}
 
     /**
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 5498f74..cb9463a 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -34,9 +34,13 @@
 import static android.net.NetworkStats.ROAMING_YES;
 import static android.net.wifi.WifiInfo.sanitizeSsid;
 
+import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.Annotation.NetworkType;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
 import android.util.BackupUtils;
 import android.util.Log;
 
@@ -73,6 +77,14 @@
     public static final int MATCH_BLUETOOTH = 8;
     public static final int MATCH_PROXY = 9;
 
+    /**
+     * Include all network types when filtering. This is meant to merge in with the
+     * {@code TelephonyManager.NETWORK_TYPE_*} constants, and thus needs to stay in sync.
+     *
+     * @hide
+     */
+    public static final int NETWORK_TYPE_ALL = -1;
+
     private static boolean isKnownMatchRule(final int rule) {
         switch (rule) {
             case MATCH_MOBILE:
@@ -117,7 +129,22 @@
     }
 
     /**
-     * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks,
+     * Template to match cellular networks with the given IMSI and {@code ratType}.
+     * Use {@link #NETWORK_TYPE_ALL} to include all network types when filtering.
+     * See {@code TelephonyManager.NETWORK_TYPE_*}.
+     */
+    public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId,
+            @NetworkType int ratType) {
+        if (TextUtils.isEmpty(subscriberId)) {
+            return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null,
+                    METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType);
+        }
+        return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null,
+                METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType);
+    }
+
+    /**
+     * Template to match metered {@link ConnectivityManager#TYPE_MOBILE} networks,
      * regardless of IMSI.
      */
     @UnsupportedAppUsage
@@ -126,7 +153,7 @@
     }
 
     /**
-     * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks,
+     * Template to match all metered {@link ConnectivityManager#TYPE_WIFI} networks,
      * regardless of SSID.
      */
     @UnsupportedAppUsage
@@ -192,6 +219,7 @@
     private final int mMetered;
     private final int mRoaming;
     private final int mDefaultNetwork;
+    private final int mSubType;
 
     @UnsupportedAppUsage
     public NetworkTemplate(int matchRule, String subscriberId, String networkId) {
@@ -201,11 +229,11 @@
     public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
             String networkId) {
         this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL,
-                DEFAULT_NETWORK_ALL);
+                DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL);
     }
 
     public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
-            String networkId, int metered, int roaming, int defaultNetwork) {
+            String networkId, int metered, int roaming, int defaultNetwork, int subType) {
         mMatchRule = matchRule;
         mSubscriberId = subscriberId;
         mMatchSubscriberIds = matchSubscriberIds;
@@ -213,6 +241,7 @@
         mMetered = metered;
         mRoaming = roaming;
         mDefaultNetwork = defaultNetwork;
+        mSubType = subType;
 
         if (!isKnownMatchRule(matchRule)) {
             Log.e(TAG, "Unknown network template rule " + matchRule
@@ -228,6 +257,7 @@
         mMetered = in.readInt();
         mRoaming = in.readInt();
         mDefaultNetwork = in.readInt();
+        mSubType = in.readInt();
     }
 
     @Override
@@ -239,6 +269,7 @@
         dest.writeInt(mMetered);
         dest.writeInt(mRoaming);
         dest.writeInt(mDefaultNetwork);
+        dest.writeInt(mSubType);
     }
 
     @Override
@@ -271,13 +302,16 @@
             builder.append(", defaultNetwork=").append(NetworkStats.defaultNetworkToString(
                     mDefaultNetwork));
         }
+        if (mSubType != NETWORK_TYPE_ALL) {
+            builder.append(", subType=").append(mSubType);
+        }
         return builder.toString();
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming,
-                mDefaultNetwork);
+                mDefaultNetwork, mSubType);
     }
 
     @Override
@@ -289,7 +323,8 @@
                     && Objects.equals(mNetworkId, other.mNetworkId)
                     && mMetered == other.mMetered
                     && mRoaming == other.mRoaming
-                    && mDefaultNetwork == other.mDefaultNetwork;
+                    && mDefaultNetwork == other.mDefaultNetwork
+                    && mSubType == other.mSubType;
         }
         return false;
     }
@@ -376,6 +411,11 @@
             || (mDefaultNetwork == DEFAULT_NETWORK_NO && !ident.mDefaultNetwork);
     }
 
+    private boolean matchesCollapsedRatType(NetworkIdentity ident) {
+        return mSubType == NETWORK_TYPE_ALL
+                || getCollapsedRatType(mSubType) == getCollapsedRatType(ident.mSubType);
+    }
+
     public boolean matchesSubscriberId(String subscriberId) {
         return ArrayUtils.contains(mMatchSubscriberIds, subscriberId);
     }
@@ -388,9 +428,52 @@
             // TODO: consider matching against WiMAX subscriber identity
             return true;
         } else {
+            // Only metered mobile network would be matched regardless of metered filter.
+            // This is used to exclude non-metered APNs, e.g. IMS. See ag/908650.
+            // TODO: Respect metered filter and remove mMetered condition.
             return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered))
                     && !ArrayUtils.isEmpty(mMatchSubscriberIds)
-                    && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId);
+                    && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId)
+                    && matchesCollapsedRatType(ident);
+        }
+    }
+
+    /**
+     * Get a Radio Access Technology(RAT) type that is representative of a group of RAT types.
+     * The mapping is corresponding to {@code TelephonyManager#NETWORK_CLASS_BIT_MASK_*}.
+     *
+     * @param ratType An integer defined in {@code TelephonyManager#NETWORK_TYPE_*}.
+     */
+    // TODO: 1. Consider move this to TelephonyManager if used by other modules.
+    //       2. Consider make this configurable.
+    //       3. Use TelephonyManager APIs when available.
+    public static int getCollapsedRatType(int ratType) {
+        switch (ratType) {
+            case TelephonyManager.NETWORK_TYPE_GPRS:
+            case TelephonyManager.NETWORK_TYPE_GSM:
+            case TelephonyManager.NETWORK_TYPE_EDGE:
+            case TelephonyManager.NETWORK_TYPE_IDEN:
+            case TelephonyManager.NETWORK_TYPE_CDMA:
+            case TelephonyManager.NETWORK_TYPE_1xRTT:
+                return TelephonyManager.NETWORK_TYPE_GSM;
+            case TelephonyManager.NETWORK_TYPE_EVDO_0:
+            case TelephonyManager.NETWORK_TYPE_EVDO_A:
+            case TelephonyManager.NETWORK_TYPE_EVDO_B:
+            case TelephonyManager.NETWORK_TYPE_EHRPD:
+            case TelephonyManager.NETWORK_TYPE_UMTS:
+            case TelephonyManager.NETWORK_TYPE_HSDPA:
+            case TelephonyManager.NETWORK_TYPE_HSUPA:
+            case TelephonyManager.NETWORK_TYPE_HSPA:
+            case TelephonyManager.NETWORK_TYPE_HSPAP:
+            case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
+                return TelephonyManager.NETWORK_TYPE_UMTS;
+            case TelephonyManager.NETWORK_TYPE_LTE:
+            case TelephonyManager.NETWORK_TYPE_IWLAN:
+                return TelephonyManager.NETWORK_TYPE_LTE;
+            case TelephonyManager.NETWORK_TYPE_NR:
+                return TelephonyManager.NETWORK_TYPE_NR;
+            default:
+                return TelephonyManager.NETWORK_TYPE_UNKNOWN;
         }
     }
 
@@ -421,7 +504,8 @@
         if (ident.mType == TYPE_WIMAX) {
             return true;
         } else {
-            return sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered);
+            return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered))
+                    && matchesCollapsedRatType(ident);
         }
     }
 
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index 2b9e9fe..fec2df4 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -527,6 +527,26 @@
     }
 
     /**
+     * Compares this RouteInfo object against the specified object and indicates if the
+     * destinations of both routes are equal.
+     * @return {@code true} if the route destinations are equal, {@code false} otherwise.
+     *
+     * @hide
+     */
+    public boolean isSameDestinationAs(@Nullable Object obj) {
+        if (this == obj) return true;
+
+        if (!(obj instanceof RouteInfo)) return false;
+
+        RouteInfo target = (RouteInfo) obj;
+
+        if (Objects.equals(mDestination, target.getDestination())) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
      *  Returns a hashcode for this <code>RouteInfo</code> object.
      */
     public int hashCode() {
diff --git a/core/java/android/net/util/SocketUtils.java b/core/java/android/net/util/SocketUtils.java
index e9ea99f..6967084 100644
--- a/core/java/android/net/util/SocketUtils.java
+++ b/core/java/android/net/util/SocketUtils.java
@@ -66,6 +66,10 @@
 
     /**
      * Make socket address that packet sockets can bind to.
+     *
+     * @param protocol the layer 2 protocol of the packets to receive. One of the {@code ETH_P_*}
+     *                 constants in {@link android.system.OsConstants}.
+     * @param ifIndex the interface index on which packets will be received.
      */
     @NonNull
     public static SocketAddress makePacketSocketAddress(int protocol, int ifIndex) {
@@ -78,6 +82,9 @@
     /**
      * Make a socket address that packet socket can send packets to.
      * @deprecated Use {@link #makePacketSocketAddress(int, int, byte[])} instead.
+     *
+     * @param ifIndex the interface index on which packets will be sent.
+     * @param hwAddr the hardware address to which packets will be sent.
      */
     @Deprecated
     @NonNull
@@ -89,7 +96,12 @@
     }
 
     /**
-     * Make a socket address that packet socket can send packets to.
+     * Make a socket address that a packet socket can send packets to.
+     *
+     * @param protocol the layer 2 protocol of the packets to send. One of the {@code ETH_P_*}
+     *                 constants in {@link android.system.OsConstants}.
+     * @param ifIndex the interface index on which packets will be sent.
+     * @param hwAddr the hardware address to which packets will be sent.
      */
     @NonNull
     public static SocketAddress makePacketSocketAddress(int protocol, int ifIndex,
diff --git a/core/java/android/os/ConfigUpdate.java b/core/java/android/os/ConfigUpdate.java
index 590fbb3..a28f5fb 100644
--- a/core/java/android/os/ConfigUpdate.java
+++ b/core/java/android/os/ConfigUpdate.java
@@ -17,6 +17,8 @@
 package android.os;
 
 import android.annotation.RequiresPermission;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
 
 /**
@@ -125,6 +127,7 @@
     */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.UPDATE_CONFIG)
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_UPDATE_EMERGENCY_NUMBER_DB =
             "android.os.action.UPDATE_EMERGENCY_NUMBER_DB";
 
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 4a42230..82a7d78 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -58,6 +58,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 import java.util.function.IntConsumer;
 
@@ -214,6 +215,7 @@
     @BinderThread
     public abstract void onGrantOrUpgradeDefaultRuntimePermissions(@NonNull Runnable callback);
 
+
     /**
      * Called by system to update the
      * {@link PackageManager}{@code .FLAG_PERMISSION_USER_SENSITIVE_WHEN_*} flags for permissions.
@@ -223,10 +225,22 @@
      *
      * Typically called by the system when a new app is installed or updated or when creating a
      * new user or upgrading either system or permission controller package.
+     *
+     * The callback will be executed by the provided Executor.
+     */
+    @BinderThread
+    public void onUpdateUserSensitivePermissionFlags(int uid, @NonNull Executor executor,
+            @NonNull Runnable callback) {
+        throw new AbstractMethodError("Must be overridden in implementing class");
+    }
+
+    /**
+     * Runs {@link #onUpdateUserSensitivePermissionFlags(int, Executor, Runnable)} with the main
+     * executor.
      */
     @BinderThread
     public void onUpdateUserSensitivePermissionFlags(int uid, @NonNull Runnable callback) {
-        throw new AbstractMethodError("Must be overridden in implementing class");
+        onUpdateUserSensitivePermissionFlags(uid, getMainExecutor(), callback);
     }
 
     /**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d8679b2..789b8d1 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9718,6 +9718,8 @@
        public static final String NETSTATS_SAMPLE_ENABLED = "netstats_sample_enabled";
        /** {@hide} */
        public static final String NETSTATS_AUGMENT_ENABLED = "netstats_augment_enabled";
+       /** {@hide} */
+       public static final String NETSTATS_COMBINE_SUBTYPE_ENABLED = "netstats_combine_subtype_enabled";
 
        /** {@hide} */
        public static final String NETSTATS_DEV_BUCKET_DURATION = "netstats_dev_bucket_duration";
@@ -14192,19 +14194,6 @@
                 "power_button_suppression_delay_after_gesture_wake";
 
         /**
-         * An integer indicating whether the device is in Common Criteria mode. When enabled,
-         * certain device functionalities are tuned to meet the higher security level required
-         * by Common Criteria certification. Examples include:
-         *   Bluetooth long term key material is additionally integrity-protected with AES-GCM.
-         *   WiFi configuration store is additionally integrity-protected with AES-GCM.
-         * A value of 0 means Common Criteria mode is not enabled (default), a value of non-zero
-         * means Common Criteria mode is enabled.
-         * @hide
-         */
-        @SystemApi
-        public static final String COMMON_CRITERIA_MODE = "common_criteria_mode";
-
-        /**
          * The usage amount of advanced battery. The value is 0~100.
          *
          * @hide
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index 06b5fa0..bc08b84 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -88,8 +88,6 @@
     private final @Nullable UserData mUserData;
     private final @Nullable int[] mCancelIds;
     private final boolean mSupportsInlineSuggestions;
-    // TODO(b/149240554): revert back to use ParceledListSlice after the bug is resolved.
-    private final @Nullable ArrayList<InlineAction> mInlineActions;
 
     private FillResponse(@NonNull Builder builder) {
         mDatasets = (builder.mDatasets != null) ? new ParceledListSlice<>(builder.mDatasets) : null;
@@ -109,7 +107,6 @@
         mUserData = builder.mUserData;
         mCancelIds = builder.mCancelIds;
         mSupportsInlineSuggestions = builder.mSupportsInlineSuggestions;
-        mInlineActions = builder.mInlineActions;
     }
 
     /** @hide */
@@ -212,11 +209,6 @@
         return mSupportsInlineSuggestions;
     }
 
-    /** @hide */
-    public @Nullable List<InlineAction> getInlineActions() {
-        return mInlineActions;
-    }
-
     /**
      * Builder for {@link FillResponse} objects. You must to provide at least
      * one dataset or set an authentication intent with a presentation view.
@@ -239,7 +231,6 @@
         private UserData mUserData;
         private int[] mCancelIds;
         private boolean mSupportsInlineSuggestions;
-        private ArrayList<InlineAction> mInlineActions;
 
         /**
          * Triggers a custom UI before before autofilling the screen with any data set in this
@@ -656,22 +647,6 @@
         }
 
         /**
-         * Adds a new {@link InlineAction} to this response representing an action UI.
-         *
-         * @return This builder.
-         */
-        @NonNull
-        public Builder addInlineAction(@NonNull InlineAction inlineAction) {
-            throwIfDestroyed();
-            throwIfAuthenticationCalled();
-            if (mInlineActions == null) {
-                mInlineActions = new ArrayList<>();
-            }
-            mInlineActions.add(inlineAction);
-            return this;
-        }
-
-        /**
          * Builds a new {@link FillResponse} instance.
          *
          * @throws IllegalStateException if any of the following conditions occur:
@@ -788,9 +763,6 @@
             builder.append(", mCancelIds=").append(mCancelIds.length);
         }
         builder.append(", mSupportInlinePresentations=").append(mSupportsInlineSuggestions);
-        if (mInlineActions != null) {
-            builder.append(", mInlineActions=" + mInlineActions);
-        }
         return builder.append("]").toString();
     }
 
@@ -820,7 +792,6 @@
         parcel.writeParcelableArray(mFieldClassificationIds, flags);
         parcel.writeInt(mFlags);
         parcel.writeIntArray(mCancelIds);
-        parcel.writeTypedList(mInlineActions, flags);
         parcel.writeInt(mRequestId);
     }
 
@@ -878,14 +849,6 @@
             final int[] cancelIds = parcel.createIntArray();
             builder.setPresentationCancelIds(cancelIds);
 
-            final List<InlineAction> inlineActions = parcel.createTypedArrayList(
-                    InlineAction.CREATOR);
-            if (inlineActions != null) {
-                for (InlineAction inlineAction : inlineActions) {
-                    builder.addInlineAction(inlineAction);
-                }
-            }
-
             final FillResponse response = builder.build();
             response.setRequestId(parcel.readInt());
 
diff --git a/core/java/android/service/autofill/InlineAction.aidl b/core/java/android/service/autofill/InlineAction.aidl
deleted file mode 100644
index 7f85118..0000000
--- a/core/java/android/service/autofill/InlineAction.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2020 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.autofill;
-
-parcelable InlineAction;
diff --git a/core/java/android/service/autofill/InlineAction.java b/core/java/android/service/autofill/InlineAction.java
deleted file mode 100644
index 17c4b33..0000000
--- a/core/java/android/service/autofill/InlineAction.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2020 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.autofill;
-
-import android.annotation.NonNull;
-import android.content.IntentSender;
-import android.os.Parcelable;
-
-import com.android.internal.util.DataClass;
-
-/**
- * Represents an inline action as part of the autofill/augmented autofill response.
- *
- * <p> It includes both the action intent and the UI presentation. For example, the UI can be
- * associated with an intent which can open an activity for the user to manage the Autofill provider
- * settings.
- */
-@DataClass(
-        genToString = true,
-        genHiddenConstDefs = true,
-        genEqualsHashCode = true)
-public final class InlineAction implements Parcelable {
-
-    /**
-     * Representation of the inline action.
-     */
-    private final @NonNull InlinePresentation mInlinePresentation;
-
-    /**
-     * The associated intent which will be triggered when the action is selected. It will only be
-     * called by the OS.
-     */
-    private final @NonNull IntentSender mAction;
-
-
-
-    // Code below generated by codegen v1.0.15.
-    //
-    // DO NOT MODIFY!
-    // CHECKSTYLE:OFF Generated code
-    //
-    // To regenerate run:
-    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/autofill/InlineAction.java
-    //
-    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
-    //   Settings > Editor > Code Style > Formatter Control
-    //@formatter:off
-
-
-    /**
-     * Creates a new InlineAction.
-     *
-     * @param inlinePresentation
-     *   Representation of the inline action.
-     * @param action
-     *   The associated intent which will be triggered when the action is selected. It will only be
-     *   invoked by the OS.
-     */
-    @DataClass.Generated.Member
-    public InlineAction(
-            @NonNull InlinePresentation inlinePresentation,
-            @NonNull IntentSender action) {
-        this.mInlinePresentation = inlinePresentation;
-        com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mInlinePresentation);
-        this.mAction = action;
-        com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mAction);
-
-        // onConstructed(); // You can define this method to get a callback
-    }
-
-    /**
-     * Representation of the inline action.
-     */
-    @DataClass.Generated.Member
-    public @NonNull InlinePresentation getInlinePresentation() {
-        return mInlinePresentation;
-    }
-
-    /**
-     * The associated intent which will be triggered when the action is selected. It will only be
-     * invoked by the OS.
-     */
-    @DataClass.Generated.Member
-    public @NonNull IntentSender getAction() {
-        return mAction;
-    }
-
-    @Override
-    @DataClass.Generated.Member
-    public String toString() {
-        // You can override field toString logic by defining methods like:
-        // String fieldNameToString() { ... }
-
-        return "InlineAction { " +
-                "inlinePresentation = " + mInlinePresentation + ", " +
-                "action = " + mAction +
-        " }";
-    }
-
-    @Override
-    @DataClass.Generated.Member
-    public boolean equals(@android.annotation.Nullable Object o) {
-        // You can override field equality logic by defining either of the methods like:
-        // boolean fieldNameEquals(InlineAction other) { ... }
-        // boolean fieldNameEquals(FieldType otherValue) { ... }
-
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-        @SuppressWarnings("unchecked")
-        InlineAction that = (InlineAction) o;
-        //noinspection PointlessBooleanExpression
-        return true
-                && java.util.Objects.equals(mInlinePresentation, that.mInlinePresentation)
-                && java.util.Objects.equals(mAction, that.mAction);
-    }
-
-    @Override
-    @DataClass.Generated.Member
-    public int hashCode() {
-        // You can override field hashCode logic by defining methods like:
-        // int fieldNameHashCode() { ... }
-
-        int _hash = 1;
-        _hash = 31 * _hash + java.util.Objects.hashCode(mInlinePresentation);
-        _hash = 31 * _hash + java.util.Objects.hashCode(mAction);
-        return _hash;
-    }
-
-    @Override
-    @DataClass.Generated.Member
-    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
-        // You can override field parcelling by defining methods like:
-        // void parcelFieldName(Parcel dest, int flags) { ... }
-
-        dest.writeTypedObject(mInlinePresentation, flags);
-        dest.writeTypedObject(mAction, flags);
-    }
-
-    @Override
-    @DataClass.Generated.Member
-    public int describeContents() { return 0; }
-
-    /** @hide */
-    @SuppressWarnings({"unchecked", "RedundantCast"})
-    @DataClass.Generated.Member
-    /* package-private */ InlineAction(@NonNull android.os.Parcel in) {
-        // You can override field unparcelling by defining methods like:
-        // static FieldType unparcelFieldName(Parcel in) { ... }
-
-        InlinePresentation inlinePresentation = (InlinePresentation) in.readTypedObject(InlinePresentation.CREATOR);
-        IntentSender action = (IntentSender) in.readTypedObject(IntentSender.CREATOR);
-
-        this.mInlinePresentation = inlinePresentation;
-        com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mInlinePresentation);
-        this.mAction = action;
-        com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mAction);
-
-        // onConstructed(); // You can define this method to get a callback
-    }
-
-    @DataClass.Generated.Member
-    public static final @NonNull Parcelable.Creator<InlineAction> CREATOR
-            = new Parcelable.Creator<InlineAction>() {
-        @Override
-        public InlineAction[] newArray(int size) {
-            return new InlineAction[size];
-        }
-
-        @Override
-        public InlineAction createFromParcel(@NonNull android.os.Parcel in) {
-            return new InlineAction(in);
-        }
-    };
-
-    @DataClass.Generated(
-            time = 1583798182424L,
-            codegenVersion = "1.0.15",
-            sourceFile = "frameworks/base/core/java/android/service/autofill/InlineAction.java",
-            inputSignatures = "private final @android.annotation.NonNull android.service.autofill.InlinePresentation mInlinePresentation\nprivate final @android.annotation.NonNull android.content.IntentSender mAction\nclass InlineAction extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genEqualsHashCode=true)")
-    @Deprecated
-    private void __metadata() {}
-
-
-    //@formatter:on
-    // End of generated code
-
-}
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index 5b08ae2..1efa3dd 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -40,7 +40,6 @@
 import android.os.SystemClock;
 import android.service.autofill.Dataset;
 import android.service.autofill.FillEventHistory;
-import android.service.autofill.InlineAction;
 import android.service.autofill.augmented.PresentationParams.SystemPopupPresentationParams;
 import android.util.Log;
 import android.util.Pair;
@@ -559,10 +558,9 @@
             }
         }
 
-        void reportResult(@Nullable List<Dataset> inlineSuggestionsData,
-                @Nullable List<InlineAction> inlineActions) {
+        void reportResult(@Nullable List<Dataset> inlineSuggestionsData) {
             try {
-                mCallback.onSuccess(inlineSuggestionsData, inlineActions);
+                mCallback.onSuccess(inlineSuggestionsData);
             } catch (RemoteException e) {
                 Log.e(TAG, "Error calling back with the inline suggestions data: " + e);
             }
diff --git a/core/java/android/service/autofill/augmented/FillCallback.java b/core/java/android/service/autofill/augmented/FillCallback.java
index 6b4e118..526a749 100644
--- a/core/java/android/service/autofill/augmented/FillCallback.java
+++ b/core/java/android/service/autofill/augmented/FillCallback.java
@@ -55,14 +55,14 @@
 
         if (response == null) {
             mProxy.logEvent(AutofillProxy.REPORT_EVENT_NO_RESPONSE);
-            mProxy.reportResult(/* inlineSuggestionsData */ null, /* inlineActions */null);
+            mProxy.reportResult(/* inlineSuggestionsData */ null);
             return;
         }
 
         List<Dataset> inlineSuggestions = response.getInlineSuggestions();
         if (inlineSuggestions != null && !inlineSuggestions.isEmpty()) {
             mProxy.logEvent(AutofillProxy.REPORT_EVENT_INLINE_RESPONSE);
-            mProxy.reportResult(inlineSuggestions, response.getInlineActions());
+            mProxy.reportResult(inlineSuggestions);
             return;
         }
 
diff --git a/core/java/android/service/autofill/augmented/FillResponse.java b/core/java/android/service/autofill/augmented/FillResponse.java
index f564b3b..f72eb78 100644
--- a/core/java/android/service/autofill/augmented/FillResponse.java
+++ b/core/java/android/service/autofill/augmented/FillResponse.java
@@ -21,7 +21,6 @@
 import android.annotation.TestApi;
 import android.os.Bundle;
 import android.service.autofill.Dataset;
-import android.service.autofill.InlineAction;
 
 import com.android.internal.util.DataClass;
 
@@ -53,12 +52,6 @@
     private @Nullable List<Dataset> mInlineSuggestions;
 
     /**
-     * Defaults to null if no inline actions are provided.
-     */
-    @DataClass.PluralOf("inlineAction")
-    private @Nullable List<InlineAction> mInlineActions;
-
-    /**
      * The client state that {@link AugmentedAutofillService} implementation can put anything in to
      * identify the request and the response when calling
      * {@link AugmentedAutofillService#getFillEventHistory()}.
@@ -73,10 +66,6 @@
         return null;
     }
 
-    private static List<InlineAction> defaultInlineActions() {
-        return null;
-    }
-
     private static Bundle defaultClientState() {
         return null;
     }
@@ -85,7 +74,6 @@
     /** @hide */
     abstract static class BaseBuilder {
         abstract FillResponse.Builder addInlineSuggestion(@NonNull Dataset value);
-        abstract FillResponse.Builder addInlineAction(@NonNull InlineAction value);
     }
 
 
@@ -107,11 +95,9 @@
     /* package-private */ FillResponse(
             @Nullable FillWindow fillWindow,
             @Nullable List<Dataset> inlineSuggestions,
-            @Nullable List<InlineAction> inlineActions,
             @Nullable Bundle clientState) {
         this.mFillWindow = fillWindow;
         this.mInlineSuggestions = inlineSuggestions;
-        this.mInlineActions = inlineActions;
         this.mClientState = clientState;
 
         // onConstructed(); // You can define this method to get a callback
@@ -139,16 +125,6 @@
     }
 
     /**
-     * Defaults to null if no inline actions are provided.
-     *
-     * @hide
-     */
-    @DataClass.Generated.Member
-    public @Nullable List<InlineAction> getInlineActions() {
-        return mInlineActions;
-    }
-
-    /**
      * The client state that {@link AugmentedAutofillService} implementation can put anything in to
      * identify the request and the response when calling
      * {@link AugmentedAutofillService#getFillEventHistory()}.
@@ -169,7 +145,6 @@
 
         private @Nullable FillWindow mFillWindow;
         private @Nullable List<Dataset> mInlineSuggestions;
-        private @Nullable List<InlineAction> mInlineActions;
         private @Nullable Bundle mClientState;
 
         private long mBuilderFieldsSet = 0L;
@@ -210,26 +185,6 @@
         }
 
         /**
-         * Defaults to null if no inline actions are provided.
-         */
-        @DataClass.Generated.Member
-        public @NonNull Builder setInlineActions(@NonNull List<InlineAction> value) {
-            checkNotUsed();
-            mBuilderFieldsSet |= 0x4;
-            mInlineActions = value;
-            return this;
-        }
-
-        /** @see #setInlineActions */
-        @DataClass.Generated.Member
-        @Override
-        @NonNull FillResponse.Builder addInlineAction(@NonNull InlineAction value) {
-            if (mInlineActions == null) setInlineActions(new ArrayList<>());
-            mInlineActions.add(value);
-            return this;
-        }
-
-        /**
          * The client state that {@link AugmentedAutofillService} implementation can put anything in to
          * identify the request and the response when calling
          * {@link AugmentedAutofillService#getFillEventHistory()}.
@@ -237,7 +192,7 @@
         @DataClass.Generated.Member
         public @NonNull Builder setClientState(@NonNull Bundle value) {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x8;
+            mBuilderFieldsSet |= 0x4;
             mClientState = value;
             return this;
         }
@@ -245,7 +200,7 @@
         /** Builds the instance. This builder should not be touched after calling this! */
         public @NonNull FillResponse build() {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x10; // Mark builder used
+            mBuilderFieldsSet |= 0x8; // Mark builder used
 
             if ((mBuilderFieldsSet & 0x1) == 0) {
                 mFillWindow = defaultFillWindow();
@@ -254,21 +209,17 @@
                 mInlineSuggestions = defaultInlineSuggestions();
             }
             if ((mBuilderFieldsSet & 0x4) == 0) {
-                mInlineActions = defaultInlineActions();
-            }
-            if ((mBuilderFieldsSet & 0x8) == 0) {
                 mClientState = defaultClientState();
             }
             FillResponse o = new FillResponse(
                     mFillWindow,
                     mInlineSuggestions,
-                    mInlineActions,
                     mClientState);
             return o;
         }
 
         private void checkNotUsed() {
-            if ((mBuilderFieldsSet & 0x10) != 0) {
+            if ((mBuilderFieldsSet & 0x8) != 0) {
                 throw new IllegalStateException(
                         "This Builder should not be reused. Use a new Builder instance instead");
             }
@@ -276,10 +227,10 @@
     }
 
     @DataClass.Generated(
-            time = 1583793032373L,
+            time = 1584480900526L,
             codegenVersion = "1.0.15",
             sourceFile = "frameworks/base/core/java/android/service/autofill/augmented/FillResponse.java",
-            inputSignatures = "private @android.annotation.Nullable android.service.autofill.augmented.FillWindow mFillWindow\nprivate @com.android.internal.util.DataClass.PluralOf(\"inlineSuggestion\") @android.annotation.Nullable java.util.List<android.service.autofill.Dataset> mInlineSuggestions\nprivate @com.android.internal.util.DataClass.PluralOf(\"inlineAction\") @android.annotation.Nullable java.util.List<android.service.autofill.InlineAction> mInlineActions\nprivate @android.annotation.Nullable android.os.Bundle mClientState\nprivate static  android.service.autofill.augmented.FillWindow defaultFillWindow()\nprivate static  java.util.List<android.service.autofill.Dataset> defaultInlineSuggestions()\nprivate static  java.util.List<android.service.autofill.InlineAction> defaultInlineActions()\nprivate static  android.os.Bundle defaultClientState()\nclass FillResponse extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genHiddenGetters=true)\nabstract  android.service.autofill.augmented.FillResponse.Builder addInlineSuggestion(android.service.autofill.Dataset)\nabstract  android.service.autofill.augmented.FillResponse.Builder addInlineAction(android.service.autofill.InlineAction)\nclass BaseBuilder extends java.lang.Object implements []")
+            inputSignatures = "private @android.annotation.Nullable android.service.autofill.augmented.FillWindow mFillWindow\nprivate @com.android.internal.util.DataClass.PluralOf(\"inlineSuggestion\") @android.annotation.Nullable java.util.List<android.service.autofill.Dataset> mInlineSuggestions\nprivate @android.annotation.Nullable android.os.Bundle mClientState\nprivate static  android.service.autofill.augmented.FillWindow defaultFillWindow()\nprivate static  java.util.List<android.service.autofill.Dataset> defaultInlineSuggestions()\nprivate static  android.os.Bundle defaultClientState()\nclass FillResponse extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genHiddenGetters=true)\nabstract  android.service.autofill.augmented.FillResponse.Builder addInlineSuggestion(android.service.autofill.Dataset)\nclass BaseBuilder extends java.lang.Object implements []")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/service/autofill/augmented/IFillCallback.aidl b/core/java/android/service/autofill/augmented/IFillCallback.aidl
index 545dab2..24af1e5 100644
--- a/core/java/android/service/autofill/augmented/IFillCallback.aidl
+++ b/core/java/android/service/autofill/augmented/IFillCallback.aidl
@@ -20,7 +20,6 @@
 import android.os.ICancellationSignal;
 
 import android.service.autofill.Dataset;
-import android.service.autofill.InlineAction;
 
 import java.util.List;
 
@@ -31,8 +30,7 @@
  */
 interface IFillCallback {
     void onCancellable(in ICancellationSignal cancellation);
-    void onSuccess(in @nullable List<Dataset> inlineSuggestionsData,
-                   in @nullable List<InlineAction> inlineActions);
+    void onSuccess(in @nullable List<Dataset> inlineSuggestionsData);
     boolean isCompleted();
     void cancel();
 }
diff --git a/core/java/android/service/dataloader/DataLoaderService.java b/core/java/android/service/dataloader/DataLoaderService.java
index d4db79e..0170726 100644
--- a/core/java/android/service/dataloader/DataLoaderService.java
+++ b/core/java/android/service/dataloader/DataLoaderService.java
@@ -102,21 +102,18 @@
     }
 
     private class DataLoaderBinderService extends IDataLoader.Stub {
-        private int mId;
-
         @Override
         public void create(int id, @NonNull DataLoaderParamsParcel params,
                 @NonNull FileSystemControlParcel control,
                 @NonNull IDataLoaderStatusListener listener)
                 throws RuntimeException {
-            mId = id;
             try {
                 if (!nativeCreateDataLoader(id, control, params, listener)) {
-                    Slog.e(TAG, "Failed to create native loader for " + mId);
+                    Slog.e(TAG, "Failed to create native loader for " + id);
                 }
             } catch (Exception ex) {
-                Slog.e(TAG, "Failed to create native loader for " + mId, ex);
-                destroy();
+                Slog.e(TAG, "Failed to create native loader for " + id, ex);
+                destroy(id);
                 throw new RuntimeException(ex);
             } finally {
                 // Closing FDs.
@@ -150,30 +147,31 @@
         }
 
         @Override
-        public void start() {
-            if (!nativeStartDataLoader(mId)) {
-                Slog.e(TAG, "Failed to start loader: " + mId);
+        public void start(int id) {
+            if (!nativeStartDataLoader(id)) {
+                Slog.e(TAG, "Failed to start loader: " + id);
             }
         }
 
         @Override
-        public void stop() {
-            if (!nativeStopDataLoader(mId)) {
-                Slog.w(TAG, "Failed to stop loader: " + mId);
+        public void stop(int id) {
+            if (!nativeStopDataLoader(id)) {
+                Slog.w(TAG, "Failed to stop loader: " + id);
             }
         }
 
         @Override
-        public void destroy() {
-            if (!nativeDestroyDataLoader(mId)) {
-                Slog.w(TAG, "Failed to destroy loader: " + mId);
+        public void destroy(int id) {
+            if (!nativeDestroyDataLoader(id)) {
+                Slog.w(TAG, "Failed to destroy loader: " + id);
             }
         }
 
         @Override
-        public void prepareImage(InstallationFileParcel[] addedFiles, String[] removedFiles) {
-            if (!nativePrepareImage(mId, addedFiles, removedFiles)) {
-                Slog.w(TAG, "Failed to prepare image for data loader: " + mId);
+        public void prepareImage(int id, InstallationFileParcel[] addedFiles,
+                String[] removedFiles) {
+            if (!nativePrepareImage(id, addedFiles, removedFiles)) {
+                Slog.w(TAG, "Failed to prepare image for data loader: " + id);
             }
         }
     }
diff --git a/core/java/android/service/quickaccesswallet/WalletServiceEvent.java b/core/java/android/service/quickaccesswallet/WalletServiceEvent.java
index fb524be..5ee92da 100644
--- a/core/java/android/service/quickaccesswallet/WalletServiceEvent.java
+++ b/core/java/android/service/quickaccesswallet/WalletServiceEvent.java
@@ -40,10 +40,16 @@
     public static final int TYPE_NFC_PAYMENT_STARTED = 1;
 
     /**
+     * Indicates that the wallet cards have changed and should be refreshed.
+     * @hide
+     */
+    public static final int TYPE_WALLET_CARDS_UPDATED = 2;
+
+    /**
      * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({TYPE_NFC_PAYMENT_STARTED})
+    @IntDef({TYPE_NFC_PAYMENT_STARTED, TYPE_WALLET_CARDS_UPDATED})
     public @interface EventType {
     }
 
diff --git a/core/java/android/telephony/SubscriptionPlan.java b/core/java/android/telephony/SubscriptionPlan.java
index ff2f4ad..901957f 100644
--- a/core/java/android/telephony/SubscriptionPlan.java
+++ b/core/java/android/telephony/SubscriptionPlan.java
@@ -91,10 +91,11 @@
     private long dataUsageBytes = BYTES_UNKNOWN;
     private long dataUsageTime = TIME_UNKNOWN;
     private @NetworkType int[] networkTypes;
-    private long networkTypesBitMask;
 
     private SubscriptionPlan(RecurrenceRule cycleRule) {
         this.cycleRule = Preconditions.checkNotNull(cycleRule);
+        this.networkTypes = Arrays.copyOf(TelephonyManager.getAllNetworkTypes(),
+                TelephonyManager.getAllNetworkTypes().length);
     }
 
     private SubscriptionPlan(Parcel source) {
@@ -221,10 +222,10 @@
 
     /**
      * Return an array containing all {@link NetworkType}s this SubscriptionPlan applies to.
-     * A null value means this SubscriptionPlan applies to all network types.
+     * @see TelephonyManager for network types values
      */
-    public @Nullable @NetworkType int[] getNetworkTypes() {
-        return networkTypes;
+    public @NonNull @NetworkType int[] getNetworkTypes() {
+        return Arrays.copyOf(networkTypes, networkTypes.length);
     }
 
     /**
@@ -361,14 +362,14 @@
         }
 
         /**
-         * Set the network types this SubscriptionPlan applies to.
+         * Set the network types this SubscriptionPlan applies to. By default the plan will apply
+         * to all network types. An empty array means this plan applies to no network types.
          *
-         * @param networkTypes a set of all {@link NetworkType}s that apply to this plan.
-         *            A null value means the plan applies to all network types,
-         *            and an empty array means the plan applies to no network types.
+         * @param networkTypes an array of all {@link NetworkType}s that apply to this plan.
+         * @see TelephonyManager for network type values
          */
-        public @NonNull Builder setNetworkTypes(@Nullable @NetworkType int[] networkTypes) {
-            plan.networkTypes = networkTypes;
+        public @NonNull Builder setNetworkTypes(@NonNull @NetworkType int[] networkTypes) {
+            plan.networkTypes = Arrays.copyOf(networkTypes, networkTypes.length);
             return this;
         }
     }
diff --git a/core/java/android/text/style/ReplacementSpan.java b/core/java/android/text/style/ReplacementSpan.java
index 0553232..9430fd3 100644
--- a/core/java/android/text/style/ReplacementSpan.java
+++ b/core/java/android/text/style/ReplacementSpan.java
@@ -63,7 +63,7 @@
                               int top, int y, int bottom, @NonNull Paint paint);
 
     /**
-     * Gets a brief description of this ImageSpan for use in accessibility support.
+     * Gets a brief description of this ReplacementSpan for use in accessibility support.
      *
      * @return The content description.
      */
@@ -73,7 +73,7 @@
     }
 
     /**
-     * Sets the specific content description into ImageSpan.
+     * Sets the specific content description into ReplacementSpan.
      * ReplacementSpans are shared with accessibility services,
      * but only the content description is available from them.
      *
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index 41a3847..cd22ad6 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -52,7 +52,7 @@
      * a SurfaceView by calling {@link SurfaceView#setChildSurfacePackage}.
      */
     public static final class SurfacePackage implements Parcelable {
-        private final SurfaceControl mSurfaceControl;
+        private SurfaceControl mSurfaceControl;
         private final IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;
 
         SurfacePackage(SurfaceControl sc, IAccessibilityEmbeddedConnection connection) {
@@ -97,6 +97,19 @@
             out.writeStrongBinder(mAccessibilityEmbeddedConnection.asBinder());
         }
 
+        /**
+         * Release the {@link SurfaceControl} associated with this package.
+         * It's not necessary to call this if you pass the package to
+         * {@link SurfaceView#setChildSurfacePackage} as {@link SurfaceView} will
+         * take ownership in that case.
+         */
+        public void release() {
+            if (mSurfaceControl != null) {
+                mSurfaceControl.release();
+             }
+             mSurfaceControl = null;
+        }
+
         public static final @NonNull Creator<SurfacePackage> CREATOR
              = new Creator<SurfacePackage>() {
                      public SurfacePackage createFromParcel(Parcel in) {
@@ -220,7 +233,7 @@
      * and render the object unusable.
      */
     public void release() {
-        mViewRoot.dispatchDetachedFromWindow();
+        mViewRoot.die(false /* immediate */);
         mSurfaceControl.release();
     }
 
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 1f7c3504..3e1e393 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -496,8 +496,17 @@
 
         updateSurface();
         releaseSurfaces();
-        mHaveFrame = false;
 
+        // We don't release this as part of releaseSurfaces as
+        // that is also called on transient visibility changes. We can't
+        // recreate this Surface, so only release it when we are fully
+        // detached.
+        if (mSurfacePackage != null) {
+            mSurfacePackage.release();
+            mSurfacePackage = null;
+        }
+
+        mHaveFrame = false;
         super.onDetachedFromWindow();
     }
 
@@ -1546,7 +1555,9 @@
      * Display the view-hierarchy embedded within a {@link SurfaceControlViewHost.SurfacePackage}
      * within this SurfaceView. If this SurfaceView is above it's host Surface (see
      * {@link #setZOrderOnTop} then the embedded Surface hierarchy will be able to receive
-     * input.
+     * input. This will take ownership of the SurfaceControl contained inside the SurfacePackage
+     * and free the caller of the obligation to call
+     * {@link SurfaceControlViewHost.SurfacePackage#release}.
      *
      * @param p The SurfacePackage to embed.
      */
@@ -1556,6 +1567,7 @@
             mSurfacePackage.getSurfaceControl() : null;
         if (mSurfaceControl != null && lastSc != null) {
             mTmpTransaction.reparent(lastSc, null).apply();
+            mSurfacePackage.release();
         } else if (mSurfaceControl != null) {
             reparentSurfacePackage(mTmpTransaction, p);
             mTmpTransaction.apply();
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 5fccf40..4980b33 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -2876,7 +2876,7 @@
     }
 
     /**
-     * Replaces any ClickableSpans in mText with placeholders.
+     * Replaces any ClickableSpan in the given {@code text} with placeholders.
      *
      * @param text The text.
      *
@@ -2910,7 +2910,7 @@
     }
 
     /**
-     * Replace any ImageSpans in mText with its content description.
+     * Replaces any ReplacementSpan in the given {@code text} if the object has content description.
      *
      * @param text The text.
      *
diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java
index 728824c..d661bc6 100644
--- a/core/java/android/widget/EditText.java
+++ b/core/java/android/widget/EditText.java
@@ -24,7 +24,6 @@
 import android.text.method.ArrowKeyMovementMethod;
 import android.text.method.MovementMethod;
 import android.util.AttributeSet;
-import android.view.accessibility.AccessibilityNodeInfo;
 
 /*
  * This is supposed to be a *very* thin veneer over TextView.
@@ -179,13 +178,4 @@
     protected boolean supportsAutoSizeText() {
         return false;
     }
-
-    /** @hide */
-    @Override
-    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfoInternal(info);
-        if (isEnabled()) {
-            info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_TEXT);
-        }
-    }
 }
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 16d9ed3..4aeea10 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -317,6 +317,7 @@
     private SelectionActionModeHelper mSelectionActionModeHelper;
 
     boolean mIsBeingLongClicked;
+    boolean mIsBeingLongClickedByAccessibility;
 
     private SuggestionsPopupWindow mSuggestionsPopupWindow;
     SuggestionRangeSpan mSuggestionRangeSpan;
@@ -1312,6 +1313,12 @@
         if (TextView.DEBUG_CURSOR) {
             logCursor("performLongClick", "handled=%s", handled);
         }
+        if (mIsBeingLongClickedByAccessibility) {
+            if (!handled) {
+                toggleInsertionActionMode();
+            }
+            return true;
+        }
         // Long press in empty space moves cursor and starts the insertion action mode.
         if (!handled && !isPositionOnText(mTouchState.getLastDownX(), mTouchState.getLastDownY())
                 && !mTouchState.isOnHandle() && mInsertionControllerEnabled) {
@@ -1359,6 +1366,14 @@
         return handled;
     }
 
+    private void toggleInsertionActionMode() {
+        if (mTextActionMode != null) {
+            stopTextActionMode();
+        } else {
+            startInsertionActionMode();
+        }
+    }
+
     float getLastUpPositionX() {
         return mTouchState.getLastUpX();
     }
@@ -5436,11 +5451,7 @@
                                 config.getScaledTouchSlop());
                         if (isWithinTouchSlop) {
                             // Tapping on the handle toggles the insertion action mode.
-                            if (mTextActionMode != null) {
-                                stopTextActionMode();
-                            } else {
-                                startInsertionActionMode();
-                            }
+                            toggleInsertionActionMode();
                         }
                     } else {
                         if (mTextActionMode != null) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 2168018..e178318 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -12108,6 +12108,23 @@
                     onEditorAction(getImeActionId());
                 }
             } return true;
+            case AccessibilityNodeInfo.ACTION_LONG_CLICK: {
+                if (isLongClickable()) {
+                    boolean handled;
+                    if (isEnabled() && (mBufferType == BufferType.EDITABLE)) {
+                        mEditor.mIsBeingLongClickedByAccessibility = true;
+                        try {
+                            handled = performLongClick();
+                        } finally {
+                            mEditor.mIsBeingLongClickedByAccessibility = false;
+                        }
+                    } else {
+                        handled = performLongClick();
+                    }
+                    return handled;
+                }
+            }
+            return false;
             default: {
                 return super.performAccessibilityActionInternal(action, arguments);
             }
diff --git a/core/java/com/android/ims/internal/uce/uceservice/ImsUceManager.java b/core/java/com/android/ims/internal/uce/uceservice/ImsUceManager.java
index 9aee879f..ef8d018 100644
--- a/core/java/com/android/ims/internal/uce/uceservice/ImsUceManager.java
+++ b/core/java/com/android/ims/internal/uce/uceservice/ImsUceManager.java
@@ -50,6 +50,16 @@
     public static final String ACTION_UCE_SERVICE_DOWN =
                                         "com.android.ims.internal.uce.UCE_SERVICE_DOWN";
 
+    /**
+     * Uce Service status received in IUceListener.setStatus() callback
+     */
+    public static final int UCE_SERVICE_STATUS_FAILURE = 0;
+    /** indicate UI to call Presence/Options API.   */
+    public static final int UCE_SERVICE_STATUS_ON = 1;
+    /** Indicate UI destroy Presence/Options   */
+    public static final int UCE_SERVICE_STATUS_CLOSED = 2;
+    /** Service up and trying to register for network events  */
+    public static final int UCE_SERVICE_STATUS_READY = 3;
 
     /**
      * Gets the instance of UCE Manager
diff --git a/core/proto/android/app/appexitinfo.proto b/core/proto/android/app/appexitinfo.proto
index 66173f6..4b9444e 100644
--- a/core/proto/android/app/appexitinfo.proto
+++ b/core/proto/android/app/appexitinfo.proto
@@ -42,4 +42,6 @@
     optional int64 rss = 12;
     optional int64 timestamp = 13;
     optional string description = 14;
+    optional bytes state = 15;
+    optional string trace_file = 16;
 }
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index ef6eb38..fc6e639 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -734,6 +734,16 @@
     // CATEGORY: SETTINGS
     // OS: R
     ACTION_SETTINGS_CHANGE_WIFI_HOTSPOT_PASSWORD = 1737;
+
+    // ACTION: Settings > Security > Toggle on Confirm Sim deletion
+    // CATEGORY: SETTINGS
+    // OS: R
+    ACTION_CONFIRM_SIM_DELETION_ON = 1738;
+
+    // ACTION: Settings > Security > Toggle off Confirm Sim deletion
+    // CATEGORY: SETTINGS
+    // OS: R
+    ACTION_CONFIRM_SIM_DELETION_OFF = 1739;
 }
 
 /**
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f7400bd..ad984e6 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -737,7 +737,7 @@
     <!-- @SystemApi Allows accessing the messages on ICC
          @hide Used internally. -->
     <permission android:name="android.permission.ACCESS_MESSAGES_ON_ICC"
-        android:protectionLevel="signature|telephony" />
+        android:protectionLevel="signature" />
 
     <!-- Used for runtime permissions related to user's SMS messages. -->
     <permission-group android:name="android.permission-group.SMS"
@@ -1109,13 +1109,12 @@
          grants your app this permission. If you don't need this permission, be sure your <a
          href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
          targetSdkVersion}</a> is 4 or higher.
-         <p>Protection level: dangerous
+         <p>Protection level: normal
     -->
     <permission android:name="android.permission.READ_PHONE_STATE"
-        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_readPhoneState"
         android:description="@string/permdesc_readPhoneState"
-        android:protectionLevel="dangerous" />
+        android:protectionLevel="normal" />
 
     <!-- Allows read access to the device's phone number(s). This is a subset of the capabilities
          granted by {@link #READ_PHONE_STATE} but is exposed to instant applications.
@@ -1699,7 +1698,7 @@
          @hide This should only be used by Settings and SystemUI.
     -->
     <permission android:name="android.permission.NETWORK_SETTINGS"
-        android:protectionLevel="signature|telephony" />
+        android:protectionLevel="signature" />
 
     <!-- Allows holder to request bluetooth/wifi scan bypassing global "use location" setting and
          location permissions.
@@ -2140,7 +2139,7 @@
     <!-- @SystemApi Allows granting runtime permissions to telephony related components.
          @hide -->
     <permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS"
-        android:protectionLevel="signature|telephony" />
+        android:protectionLevel="signature" />
 
     <!-- Allows modification of the telephony state - power on, mmi, etc.
          Does not include placing calls.
@@ -2168,7 +2167,7 @@
     <!-- @SystemApi Allows listen permission to always reported signal strength.
          @hide Used internally. -->
     <permission android:name="android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH"
-        android:protectionLevel="signature|telephony" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Protects the ability to register any PhoneAccount with
          PhoneAccount#CAPABILITY_SIM_SUBSCRIPTION. This capability indicates that the PhoneAccount
@@ -2281,21 +2280,21 @@
 
     <!-- Must be required by a telephony data service to ensure that only the
          system can bind to it.
-         <p>Protection level: signature|telephony
+         <p>Protection level: signature
          @SystemApi
          @hide
     -->
     <permission android:name="android.permission.BIND_TELEPHONY_DATA_SERVICE"
-        android:protectionLevel="signature|telephony" />
+        android:protectionLevel="signature" />
 
     <!-- Must be required by a NetworkService to ensure that only the
          system can bind to it.
-         <p>Protection level: signature|telephony
+         <p>Protection level: signature
          @SystemApi
          @hide
     -->
     <permission android:name="android.permission.BIND_TELEPHONY_NETWORK_SERVICE"
-                android:protectionLevel="signature|telephony" />
+                android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to manage embedded subscriptions (those on a eUICC)
          through EuiccManager APIs.
@@ -2307,19 +2306,19 @@
 
     <!-- @SystemApi Must be required by an EuiccService to ensure that only the system can bind to
          it.
-         <p>Protection level: signature|telephony
+         <p>Protection level: signature
          @hide
     -->
     <permission android:name="android.permission.BIND_EUICC_SERVICE"
-                android:protectionLevel="signature|telephony" />
+                android:protectionLevel="signature" />
 
     <!-- Required for reading information about carrier apps from SystemConfigManager.
-         <p>Protection level: signature|telephony
+         <p>Protection level: signature
          @SystemApi
          @hide
     -->
     <permission android:name="android.permission.READ_CARRIER_APP_INFO"
-        android:protectionLevel="signature|telephony" />
+        android:protectionLevel="signature" />
 
     <!-- ================================== -->
     <!-- Permissions for sdcard interaction -->
@@ -2439,7 +2438,7 @@
          types of interactions
          @hide -->
     <permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
-        android:protectionLevel="signature|installer|telephony" />
+        android:protectionLevel="signature|installer" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
 
     <!-- Allows interaction across profiles in the same profile group. -->
@@ -2677,7 +2676,7 @@
          @hide
      -->
     <permission android:name="android.permission.SUGGEST_TELEPHONY_TIME_AND_ZONE"
-        android:protectionLevel="signature|telephony" />
+        android:protectionLevel="signature" />
 
     <!-- Allows applications like settings to suggest the user's manually chosen time / time zone.
          <p>Not for use by third-party applications.
@@ -3099,9 +3098,8 @@
 
     <!-- Allows an application to be the status bar.  Currently used only by SystemUI.apk
     @hide -->
-    // TODO: remove telephony once decouple settings activity from phone process
     <permission android:name="android.permission.STATUS_BAR_SERVICE"
-        android:protectionLevel="signature|telephony" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to bind to third party quick settings tiles.
          <p>Should only be requested by the System, should be required by
@@ -3158,7 +3156,7 @@
          @hide
     -->
     <permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"
-        android:protectionLevel="signature|telephony" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to use
          {@link android.view.WindowManager.LayoutsParams#SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS}
@@ -3235,7 +3233,7 @@
          @hide
     -->
     <permission android:name="android.permission.SET_ACTIVITY_WATCHER"
-        android:protectionLevel="signature|telephony" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to call the activity manager shutdown() API
          to put the higher-level system there into a shutdown state.
@@ -3779,7 +3777,7 @@
          @hide
          STOPSHIP b/145526313: Remove wellbeing protection flag from MANAGE_ROLE_HOLDERS. -->
     <permission android:name="android.permission.MANAGE_ROLE_HOLDERS"
-                android:protectionLevel="signature|installer|telephony|wellbeing" />
+                android:protectionLevel="signature|installer|wellbeing" />
 
     <!-- @SystemApi Allows an application to observe role holder changes.
          @hide -->
@@ -4016,7 +4014,7 @@
         @hide
     -->
    <permission android:name="android.permission.DEVICE_POWER"
-        android:protectionLevel="signature|telephony" />
+        android:protectionLevel="signature" />
 
     <!-- Allows toggling battery saver on the system.
          Superseded by DEVICE_POWER permission. @hide @SystemApi
@@ -4051,13 +4049,13 @@
          <p>Not for use by third-party applications.
     -->
     <permission android:name="android.permission.BROADCAST_SMS"
-        android:protectionLevel="signature|telephony" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to broadcast a WAP PUSH receipt notification.
          <p>Not for use by third-party applications.
     -->
     <permission android:name="android.permission.BROADCAST_WAP_PUSH"
-        android:protectionLevel="signature|telephony" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to broadcast privileged networking requests.
          <p>Not for use by third-party applications.
@@ -4723,13 +4721,13 @@
          {@link android.provider.BlockedNumberContract}.
          @hide -->
     <permission android:name="android.permission.READ_BLOCKED_NUMBERS"
-                android:protectionLevel="signature|telephony" />
+                android:protectionLevel="signature" />
 
     <!-- Allows the holder to write blocked numbers. See
          {@link android.provider.BlockedNumberContract}.
          @hide -->
     <permission android:name="android.permission.WRITE_BLOCKED_NUMBERS"
-                android:protectionLevel="signature|telephony" />
+                android:protectionLevel="signature" />
 
     <!-- Must be required by an {@link android.service.vr.VrListenerService}, to ensure that only
          the system can bind to it.
@@ -4889,7 +4887,7 @@
     <!-- @hide Permission that allows configuring appops.
      <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.MANAGE_APPOPS"
-                android:protectionLevel="signature|telephony" />
+                android:protectionLevel="signature" />
 
     <!-- @hide Permission that allows background clipboard access.
          <p>Not for use by third-party applications. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index f3ca5ac..2496900 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -296,9 +296,6 @@
             granted to the system app predictor -->
         <flag name="appPredictor" value="0x200000" />
         <!-- Additional flag from base permission type: this permission can be automatically
-            granted to the system telephony apps -->
-        <flag name="telephony" value="0x400000" />
-        <!-- Additional flag from base permission type: this permission can be automatically
             granted to the system companion device manager service -->
         <flag name="companion" value="0x800000" />
         <!-- Additional flag from base permission type: this permission will be granted to the
@@ -1835,7 +1832,7 @@
              revoked when the app is unused for an extended amount of time.
 
              The default value is {@code false}. -->
-        <attr name="requestDontAutoRevokePermissions" format="boolean" />
+        <attr name="requestAutoRevokePermissionsExemption" format="boolean" />
 
         <!-- If {@code true} its permissions shouldn't get automatically
              revoked when the app is unused for an extended amount of time.
@@ -1843,7 +1840,7 @@
              This implies {@code requestDontAutoRevokePermissions=true}
 
              The default value is {@code false}. -->
-        <attr name="allowDontAutoRevokePermissions" format="boolean" />
+        <attr name="allowAutoRevokePermissionsExemption" format="boolean" />
     </declare-styleable>
 
     <!-- An attribution is a logical part of an app and is identified by a tag.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4993aaf..94764ca 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3641,15 +3641,6 @@
      -->
     <string name="config_defaultWellbeingPackage" translatable="false"></string>
 
-    <!-- The package name for the system telephony apps.
-         This package must be trusted, as it will be granted with permissions with special telephony
-         protection level. Note, framework by default support multiple telephony apps, each package
-         name is separated by comma.
-         Example: "com.android.phone,com.android.stk,com.android.providers.telephony"
-         (Note: shell is included for testing purposes)
-     -->
-    <string name="config_telephonyPackages" translatable="false">"com.android.phone,com.android.stk,com.android.providers.telephony,com.android.ons"</string>
-
     <!-- The component name for the default system attention service.
          This service must be trusted, as it can be activated without explicit consent of the user.
          See android.attention.AttentionManagerService.
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index cf68aff..5306518 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3014,8 +3014,8 @@
       <!-- @hide @SystemApi -->
       <public name="minExtensionVersion" />
       <public name="allowNativeHeapPointerTagging" />
-      <public name="requestDontAutoRevokePermissions" />
-      <public name="allowDontAutoRevokePermissions" />
+      <public name="requestAutoRevokePermissionsExemption" />
+      <public name="allowAutoRevokePermissionsExemption" />
       <public name="preserveLegacyExternalStorage" />
       <public name="mimeGroup" />
       <public name="enableGwpAsan" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 26024ed..2040bed 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4444,6 +4444,20 @@
     <string name="accessibility_shortcut_spoken_feedback">Press and hold both volume keys for three seconds to use
         <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g></string>
 
+    <!-- Text appearing in a prompt at the top of UI allowing the user to select a target service or feature to be assigned to the Accessibility button in the navigation bar. [CHAR LIMIT=none]-->
+    <string name="accessibility_button_prompt_text">Choose a app to use when you tap the accessibility button:</string>
+    <!-- Text appearing in a prompt at the top of UI allowing the user to select a target service or feature to be assigned to the Accessibility button when gesture navigation is enabled [CHAR LIMIT=none] -->
+    <string name="accessibility_gesture_prompt_text">Choose a app to use with the accessibility gesture (swipe up from the bottom of the screen with two fingers):</string>
+    <!-- Text appearing in a prompt at the top of UI allowing the user to select a target service or feature to be assigned to the Accessibility button when gesture navigation and TalkBack is enabled [CHAR LIMIT=none] -->
+    <string name="accessibility_gesture_3finger_prompt_text">Choose a app to use with the accessibility gesture (swipe up from the bottom of the screen with three fingers):</string>
+
+    <!-- Text describing how to display UI allowing a user to select a target service or feature to be assigned to the Accessibility button in the navigation bar. [CHAR LIMIT=none]-->
+    <string name="accessibility_button_instructional_text">To switch between apps, touch &amp; hold the accessibility button.</string>
+    <!-- Text describing how to display UI allowing a user to select a target service or feature to be assigned to the Accessibility button when gesture navigation is enabled. [CHAR LIMIT=none] -->
+    <string name="accessibility_gesture_instructional_text">To switch between apps, swipe up with two fingers and hold.</string>
+    <!-- Text describing how to display UI allowing a user to select a target service or feature to be assigned to the Accessibility button when gesture navigation and TalkBack is enabled. [CHAR LIMIT=none] -->
+    <string name="accessibility_gesture_3finger_instructional_text">To switch between apps, swipe up with three fingers and hold.</string>
+
     <!-- Text used to describe system navigation features, shown within a UI allowing a user to assign system magnification features to the Accessibility button in the navigation bar. -->
     <string name="accessibility_magnification_chooser_text">Magnification</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 8919c02..a1b00f2 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3397,7 +3397,6 @@
   <java-symbol type="string" name="config_defaultAutofillService" />
   <java-symbol type="string" name="config_defaultTextClassifierPackage" />
   <java-symbol type="string" name="config_defaultWellbeingPackage" />
-  <java-symbol type="string" name="config_telephonyPackages" />
   <java-symbol type="string" name="config_defaultContentCaptureService" />
   <java-symbol type="string" name="config_defaultAugmentedAutofillService" />
   <java-symbol type="string" name="config_defaultAppPredictionService" />
diff --git a/core/tests/coretests/src/android/app/timezonedetector/ManualTimeZoneSuggestionTest.java b/core/tests/coretests/src/android/app/timezonedetector/ManualTimeZoneSuggestionTest.java
index 02ed0ed..17838bb 100644
--- a/core/tests/coretests/src/android/app/timezonedetector/ManualTimeZoneSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/timezonedetector/ManualTimeZoneSuggestionTest.java
@@ -18,12 +18,19 @@
 
 import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
 import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable;
+import static android.app.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.os.ShellCommand;
 
 import org.junit.Test;
 
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
 public class ManualTimeZoneSuggestionTest {
 
     private static final String ARBITRARY_ZONE_ID1 = "Europe/London";
@@ -58,4 +65,36 @@
         ManualTimeZoneSuggestion rtSuggestion = roundTripParcelable(suggestion);
         assertEquals(suggestion.getDebugInfo(), rtSuggestion.getDebugInfo());
     }
+
+    @Test
+    public void testPrintCommandLineOpts() throws Exception {
+        try (StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw)) {
+            ManualTimeZoneSuggestion.printCommandLineOpts(pw);
+            assertTrue(sw.getBuffer().length() > 0);
+        }
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseCommandLineArg_noArgs() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions("");
+        ManualTimeZoneSuggestion.parseCommandLineArg(testShellCommand);
+    }
+
+    @Test
+    public void testParseCommandLineArg_validSuggestion() {
+        ShellCommand testShellCommand =
+                createShellCommandWithArgsAndOptions("--zone_id Europe/London");
+        ManualTimeZoneSuggestion expectedSuggestion =
+                new ManualTimeZoneSuggestion("Europe/London");
+        ManualTimeZoneSuggestion actualSuggestion =
+                ManualTimeZoneSuggestion.parseCommandLineArg(testShellCommand);
+        assertEquals(expectedSuggestion, actualSuggestion);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseCommandLineArg_unknownArgument() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--zone_id Europe/London --bad_arg 0");
+        ManualTimeZoneSuggestion.parseCommandLineArg(testShellCommand);
+    }
 }
diff --git a/core/tests/coretests/src/android/app/timezonedetector/ShellCommandTestSupport.java b/core/tests/coretests/src/android/app/timezonedetector/ShellCommandTestSupport.java
new file mode 100644
index 0000000..8d8290c
--- /dev/null
+++ b/core/tests/coretests/src/android/app/timezonedetector/ShellCommandTestSupport.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.timezonedetector;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.os.ShellCommand;
+
+import org.mockito.stubbing.Answer;
+
+import java.util.Arrays;
+import java.util.List;
+
+/** Utility methods related to {@link ShellCommand} objects used in several tests. */
+final class ShellCommandTestSupport {
+    private ShellCommandTestSupport() {}
+
+    static ShellCommand createShellCommandWithArgsAndOptions(String argsWithSpaces) {
+        return createShellCommandWithArgsAndOptions(Arrays.asList(argsWithSpaces.split(" ")));
+    }
+
+    static ShellCommand createShellCommandWithArgsAndOptions(List<String> args) {
+        ShellCommand command = mock(ShellCommand.class);
+        class ArgProvider {
+            private int mCount;
+
+            String getNext() {
+                if (mCount >= args.size()) {
+                    return null;
+                }
+                return args.get(mCount++);
+            }
+
+            String getNextRequired() {
+                String next = getNext();
+                if (next == null) {
+                    throw new IllegalArgumentException("No next");
+                }
+                return next;
+            }
+        }
+        ArgProvider argProvider = new ArgProvider();
+        when(command.getNextArg()).thenAnswer(
+                (Answer<String>) invocation -> argProvider.getNext());
+        when(command.getNextOption()).thenAnswer(
+                (Answer<String>) invocation -> argProvider.getNext());
+        when(command.getNextArgRequired()).thenAnswer(
+                (Answer<String>) invocation -> argProvider.getNextRequired());
+        return command;
+    }
+}
diff --git a/core/tests/coretests/src/android/app/timezonedetector/TelephonyTimeZoneSuggestionTest.java b/core/tests/coretests/src/android/app/timezonedetector/TelephonyTimeZoneSuggestionTest.java
index 59d55b7..c4ff9be 100644
--- a/core/tests/coretests/src/android/app/timezonedetector/TelephonyTimeZoneSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/timezonedetector/TelephonyTimeZoneSuggestionTest.java
@@ -18,13 +18,19 @@
 
 import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
 import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable;
+import static android.app.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 
+import android.os.ShellCommand;
+
 import org.junit.Test;
 
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
 public class TelephonyTimeZoneSuggestionTest {
     private static final int SLOT_INDEX = 99999;
 
@@ -159,4 +165,57 @@
         assertEquals(suggestion1, suggestion1_2);
         assertTrue(suggestion1_2.getDebugInfo().contains(debugString));
     }
+
+    @Test
+    public void testPrintCommandLineOpts() throws Exception {
+        try (StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw)) {
+            TelephonyTimeZoneSuggestion.printCommandLineOpts(pw);
+            assertTrue(sw.getBuffer().length() > 0);
+        }
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseCommandLineArg_noArgs() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions("");
+        TelephonyTimeZoneSuggestion.parseCommandLineArg(testShellCommand);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseCommandLineArg_noSlotIndex() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions("--zone_id _");
+        TelephonyTimeZoneSuggestion.parseCommandLineArg(testShellCommand);
+    }
+
+    @Test
+    public void testParseCommandLineArg_validEmptyZoneIdSuggestion() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--slot_index 0 --zone_id _");
+        TelephonyTimeZoneSuggestion expectedSuggestion =
+                new TelephonyTimeZoneSuggestion.Builder(0).build();
+        TelephonyTimeZoneSuggestion actualSuggestion =
+                TelephonyTimeZoneSuggestion.parseCommandLineArg(testShellCommand);
+        assertEquals(expectedSuggestion, actualSuggestion);
+    }
+
+    @Test
+    public void testParseCommandLineArg_validNonEmptySuggestion() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--slot_index 0 --zone_id Europe/London --quality single --match_type country");
+        TelephonyTimeZoneSuggestion expectedSuggestion =
+                new TelephonyTimeZoneSuggestion.Builder(0)
+                        .setZoneId("Europe/London")
+                        .setQuality(TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE)
+                        .setMatchType(TelephonyTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY)
+                        .build();
+        TelephonyTimeZoneSuggestion actualSuggestion =
+                TelephonyTimeZoneSuggestion.parseCommandLineArg(testShellCommand);
+        assertEquals(expectedSuggestion, actualSuggestion);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseCommandLineArg_unknownArgument() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--slot_index 0 --zone_id _ --bad_arg 0");
+        TelephonyTimeZoneSuggestion.parseCommandLineArg(testShellCommand);
+    }
 }
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index a72be25..45d4b38 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -65,6 +65,7 @@
 import android.app.Instrumentation;
 import android.content.ClipData;
 import android.content.ClipboardManager;
+import android.os.Bundle;
 import android.support.test.uiautomator.UiDevice;
 import android.text.InputType;
 import android.text.Selection;
@@ -75,6 +76,7 @@
 import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.MenuItem;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.textclassifier.SelectionEvent;
 import android.view.textclassifier.TextClassificationManager;
 import android.view.textclassifier.TextClassifier;
@@ -358,6 +360,20 @@
     }
 
     @Test
+    public void testToolbarAppearsAccessibilityLongClick() throws Throwable {
+        final String text = "Toolbar appears after performing accessibility's ACTION_LONG_CLICK.";
+        mActivityRule.runOnUiThread(() -> {
+            final TextView textView = mActivity.findViewById(R.id.textview);
+            final Bundle args = new Bundle();
+            textView.performAccessibilityAction(AccessibilityNodeInfo.ACTION_LONG_CLICK, args);
+        });
+        mInstrumentation.waitForIdleSync();
+
+        sleepForFloatingToolbarPopup();
+        assertFloatingToolbarIsDisplayed();
+    }
+
+    @Test
     public void testSelectionRemovedWhenNonselectableTextLosesFocus() throws Throwable {
         final TextLinks.TextLink textLink = addLinkifiedTextToTextView(R.id.nonselectable_textview);
         final int position = (textLink.getStart() + textLink.getEnd()) / 2;
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 5466ac8..87b0817 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -36,11 +36,6 @@
         <permission name="android.permission.CRYPT_KEEPER"/>
     </privapp-permissions>
 
-    <privapp-permissions package="com.android.captiveportallogin">
-        <permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
-        <permission name="android.permission.NETWORK_BYPASS_PRIVATE_DNS"/>
-    </privapp-permissions>
-
     <privapp-permissions package="com.android.cellbroadcastreceiver">
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
         <permission name="android.permission.MANAGE_USERS"/>
@@ -400,6 +395,8 @@
         <permission name="android.permission.COMPANION_APPROVE_WIFI_CONNECTIONS" />
         <!-- Permission required for testing registering pull atom callbacks. -->
         <permission name="android.permission.REGISTER_STATS_PULL_ATOM"/>
+        <!-- Permission required for testing system audio effect APIs. -->
+        <permission name="android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"/>
     </privapp-permissions>
 
     <privapp-permissions package="com.android.statementservice">
diff --git a/location/java/android/location/AbstractListenerManager.java b/location/java/android/location/AbstractListenerManager.java
index 3dc7cfc..36b8689 100644
--- a/location/java/android/location/AbstractListenerManager.java
+++ b/location/java/android/location/AbstractListenerManager.java
@@ -85,11 +85,13 @@
         }
     }
 
-    @GuardedBy("mListeners")
-    private final ArrayMap<Object, Registration<TRequest, TListener>> mListeners =
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private volatile ArrayMap<Object, Registration<TRequest, TListener>> mListeners =
             new ArrayMap<>();
 
-    @GuardedBy("mListeners")
+    @GuardedBy("mLock")
     @Nullable
     private TRequest mMergedRequest;
 
@@ -129,10 +131,16 @@
             throws RemoteException {
         Preconditions.checkNotNull(registration);
 
-        synchronized (mListeners) {
+        synchronized (mLock) {
             boolean initialRequest = mListeners.isEmpty();
 
-            Registration<TRequest, TListener> oldRegistration = mListeners.put(key, registration);
+            ArrayMap<Object, Registration<TRequest, TListener>> newListeners = new ArrayMap<>(
+                    mListeners.size() + 1);
+            newListeners.putAll(mListeners);
+            Registration<TRequest, TListener> oldRegistration = newListeners.put(key,
+                    registration);
+            mListeners = newListeners;
+
             if (oldRegistration != null) {
                 oldRegistration.unregister();
             }
@@ -151,8 +159,12 @@
     }
 
     public void removeListener(Object listener) throws RemoteException {
-        synchronized (mListeners) {
-            Registration<TRequest, TListener> oldRegistration = mListeners.remove(listener);
+        synchronized (mLock) {
+            ArrayMap<Object, Registration<TRequest, TListener>> newListeners = new ArrayMap<>(
+                    mListeners);
+            Registration<TRequest, TListener> oldRegistration = newListeners.remove(listener);
+            mListeners = newListeners;
+
             if (oldRegistration == null) {
                 return;
             }
@@ -190,18 +202,16 @@
     }
 
     protected void execute(Consumer<TListener> operation) {
-        synchronized (mListeners) {
-            for (Registration<TRequest, TListener> registration : mListeners.values()) {
-                registration.execute(operation);
-            }
+        for (Registration<TRequest, TListener> registration : mListeners.values()) {
+            registration.execute(operation);
         }
     }
 
-    @GuardedBy("mListeners")
+    @GuardedBy("mLock")
     @SuppressWarnings("unchecked")
     @Nullable
     private TRequest mergeRequests() {
-        Preconditions.checkState(Thread.holdsLock(mListeners));
+        Preconditions.checkState(Thread.holdsLock(mLock));
 
         if (mListeners.isEmpty()) {
             return null;
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index 83a8995..5e3b8aa 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -21,8 +21,8 @@
 import static android.hardware.gnss.V2_1.IGnssMeasurementCallback.GnssMeasurementFlags.HAS_CARRIER_FREQUENCY;
 import static android.hardware.gnss.V2_1.IGnssMeasurementCallback.GnssMeasurementFlags.HAS_CARRIER_PHASE;
 import static android.hardware.gnss.V2_1.IGnssMeasurementCallback.GnssMeasurementFlags.HAS_CARRIER_PHASE_UNCERTAINTY;
-import static android.hardware.gnss.V2_1.IGnssMeasurementCallback.GnssMeasurementFlags.HAS_RECEIVER_ISB;
-import static android.hardware.gnss.V2_1.IGnssMeasurementCallback.GnssMeasurementFlags.HAS_RECEIVER_ISB_UNCERTAINTY;
+import static android.hardware.gnss.V2_1.IGnssMeasurementCallback.GnssMeasurementFlags.HAS_FULL_ISB;
+import static android.hardware.gnss.V2_1.IGnssMeasurementCallback.GnssMeasurementFlags.HAS_FULL_ISB_UNCERTAINTY;
 import static android.hardware.gnss.V2_1.IGnssMeasurementCallback.GnssMeasurementFlags.HAS_SATELLITE_ISB;
 import static android.hardware.gnss.V2_1.IGnssMeasurementCallback.GnssMeasurementFlags.HAS_SATELLITE_ISB_UNCERTAINTY;
 import static android.hardware.gnss.V2_1.IGnssMeasurementCallback.GnssMeasurementFlags.HAS_SNR;
@@ -63,8 +63,8 @@
     private double mSnrInDb;
     private double mAutomaticGainControlLevelInDb;
     @NonNull private String mCodeType;
-    private double mReceiverInterSignalBiasNanos;
-    private double mReceiverInterSignalBiasUncertaintyNanos;
+    private double mFullInterSignalBiasNanos;
+    private double mFullInterSignalBiasUncertaintyNanos;
     private double mSatelliteInterSignalBiasNanos;
     private double mSatelliteInterSignalBiasUncertaintyNanos;
 
@@ -268,9 +268,9 @@
         mSnrInDb = measurement.mSnrInDb;
         mAutomaticGainControlLevelInDb = measurement.mAutomaticGainControlLevelInDb;
         mCodeType = measurement.mCodeType;
-        mReceiverInterSignalBiasNanos = measurement.mReceiverInterSignalBiasNanos;
-        mReceiverInterSignalBiasUncertaintyNanos =
-                measurement.mReceiverInterSignalBiasUncertaintyNanos;
+        mFullInterSignalBiasNanos = measurement.mFullInterSignalBiasNanos;
+        mFullInterSignalBiasUncertaintyNanos =
+                measurement.mFullInterSignalBiasUncertaintyNanos;
         mSatelliteInterSignalBiasNanos = measurement.mSatelliteInterSignalBiasNanos;
         mSatelliteInterSignalBiasUncertaintyNanos =
                 measurement.mSatelliteInterSignalBiasUncertaintyNanos;
@@ -1435,99 +1435,110 @@
     }
 
     /**
-     * Returns {@code true} if {@link #getReceiverInterSignalBiasNanos()} is available,
+     * Returns {@code true} if {@link #getFullInterSignalBiasNanos()} is available,
      * {@code false} otherwise.
      */
-    public boolean hasReceiverInterSignalBiasNanos() {
-        return isFlagSet(HAS_RECEIVER_ISB);
+    public boolean hasFullInterSignalBiasNanos() {
+        return isFlagSet(HAS_FULL_ISB);
     }
 
     /**
-     * Gets the GNSS measurement's receiver inter-signal bias in nanoseconds with sub-nanosecond
-     * accuracy.
+     * Gets the GNSS measurement's inter-signal bias in nanoseconds with sub-nanosecond accuracy.
      *
-     * <p>This value is the estimated receiver-side inter-system (different from the
-     * constellation in {@link GnssClock#getReferenceConstellationTypeForIsb()} bias and
-     * inter-frequency (different from the carrier frequency in
-     * {@link GnssClock#getReferenceCarrierFrequencyHzForIsb()}) bias. The reported receiver
-     * inter-signal bias must include signal delays caused by:
+     * <p>This value is the sum of the estimated receiver-side and the space-segment-side
+     * inter-system bias, inter-frequency bias and inter-code bias, including:
      *
      * <ul>
-     * <li>Receiver inter-constellation bias</li>
-     * <li>Receiver inter-frequency bias</li>
-     * <li>Receiver inter-code bias</li>
+     * <li>Receiver inter-constellation bias (with respect to the constellation in
+     * {@link GnssClock#getReferenceConstellationTypeForIsb())</li>
+     * <li>Receiver inter-frequency bias (with respect to the carrier frequency in
+     * {@link GnssClock#getReferenceConstellationTypeForIsb())</li>
+     * <li>Receiver inter-code bias (with respect to the code type in
+     * {@link GnssClock#getReferenceConstellationTypeForIsb())</li>
+     * <li>Master clock bias (e.g., GPS-GAL Time Offset (GGTO), GPS-UTC Time Offset (TauGps),
+     * BDS-GLO Time Offset (BGTO))(with respect to the constellation in
+     * {@link GnssClock#getReferenceConstellationTypeForIsb())</li>
+     * <li>Group delay (e.g., Total Group Delay (TGD))</li>
+     * <li>Satellite inter-frequency bias (GLO only) (with respect to the carrier frequency in
+     * {@link GnssClock#getReferenceConstellationTypeForIsb())</li>
+     * <li>Satellite inter-code bias (e.g., Differential Code Bias (DCB)) (with respect to the code
+     * type in {@link GnssClock#getReferenceConstellationTypeForIsb())</li>
      * </ul>
      *
+     * <p>If a component of the above is already compensated in the provided
+     * {@link GnssMeasurement#getReceivedSvTimeNanos()}, then it must not be included in the
+     * reported full ISB.
+     *
      * <p>The value does not include the inter-frequency Ionospheric bias.
      *
-     * <p>The value is only available if {@link #hasReceiverInterSignalBiasNanos()} is {@code true}.
+     * <p>The value is only available if {@link #hasFullInterSignalBiasNanos()} is {@code true}.
      */
-    public double getReceiverInterSignalBiasNanos() {
-        return mReceiverInterSignalBiasNanos;
+    public double getFullInterSignalBiasNanos() {
+        return mFullInterSignalBiasNanos;
     }
 
     /**
-     * Sets the GNSS measurement's receiver inter-signal bias in nanoseconds.
+     * Sets the GNSS measurement's inter-signal bias in nanoseconds.
      *
      * @hide
      */
     @TestApi
-    public void setReceiverInterSignalBiasNanos(double receiverInterSignalBiasNanos) {
-        setFlag(HAS_RECEIVER_ISB);
-        mReceiverInterSignalBiasNanos = receiverInterSignalBiasNanos;
+    public void setFullInterSignalBiasNanos(double fullInterSignalBiasNanos) {
+        setFlag(HAS_FULL_ISB);
+        mFullInterSignalBiasNanos = fullInterSignalBiasNanos;
     }
 
     /**
-     * Resets the GNSS measurement's receiver inter-signal bias in nanoseconds.
+     * Resets the GNSS measurement's inter-signal bias in nanoseconds.
      *
      * @hide
      */
     @TestApi
-    public void resetReceiverInterSignalBiasNanos() {
-        resetFlag(HAS_RECEIVER_ISB);
+    public void resetFullInterSignalBiasNanos() {
+        resetFlag(HAS_FULL_ISB);
     }
 
     /**
-     * Returns {@code true} if {@link #getReceiverInterSignalBiasUncertaintyNanos()} is available,
+     * Returns {@code true} if {@link #getFullInterSignalBiasUncertaintyNanos()} is available,
      * {@code false} otherwise.
      */
-    public boolean hasReceiverInterSignalBiasUncertaintyNanos() {
-        return isFlagSet(HAS_RECEIVER_ISB_UNCERTAINTY);
+    public boolean hasFullInterSignalBiasUncertaintyNanos() {
+        return isFlagSet(HAS_FULL_ISB_UNCERTAINTY);
     }
 
     /**
-     * Gets the GNSS measurement's receiver inter-signal bias uncertainty (1 sigma) in
+     * Gets the GNSS measurement's inter-signal bias uncertainty (1 sigma) in
      * nanoseconds with sub-nanosecond accuracy.
      *
-     * <p>The value is only available if {@link #hasReceiverInterSignalBiasUncertaintyNanos()} is
+     * <p>The value is only available if {@link #hasFullInterSignalBiasUncertaintyNanos()} is
      * {@code true}.
      */
     @FloatRange(from = 0.0)
-    public double getReceiverInterSignalBiasUncertaintyNanos() {
-        return mReceiverInterSignalBiasUncertaintyNanos;
+    public double getFullInterSignalBiasUncertaintyNanos() {
+        return mFullInterSignalBiasUncertaintyNanos;
     }
 
     /**
-     * Sets the GNSS measurement's receiver inter-signal bias uncertainty (1 sigma) in nanoseconds.
+     * Sets the GNSS measurement's inter-signal bias uncertainty (1 sigma) in nanoseconds.
      *
      * @hide
      */
     @TestApi
-    public void setReceiverInterSignalBiasUncertaintyNanos(@FloatRange(from = 0.0)
-            double receiverInterSignalBiasUncertaintyNanos) {
-        setFlag(HAS_RECEIVER_ISB_UNCERTAINTY);
-        mReceiverInterSignalBiasUncertaintyNanos = receiverInterSignalBiasUncertaintyNanos;
+    public void setFullInterSignalBiasUncertaintyNanos(@FloatRange(from = 0.0)
+            double fullInterSignalBiasUncertaintyNanos) {
+        setFlag(HAS_FULL_ISB_UNCERTAINTY);
+        mFullInterSignalBiasUncertaintyNanos = fullInterSignalBiasUncertaintyNanos;
     }
 
     /**
-     * Resets the GNSS measurement's receiver inter-signal bias uncertainty (1 sigma) in
+     * Resets the GNSS measurement's inter-signal bias uncertainty (1 sigma) in
      * nanoseconds.
      *
      * @hide
      */
     @TestApi
-    public void resetReceiverInterSignalBiasUncertaintyNanos() {
-        resetFlag(HAS_RECEIVER_ISB_UNCERTAINTY);
+    public void resetFullInterSignalBiasUncertaintyNanos() {
+        resetFlag(HAS_FULL_ISB_UNCERTAINTY);
     }
 
     /**
@@ -1542,17 +1553,18 @@
      * Gets the GNSS measurement's satellite inter-signal bias in nanoseconds with sub-nanosecond
      * accuracy.
      *
-     * <p>This value is the satellite-and-control-segment-side inter-system (different from the
-     * constellation in {@link GnssClock#getReferenceConstellationTypeForIsb()}) bias and
-     * inter-frequency (different from the carrier frequency in
-     * {@link GnssClock#getReferenceCarrierFrequencyHzForIsb()}) bias, including:
+     * <p>This value is the space-segment-side inter-system bias, inter-frequency bias and
+     * inter-code bias, including:
      *
      * <ul>
-     * <li>Master clock bias (e.g., GPS-GAL Time Offset (GGTO), GPT-UTC Time Offset (TauGps),
-     * BDS-GLO Time Offset (BGTO))</li>
+     * <li>Master clock bias (e.g., GPS-GAL Time Offset (GGTO), GPS-UTC Time Offset (TauGps),
+     * BDS-GLO Time Offset (BGTO))(with respect to the constellation in
+     * {@link GnssClock#getReferenceConstellationTypeForIsb())</li>
      * <li>Group delay (e.g., Total Group Delay (TGD))</li>
-     * <li>Satellite inter-signal bias, which includes satellite inter-frequency bias (GLO only),
-     * and satellite inter-code bias (e.g., Differential Code Bias (DCB)).</li>
+     * <li>Satellite inter-frequency bias (GLO only) (with respect to the carrier frequency in
+     * {@link GnssClock#getReferenceConstellationTypeForIsb())</li>
+     * <li>Satellite inter-code bias (e.g., Differential Code Bias (DCB)) (with respect to the code
+     * type in {@link GnssClock#getReferenceConstellationTypeForIsb())</li>
      * </ul>
      *
      * <p>The value is only available if {@link #hasSatelliteInterSignalBiasNanos()} is {@code
@@ -1654,8 +1666,8 @@
             gnssMeasurement.mAutomaticGainControlLevelInDb = parcel.readDouble();
             gnssMeasurement.mCodeType = parcel.readString();
             gnssMeasurement.mBasebandCn0DbHz = parcel.readDouble();
-            gnssMeasurement.mReceiverInterSignalBiasNanos = parcel.readDouble();
-            gnssMeasurement.mReceiverInterSignalBiasUncertaintyNanos = parcel.readDouble();
+            gnssMeasurement.mFullInterSignalBiasNanos = parcel.readDouble();
+            gnssMeasurement.mFullInterSignalBiasUncertaintyNanos = parcel.readDouble();
             gnssMeasurement.mSatelliteInterSignalBiasNanos = parcel.readDouble();
             gnssMeasurement.mSatelliteInterSignalBiasUncertaintyNanos = parcel.readDouble();
 
@@ -1692,8 +1704,8 @@
         parcel.writeDouble(mAutomaticGainControlLevelInDb);
         parcel.writeString(mCodeType);
         parcel.writeDouble(mBasebandCn0DbHz);
-        parcel.writeDouble(mReceiverInterSignalBiasNanos);
-        parcel.writeDouble(mReceiverInterSignalBiasUncertaintyNanos);
+        parcel.writeDouble(mFullInterSignalBiasNanos);
+        parcel.writeDouble(mFullInterSignalBiasUncertaintyNanos);
         parcel.writeDouble(mSatelliteInterSignalBiasNanos);
         parcel.writeDouble(mSatelliteInterSignalBiasUncertaintyNanos);
     }
@@ -1778,14 +1790,14 @@
             builder.append(String.format(format, "CodeType", mCodeType));
         }
 
-        if (hasReceiverInterSignalBiasNanos() || hasReceiverInterSignalBiasUncertaintyNanos()) {
+        if (hasFullInterSignalBiasNanos() || hasFullInterSignalBiasUncertaintyNanos()) {
             builder.append(String.format(
                     formatWithUncertainty,
-                    "ReceiverInterSignalBiasNs",
-                    hasReceiverInterSignalBiasNanos() ? mReceiverInterSignalBiasNanos : null,
-                    "ReceiverInterSignalBiasUncertaintyNs",
-                    hasReceiverInterSignalBiasUncertaintyNanos()
-                            ? mReceiverInterSignalBiasUncertaintyNanos : null));
+                    "InterSignalBiasNs",
+                    hasFullInterSignalBiasNanos() ? mFullInterSignalBiasNanos : null,
+                    "InterSignalBiasUncertaintyNs",
+                    hasFullInterSignalBiasUncertaintyNanos()
+                            ? mFullInterSignalBiasUncertaintyNanos : null));
         }
 
         if (hasSatelliteInterSignalBiasNanos() || hasSatelliteInterSignalBiasUncertaintyNanos()) {
@@ -1824,8 +1836,8 @@
         resetAutomaticGainControlLevel();
         resetCodeType();
         resetBasebandCn0DbHz();
-        resetReceiverInterSignalBiasNanos();
-        resetReceiverInterSignalBiasUncertaintyNanos();
+        resetFullInterSignalBiasNanos();
+        resetFullInterSignalBiasUncertaintyNanos();
         resetSatelliteInterSignalBiasNanos();
         resetSatelliteInterSignalBiasUncertaintyNanos();
     }
diff --git a/media/java/android/media/AudioMetadata.java b/media/java/android/media/AudioMetadata.java
index e67ba59..1a9517c 100644
--- a/media/java/android/media/AudioMetadata.java
+++ b/media/java/android/media/AudioMetadata.java
@@ -41,43 +41,47 @@
     private static final String TAG = "AudioMetadata";
 
     /**
-     * Key interface for the map.
+     * Key interface for the {@code AudioMetadata} map.
      *
-     * The presence of this {@code Key} interface on an object allows
-     * it to be used to reference metadata in the Audio Framework.
+     * <p>The presence of this {@code Key} interface on an object allows
+     * it to reference metadata in the Audio Framework.</p>
+     *
+     * <p>Vendors are allowed to implement this {@code Key} interface for their debugging or
+     * private application use. To avoid name conflicts, vendor key names should be qualified by
+     * the vendor company name followed by a dot; for example, "vendorCompany.someVolume".</p>
      *
      * @param <T> type of value associated with {@code Key}.
      */
-    // Conceivably metadata keys exposing multiple interfaces
-    // could be eligible to work in multiple framework domains.
+    /*
+     * Internal details:
+     * Conceivably metadata keys exposing multiple interfaces
+     * could be eligible to work in multiple framework domains.
+     */
     public interface Key<T> {
         /**
-         * Returns the internal name of the key.
+         * Returns the internal name of the key.  The name should be unique in the
+         * {@code AudioMetadata} namespace.  Vendors should prefix their keys with
+         * the company name followed by a dot.
          */
         @NonNull
         String getName();
 
         /**
-         * Returns the class type of the associated value.
+         * Returns the class type {@code T} of the associated value.  Valid class types for
+         * {@link android.os.Build.VERSION_CODES#R} are
+         * {@code Integer.class}, {@code Long.class}, {@code Float.class}, {@code Double.class},
+         * {@code String.class}.
          */
         @NonNull
         Class<T> getValueClass();
 
         // TODO: consider adding bool isValid(@NonNull T value)
-
-        /**
-         * Do not allow non-framework apps to create their own keys
-         * by implementing this interface; keep a method hidden.
-         *
-         * @hide
-         */
-        boolean isFromFramework();
     }
 
     /**
      * A read only {@code Map} interface of {@link Key} value pairs.
      *
-     * Using a {@link Key} interface, look up the corresponding value.
+     * <p>Using a {@link Key} interface, the map looks up the corresponding value.</p>
      */
     public interface ReadMap {
         /**
@@ -301,12 +305,6 @@
                 return mType;
             }
 
-            // hidden interface method to prevent user class implements the of Key interface.
-            @Override
-            public boolean isFromFramework() {
-                return true;
-            }
-
             /**
              * Return true if the name and the type of two objects are the same.
              */
diff --git a/media/java/android/media/tv/OWNERS b/media/java/android/media/tv/OWNERS
index 64c0bb5..a891154 100644
--- a/media/java/android/media/tv/OWNERS
+++ b/media/java/android/media/tv/OWNERS
@@ -3,3 +3,7 @@
 shubang@google.com
 quxiangfang@google.com
 
+# For android remote service
+per-file ITvRemoteServiceInput.aidl = file:/media/lib/tvremote/OWNERS
+per-file ITvRemoteProvider.aidl = file:/media/lib/tvremote/OWNERS
+
diff --git a/media/java/android/media/tv/tuner/Lnb.java b/media/java/android/media/tv/tuner/Lnb.java
index 525ee4d..9ce895e 100644
--- a/media/java/android/media/tv/tuner/Lnb.java
+++ b/media/java/android/media/tv/tuner/Lnb.java
@@ -19,7 +19,6 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.content.Context;
 import android.hardware.tv.tuner.V1_0.Constants;
@@ -173,10 +172,8 @@
      * @param voltage the power voltage constant the Lnb to use.
      * @return result status of the operation.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     @Result
     public int setVoltage(@Voltage int voltage) {
-        TunerUtils.checkTunerPermission(mContext);
         return nativeSetVoltage(voltage);
     }
 
@@ -186,10 +183,8 @@
      * @param tone the tone mode the Lnb to use.
      * @return result status of the operation.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     @Result
     public int setTone(@Tone int tone) {
-        TunerUtils.checkTunerPermission(mContext);
         return nativeSetTone(tone);
     }
 
@@ -199,10 +194,8 @@
      * @param position the position the Lnb to use.
      * @return result status of the operation.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     @Result
     public int setSatellitePosition(@Position int position) {
-        TunerUtils.checkTunerPermission(mContext);
         return nativeSetSatellitePosition(position);
     }
 
@@ -216,19 +209,15 @@
      *
      * @return result status of the operation.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     @Result
     public int sendDiseqcMessage(@NonNull byte[] message) {
-        TunerUtils.checkTunerPermission(mContext);
         return nativeSendDiseqcMessage(message);
     }
 
     /**
      * Releases the LNB instance.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     public void close() {
-        TunerUtils.checkTunerPermission(mContext);
         nativeClose();
     }
 }
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index d24d752..3eb77d5 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -43,6 +43,8 @@
 import android.media.tv.tuner.frontend.OnTuneEventListener;
 import android.media.tv.tuner.frontend.ScanCallback;
 import android.media.tv.tunerresourcemanager.ResourceClientProfile;
+import android.media.tv.tunerresourcemanager.TunerDemuxRequest;
+import android.media.tv.tunerresourcemanager.TunerDescramblerRequest;
 import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
 import android.media.tv.tunerresourcemanager.TunerLnbRequest;
 import android.media.tv.tunerresourcemanager.TunerResourceManager;
@@ -218,6 +220,8 @@
     @Nullable
     private Executor mOnResourceLostListenerExecutor;
 
+    private Integer mDemuxHandle;
+    private Integer mDescramblerHandle;
 
     private final TunerResourceManager.ResourcesReclaimListener mResourceListener =
             new TunerResourceManager.ResourcesReclaimListener() {
@@ -255,7 +259,6 @@
      * @param executor the executor on which the listener should be invoked.
      * @param listener the listener that will be run.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     public void setResourceLostListener(@NonNull @CallbackExecutor Executor executor,
             @NonNull OnResourceLostListener listener) {
         Objects.requireNonNull(executor, "OnResourceLostListener must not be null");
@@ -267,7 +270,6 @@
     /**
      * Removes the listener for resource lost.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     public void clearResourceLostListener() {
         mOnResourceLostListener = null;
         mOnResourceLostListenerExecutor = null;
@@ -278,9 +280,10 @@
      *
      * @param tuner the Tuner instance to share frontend resource with.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     public void shareFrontendFromTuner(@NonNull Tuner tuner) {
-        // TODO: implementation.
+        mTunerResourceManager.shareFrontend(mClientId, tuner.mClientId);
+        mFrontendHandle = tuner.mFrontendHandle;
+        nativeOpenFrontendByHandle(mFrontendHandle);
     }
 
     /**
@@ -294,9 +297,8 @@
      * @param priority the new priority.
      * @param niceValue the nice value.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     public void updateResourcePriority(int priority, int niceValue) {
-        // TODO: implementation.
+        mTunerResourceManager.updateClientPriority(mClientId, priority, niceValue);
     }
 
     private long mNativeContext; // used by native jMediaTuner
@@ -304,10 +306,16 @@
     /**
      * Releases the Tuner instance.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     @Override
     public void close() {
-        // TODO: implementation.
+        if (mFrontendHandle != null) {
+            mTunerResourceManager.releaseFrontend(mFrontendHandle);
+            mFrontendHandle = null;
+        }
+        if (mLnb != null) {
+            mTunerResourceManager.releaseLnb(mLnbHandle);
+            mLnb = null;
+        }
     }
 
     /**
@@ -429,10 +437,8 @@
      * @throws SecurityException if the caller does not have appropriate permissions.
      * @see #tune(FrontendSettings)
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     public void setOnTuneEventListener(@NonNull @CallbackExecutor Executor executor,
             @NonNull OnTuneEventListener eventListener) {
-        TunerUtils.checkTunerPermission(mContext);
         mOnTuneEventListener = eventListener;
         mOnTunerEventExecutor = executor;
     }
@@ -443,7 +449,6 @@
      * @throws SecurityException if the caller does not have appropriate permissions.
      * @see #setOnTuneEventListener(Executor, OnTuneEventListener)
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     public void clearOnTuneEventListener() {
         TunerUtils.checkTunerPermission(mContext);
         mOnTuneEventListener = null;
@@ -474,7 +479,6 @@
      * @throws SecurityException if the caller does not have appropriate permissions.
      * @see #setOnTuneEventListener(Executor, OnTuneEventListener)
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     @Result
     public int tune(@NonNull FrontendSettings settings) {
         mFrontendType = settings.getType();
@@ -491,7 +495,6 @@
      *
      * @return result status of the operation.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     @Result
     public int cancelTuning() {
         TunerUtils.checkTunerPermission(mContext);
@@ -509,7 +512,6 @@
      * @throws IllegalStateException if {@code scan} is called again before
      *                               {@link #cancelScanning()} is called.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     @Result
     public int scan(@NonNull FrontendSettings settings, @ScanType int scanType,
             @NonNull @CallbackExecutor Executor executor, @NonNull ScanCallback scanCallback) {
@@ -537,10 +539,8 @@
      *
      * @throws SecurityException if the caller does not have appropriate permissions.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     @Result
     public int cancelScanning() {
-        TunerUtils.checkTunerPermission(mContext);
         int retVal = nativeStopScan();
         mScanCallback = null;
         mScanCallbackExecutor = null;
@@ -548,11 +548,11 @@
     }
 
     private boolean requestFrontend() {
-        int[] feId = new int[1];
+        int[] feHandle = new int[1];
         TunerFrontendRequest request = new TunerFrontendRequest(mClientId, mFrontendType);
-        boolean granted = mTunerResourceManager.requestFrontend(request, feId);
+        boolean granted = mTunerResourceManager.requestFrontend(request, feHandle);
         if (granted) {
-            mFrontendHandle = feId[0];
+            mFrontendHandle = feHandle[0];
         }
         return granted;
     }
@@ -579,10 +579,8 @@
      *
      * @return result status of the operation.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     @Result
     public int setLnaEnabled(boolean enable) {
-        TunerUtils.checkTunerPermission(mContext);
         return nativeSetLna(enable);
     }
 
@@ -605,9 +603,8 @@
      * @param filter the filter instance for the hardware sync ID.
      * @return the id of hardware A/V sync.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     public int getAvSyncHwId(@NonNull Filter filter) {
-        TunerUtils.checkTunerPermission(mContext);
+        checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX);
         Integer id = nativeGetAvSyncHwId(filter);
         return id == null ? INVALID_AV_SYNC_ID : id;
     }
@@ -621,9 +618,8 @@
      * @param avSyncHwId the hardware id of A/V sync.
      * @return the current timestamp of hardware A/V sync.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     public long getAvSyncTime(int avSyncHwId) {
-        TunerUtils.checkTunerPermission(mContext);
+        checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX);
         Long time = nativeGetAvSyncTime(avSyncHwId);
         return time == null ? INVALID_TIMESTAMP : time;
     }
@@ -637,10 +633,9 @@
      * @param ciCamId specify CI-CAM Id to connect.
      * @return result status of the operation.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     @Result
     public int connectCiCam(int ciCamId) {
-        TunerUtils.checkTunerPermission(mContext);
+        checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX);
         return nativeConnectCiCam(ciCamId);
     }
 
@@ -651,10 +646,9 @@
      *
      * @return result status of the operation.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     @Result
     public int disconnectCiCam() {
-        TunerUtils.checkTunerPermission(mContext);
+        checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX);
         return nativeDisconnectCiCam();
     }
 
@@ -663,10 +657,9 @@
      *
      * @return The frontend information. {@code null} if the operation failed.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     @Nullable
     public FrontendInfo getFrontendInfo() {
-        TunerUtils.checkTunerPermission(mContext);
+        checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND);
         if (mFrontend == null) {
             throw new IllegalStateException("frontend is not initialized");
         }
@@ -679,14 +672,11 @@
     /**
      * Gets Demux capabilities.
      *
-     * @param context the context of the caller.
      * @return A {@link DemuxCapabilities} instance that represents the demux capabilities.
      *         {@code null} if the operation failed.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     @Nullable
-    public static DemuxCapabilities getDemuxCapabilities(@NonNull Context context) {
-        TunerUtils.checkTunerPermission(context);
+    public DemuxCapabilities getDemuxCapabilities() {
         return nativeGetDemuxCapabilities();
     }
 
@@ -792,12 +782,11 @@
      * @param cb the callback to receive notifications from filter.
      * @return the opened filter. {@code null} if the operation failed.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     @Nullable
     public Filter openFilter(@Type int mainType, @Subtype int subType,
             @BytesLong long bufferSize, @CallbackExecutor @Nullable Executor executor,
             @Nullable FilterCallback cb) {
-        TunerUtils.checkTunerPermission(mContext);
+        checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX);
         Filter filter = nativeOpenFilter(
                 mainType, TunerUtils.getFilterSubtype(mainType, subType), bufferSize);
         if (filter != null) {
@@ -821,13 +810,11 @@
      * @param cb the callback to receive notifications from LNB.
      * @return the opened LNB object. {@code null} if the operation failed.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     @Nullable
     public Lnb openLnb(@CallbackExecutor @NonNull Executor executor, @NonNull LnbCallback cb) {
         Objects.requireNonNull(executor, "executor must not be null");
         Objects.requireNonNull(cb, "LnbCallback must not be null");
         checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_LNB);
-        // TODO: update JNI code for LNB handle,
         return nativeOpenLnbByHandle(mLnbHandle);
     }
 
@@ -840,23 +827,22 @@
      * @param cb the callback to receive notifications from LNB.
      * @return the opened LNB object. {@code null} if the operation failed.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     @Nullable
     public Lnb openLnbByName(@NonNull String name, @CallbackExecutor @NonNull Executor executor,
             @NonNull LnbCallback cb) {
         Objects.requireNonNull(name, "LNB name must not be null");
         Objects.requireNonNull(executor, "executor must not be null");
         Objects.requireNonNull(cb, "LnbCallback must not be null");
-        TunerUtils.checkTunerPermission(mContext);
+        checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_LNB);
         return nativeOpenLnbByName(name);
     }
 
     private boolean requestLnb() {
-        int[] lnbId = new int[1];
+        int[] lnbHandle = new int[1];
         TunerLnbRequest request = new TunerLnbRequest(mClientId);
-        boolean granted = mTunerResourceManager.requestLnb(request, lnbId);
+        boolean granted = mTunerResourceManager.requestLnb(request, lnbHandle);
         if (granted) {
-            mLnbHandle = lnbId[0];
+            mLnbHandle = lnbHandle[0];
         }
         return granted;
     }
@@ -868,6 +854,7 @@
      */
     @Nullable
     public TimeFilter openTimeFilter() {
+        checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX);
         return nativeOpenTimeFilter();
     }
 
@@ -885,7 +872,7 @@
     @RequiresPermission(android.Manifest.permission.ACCESS_TV_DESCRAMBLER)
     @Nullable
     public Descrambler openDescrambler() {
-        TunerUtils.checkDescramblerPermission(mContext);
+        checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_DESCRAMBLER);
         return nativeOpenDescrambler();
     }
 
@@ -899,7 +886,6 @@
      * @param l the listener to receive notifications from DVR recorder.
      * @return the opened DVR recorder object. {@code null} if the operation failed.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     @Nullable
     public DvrRecorder openDvrRecorder(
             @BytesLong long bufferSize,
@@ -907,7 +893,7 @@
             @NonNull OnRecordStatusChangedListener l) {
         Objects.requireNonNull(executor, "executor must not be null");
         Objects.requireNonNull(l, "OnRecordStatusChangedListener must not be null");
-        TunerUtils.checkTunerPermission(mContext);
+        checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX);
         DvrRecorder dvr = nativeOpenDvrRecorder(bufferSize);
         return dvr;
     }
@@ -922,7 +908,6 @@
      * @param l the listener to receive notifications from DVR recorder.
      * @return the opened DVR playback object. {@code null} if the operation failed.
      */
-    @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER)
     @Nullable
     public DvrPlayback openDvrPlayback(
             @BytesLong long bufferSize,
@@ -930,13 +915,32 @@
             @NonNull OnPlaybackStatusChangedListener l) {
         Objects.requireNonNull(executor, "executor must not be null");
         Objects.requireNonNull(l, "OnPlaybackStatusChangedListener must not be null");
-        TunerUtils.checkTunerPermission(mContext);
+        checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX);
         DvrPlayback dvr = nativeOpenDvrPlayback(bufferSize);
         return dvr;
     }
 
+    private boolean requestDemux() {
+        int[] demuxHandle = new int[1];
+        TunerDemuxRequest request = new TunerDemuxRequest(mClientId);
+        boolean granted = mTunerResourceManager.requestDemux(request, demuxHandle);
+        if (granted) {
+            mDemuxHandle = demuxHandle[0];
+        }
+        return granted;
+    }
+
+    private boolean requestDescrambler() {
+        int[] descramblerHandle = new int[1];
+        TunerDescramblerRequest request = new TunerDescramblerRequest(mClientId);
+        boolean granted = mTunerResourceManager.requestDescrambler(request, descramblerHandle);
+        if (granted) {
+            mDescramblerHandle = descramblerHandle[0];
+        }
+        return granted;
+    }
+
     private boolean checkResource(int resourceType)  {
-        // TODO: demux and descrambler
         switch (resourceType) {
             case TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND: {
                 if (mFrontendHandle == null && !requestFrontend()) {
@@ -950,6 +954,18 @@
                 }
                 break;
             }
+            case TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX: {
+                if (mDemuxHandle == null && !requestDemux()) {
+                    return false;
+                }
+                break;
+            }
+            case TunerResourceManager.TUNER_RESOURCE_TYPE_DESCRAMBLER: {
+                if (mDescramblerHandle == null && !requestDescrambler()) {
+                    return false;
+                }
+                break;
+            }
         }
         return true;
     }
diff --git a/media/java/android/media/tv/tuner/TunerUtils.java b/media/java/android/media/tv/tuner/TunerUtils.java
index c3be12a..a41b397 100644
--- a/media/java/android/media/tv/tuner/TunerUtils.java
+++ b/media/java/android/media/tv/tuner/TunerUtils.java
@@ -60,6 +60,7 @@
      * @throws SecurityException if the caller doesn't have the permission.
      */
     public static void checkPermission(Context context, String permission) {
+        // TODO: remove checkPermission methods
         if (context.checkCallingOrSelfPermission(permission)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Caller must have " + permission + " permission.");
diff --git a/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
index 8a29442..e40b080 100644
--- a/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
@@ -125,8 +125,8 @@
      * Builder for {@link AlpFilterConfiguration}.
      */
     public static final class Builder {
-        private int mPacketType;
-        private int mLengthType;
+        private int mPacketType = PACKET_TYPE_IPV4;
+        private int mLengthType = LENGTH_TYPE_UNDEFINED;
         private Settings mSettings;
 
         private Builder() {
@@ -136,6 +136,7 @@
          * Sets packet type.
          *
          * <p>The meaning of each packet type value is shown in ATSC A/330:2019 table 5.2.
+         * <p>Default value is {@link #PACKET_TYPE_IPV4}.
          */
         @NonNull
         public Builder setPacketType(int packetType) {
@@ -144,6 +145,8 @@
         }
         /**
          * Sets length type.
+         *
+         * <p>Default value is {@link #LENGTH_TYPE_UNDEFINED}.
          */
         @NonNull
         public Builder setLengthType(@LengthType int lengthType) {
diff --git a/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
index 04f3410..de75a4f 100644
--- a/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
@@ -106,11 +106,11 @@
      * Builder for {@link IpFilterConfiguration}.
      */
     public static final class Builder {
-        private byte[] mSrcIpAddress;
-        private byte[] mDstIpAddress;
-        private int mSrcPort;
-        private int mDstPort;
-        private boolean mPassthrough;
+        private byte[] mSrcIpAddress = {0, 0, 0, 0};
+        private byte[] mDstIpAddress = {0, 0, 0, 0};;
+        private int mSrcPort = 0;
+        private int mDstPort = 0;
+        private boolean mPassthrough = false;
         private Settings mSettings;
 
         private Builder() {
@@ -118,6 +118,8 @@
 
         /**
          * Sets source IP address.
+         *
+         * <p>Default value is 0.0.0.0, an invalid IP address.
          */
         @NonNull
         public Builder setSrcIpAddress(@NonNull byte[] srcIpAddress) {
@@ -126,6 +128,8 @@
         }
         /**
          * Sets destination IP address.
+         *
+         * <p>Default value is 0.0.0.0, an invalid IP address.
          */
         @NonNull
         public Builder setDstIpAddress(@NonNull byte[] dstIpAddress) {
@@ -134,6 +138,8 @@
         }
         /**
          * Sets source port.
+         *
+         * <p>Default value is 0.
          */
         @NonNull
         public Builder setSrcPort(int srcPort) {
@@ -142,6 +148,8 @@
         }
         /**
          * Sets destination port.
+         *
+         * <p>Default value is 0.
          */
         @NonNull
         public Builder setDstPort(int dstPort) {
@@ -150,6 +158,8 @@
         }
         /**
          * Sets passthrough.
+         *
+         * <p>Default value is {@code false}.
          */
         @NonNull
         public Builder setPassthrough(boolean passthrough) {
diff --git a/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
index c0453b4..f19edc9 100644
--- a/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
@@ -21,6 +21,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.content.Context;
+import android.media.tv.tuner.Tuner;
 import android.media.tv.tuner.TunerUtils;
 
 /**
@@ -67,7 +68,7 @@
      * Builder for {@link IpFilterConfiguration}.
      */
     public static final class Builder {
-        private int mMmtpPid;
+        private int mMmtpPid = Tuner.INVALID_TS_PID;
         private Settings mSettings;
 
         private Builder() {
@@ -75,6 +76,8 @@
 
         /**
          * Sets MMTP Packet ID.
+         *
+         * <p>Default value is {@link Tuner#INVALID_TS_PID}.
          */
         @NonNull
         public Builder setMmtpPacketId(int mmtpPid) {
diff --git a/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
index c5191bf..eb1de52 100644
--- a/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
@@ -110,9 +110,9 @@
      * Builder for {@link TlvFilterConfiguration}.
      */
     public static final class Builder {
-        private int mPacketType;
-        private boolean mIsCompressedIpPacket;
-        private boolean mPassthrough;
+        private int mPacketType = PACKET_TYPE_NULL;
+        private boolean mIsCompressedIpPacket = false;
+        private boolean mPassthrough = false;
         private Settings mSettings;
 
         private Builder() {
@@ -122,6 +122,7 @@
          * Sets packet type.
          *
          * <p>The description of each packet type value is shown in ITU-R BT.1869 table 2.
+         * <p>Default value is {@link #PACKET_TYPE_NULL}.
          */
         @NonNull
         public Builder setPacketType(int packetType) {
@@ -130,6 +131,8 @@
         }
         /**
          * Sets whether the data is compressed IP packet.
+         *
+         * <p>Default value is {@code false}.
          */
         @NonNull
         public Builder setCompressedIpPacket(boolean isCompressedIpPacket) {
@@ -138,6 +141,8 @@
         }
         /**
          * Sets whether it's passthrough.
+         *
+         * <p>Default value is {@code false}.
          */
         @NonNull
         public Builder setPassthrough(boolean passthrough) {
diff --git a/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java
index a7140eb..0579269 100644
--- a/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java
@@ -65,7 +65,7 @@
      * Builder for {@link TsFilterConfiguration}.
      */
     public static final class Builder {
-        private int mTpid;
+        private int mTpid = 0;
         private Settings mSettings;
 
         private Builder() {
@@ -74,6 +74,8 @@
         /**
          * Sets Tag Protocol ID.
          *
+         * <p>Default value is 0.
+         *
          * @param tpid the Tag Protocol ID.
          */
         @NonNull
diff --git a/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java
index 382cc85..e68585d 100644
--- a/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java
@@ -215,14 +215,16 @@
      * Builder for {@link AnalogFrontendSettings}.
      */
     public static class Builder {
-        private int mFrequency;
-        private int mSignalType;
-        private int mSifStandard;
+        private int mFrequency = 0;
+        private int mSignalType = SIGNAL_TYPE_UNDEFINED;
+        private int mSifStandard = SIF_UNDEFINED;
 
         private Builder() {}
 
         /**
          * Sets frequency in Hz.
+         *
+         * <p>Default value is 0.
          */
         @NonNull
         @IntRange(from = 1)
@@ -233,6 +235,8 @@
 
         /**
          * Sets analog signal type.
+         *
+         * <p>Default value is {@link #SIGNAL_TYPE_UNDEFINED}.
          */
         @NonNull
         public Builder setSignalType(@SignalType int signalType) {
@@ -242,6 +246,8 @@
 
         /**
          * Sets Standard Interchange Format (SIF).
+         *
+         * <p>Default value is {@link #SIF_UNDEFINED}.
          */
         @NonNull
         public Builder setSifStandard(@SifStandard int sifStandard) {
diff --git a/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java
index 1394716..bf4f3b2 100644
--- a/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java
@@ -327,16 +327,18 @@
      * Builder for {@link Atsc3FrontendSettings}.
      */
     public static class Builder {
-        private int mFrequency;
-        private int mBandwidth;
-        private int mDemodOutputFormat;
-        private Atsc3PlpSettings[] mPlpSettings;
+        private int mFrequency = 0;
+        private int mBandwidth = BANDWIDTH_UNDEFINED;
+        private int mDemodOutputFormat = DEMOD_OUTPUT_FORMAT_UNDEFINED;
+        private Atsc3PlpSettings[] mPlpSettings = {};
 
         private Builder() {
         }
 
         /**
          * Sets frequency in Hz.
+         *
+         * <p>Default value is 0.
          */
         @NonNull
         @IntRange(from = 1)
@@ -347,6 +349,8 @@
 
         /**
          * Sets bandwidth.
+         *
+         * <p>Default value is {@link #BANDWIDTH_UNDEFINED}.
          */
         @NonNull
         public Builder setBandwidth(int bandwidth) {
@@ -355,6 +359,8 @@
         }
         /**
          * Sets Demod Output Format.
+         *
+         * <p>Default value is {@link #DEMOD_OUTPUT_FORMAT_UNDEFINED}.
          */
         @NonNull
         public Builder setDemodOutputFormat(@DemodOutputFormat int demodOutputFormat) {
@@ -363,6 +369,8 @@
         }
         /**
          * Sets PLP Settings.
+         *
+         * <p>Default value an empty array.
          */
         @NonNull
         public Builder setPlpSettings(@NonNull Atsc3PlpSettings[] plpSettings) {
diff --git a/media/java/android/media/tv/tuner/frontend/AtscFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/AtscFrontendSettings.java
index 53352f0..0674f6e 100644
--- a/media/java/android/media/tv/tuner/frontend/AtscFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/AtscFrontendSettings.java
@@ -93,14 +93,16 @@
      * Builder for {@link AtscFrontendSettings}.
      */
     public static class Builder {
-        private int mFrequency;
-        private int mModulation;
+        private int mFrequency = 0;
+        private int mModulation = MODULATION_UNDEFINED;
 
         private Builder() {
         }
 
         /**
          * Sets frequency in Hz.
+         *
+         * <p>Default value is 0.
          */
         @NonNull
         @IntRange(from = 1)
@@ -111,6 +113,8 @@
 
         /**
          * Sets Modulation.
+         *
+         * <p>Default value is {@link #MODULATION_UNDEFINED}.
          */
         @NonNull
         public Builder setModulation(@Modulation int modulation) {
diff --git a/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
index 6d58570..121de5d 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
@@ -220,19 +220,21 @@
      * Builder for {@link DvbcFrontendSettings}.
      */
     public static class Builder {
-        private int mFrequency;
-        private int mModulation;
-        private long mInnerFec;
-        private int mSymbolRate;
-        private int mOuterFec;
-        private int mAnnex;
-        private int mSpectralInversion;
+        private int mFrequency = 0;
+        private int mModulation = MODULATION_UNDEFINED;
+        private long mInnerFec = FEC_UNDEFINED;
+        private int mSymbolRate = 0;
+        private int mOuterFec = OUTER_FEC_UNDEFINED;
+        private int mAnnex = ANNEX_UNDEFINED;
+        private int mSpectralInversion = SPECTRAL_INVERSION_UNDEFINED;
 
         private Builder() {
         }
 
         /**
          * Sets frequency in Hz.
+         *
+         * <p>Default value is 0.
          */
         @NonNull
         @IntRange(from = 1)
@@ -243,6 +245,8 @@
 
         /**
          * Sets Modulation.
+         *
+         * <p>Default value is {@link #MODULATION_UNDEFINED}.
          */
         @NonNull
         public Builder setModulation(@Modulation int modulation) {
@@ -251,6 +255,8 @@
         }
         /**
          * Sets Inner Forward Error Correction.
+         *
+         * <p>Default value is {@link #FEC_UNDEFINED}.
          */
         @NonNull
         public Builder setInnerFec(@InnerFec long fec) {
@@ -259,6 +265,8 @@
         }
         /**
          * Sets Symbol Rate in symbols per second.
+         *
+         * <p>Default value is 0.
          */
         @NonNull
         public Builder setSymbolRate(int symbolRate) {
@@ -267,6 +275,8 @@
         }
         /**
          * Sets Outer Forward Error Correction.
+         *
+         * <p>Default value is {@link #OUTER_FEC_UNDEFINED}.
          */
         @NonNull
         public Builder setOuterFec(@OuterFec int outerFec) {
@@ -275,6 +285,8 @@
         }
         /**
          * Sets Annex.
+         *
+         * <p>Default value is {@link #ANNEX_UNDEFINED}.
          */
         @NonNull
         public Builder setAnnex(@Annex int annex) {
@@ -283,6 +295,8 @@
         }
         /**
          * Sets Spectral Inversion.
+         *
+         * <p>Default value is {@link #SPECTRAL_INVERSION_UNDEFINED}.
          */
         @NonNull
         public Builder setSpectralInversion(@SpectralInversion int spectralInversion) {
diff --git a/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
index 9c45dd1..afc79ab 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
@@ -24,6 +24,7 @@
 import android.annotation.SystemApi;
 import android.content.Context;
 import android.hardware.tv.tuner.V1_0.Constants;
+import android.media.tv.tuner.Tuner;
 import android.media.tv.tuner.TunerUtils;
 
 import java.lang.annotation.Retention;
@@ -305,21 +306,23 @@
      * Builder for {@link DvbsFrontendSettings}.
      */
     public static class Builder {
-        private int mFrequency;
-        private int mModulation;
-        private DvbsCodeRate mCodeRate;
-        private int mSymbolRate;
-        private int mRolloff;
-        private int mPilot;
-        private int mInputStreamId;
-        private int mStandard;
-        private int mVcmMode;
+        private int mFrequency = 0;
+        private int mModulation = MODULATION_UNDEFINED;
+        private DvbsCodeRate mCodeRate = null;
+        private int mSymbolRate = 0;
+        private int mRolloff = ROLLOFF_UNDEFINED;
+        private int mPilot = PILOT_UNDEFINED;
+        private int mInputStreamId = Tuner.INVALID_STREAM_ID;
+        private int mStandard = STANDARD_AUTO;
+        private int mVcmMode = VCM_MODE_UNDEFINED;
 
         private Builder() {
         }
 
         /**
          * Sets frequency in Hz.
+         *
+         * <p>Default value is 0.
          */
         @NonNull
         @IntRange(from = 1)
@@ -330,6 +333,8 @@
 
         /**
          * Sets Modulation.
+         *
+         * <p>Default value is {@link #MODULATION_UNDEFINED}.
          */
         @NonNull
         public Builder setModulation(@Modulation int modulation) {
@@ -338,6 +343,8 @@
         }
         /**
          * Sets Code rate.
+         *
+         * <p>Default value is {@code null}.
          */
         @NonNull
         public Builder setCodeRate(@Nullable DvbsCodeRate codeRate) {
@@ -346,6 +353,8 @@
         }
         /**
          * Sets Symbol Rate.
+         *
+         * <p>Default value is 0.
          */
         @NonNull
         public Builder setSymbolRate(int symbolRate) {
@@ -354,6 +363,8 @@
         }
         /**
          * Sets Rolloff.
+         *
+         * <p>Default value is {@link #ROLLOFF_UNDEFINED}.
          */
         @NonNull
         public Builder setRolloff(@Rolloff int rolloff) {
@@ -362,6 +373,8 @@
         }
         /**
          * Sets Pilot mode.
+         *
+         * <p>Default value is {@link #PILOT_UNDEFINED}.
          */
         @NonNull
         public Builder setPilot(@Pilot int pilot) {
@@ -370,6 +383,8 @@
         }
         /**
          * Sets Input Stream ID.
+         *
+         * <p>Default value is {@link Tuner#INVALID_STREAM_ID}.
          */
         @NonNull
         public Builder setInputStreamId(int inputStreamId) {
@@ -378,6 +393,8 @@
         }
         /**
          * Sets Standard.
+         *
+         * <p>Default value is {@link #STANDARD_AUTO}.
          */
         @NonNull
         public Builder setStandard(@Standard int standard) {
@@ -386,6 +403,8 @@
         }
         /**
          * Sets VCM mode.
+         *
+         * <p>Default value is {@link #VCM_MODE_UNDEFINED}.
          */
         @NonNull
         public Builder setVcmMode(@VcmMode int vcm) {
diff --git a/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
index 4accabb..67a9fdc 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
@@ -508,26 +508,28 @@
      * Builder for {@link DvbtFrontendSettings}.
      */
     public static class Builder {
-        private int mFrequency;
-        private int mTransmissionMode;
-        private int mBandwidth;
-        private int mConstellation;
-        private int mHierarchy;
-        private int mHpCodeRate;
-        private int mLpCodeRate;
-        private int mGuardInterval;
-        private boolean mIsHighPriority;
-        private int mStandard;
-        private boolean mIsMiso;
-        private int mPlpMode;
-        private int mPlpId;
-        private int mPlpGroupId;
+        private int mFrequency = 0;
+        private int mTransmissionMode = TRANSMISSION_MODE_UNDEFINED;
+        private int mBandwidth = BANDWIDTH_UNDEFINED;
+        private int mConstellation = CONSTELLATION_UNDEFINED;
+        private int mHierarchy = HIERARCHY_UNDEFINED;
+        private int mHpCodeRate = CODERATE_UNDEFINED;
+        private int mLpCodeRate = CODERATE_UNDEFINED;
+        private int mGuardInterval = GUARD_INTERVAL_UNDEFINED;
+        private boolean mIsHighPriority = false;
+        private int mStandard = STANDARD_AUTO;
+        private boolean mIsMiso = false;
+        private int mPlpMode = PLP_MODE_UNDEFINED;
+        private int mPlpId = 0;
+        private int mPlpGroupId = 0;
 
         private Builder() {
         }
 
         /**
          * Sets frequency in Hz.
+         *
+         * <p>Default value is 0.
          */
         @NonNull
         @IntRange(from = 1)
@@ -538,6 +540,8 @@
 
         /**
          * Sets Transmission Mode.
+         *
+         * <p>Default value is {@link #TRANSMISSION_MODE_UNDEFINED}.
          */
         @NonNull
         public Builder setTransmissionMode(@TransmissionMode int transmissionMode) {
@@ -546,6 +550,8 @@
         }
         /**
          * Sets Bandwidth.
+         *
+         * <p>Default value is {@link #BANDWIDTH_UNDEFINED}.
          */
         @NonNull
         public Builder setBandwidth(@Bandwidth int bandwidth) {
@@ -554,6 +560,8 @@
         }
         /**
          * Sets Constellation.
+         *
+         * <p>Default value is {@link #CONSTELLATION_UNDEFINED}.
          */
         @NonNull
         public Builder setConstellation(@Constellation int constellation) {
@@ -562,6 +570,8 @@
         }
         /**
          * Sets Hierarchy.
+         *
+         * <p>Default value is {@link #HIERARCHY_UNDEFINED}.
          */
         @NonNull
         public Builder setHierarchy(@Hierarchy int hierarchy) {
@@ -570,6 +580,8 @@
         }
         /**
          * Sets Code Rate for High Priority level.
+         *
+         * <p>Default value is {@link #CODERATE_UNDEFINED}.
          */
         @NonNull
         public Builder setHighPriorityCodeRate(@CodeRate int hpCodeRate) {
@@ -578,6 +590,8 @@
         }
         /**
          * Sets Code Rate for Low Priority level.
+         *
+         * <p>Default value is {@link #CODERATE_UNDEFINED}.
          */
         @NonNull
         public Builder setLowPriorityCodeRate(@CodeRate int lpCodeRate) {
@@ -586,6 +600,8 @@
         }
         /**
          * Sets Guard Interval.
+         *
+         * <p>Default value is {@link #GUARD_INTERVAL_UNDEFINED}.
          */
         @NonNull
         public Builder setGuardInterval(@GuardInterval int guardInterval) {
@@ -594,6 +610,8 @@
         }
         /**
          * Sets whether it's high priority.
+         *
+         * <p>Default value is {@code false}.
          */
         @NonNull
         public Builder setHighPriority(boolean isHighPriority) {
@@ -602,6 +620,8 @@
         }
         /**
          * Sets Standard.
+         *
+         * <p>Default value is {@link #STANDARD_AUTO}.
          */
         @NonNull
         public Builder setStandard(@Standard int standard) {
@@ -610,6 +630,8 @@
         }
         /**
          * Sets whether it's MISO.
+         *
+         * <p>Default value is {@code false}.
          */
         @NonNull
         public Builder setMiso(boolean isMiso) {
@@ -618,6 +640,8 @@
         }
         /**
          * Sets Physical Layer Pipe (PLP) Mode.
+         *
+         * <p>Default value is {@link #PLP_MODE_UNDEFINED}.
          */
         @NonNull
         public Builder setPlpMode(@PlpMode int plpMode) {
@@ -626,6 +650,8 @@
         }
         /**
          * Sets Physical Layer Pipe (PLP) ID.
+         *
+         * <p>Default value is 0.
          */
         @NonNull
         public Builder setPlpId(int plpId) {
@@ -634,6 +660,8 @@
         }
         /**
          * Sets Physical Layer Pipe (PLP) group ID.
+         *
+         * <p>Default value is 0.
          */
         @NonNull
         public Builder setPlpGroupId(int plpGroupId) {
diff --git a/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java
index f385379..e0077ca 100644
--- a/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java
@@ -23,6 +23,7 @@
 import android.annotation.SystemApi;
 import android.content.Context;
 import android.hardware.tv.tuner.V1_0.Constants;
+import android.media.tv.tuner.Tuner;
 import android.media.tv.tuner.TunerUtils;
 
 import java.lang.annotation.Retention;
@@ -226,19 +227,21 @@
      * Builder for {@link Isdbs3FrontendSettings}.
      */
     public static class Builder {
-        private int mFrequency;
-        private int mStreamId;
-        private int mStreamIdType;
-        private int mModulation;
-        private int mCodeRate;
-        private int mSymbolRate;
-        private int mRolloff;
+        private int mFrequency = 0;
+        private int mStreamId = Tuner.INVALID_STREAM_ID;
+        private int mStreamIdType = IsdbsFrontendSettings.STREAM_ID_TYPE_ID;
+        private int mModulation = MODULATION_UNDEFINED;
+        private int mCodeRate = CODERATE_UNDEFINED;
+        private int mSymbolRate = 0;
+        private int mRolloff = ROLLOFF_UNDEFINED;
 
         private Builder() {
         }
 
         /**
          * Sets frequency in Hz.
+         *
+         * <p>Default value is 0.
          */
         @NonNull
         @IntRange(from = 1)
@@ -249,6 +252,8 @@
 
         /**
          * Sets Stream ID.
+         *
+         * <p>Default value is {@link Tuner#INVALID_STREAM_ID}.
          */
         @NonNull
         public Builder setStreamId(int streamId) {
@@ -257,6 +262,8 @@
         }
         /**
          * Sets StreamIdType.
+         *
+         * <p>Default value is {@link IsdbsFrontendSettings#STREAM_ID_TYPE_ID}.
          */
         @NonNull
         public Builder setStreamIdType(@IsdbsFrontendSettings.StreamIdType int streamIdType) {
@@ -265,6 +272,8 @@
         }
         /**
          * Sets Modulation.
+         *
+         * <p>Default value is {@link #MODULATION_UNDEFINED}.
          */
         @NonNull
         public Builder setModulation(@Modulation int modulation) {
@@ -273,6 +282,8 @@
         }
         /**
          * Sets Code rate.
+         *
+         * <p>Default value is {@link #CODERATE_UNDEFINED}.
          */
         @NonNull
         public Builder setCodeRate(@CodeRate int codeRate) {
@@ -281,6 +292,8 @@
         }
         /**
          * Sets Symbol Rate in symbols per second.
+         *
+         * <p>Default value is 0.
          */
         @NonNull
         public Builder setSymbolRate(int symbolRate) {
@@ -289,6 +302,8 @@
         }
         /**
          * Sets Roll off type.
+         *
+         * <p>Default value is {@link #ROLLOFF_UNDEFINED}.
          */
         @NonNull
         public Builder setRolloff(@Rolloff int rolloff) {
diff --git a/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java
index 4667b9b..8dc591b 100644
--- a/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java
@@ -23,6 +23,7 @@
 import android.annotation.SystemApi;
 import android.content.Context;
 import android.hardware.tv.tuner.V1_0.Constants;
+import android.media.tv.tuner.Tuner;
 import android.media.tv.tuner.TunerUtils;
 
 import java.lang.annotation.Retention;
@@ -210,19 +211,21 @@
      * Builder for {@link IsdbsFrontendSettings}.
      */
     public static class Builder {
-        private int mFrequency;
-        private int mStreamId;
-        private int mStreamIdType;
-        private int mModulation;
-        private int mCodeRate;
-        private int mSymbolRate;
-        private int mRolloff;
+        private int mFrequency = 0;
+        private int mStreamId = Tuner.INVALID_STREAM_ID;
+        private int mStreamIdType = STREAM_ID_TYPE_ID;
+        private int mModulation = MODULATION_UNDEFINED;
+        private int mCodeRate = CODERATE_UNDEFINED;
+        private int mSymbolRate = 0;
+        private int mRolloff = ROLLOFF_UNDEFINED;
 
         private Builder() {
         }
 
         /**
          * Sets frequency in Hz.
+         *
+         * <p>Default value is 0.
          */
         @NonNull
         @IntRange(from = 1)
@@ -233,6 +236,8 @@
 
         /**
          * Sets Stream ID.
+         *
+         * <p>Default value is {@link Tuner#INVALID_STREAM_ID}.
          */
         @NonNull
         public Builder setStreamId(int streamId) {
@@ -241,6 +246,8 @@
         }
         /**
          * Sets StreamIdType.
+         *
+         * <p>Default value is {@link #STREAM_ID_TYPE_ID}.
          */
         @NonNull
         public Builder setStreamIdType(@StreamIdType int streamIdType) {
@@ -249,6 +256,8 @@
         }
         /**
          * Sets Modulation.
+         *
+         * <p>Default value is {@link #MODULATION_UNDEFINED}.
          */
         @NonNull
         public Builder setModulation(@Modulation int modulation) {
@@ -257,6 +266,8 @@
         }
         /**
          * Sets Code rate.
+         *
+         * <p>Default value is {@link #CODERATE_UNDEFINED}.
          */
         @NonNull
         public Builder setCodeRate(@CodeRate int codeRate) {
@@ -265,6 +276,8 @@
         }
         /**
          * Sets Symbol Rate in symbols per second.
+         *
+         * <p>Default value is 0.
          */
         @NonNull
         public Builder setSymbolRate(int symbolRate) {
@@ -273,6 +286,8 @@
         }
         /**
          * Sets Roll off type.
+         *
+         * <p>Default value is {@link #ROLLOFF_UNDEFINED}.
          */
         @NonNull
         public Builder setRolloff(@Rolloff int rolloff) {
diff --git a/media/java/android/media/tv/tuner/frontend/IsdbtFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/IsdbtFrontendSettings.java
index b607623..915380e 100644
--- a/media/java/android/media/tv/tuner/frontend/IsdbtFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/IsdbtFrontendSettings.java
@@ -204,19 +204,21 @@
      * Builder for {@link IsdbtFrontendSettings}.
      */
     public static class Builder {
-        private int mFrequency;
-        private int mModulation;
-        private int mBandwidth;
-        private int mMode;
-        private int mCodeRate;
-        private int mGuardInterval;
-        private int mServiceAreaId;
+        private int mFrequency = 0;
+        private int mModulation = MODULATION_UNDEFINED;
+        private int mBandwidth = BANDWIDTH_UNDEFINED;
+        private int mMode = MODE_UNDEFINED;
+        private int mCodeRate = DvbtFrontendSettings.CODERATE_UNDEFINED;
+        private int mGuardInterval = DvbtFrontendSettings.GUARD_INTERVAL_UNDEFINED;
+        private int mServiceAreaId = 0;
 
         private Builder() {
         }
 
         /**
          * Sets frequency in Hz.
+         *
+         * <p>Default value is 0.
          */
         @NonNull
         @IntRange(from = 1)
@@ -227,6 +229,8 @@
 
         /**
          * Sets Modulation.
+         *
+         * <p>Default value is {@link #MODULATION_UNDEFINED}.
          */
         @NonNull
         public Builder setModulation(@Modulation int modulation) {
@@ -235,6 +239,8 @@
         }
         /**
          * Sets Bandwidth.
+         *
+         * <p>Default value is {@link #BANDWIDTH_UNDEFINED}.
          */
         @NonNull
         public Builder setBandwidth(@Bandwidth int bandwidth) {
@@ -243,6 +249,8 @@
         }
         /**
          * Sets ISDBT mode.
+         *
+         * <p>Default value is {@link #MODE_UNDEFINED}.
          */
         @NonNull
         public Builder setMode(@Mode int mode) {
@@ -251,14 +259,18 @@
         }
         /**
          * Sets Code rate.
+         *
+         * <p>Default value is {@link DvbtFrontendSettings#CODERATE_UNDEFINED}.
          */
         @NonNull
-        public Builder setCodeRate(@CodeRate int codeRate) {
+        public Builder setCodeRate(@DvbtFrontendSettings.CodeRate int codeRate) {
             mCodeRate = codeRate;
             return this;
         }
         /**
          * Sets Guard Interval.
+         *
+         * <p>Default value is {@link DvbtFrontendSettings#GUARD_INTERVAL_UNDEFINED}.
          */
         @NonNull
         public Builder setGuardInterval(@DvbtFrontendSettings.GuardInterval int guardInterval) {
@@ -267,6 +279,8 @@
         }
         /**
          * Sets Service Area ID.
+         *
+         * <p>Default value is 0.
          */
         @NonNull
         public Builder setServiceAreaId(int serviceAreaId) {
diff --git a/mms/java/android/telephony/MmsManager.java b/mms/java/android/telephony/MmsManager.java
index f07cd5e..6e47741 100644
--- a/mms/java/android/telephony/MmsManager.java
+++ b/mms/java/android/telephony/MmsManager.java
@@ -32,6 +32,7 @@
 /**
  * Manages MMS operations such as sending multimedia messages.
  * Get this object by calling Context#getSystemService(Context#MMS_SERVICE).
+ * @hide
  */
 @SystemService(Context.MMS_SERVICE)
 public class MmsManager {
diff --git a/packages/CarSystemUI/proguard.flags b/packages/CarSystemUI/proguard.flags
index a81c7e0..66cbf26 100644
--- a/packages/CarSystemUI/proguard.flags
+++ b/packages/CarSystemUI/proguard.flags
@@ -1,3 +1,4 @@
 -keep class com.android.systemui.CarSystemUIFactory
+-keep class com.android.car.notification.headsup.animationhelper.**
 
 -include ../SystemUI/proguard.flags
diff --git a/packages/CarSystemUI/res/drawable/headsup_scrim_bottom.xml b/packages/CarSystemUI/res/drawable/headsup_scrim_bottom.xml
new file mode 100644
index 0000000..1724ef0
--- /dev/null
+++ b/packages/CarSystemUI/res/drawable/headsup_scrim_bottom.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <gradient
+        android:startColor="@android:color/black"
+        android:endColor="@android:color/transparent"
+        android:angle="90" />
+</shape>
diff --git a/packages/CarSystemUI/res/layout/headsup_container_bottom.xml b/packages/CarSystemUI/res/layout/headsup_container_bottom.xml
new file mode 100644
index 0000000..caf1677
--- /dev/null
+++ b/packages/CarSystemUI/res/layout/headsup_container_bottom.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 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.
+  -->
+
+<androidx.constraintlayout.widget.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/notification_headsup"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <androidx.constraintlayout.widget.Guideline
+        android:id="@+id/gradient_edge"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        app:layout_constraintGuide_begin="@dimen/headsup_scrim_height"/>
+
+    <View
+        android:id="@+id/scrim"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:background="@drawable/headsup_scrim_bottom"
+        app:layout_constraintBottom_toBottomOf="@+id/gradient_edge"
+        app:layout_constraintTop_toTopOf="parent"/>
+
+    <FrameLayout
+        android:id="@+id/headsup_content"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/headsup_notification_top_margin"
+        app:layout_constraintEnd_toStartOf="parent"
+        app:layout_constraintStart_toEndOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+    />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml
index aaa65de..2077e77 100644
--- a/packages/CarSystemUI/res/values/config.xml
+++ b/packages/CarSystemUI/res/values/config.xml
@@ -34,6 +34,13 @@
 
     <!-- Whether heads-up notifications should be shown when shade is open. -->
     <bool name="config_enableHeadsUpNotificationWhenNotificationShadeOpen">true</bool>
+    <!-- Whether heads-up notifications should be shown on the bottom. If false, heads-up
+         notifications will be shown pushed to the top of their parent container. If true, they will
+         be shown pushed to the bottom of their parent container. If true, then should override
+         config_headsUpNotificationAnimationHelper to use a different AnimationHelper, such as
+         com.android.car.notification.headsup.animationhelper.
+         CarHeadsUpNotificationBottomAnimationHelper. -->
+    <bool name="config_showHeadsUpNotificationOnBottom">false</bool>
 
     <bool name="config_hideNavWhenKeyguardBouncerShown">true</bool>
     <bool name="config_enablePersistentDockedActivity">false</bool>
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java
index 689d2d5..53e5d9f 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java
@@ -60,6 +60,8 @@
         mCarDeviceProvisionedController = deviceProvisionedController;
         mCarStatusBarLazy = carStatusBarLazy;
 
+        boolean showOnBottom = resources.getBoolean(R.bool.config_showHeadsUpNotificationOnBottom);
+
         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
                 WindowManager.LayoutParams.WRAP_CONTENT,
@@ -68,11 +70,13 @@
                         | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
                 PixelFormat.TRANSLUCENT);
 
-        lp.gravity = Gravity.TOP;
+        lp.gravity = showOnBottom ? Gravity.BOTTOM : Gravity.TOP;
         lp.setTitle("HeadsUpNotification");
 
-        mWindow = (ViewGroup) LayoutInflater.from(context)
-                .inflate(R.layout.headsup_container, null, false);
+        int layoutId = showOnBottom
+                ? R.layout.headsup_container_bottom
+                : R.layout.headsup_container;
+        mWindow = (ViewGroup) LayoutInflater.from(context).inflate(layoutId, null, false);
         windowManager.addView(mWindow, lp);
         mWindow.setVisibility(View.INVISIBLE);
         mHeadsUpContentFrame = mWindow.findViewById(R.id.headsup_content);
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java b/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java
index e351615..dad82ee 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java
@@ -63,7 +63,7 @@
     }
 
     public UidDetailProvider(Context context) {
-        mContext = context.getApplicationContext();
+        mContext = context;
         mUidDetailCache = new SparseArray<UidDetail>();
     }
 
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 610165a..24cc3c9 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -199,7 +199,6 @@
                     Settings.Global.CERT_PIN_UPDATE_CONTENT_URL,
                     Settings.Global.CERT_PIN_UPDATE_METADATA_URL,
                     Settings.Global.COMPATIBILITY_MODE,
-                    Settings.Global.COMMON_CRITERIA_MODE,
                     Settings.Global.CONNECTIVITY_CHANGE_DELAY,
                     Settings.Global.CONNECTIVITY_METRICS_BUFFER_SIZE,
                     Settings.Global.CONNECTIVITY_SAMPLING_INTERVAL_IN_SECONDS,
@@ -356,6 +355,7 @@
                     Settings.Global.NETSTATS_POLL_INTERVAL,
                     Settings.Global.NETSTATS_SAMPLE_ENABLED,
                     Settings.Global.NETSTATS_AUGMENT_ENABLED,
+                    Settings.Global.NETSTATS_COMBINE_SUBTYPE_ENABLED,
                     Settings.Global.NETSTATS_TIME_CACHE_MAX_AGE,
                     Settings.Global.NETSTATS_UID_BUCKET_DURATION,
                     Settings.Global.NETSTATS_UID_DELETE_AGE,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 8f859b2..8105114 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -278,6 +278,9 @@
     <!-- Permission needed to modify settings overrideable by restore in CTS tests -->
     <uses-permission android:name="android.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE" />
 
+    <!-- Permission required for testing system audio effect APIs. -->
+    <uses-permission android:name="android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"/>
+
     <application android:label="@string/app_label"
                 android:theme="@android:style/Theme.DeviceDefault.DayNight"
                 android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/res/layout/controls_no_favorites.xml b/packages/SystemUI/res/layout/controls_no_favorites.xml
index 8074efd..74fc167 100644
--- a/packages/SystemUI/res/layout/controls_no_favorites.xml
+++ b/packages/SystemUI/res/layout/controls_no_favorites.xml
@@ -40,14 +40,20 @@
         android:paddingBottom="8dp" />
 
     <TextView
+        style="@style/TextAppearance.ControlSetup.Title"
         android:id="@+id/controls_title"
         android:text="@string/quick_controls_title"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:singleLine="true"
-        android:layout_gravity="center"
-        android:textSize="25sp"
-        android:textColor="@*android:color/foreground_material_dark"
-        android:fontFamily="@*android:string/config_headlineFontFamily" />
+        android:layout_gravity="center" />
+
+    <TextView
+        style="@style/TextAppearance.ControlSetup.Subtitle"
+        android:id="@+id/controls_subtitle"
+        android:visibility="gone"
+        android:layout_marginTop="12dp"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center" />
   </LinearLayout>
 </merge>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
index 44c409e..b5822c8 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
@@ -35,7 +35,34 @@
         android:forceHasOverlappingRendering="false"
         android:clipChildren="false"
         >
-        <include layout="@layout/status_bar_notification_section_header_contents"/>
+        <FrameLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="start|center_vertical"
+            android:layout_weight="1">
+
+            <TextView
+                style="@style/TextAppearance.NotificationSectionHeaderButton"
+                android:id="@+id/header_label"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:forceHasOverlappingRendering="false"
+                android:text="@string/notification_section_header_gentle"
+            />
+
+        </FrameLayout>
+        <ImageView
+            android:id="@+id/btn_clear_all"
+            android:layout_width="48dp"
+            android:layout_height="48dp"
+            android:src="@drawable/status_bar_notification_section_header_clear_btn"
+            android:contentDescription="@string/accessibility_notification_section_header_gentle_clear_all"
+            android:scaleType="center"
+            android:tint="?attr/wallpaperTextColor"
+            android:tintMode="src_in"
+            android:visibility="gone"
+            android:forceHasOverlappingRendering="false"
+        />
     </LinearLayout>
 
 </com.android.systemui.statusbar.notification.stack.SectionHeaderView>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_section_header_contents.xml b/packages/SystemUI/res/layout/status_bar_notification_section_header_contents.xml
deleted file mode 100644
index 3b9c44d..0000000
--- a/packages/SystemUI/res/layout/status_bar_notification_section_header_contents.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<!--
-  ~ 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
-  -->
-
-<!-- Used by both status_bar_notification_header and SectionHeaderView -->
-<merge xmlns:android="http://schemas.android.com/apk/res/android" >
-    <FrameLayout
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:gravity="start|center_vertical"
-        android:layout_weight="1">
-
-        <TextView
-            style="@style/TextAppearance.NotificationSectionHeaderButton"
-            android:id="@+id/header_label"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:forceHasOverlappingRendering="false"
-            android:text="@string/notification_section_header_gentle"
-        />
-
-    </FrameLayout>
-    <ImageView
-        android:id="@+id/btn_clear_all"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:src="@drawable/status_bar_notification_section_header_clear_btn"
-        android:contentDescription="@string/accessibility_notification_section_header_gentle_clear_all"
-        android:scaleType="center"
-        android:tint="?attr/wallpaperTextColor"
-        android:tintMode="src_in"
-        android:visibility="gone"
-        android:forceHasOverlappingRendering="false"
-    />
-</merge>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 06e027d..4d6b759 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -532,4 +532,8 @@
     <!-- Respect drawable/rounded.xml intrinsic size for multiple radius corner path customization -->
     <bool name="config_roundedCornerMultipleRadius">false</bool>
 
+    <!-- Controls can query a preferred application for limited number of suggested controls.
+         This config value should contain the package name of that preferred application.
+    -->
+    <string translatable="false" name="config_controlsPreferredPackage"></string>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 93bafdb..cb08840 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2657,4 +2657,8 @@
 
     <!-- Tooltip to show in management screen when there are multiple structures [CHAR_LIMIT=50] -->
     <string name="controls_structure_tooltip">Swipe to see other structures</string>
+
+    <!-- Message to tell the user to wait while systemui attempts to load a set of
+         recommended controls [CHAR_LIMIT=30] -->
+    <string name="controls_seeding_in_progress">Loading recommendations</string>
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 20b88a1..1283fe0 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -699,6 +699,20 @@
         <item name="*android:colorPopupBackground">@color/control_list_popup_background</item>
     </style>
 
+    <style name="TextAppearance.ControlSetup">
+        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+        <item name="android:textColor">@color/control_primary_text</item>
+        <item name="android:singleLine">true</item>
+    </style>
+
+    <style name="TextAppearance.ControlSetup.Title">
+        <item name="android:textSize">25sp</item>
+    </style>
+
+    <style name="TextAppearance.ControlSetup.Subtitle">
+        <item name="android:textSize">16sp</item>
+    </style>
+
     <style name="Theme.ControlsRequestDialog" parent="@style/Theme.SystemUI.MediaProjectionAlertDialog"/>
 
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index a8a3cae..5f004a6 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -122,7 +122,7 @@
     protected int mRoundedDefaultBottom;
     @VisibleForTesting
     protected View[] mOverlays;
-    private DisplayCutoutView[] mCutoutViews;
+    private DisplayCutoutView[] mCutoutViews = new DisplayCutoutView[BOUNDS_POSITION_LENGTH];
     private float mDensity;
     private WindowManager mWindowManager;
     private int mRotation;
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt
index c5af436..d4d4d2a 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt
@@ -43,6 +43,14 @@
     fun bindAndLoad(component: ComponentName, callback: LoadCallback): Runnable
 
     /**
+     * Request bind to a service and load a limited number of suggested controls.
+     *
+     * @param component The [ComponentName] of the service to bind
+     * @param callback a callback to return the loaded controls to (or an error).
+     */
+    fun bindAndLoadSuggested(component: ComponentName, callback: LoadCallback)
+
+    /**
      * Request to bind to the given service.
      *
      * @param component The [ComponentName] of the service to bind
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
index f8d4a39..5d03fc5 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
@@ -44,6 +44,8 @@
 
     companion object {
         private const val TAG = "ControlsBindingControllerImpl"
+        private const val MAX_CONTROLS_REQUEST = 100000L
+        private const val SUGGESTED_CONTROLS_REQUEST = 4L
     }
 
     private var currentUser = UserHandle.of(ActivityManager.getCurrentUser())
@@ -97,24 +99,37 @@
         component: ComponentName,
         callback: ControlsBindingController.LoadCallback
     ): Runnable {
-        val subscriber = LoadSubscriber(callback)
+        val subscriber = LoadSubscriber(callback, MAX_CONTROLS_REQUEST)
         retrieveLifecycleManager(component).maybeBindAndLoad(subscriber)
         return subscriber.loadCancel()
     }
 
+    override fun bindAndLoadSuggested(
+        component: ComponentName,
+        callback: ControlsBindingController.LoadCallback
+    ) {
+        val subscriber = LoadSubscriber(callback, SUGGESTED_CONTROLS_REQUEST)
+        retrieveLifecycleManager(component).maybeBindAndLoadSuggested(subscriber)
+    }
+
     override fun subscribe(structureInfo: StructureInfo) {
         // make sure this has happened. only allow one active subscription
         unsubscribe()
 
-        statefulControlSubscriber = null
         val provider = retrieveLifecycleManager(structureInfo.componentName)
-        val scs = StatefulControlSubscriber(lazyController.get(), provider, backgroundExecutor)
+        val scs = StatefulControlSubscriber(
+            lazyController.get(),
+            provider,
+            backgroundExecutor,
+            MAX_CONTROLS_REQUEST
+        )
         statefulControlSubscriber = scs
         provider.maybeBindAndSubscribe(structureInfo.controls.map { it.controlId }, scs)
     }
 
     override fun unsubscribe() {
         statefulControlSubscriber?.cancel()
+        statefulControlSubscriber = null
     }
 
     override fun action(
@@ -201,10 +216,11 @@
 
     private inner class OnSubscribeRunnable(
         token: IBinder,
-        val subscription: IControlsSubscription
+        val subscription: IControlsSubscription,
+        val requestLimit: Long
     ) : CallbackRunnable(token) {
         override fun doRun() {
-            provider?.startSubscription(subscription)
+            provider?.startSubscription(subscription, requestLimit)
         }
     }
 
@@ -234,7 +250,8 @@
     }
 
     private inner class LoadSubscriber(
-        val callback: ControlsBindingController.LoadCallback
+        val callback: ControlsBindingController.LoadCallback,
+        val requestLimit: Long
     ) : IControlsSubscriber.Stub() {
         val loadedControls = ArrayList<Control>()
         var hasError = false
@@ -246,7 +263,7 @@
 
         override fun onSubscribe(token: IBinder, subs: IControlsSubscription) {
             _loadCancelInternal = subs::cancel
-            backgroundExecutor.execute(OnSubscribeRunnable(token, subs))
+            backgroundExecutor.execute(OnSubscribeRunnable(token, subs, requestLimit))
         }
 
         override fun onNext(token: IBinder, c: Control) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
index 9e0d26c..ae75dd4 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
@@ -114,6 +114,25 @@
     // FAVORITE MANAGEMENT
 
     /**
+     * Send a request to seed favorites into the persisted XML file
+     *
+     * @param componentName the component to seed controls from
+     * @param callback true if the favorites were persisted
+     */
+    fun seedFavoritesForComponent(
+        componentName: ComponentName,
+        callback: Consumer<Boolean>
+    )
+
+    /**
+     * Callback to be informed when the seeding process has finished
+     *
+     * @param callback consumer accepts true if successful
+     * @return true if seeding is in progress and the callback was added
+     */
+    fun addSeedingFavoritesCallback(callback: Consumer<Boolean>): Boolean
+
+    /**
      * Get all the favorites.
      *
      * @return a list of the structures that have at least one favorited control
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
index 9cb902f..2e34ea5 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -31,6 +31,7 @@
 import android.provider.Settings
 import android.service.controls.Control
 import android.service.controls.actions.ControlAction
+import android.util.ArrayMap
 import android.util.Log
 import com.android.internal.annotations.VisibleForTesting
 import com.android.systemui.Dumpable
@@ -74,6 +75,9 @@
 
     private var loadCanceller: Runnable? = null
 
+    private var seedingInProgress = false
+    private val seedingCallbacks = mutableListOf<Consumer<Boolean>>()
+
     private var currentUser = UserHandle.of(ActivityManager.getCurrentUser())
     override val currentUserId
         get() = currentUser.identifier
@@ -280,6 +284,84 @@
         )
     }
 
+    override fun addSeedingFavoritesCallback(callback: Consumer<Boolean>): Boolean {
+        if (!seedingInProgress) return false
+        executor.execute {
+            // status may have changed by this point, so check again and inform the
+            // caller if necessary
+            if (seedingInProgress) seedingCallbacks.add(callback)
+            else callback.accept(false)
+        }
+        return true
+    }
+
+    override fun seedFavoritesForComponent(
+        componentName: ComponentName,
+        callback: Consumer<Boolean>
+    ) {
+        Log.i(TAG, "Beginning request to seed favorites for: $componentName")
+        if (!confirmAvailability()) {
+            if (userChanging) {
+                // Try again later, userChanging should not last forever. If so, we have bigger
+                // problems. This will return a runnable that allows to cancel the delayed version,
+                // it will not be able to cancel the load if
+                executor.executeDelayed(
+                    { seedFavoritesForComponent(componentName, callback) },
+                    USER_CHANGE_RETRY_DELAY,
+                    TimeUnit.MILLISECONDS
+                )
+            } else {
+                callback.accept(false)
+            }
+            return
+        }
+        seedingInProgress = true
+        bindingController.bindAndLoadSuggested(
+            componentName,
+            object : ControlsBindingController.LoadCallback {
+                override fun accept(controls: List<Control>) {
+                    executor.execute {
+                        val structureToControls =
+                            ArrayMap<CharSequence, MutableList<ControlInfo>>()
+
+                        controls.forEach {
+                            val structure = it.structure ?: ""
+                            val list = structureToControls.get(structure)
+                            ?: mutableListOf<ControlInfo>()
+                            list.add(ControlInfo(it.controlId, it.title, it.deviceType))
+                            structureToControls.put(structure, list)
+                        }
+
+                        structureToControls.forEach {
+                            (s, cs) -> Favorites.replaceControls(
+                                StructureInfo(componentName, s, cs))
+                        }
+
+                        persistenceWrapper.storeFavorites(Favorites.getAllStructures())
+                        callback.accept(true)
+                        endSeedingCall(true)
+                    }
+                }
+
+                override fun error(message: String) {
+                    Log.e(TAG, "Unable to seed favorites: $message")
+                    executor.execute {
+                        callback.accept(false)
+                        endSeedingCall(false)
+                    }
+                }
+            }
+        )
+    }
+
+    private fun endSeedingCall(state: Boolean) {
+        seedingInProgress = false
+        seedingCallbacks.forEach {
+            it.accept(state)
+        }
+        seedingCallbacks.clear()
+    }
+
     override fun cancelLoad() {
         loadCanceller?.let {
             executor.execute(it)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
index 4918bd7..209d056 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
@@ -66,22 +66,17 @@
     @GuardedBy("subscriptions")
     private val subscriptions = mutableListOf<IControlsSubscription>()
     private var requiresBound = false
-    @GuardedBy("queuedMessages")
-    private val queuedMessages: MutableSet<Message> = ArraySet()
+    @GuardedBy("queuedServiceMethods")
+    private val queuedServiceMethods: MutableSet<ServiceMethod> = ArraySet()
     private var wrapper: ServiceWrapper? = null
     private var bindTryCount = 0
     private val TAG = javaClass.simpleName
     private var onLoadCanceller: Runnable? = null
 
     companion object {
-        private const val MSG_LOAD = 0
-        private const val MSG_SUBSCRIBE = 1
-        private const val MSG_ACTION = 2
-        private const val MSG_UNBIND = 3
         private const val BIND_RETRY_DELAY = 1000L // ms
         private const val LOAD_TIMEOUT_SECONDS = 30L // seconds
         private const val MAX_BIND_RETRIES = 5
-        private const val MAX_CONTROLS_REQUEST = 100000L
         private const val DEBUG = true
         private val BIND_FLAGS = Context.BIND_AUTO_CREATE or Context.BIND_FOREGROUND_SERVICE or
                 Context.BIND_WAIVE_PRIORITY
@@ -130,7 +125,7 @@
             try {
                 service.linkToDeath(this@ControlsProviderLifecycleManager, 0)
             } catch (_: RemoteException) {}
-            handlePendingMessages()
+            handlePendingServiceMethods()
         }
 
         override fun onServiceDisconnected(name: ComponentName?) {
@@ -140,29 +135,14 @@
         }
     }
 
-    private fun handlePendingMessages() {
-        val queue = synchronized(queuedMessages) {
-            ArraySet(queuedMessages).also {
-                queuedMessages.clear()
+    private fun handlePendingServiceMethods() {
+        val queue = synchronized(queuedServiceMethods) {
+            ArraySet(queuedServiceMethods).also {
+                queuedServiceMethods.clear()
             }
         }
-        if (Message.Unbind in queue) {
-            bindService(false)
-            return
-        }
-
-        queue.filter { it is Message.Load }.forEach {
-            val msg = it as Message.Load
-            load(msg.subscriber)
-        }
-
-        queue.filter { it is Message.Subscribe }.forEach {
-            val msg = it as Message.Subscribe
-            subscribe(msg.list, msg.subscriber)
-        }
-        queue.filter { it is Message.Action }.forEach {
-            val msg = it as Message.Action
-            action(msg.id, msg.action)
+        queue.forEach {
+            it.run()
         }
     }
 
@@ -177,33 +157,17 @@
         }
     }
 
-    private fun queueMessage(message: Message) {
-        synchronized(queuedMessages) {
-            queuedMessages.add(message)
+    private fun queueServiceMethod(sm: ServiceMethod) {
+        synchronized(queuedServiceMethods) {
+            queuedServiceMethods.add(sm)
         }
     }
 
-    private fun unqueueMessageType(type: Int) {
-        synchronized(queuedMessages) {
-            queuedMessages.removeIf { it.type == type }
-        }
-    }
-
-    private fun load(subscriber: IControlsSubscriber.Stub) {
-        if (DEBUG) {
-            Log.d(TAG, "load $componentName")
-        }
-        if (!(wrapper?.load(subscriber) ?: false)) {
-            queueMessage(Message.Load(subscriber))
-            binderDied()
-        }
-    }
-
-    private inline fun invokeOrQueue(f: () -> Unit, msg: Message) {
+    private fun invokeOrQueue(sm: ServiceMethod) {
         wrapper?.run {
-            f()
+            sm.run()
         } ?: run {
-            queueMessage(msg)
+            queueServiceMethod(sm)
             bindService(true)
         }
     }
@@ -217,7 +181,6 @@
      * @param subscriber the subscriber that manages coordination for loading controls
      */
     fun maybeBindAndLoad(subscriber: IControlsSubscriber.Stub) {
-        unqueueMessageType(MSG_UNBIND)
         onLoadCanceller = executor.executeDelayed({
             // Didn't receive a response in time, log and send back error
             Log.d(TAG, "Timeout waiting onLoad for $componentName")
@@ -225,7 +188,26 @@
             unbindService()
         }, LOAD_TIMEOUT_SECONDS, TimeUnit.SECONDS)
 
-        invokeOrQueue({ load(subscriber) }, Message.Load(subscriber))
+        invokeOrQueue(Load(subscriber))
+    }
+
+    /**
+     * Request a call to [IControlsProvider.loadSuggested].
+     *
+     * If the service is not bound, the call will be queued and the service will be bound first.
+     * The service will be unbound after the controls are returned or the call times out.
+     *
+     * @param subscriber the subscriber that manages coordination for loading controls
+     */
+    fun maybeBindAndLoadSuggested(subscriber: IControlsSubscriber.Stub) {
+        onLoadCanceller = executor.executeDelayed({
+            // Didn't receive a response in time, log and send back error
+            Log.d(TAG, "Timeout waiting onLoadSuggested for $componentName")
+            subscriber.onError(token, "Timeout waiting onLoadSuggested")
+            unbindService()
+        }, LOAD_TIMEOUT_SECONDS, TimeUnit.SECONDS)
+
+        invokeOrQueue(Suggest(subscriber))
     }
 
     fun cancelLoadTimeout() {
@@ -240,23 +222,8 @@
      *
      * @param controlIds a list of the ids of controls to send status back.
      */
-    fun maybeBindAndSubscribe(controlIds: List<String>, subscriber: IControlsSubscriber) {
-        invokeOrQueue(
-            { subscribe(controlIds, subscriber) },
-            Message.Subscribe(controlIds, subscriber)
-        )
-    }
-
-    private fun subscribe(controlIds: List<String>, subscriber: IControlsSubscriber) {
-        if (DEBUG) {
-            Log.d(TAG, "subscribe $componentName - $controlIds")
-        }
-
-        if (!(wrapper?.subscribe(controlIds, subscriber) ?: false)) {
-            queueMessage(Message.Subscribe(controlIds, subscriber))
-            binderDied()
-        }
-    }
+    fun maybeBindAndSubscribe(controlIds: List<String>, subscriber: IControlsSubscriber) =
+        invokeOrQueue(Subscribe(controlIds, subscriber))
 
     /**
      * Request a call to [ControlsProviderService.performControlAction].
@@ -266,19 +233,8 @@
      * @param controlId the id of the [Control] the action is performed on
      * @param action the action performed
      */
-    fun maybeBindAndSendAction(controlId: String, action: ControlAction) {
-        invokeOrQueue({ action(controlId, action) }, Message.Action(controlId, action))
-    }
-
-    private fun action(controlId: String, action: ControlAction) {
-        if (DEBUG) {
-            Log.d(TAG, "onAction $componentName - $controlId")
-        }
-        if (!(wrapper?.action(controlId, action, actionCallbackService) ?: false)) {
-            queueMessage(Message.Action(controlId, action))
-            binderDied()
-        }
-    }
+    fun maybeBindAndSendAction(controlId: String, action: ControlAction) =
+        invokeOrQueue(Action(controlId, action))
 
     /**
      * Starts the subscription to the [ControlsProviderService] and requests status of controls.
@@ -286,14 +242,14 @@
      * @param subscription the subscription to use to request controls
      * @see maybeBindAndLoad
      */
-    fun startSubscription(subscription: IControlsSubscription) {
+    fun startSubscription(subscription: IControlsSubscription, requestLimit: Long) {
         if (DEBUG) {
             Log.d(TAG, "startSubscription: $subscription")
         }
         synchronized(subscriptions) {
             subscriptions.add(subscription)
         }
-        wrapper?.request(subscription, MAX_CONTROLS_REQUEST)
+        wrapper?.request(subscription, requestLimit)
     }
 
     /**
@@ -316,7 +272,6 @@
      * Request bind to the service.
      */
     fun bindService() {
-        unqueueMessageType(MSG_UNBIND)
         bindService(true)
     }
 
@@ -350,21 +305,55 @@
     }
 
     /**
-     * Messages for the internal queue.
+     * Service methods that can be queued or invoked, and are retryable for failure scenarios
      */
-    sealed class Message {
-        abstract val type: Int
-        class Load(val subscriber: IControlsSubscriber.Stub) : Message() {
-            override val type = MSG_LOAD
+    abstract inner class ServiceMethod {
+        fun run() {
+            if (!callWrapper()) {
+                queueServiceMethod(this)
+                binderDied()
+            }
         }
-        object Unbind : Message() {
-            override val type = MSG_UNBIND
+
+        internal abstract fun callWrapper(): Boolean
+    }
+
+    inner class Load(val subscriber: IControlsSubscriber.Stub) : ServiceMethod() {
+        override fun callWrapper(): Boolean {
+            if (DEBUG) {
+                Log.d(TAG, "load $componentName")
+            }
+            return wrapper?.load(subscriber) ?: false
         }
-        class Subscribe(val list: List<String>, val subscriber: IControlsSubscriber) : Message() {
-            override val type = MSG_SUBSCRIBE
+    }
+
+    inner class Suggest(val subscriber: IControlsSubscriber.Stub) : ServiceMethod() {
+        override fun callWrapper(): Boolean {
+            if (DEBUG) {
+                Log.d(TAG, "suggest $componentName")
+            }
+            return wrapper?.loadSuggested(subscriber) ?: false
         }
-        class Action(val id: String, val action: ControlAction) : Message() {
-            override val type = MSG_ACTION
+    }
+    inner class Subscribe(
+        val list: List<String>,
+        val subscriber: IControlsSubscriber
+    ) : ServiceMethod() {
+        override fun callWrapper(): Boolean {
+            if (DEBUG) {
+                Log.d(TAG, "subscribe $componentName - $list")
+            }
+
+            return wrapper?.subscribe(list, subscriber) ?: false
+        }
+    }
+
+    inner class Action(val id: String, val action: ControlAction) : ServiceMethod() {
+        override fun callWrapper(): Boolean {
+            if (DEBUG) {
+                Log.d(TAG, "onAction $componentName - $id")
+            }
+            return wrapper?.action(id, action, actionCallbackService) ?: false
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ServiceWrapper.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ServiceWrapper.kt
index b2afd3c..2c717f5 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ServiceWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ServiceWrapper.kt
@@ -50,6 +50,12 @@
         }
     }
 
+    fun loadSuggested(subscriber: IControlsSubscriber): Boolean {
+        return callThroughService {
+            service.loadSuggested(subscriber)
+        }
+    }
+
     fun subscribe(controlIds: List<String>, subscriber: IControlsSubscriber): Boolean {
         return callThroughService {
             service.subscribe(controlIds, subscriber)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/StatefulControlSubscriber.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/StatefulControlSubscriber.kt
index a371aa6..e3eabff 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/StatefulControlSubscriber.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/StatefulControlSubscriber.kt
@@ -31,7 +31,8 @@
 class StatefulControlSubscriber(
     private val controller: ControlsController,
     private val provider: ControlsProviderLifecycleManager,
-    private val bgExecutor: DelayableExecutor
+    private val bgExecutor: DelayableExecutor,
+    private val requestLimit: Long
 ) : IControlsSubscriber.Stub() {
     private var subscriptionOpen = false
     private var subscription: IControlsSubscription? = null
@@ -50,7 +51,7 @@
         run(token) {
             subscriptionOpen = true
             subscription = subs
-            provider.startSubscription(subs)
+            provider.startSubscription(subs, requestLimit)
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt
index a7fc2ac8..74a6c87 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt
@@ -55,7 +55,7 @@
     private lateinit var control: Control
     private var dialog: Dialog? = null
     private val callback = object : ControlsListingController.ControlsListingCallback {
-        override fun onServicesUpdated(candidates: List<ControlsServiceInfo>) {}
+        override fun onServicesUpdated(serviceInfos: List<ControlsServiceInfo>) {}
     }
 
     private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 138cd47..ffae4653 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -52,6 +52,7 @@
 import dagger.Lazy
 
 import java.text.Collator
+import java.util.function.Consumer
 
 import javax.inject.Inject
 import javax.inject.Singleton
@@ -89,6 +90,7 @@
     private var popup: ListPopupWindow? = null
     private var activeDialog: Dialog? = null
     private val addControlsItem: SelectionItem
+    private var hidden = true
 
     init {
         val addDrawable = context.getDrawable(R.drawable.ic_add).apply {
@@ -134,11 +136,15 @@
     override fun show(parent: ViewGroup) {
         Log.d(ControlsUiController.TAG, "show()")
         this.parent = parent
+        hidden = false
 
         allStructures = controlsController.get().getFavorites()
         selectedStructure = loadPreference(allStructures)
 
-        if (selectedStructure.controls.isEmpty() && allStructures.size <= 1) {
+        val cb = Consumer<Boolean> { _ -> reload(parent) }
+        if (controlsController.get().addSeedingFavoritesCallback(cb)) {
+            listingCallback = createCallback(::showSeedingView)
+        } else if (selectedStructure.controls.isEmpty() && allStructures.size <= 1) {
             // only show initial view if there are really no favorites across any structure
             listingCallback = createCallback(::showInitialSetupView)
         } else {
@@ -154,6 +160,20 @@
         controlsListingController.get().addCallback(listingCallback)
     }
 
+    private fun reload(parent: ViewGroup) {
+        if (hidden) return
+        show(parent)
+    }
+
+    private fun showSeedingView(items: List<SelectionItem>) {
+        parent.removeAllViews()
+
+        val inflater = LayoutInflater.from(context)
+        inflater.inflate(R.layout.controls_no_favorites, parent, true)
+        val subtitle = parent.requireViewById<TextView>(R.id.controls_subtitle)
+        subtitle.setVisibility(View.VISIBLE)
+    }
+
     private fun showInitialSetupView(items: List<SelectionItem>) {
         parent.removeAllViews()
 
@@ -320,13 +340,14 @@
                 selectedStructure = newSelection
                 updatePreferences(selectedStructure)
                 controlsListingController.get().removeCallback(listingCallback)
-                show(parent)
+                reload(parent)
             }
         }
     }
 
     override fun hide() {
         Log.d(ControlsUiController.TAG, "hide()")
+        hidden = true
         popup?.dismiss()
         activeDialog?.dismiss()
 
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index b99d765..73539f9 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -31,11 +31,13 @@
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.TrustManager;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.SharedPreferences;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.database.ContentObserver;
@@ -92,6 +94,8 @@
 import com.android.systemui.MultiListLayout.MultiListAdapter;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.controls.ControlsServiceInfo;
+import com.android.systemui.controls.controller.ControlsController;
 import com.android.systemui.controls.management.ControlsListingController;
 import com.android.systemui.controls.ui.ControlsUiController;
 import com.android.systemui.dagger.qualifiers.Background;
@@ -148,6 +152,9 @@
     private static final String GLOBAL_ACTION_KEY_EMERGENCY = "emergency";
     private static final String GLOBAL_ACTION_KEY_SCREENSHOT = "screenshot";
 
+    private static final String PREFS_CONTROLS_SEEDING_COMPLETED = "ControlsSeedingCompleted";
+    private static final String PREFS_CONTROLS_FILE = "controls_prefs";
+
     private final Context mContext;
     private final GlobalActionsManager mWindowManagerFuncs;
     private final AudioManager mAudioManager;
@@ -215,7 +222,8 @@
             NotificationShadeWindowController notificationShadeWindowController,
             ControlsUiController controlsUiController, IWindowManager iWindowManager,
             @Background Executor backgroundExecutor,
-            ControlsListingController controlsListingController) {
+            ControlsListingController controlsListingController,
+            ControlsController controlsController) {
         mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme);
         mWindowManagerFuncs = windowManagerFuncs;
         mAudioManager = audioManager;
@@ -279,9 +287,46 @@
             }
         });
 
-        mControlsListingController.addCallback(list -> mAnyControlsProviders = !list.isEmpty());
+        String preferredControlsPackage = mContext.getResources()
+                .getString(com.android.systemui.R.string.config_controlsPreferredPackage);
+        mControlsListingController.addCallback(list -> {
+            mAnyControlsProviders = !list.isEmpty();
+
+            /*
+             * See if any service providers match the preferred component. If they do,
+             * and there are no current favorites, and we haven't successfully loaded favorites to
+             * date, query the preferred component for a limited number of suggested controls.
+             */
+            ComponentName preferredComponent = null;
+            for (ControlsServiceInfo info : list) {
+                if (info.componentName.getPackageName().equals(preferredControlsPackage)) {
+                    preferredComponent = info.componentName;
+                    break;
+                }
+            }
+
+            if (preferredComponent == null) return;
+
+            SharedPreferences prefs = context.getSharedPreferences(PREFS_CONTROLS_FILE,
+                    Context.MODE_PRIVATE);
+            boolean isSeeded = prefs.getBoolean(PREFS_CONTROLS_SEEDING_COMPLETED, false);
+            boolean hasFavorites = controlsController.getFavorites().size() > 0;
+            if (!isSeeded && !hasFavorites) {
+                controlsController.seedFavoritesForComponent(
+                        preferredComponent,
+                        (accepted) -> {
+                            Log.i(TAG, "Controls seeded: " + accepted);
+                            prefs.edit().putBoolean(PREFS_CONTROLS_SEEDING_COMPLETED,
+                                    accepted).apply();
+                        }
+                );
+            }
+        });
     }
 
+
+
+
     /**
      * Show the global actions dialog (creating if necessary)
      *
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
index 42a7c6a..f6f8363 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java
@@ -447,7 +447,6 @@
         }
     }
 
-
     @VisibleForTesting
     ExpandableView getGentleHeaderView() {
         return mGentleHeader;
@@ -471,7 +470,7 @@
     private final ConfigurationListener mConfigurationListener = new ConfigurationListener() {
         @Override
         public void onLocaleListChanged() {
-            mGentleHeader.reinflateContents();
+            reinflateViews(LayoutInflater.from(mParent.getContext()));
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
index 1b4f98f..bc25c71 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
@@ -76,9 +76,7 @@
             }
         }
 
-    override fun needsClippingToShelf(): Boolean {
-        return true
-    }
+    override fun needsClippingToShelf(): Boolean = true
 
     override fun applyContentTransformation(contentAlpha: Float, translationY: Float) {
         super.applyContentTransformation(contentAlpha, translationY)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
index deb5532..a3d8eec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
@@ -20,7 +20,6 @@
 import android.annotation.StringRes;
 import android.content.Context;
 import android.util.AttributeSet;
-import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
@@ -30,16 +29,17 @@
 import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
 
-import java.util.Objects;
-
 /**
- * Similar in size and appearance to the NotificationShelf, appears at the beginning of some
- * notification sections. Currently only used for gentle notifications.
+ * Header displayed above a notification section in the shade. Currently used for Alerting and
+ * Silent sections.
  */
 public class SectionHeaderView extends StackScrollerDecorView {
+
     private ViewGroup mContents;
     private TextView mLabelView;
     private ImageView mClearAllButton;
+    @StringRes @Nullable private Integer mLabelTextId;
+    @Nullable private View.OnClickListener mLabelClickListener = null;
     @Nullable private View.OnClickListener mOnClearClickListener = null;
 
     public SectionHeaderView(Context context, AttributeSet attrs) {
@@ -48,18 +48,24 @@
 
     @Override
     protected void onFinishInflate() {
-        mContents = Objects.requireNonNull(findViewById(R.id.content));
+        mContents = requireViewById(R.id.content);
         bindContents();
         super.onFinishInflate();
         setVisible(true /* nowVisible */, false /* animate */);
     }
 
     private void bindContents() {
-        mLabelView = Objects.requireNonNull(findViewById(R.id.header_label));
-        mClearAllButton = Objects.requireNonNull(findViewById(R.id.btn_clear_all));
+        mLabelView = requireViewById(R.id.header_label);
+        mClearAllButton = requireViewById(R.id.btn_clear_all);
         if (mOnClearClickListener != null) {
             mClearAllButton.setOnClickListener(mOnClearClickListener);
         }
+        if (mLabelClickListener != null) {
+            mLabelView.setOnClickListener(mLabelClickListener);
+        }
+        if (mLabelTextId != null) {
+            mLabelView.setText(mLabelTextId);
+        }
     }
 
     @Override
@@ -72,21 +78,6 @@
         return null;
     }
 
-    /**
-     * Destroys and reinflates the visible contents of the section header. For use on configuration
-     * changes or any other time that layout values might need to be re-evaluated.
-     *
-     * Does not reinflate the base content view itself ({@link #findContentView()} or any of the
-     * decorator views, such as the background view or shadow view.
-     */
-    void reinflateContents() {
-        mContents.removeAllViews();
-        LayoutInflater.from(getContext()).inflate(
-                R.layout.status_bar_notification_section_header_contents,
-                mContents);
-        bindContents();
-    }
-
     @Override
     public boolean isTransparent() {
         return true;
@@ -105,6 +96,7 @@
      * Fired whenever the user clicks on the body of the header (e.g. no sub-buttons or anything).
      */
     void setOnHeaderClickListener(View.OnClickListener listener) {
+        mLabelClickListener = listener;
         mLabelView.setOnClickListener(listener);
     }
 
@@ -129,6 +121,7 @@
     }
 
     void setHeaderText(@StringRes int resId) {
+        mLabelTextId = resId;
         mLabelView.setText(resId);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
index c25d4e2..2ff2b2a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
@@ -207,6 +207,56 @@
     }
 
     @Test
+    fun testBindAndLoadSuggested() {
+        val callback = object : ControlsBindingController.LoadCallback {
+            override fun error(message: String) {}
+
+            override fun accept(t: List<Control>) {}
+        }
+        controller.bindAndLoadSuggested(TEST_COMPONENT_NAME_1, callback)
+
+        verify(providers[0]).maybeBindAndLoadSuggested(any())
+    }
+
+    @Test
+    fun testLoadSuggested_onCompleteRemovesTimeout() {
+        val callback = object : ControlsBindingController.LoadCallback {
+            override fun error(message: String) {}
+
+            override fun accept(t: List<Control>) {}
+        }
+        val subscription = mock(IControlsSubscription::class.java)
+
+        controller.bindAndLoadSuggested(TEST_COMPONENT_NAME_1, callback)
+
+        verify(providers[0]).maybeBindAndLoadSuggested(capture(subscriberCaptor))
+        val b = Binder()
+        subscriberCaptor.value.onSubscribe(b, subscription)
+
+        subscriberCaptor.value.onComplete(b)
+        verify(providers[0]).cancelLoadTimeout()
+    }
+
+    @Test
+    fun testLoadSuggested_onErrorRemovesTimeout() {
+        val callback = object : ControlsBindingController.LoadCallback {
+            override fun error(message: String) {}
+
+            override fun accept(t: List<Control>) {}
+        }
+        val subscription = mock(IControlsSubscription::class.java)
+
+        controller.bindAndLoadSuggested(TEST_COMPONENT_NAME_1, callback)
+
+        verify(providers[0]).maybeBindAndLoadSuggested(capture(subscriberCaptor))
+        val b = Binder()
+        subscriberCaptor.value.onSubscribe(b, subscription)
+
+        subscriberCaptor.value.onError(b, "")
+        verify(providers[0]).cancelLoadTimeout()
+    }
+
+    @Test
     fun testBindService() {
         controller.bindService(TEST_COMPONENT_NAME_1)
         executor.runAllReady()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
index f9c9815..971d14c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
@@ -80,6 +80,10 @@
 
     @Captor
     private lateinit var structureInfoCaptor: ArgumentCaptor<StructureInfo>
+
+    @Captor
+    private lateinit var booleanConsumer: ArgumentCaptor<Consumer<Boolean>>
+
     @Captor
     private lateinit var controlLoadCallbackCaptor:
             ArgumentCaptor<ControlsBindingController.LoadCallback>
@@ -155,9 +159,13 @@
         verify(listingController).addCallback(capture(listingCallbackCaptor))
     }
 
-    private fun builderFromInfo(controlInfo: ControlInfo): Control.StatelessBuilder {
+    private fun builderFromInfo(
+        controlInfo: ControlInfo,
+        structure: CharSequence = ""
+    ): Control.StatelessBuilder {
         return Control.StatelessBuilder(controlInfo.controlId, pendingIntent)
                 .setDeviceType(controlInfo.deviceType).setTitle(controlInfo.controlTitle)
+                .setStructure(structure)
     }
 
     @Test
@@ -746,4 +754,70 @@
         inOrder.verify(persistenceWrapper).readFavorites()
         inOrder.verify(listingController).addCallback(listingCallbackCaptor.value)
     }
+
+    @Test
+    fun testSeedFavoritesForComponent() {
+        var succeeded = false
+        val control = builderFromInfo(TEST_CONTROL_INFO, TEST_STRUCTURE_INFO.structure).build()
+
+        controller.seedFavoritesForComponent(TEST_COMPONENT, Consumer { accepted ->
+            succeeded = accepted
+        })
+
+        verify(bindingController).bindAndLoadSuggested(eq(TEST_COMPONENT),
+                capture(controlLoadCallbackCaptor))
+
+        controlLoadCallbackCaptor.value.accept(listOf(control))
+
+        delayableExecutor.runAllReady()
+
+        assertEquals(listOf(TEST_STRUCTURE_INFO),
+            controller.getFavoritesForComponent(TEST_COMPONENT))
+        assertTrue(succeeded)
+    }
+
+    @Test
+    fun testSeedFavoritesForComponent_error() {
+        var succeeded = false
+
+        controller.seedFavoritesForComponent(TEST_COMPONENT, Consumer { accepted ->
+            succeeded = accepted
+        })
+
+        verify(bindingController).bindAndLoadSuggested(eq(TEST_COMPONENT),
+                capture(controlLoadCallbackCaptor))
+
+        controlLoadCallbackCaptor.value.error("Error loading")
+
+        delayableExecutor.runAllReady()
+
+        assertEquals(listOf<StructureInfo>(), controller.getFavoritesForComponent(TEST_COMPONENT))
+        assertFalse(succeeded)
+    }
+
+    @Test
+    fun testSeedFavoritesForComponent_inProgressCallback() {
+        var succeeded = false
+        var seeded = false
+        val control = builderFromInfo(TEST_CONTROL_INFO, TEST_STRUCTURE_INFO.structure).build()
+
+        controller.seedFavoritesForComponent(TEST_COMPONENT, Consumer { accepted ->
+            succeeded = accepted
+        })
+
+        verify(bindingController).bindAndLoadSuggested(eq(TEST_COMPONENT),
+                capture(controlLoadCallbackCaptor))
+
+        controller.addSeedingFavoritesCallback(Consumer { accepted ->
+            seeded = accepted
+        })
+        controlLoadCallbackCaptor.value.accept(listOf(control))
+
+        delayableExecutor.runAllReady()
+
+        assertEquals(listOf(TEST_STRUCTURE_INFO),
+            controller.getFavoritesForComponent(TEST_COMPONENT))
+        assertTrue(succeeded)
+        assertTrue(seeded)
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ServiceWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ServiceWrapperTest.kt
index cd82844..789d6df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ServiceWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ServiceWrapperTest.kt
@@ -92,6 +92,22 @@
     }
 
     @Test
+    fun testLoadSuggested_happyPath() {
+        val result = wrapper.loadSuggested(subscriber)
+
+        assertTrue(result)
+        verify(service).loadSuggested(subscriber)
+    }
+
+    @Test
+    fun testLoadSuggested_error() {
+        `when`(service.loadSuggested(any())).thenThrow(exception)
+        val result = wrapper.loadSuggested(subscriber)
+
+        assertFalse(result)
+    }
+
+    @Test
     fun testSubscribe_happyPath() {
         val list = listOf("TEST_ID")
         val result = wrapper.subscribe(list, subscriber)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/StatefulControlSubscriberTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/StatefulControlSubscriberTest.kt
index ff5c8d4..267520e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/StatefulControlSubscriberTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/StatefulControlSubscriberTest.kt
@@ -59,13 +59,15 @@
 
     private lateinit var scs: StatefulControlSubscriber
 
+    private val REQUEST_LIMIT = 5L
+
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
 
         `when`(provider.componentName).thenReturn(TEST_COMPONENT)
         `when`(provider.token).thenReturn(token)
-        scs = StatefulControlSubscriber(controller, provider, executor)
+        scs = StatefulControlSubscriber(controller, provider, executor, REQUEST_LIMIT)
     }
 
     @Test
@@ -73,7 +75,7 @@
         scs.onSubscribe(token, subscription)
 
         executor.runAllReady()
-        verify(provider).startSubscription(subscription)
+        verify(provider).startSubscription(subscription, REQUEST_LIMIT)
     }
 
     @Test
@@ -81,7 +83,7 @@
         scs.onSubscribe(badToken, subscription)
 
         executor.runAllReady()
-        verify(provider, never()).startSubscription(subscription)
+        verify(provider, never()).startSubscription(subscription, REQUEST_LIMIT)
     }
 
     @Test
diff --git a/packages/Tethering/common/TetheringLib/api/module-lib-current.txt b/packages/Tethering/common/TetheringLib/api/module-lib-current.txt
index e25d77d..e823e17 100644
--- a/packages/Tethering/common/TetheringLib/api/module-lib-current.txt
+++ b/packages/Tethering/common/TetheringLib/api/module-lib-current.txt
@@ -62,19 +62,20 @@
     field public static final int TETHERING_WIFI = 0; // 0x0
     field public static final int TETHERING_WIFI_P2P = 3; // 0x3
     field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc
-    field public static final int TETHER_ERROR_DISABLE_NAT_ERROR = 9; // 0x9
-    field public static final int TETHER_ERROR_ENABLE_NAT_ERROR = 8; // 0x8
+    field public static final int TETHER_ERROR_DISABLE_FORWARDING_ERROR = 9; // 0x9
+    field public static final int TETHER_ERROR_ENABLE_FORWARDING_ERROR = 8; // 0x8
     field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd
     field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa
-    field public static final int TETHER_ERROR_MASTER_ERROR = 5; // 0x5
+    field public static final int TETHER_ERROR_INTERNAL_ERROR = 5; // 0x5
     field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf
     field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe
     field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
-    field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
+    field public static final int TETHER_ERROR_PROVISIONING_FAILED = 11; // 0xb
     field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2
     field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6
     field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4
     field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
+    field public static final int TETHER_ERROR_UNKNOWN_TYPE = 16; // 0x10
     field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
     field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
     field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2
@@ -86,29 +87,26 @@
     method public void onTetheringEntitlementResult(int);
   }
 
-  public abstract static class TetheringManager.StartTetheringCallback {
-    ctor public TetheringManager.StartTetheringCallback();
-    method public void onTetheringFailed(int);
-    method public void onTetheringStarted();
+  public static interface TetheringManager.StartTetheringCallback {
+    method public default void onTetheringFailed(int);
+    method public default void onTetheringStarted();
   }
 
-  public abstract static class TetheringManager.TetheringEventCallback {
-    ctor public TetheringManager.TetheringEventCallback();
-    method public void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
-    method public void onError(@NonNull String, int);
-    method public void onOffloadStatusChanged(int);
-    method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
-    method public void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
-    method public void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
-    method public void onTetheringSupported(boolean);
-    method public void onUpstreamChanged(@Nullable android.net.Network);
+  public static interface TetheringManager.TetheringEventCallback {
+    method public default void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
+    method public default void onError(@NonNull String, int);
+    method public default void onOffloadStatusChanged(int);
+    method public default void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
+    method public default void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
+    method public default void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
+    method public default void onTetheringSupported(boolean);
+    method public default void onUpstreamChanged(@Nullable android.net.Network);
   }
 
-  @Deprecated public static class TetheringManager.TetheringInterfaceRegexps {
-    ctor @Deprecated public TetheringManager.TetheringInterfaceRegexps(@NonNull String[], @NonNull String[], @NonNull String[]);
-    method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableBluetoothRegexs();
-    method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableUsbRegexs();
-    method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
+  public static class TetheringManager.TetheringInterfaceRegexps {
+    method @NonNull public java.util.List<java.lang.String> getTetherableBluetoothRegexs();
+    method @NonNull public java.util.List<java.lang.String> getTetherableUsbRegexs();
+    method @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
   }
 
   public static class TetheringManager.TetheringRequest {
@@ -117,9 +115,14 @@
   public static class TetheringManager.TetheringRequest.Builder {
     ctor public TetheringManager.TetheringRequest.Builder(int);
     method @NonNull public android.net.TetheringManager.TetheringRequest build();
+    method @Nullable public android.net.LinkAddress getClientStaticIpv4Address();
+    method @Nullable public android.net.LinkAddress getLocalIpv4Address();
+    method public boolean getShouldShowEntitlementUi();
+    method public int getTetheringType();
+    method public boolean isExemptFromEntitlementCheck();
     method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean);
-    method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setSilentProvisioning(boolean);
-    method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder useStaticIpv4Addresses(@NonNull android.net.LinkAddress);
+    method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setShouldShowEntitlementUi(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setStaticIpv4Addresses(@NonNull android.net.LinkAddress, @NonNull android.net.LinkAddress);
   }
 
 }
diff --git a/packages/Tethering/common/TetheringLib/api/system-current.txt b/packages/Tethering/common/TetheringLib/api/system-current.txt
index d6fcb62..3751135 100644
--- a/packages/Tethering/common/TetheringLib/api/system-current.txt
+++ b/packages/Tethering/common/TetheringLib/api/system-current.txt
@@ -40,19 +40,20 @@
     field public static final int TETHERING_WIFI = 0; // 0x0
     field public static final int TETHERING_WIFI_P2P = 3; // 0x3
     field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc
-    field public static final int TETHER_ERROR_DISABLE_NAT_ERROR = 9; // 0x9
-    field public static final int TETHER_ERROR_ENABLE_NAT_ERROR = 8; // 0x8
+    field public static final int TETHER_ERROR_DISABLE_FORWARDING_ERROR = 9; // 0x9
+    field public static final int TETHER_ERROR_ENABLE_FORWARDING_ERROR = 8; // 0x8
     field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd
     field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa
-    field public static final int TETHER_ERROR_MASTER_ERROR = 5; // 0x5
+    field public static final int TETHER_ERROR_INTERNAL_ERROR = 5; // 0x5
     field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf
     field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe
     field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
-    field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
+    field public static final int TETHER_ERROR_PROVISIONING_FAILED = 11; // 0xb
     field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2
     field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6
     field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4
     field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
+    field public static final int TETHER_ERROR_UNKNOWN_TYPE = 16; // 0x10
     field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
     field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
     field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2
@@ -64,29 +65,19 @@
     method public void onTetheringEntitlementResult(int);
   }
 
-  public abstract static class TetheringManager.StartTetheringCallback {
-    ctor public TetheringManager.StartTetheringCallback();
-    method public void onTetheringFailed(int);
-    method public void onTetheringStarted();
+  public static interface TetheringManager.StartTetheringCallback {
+    method public default void onTetheringFailed(int);
+    method public default void onTetheringStarted();
   }
 
-  public abstract static class TetheringManager.TetheringEventCallback {
-    ctor public TetheringManager.TetheringEventCallback();
-    method public void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
-    method public void onError(@NonNull String, int);
-    method public void onOffloadStatusChanged(int);
-    method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
-    method public void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
-    method public void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
-    method public void onTetheringSupported(boolean);
-    method public void onUpstreamChanged(@Nullable android.net.Network);
-  }
-
-  @Deprecated public static class TetheringManager.TetheringInterfaceRegexps {
-    ctor @Deprecated public TetheringManager.TetheringInterfaceRegexps(@NonNull String[], @NonNull String[], @NonNull String[]);
-    method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableBluetoothRegexs();
-    method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableUsbRegexs();
-    method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
+  public static interface TetheringManager.TetheringEventCallback {
+    method public default void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
+    method public default void onError(@NonNull String, int);
+    method public default void onOffloadStatusChanged(int);
+    method public default void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
+    method public default void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
+    method public default void onTetheringSupported(boolean);
+    method public default void onUpstreamChanged(@Nullable android.net.Network);
   }
 
   public static class TetheringManager.TetheringRequest {
@@ -95,9 +86,14 @@
   public static class TetheringManager.TetheringRequest.Builder {
     ctor public TetheringManager.TetheringRequest.Builder(int);
     method @NonNull public android.net.TetheringManager.TetheringRequest build();
+    method @Nullable public android.net.LinkAddress getClientStaticIpv4Address();
+    method @Nullable public android.net.LinkAddress getLocalIpv4Address();
+    method public boolean getShouldShowEntitlementUi();
+    method public int getTetheringType();
+    method public boolean isExemptFromEntitlementCheck();
     method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean);
-    method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setSilentProvisioning(boolean);
-    method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder useStaticIpv4Addresses(@NonNull android.net.LinkAddress);
+    method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setShouldShowEntitlementUi(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setStaticIpv4Addresses(@NonNull android.net.LinkAddress, @NonNull android.net.LinkAddress);
   }
 
 }
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index 7f831ce..86ef7f0 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -115,6 +115,19 @@
      */
     public static final String EXTRA_ERRORED_TETHER = "erroredArray";
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = false, value = {
+            TETHERING_WIFI,
+            TETHERING_USB,
+            TETHERING_BLUETOOTH,
+            TETHERING_WIFI_P2P,
+            TETHERING_NCM,
+            TETHERING_ETHERNET,
+    })
+    public @interface TetheringType {
+    }
+
     /**
      * Invalid tethering type.
      * @see #startTethering.
@@ -158,22 +171,60 @@
      */
     public static final int TETHERING_ETHERNET = 5;
 
-    public static final int TETHER_ERROR_NO_ERROR           = 0;
-    public static final int TETHER_ERROR_UNKNOWN_IFACE      = 1;
-    public static final int TETHER_ERROR_SERVICE_UNAVAIL    = 2;
-    public static final int TETHER_ERROR_UNSUPPORTED        = 3;
-    public static final int TETHER_ERROR_UNAVAIL_IFACE      = 4;
-    public static final int TETHER_ERROR_MASTER_ERROR       = 5;
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {
+            TETHER_ERROR_NO_ERROR,
+            TETHER_ERROR_PROVISIONING_FAILED,
+            TETHER_ERROR_ENTITLEMENT_UNKNOWN,
+    })
+    public @interface EntitlementResult {
+    }
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {
+            TETHER_ERROR_NO_ERROR,
+            TETHER_ERROR_UNKNOWN_IFACE,
+            TETHER_ERROR_SERVICE_UNAVAIL,
+            TETHER_ERROR_INTERNAL_ERROR,
+            TETHER_ERROR_TETHER_IFACE_ERROR,
+            TETHER_ERROR_ENABLE_FORWARDING_ERROR,
+            TETHER_ERROR_DISABLE_FORWARDING_ERROR,
+            TETHER_ERROR_IFACE_CFG_ERROR,
+            TETHER_ERROR_DHCPSERVER_ERROR,
+    })
+    public @interface TetheringIfaceError {
+    }
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {
+            TETHER_ERROR_SERVICE_UNAVAIL,
+            TETHER_ERROR_INTERNAL_ERROR,
+            TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION,
+            TETHER_ERROR_UNKNOWN_TYPE,
+    })
+    public @interface StartTetheringError {
+    }
+
+    public static final int TETHER_ERROR_NO_ERROR = 0;
+    public static final int TETHER_ERROR_UNKNOWN_IFACE = 1;
+    public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2;
+    public static final int TETHER_ERROR_UNSUPPORTED = 3;
+    public static final int TETHER_ERROR_UNAVAIL_IFACE = 4;
+    public static final int TETHER_ERROR_INTERNAL_ERROR = 5;
     public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6;
     public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7;
-    public static final int TETHER_ERROR_ENABLE_NAT_ERROR     = 8;
-    public static final int TETHER_ERROR_DISABLE_NAT_ERROR    = 9;
-    public static final int TETHER_ERROR_IFACE_CFG_ERROR      = 10;
-    public static final int TETHER_ERROR_PROVISION_FAILED     = 11;
-    public static final int TETHER_ERROR_DHCPSERVER_ERROR     = 12;
+    public static final int TETHER_ERROR_ENABLE_FORWARDING_ERROR = 8;
+    public static final int TETHER_ERROR_DISABLE_FORWARDING_ERROR = 9;
+    public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10;
+    public static final int TETHER_ERROR_PROVISIONING_FAILED = 11;
+    public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12;
     public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13;
     public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14;
     public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15;
+    public static final int TETHER_ERROR_UNKNOWN_TYPE = 16;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -508,23 +559,40 @@
             private final TetheringRequestParcel mBuilderParcel;
 
             /** Default constructor of Builder. */
-            public Builder(final int type) {
+            public Builder(@TetheringType final int type) {
                 mBuilderParcel = new TetheringRequestParcel();
                 mBuilderParcel.tetheringType = type;
                 mBuilderParcel.localIPv4Address = null;
+                mBuilderParcel.staticClientAddress = null;
                 mBuilderParcel.exemptFromEntitlementCheck = false;
                 mBuilderParcel.showProvisioningUi = true;
             }
 
             /**
-             * Configure tethering with static IPv4 assignment (with DHCP disabled).
+             * Configure tethering with static IPv4 assignment.
              *
-             * @param localIPv4Address The preferred local IPv4 address to use.
+             * The clientAddress must be in the localIPv4Address prefix. A DHCP server will be
+             * started, but will only be able to offer the client address. The two addresses must
+             * be in the same prefix.
+             *
+             * @param localIPv4Address The preferred local IPv4 link address to use.
+             * @param clientAddress The static client address.
              */
             @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
             @NonNull
-            public Builder useStaticIpv4Addresses(@NonNull final LinkAddress localIPv4Address) {
+            public Builder setStaticIpv4Addresses(@NonNull final LinkAddress localIPv4Address,
+                    @NonNull final LinkAddress clientAddress) {
+                Objects.requireNonNull(localIPv4Address);
+                Objects.requireNonNull(clientAddress);
+                if (localIPv4Address.getPrefixLength() != clientAddress.getPrefixLength()
+                        || !localIPv4Address.isIpv4() || !clientAddress.isIpv4()
+                        || !new IpPrefix(localIPv4Address.toString()).equals(
+                        new IpPrefix(clientAddress.toString()))) {
+                    throw new IllegalArgumentException("Invalid server or client addresses");
+                }
+
                 mBuilderParcel.localIPv4Address = localIPv4Address;
+                mBuilderParcel.staticClientAddress = clientAddress;
                 return this;
             }
 
@@ -536,11 +604,14 @@
                 return this;
             }
 
-            /** Start tethering without showing the provisioning UI. */
+            /**
+             * If an entitlement check is needed, sets whether to show the entitlement UI or to
+             * perform a silent entitlement check. By default, the entitlement UI is shown.
+             */
             @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
             @NonNull
-            public Builder setSilentProvisioning(boolean silent) {
-                mBuilderParcel.showProvisioningUi = silent;
+            public Builder setShouldShowEntitlementUi(boolean showUi) {
+                mBuilderParcel.showProvisioningUi = showUi;
                 return this;
             }
 
@@ -549,6 +620,33 @@
             public TetheringRequest build() {
                 return new TetheringRequest(mBuilderParcel);
             }
+
+            @Nullable
+            public LinkAddress getLocalIpv4Address() {
+                return mBuilderParcel.localIPv4Address;
+            }
+
+            /** Get static client address. */
+            @Nullable
+            public LinkAddress getClientStaticIpv4Address() {
+                return mBuilderParcel.staticClientAddress;
+            }
+
+            /** Get tethering type. */
+            @TetheringType
+            public int getTetheringType() {
+                return mBuilderParcel.tetheringType;
+            }
+
+            /** Check if exempt from entitlement check. */
+            public boolean isExemptFromEntitlementCheck() {
+                return mBuilderParcel.exemptFromEntitlementCheck;
+            }
+
+            /** Check if show entitlement ui.  */
+            public boolean getShouldShowEntitlementUi() {
+                return mBuilderParcel.showProvisioningUi;
+            }
         }
 
         /**
@@ -563,6 +661,7 @@
         public String toString() {
             return "TetheringRequest [ type= " + mRequestParcel.tetheringType
                     + ", localIPv4Address= " + mRequestParcel.localIPv4Address
+                    + ", staticClientAddress= " + mRequestParcel.staticClientAddress
                     + ", exemptFromEntitlementCheck= "
                     + mRequestParcel.exemptFromEntitlementCheck + ", showProvisioningUi= "
                     + mRequestParcel.showProvisioningUi + " ]";
@@ -572,18 +671,18 @@
     /**
      * Callback for use with {@link #startTethering} to find out whether tethering succeeded.
      */
-    public abstract static class StartTetheringCallback {
+    public interface StartTetheringCallback {
         /**
          * Called when tethering has been successfully started.
          */
-        public void onTetheringStarted() {}
+        default void onTetheringStarted() {}
 
         /**
          * Called when starting tethering failed.
          *
-         * @param resultCode One of the {@code TETHER_ERROR_*} constants.
+         * @param error The error that caused the failure.
          */
-        public void onTetheringFailed(final int resultCode) {}
+        default void onTetheringFailed(@StartTetheringError final int error) {}
     }
 
     /**
@@ -654,7 +753,7 @@
             android.Manifest.permission.TETHER_PRIVILEGED,
             android.Manifest.permission.WRITE_SETTINGS
     })
-    public void stopTethering(final int type) {
+    public void stopTethering(@TetheringType final int type) {
         final String callerPkg = mContext.getOpPackageName();
         Log.i(TAG, "stopTethering caller:" + callerPkg);
 
@@ -679,10 +778,10 @@
          *
          * @param resultCode an int value of entitlement result. It may be one of
          *         {@link #TETHER_ERROR_NO_ERROR},
-         *         {@link #TETHER_ERROR_PROVISION_FAILED}, or
+         *         {@link #TETHER_ERROR_PROVISIONING_FAILED}, or
          *         {@link #TETHER_ERROR_ENTITLEMENT_UNKNOWN}.
          */
-        void onTetheringEntitlementResult(int resultCode);
+        void onTetheringEntitlementResult(@EntitlementResult int result);
     }
 
     /**
@@ -697,7 +796,8 @@
      * fail if a tethering entitlement check is required.
      *
      * @param type the downstream type of tethering. Must be one of {@code #TETHERING_*} constants.
-     * @param showEntitlementUi a boolean indicating whether to run UI-based entitlement check.
+     * @param showEntitlementUi a boolean indicating whether to check result for the UI-based
+     *         entitlement check or the silent entitlement check.
      * @param executor the executor on which callback will be invoked.
      * @param listener an {@link OnTetheringEntitlementResultListener} which will be called to
      *         notify the caller of the result of entitlement check. The listener may be called zero
@@ -707,7 +807,8 @@
             android.Manifest.permission.TETHER_PRIVILEGED,
             android.Manifest.permission.WRITE_SETTINGS
     })
-    public void requestLatestTetheringEntitlementResult(int type, boolean showEntitlementUi,
+    public void requestLatestTetheringEntitlementResult(@TetheringType int type,
+            boolean showEntitlementUi,
             @NonNull Executor executor,
             @NonNull final OnTetheringEntitlementResultListener listener) {
         if (listener == null) {
@@ -736,7 +837,7 @@
      */
     // TODO: improve the usage of ResultReceiver, b/145096122
     @SystemApi(client = MODULE_LIBRARIES)
-    public void requestLatestTetheringEntitlementResult(final int type,
+    public void requestLatestTetheringEntitlementResult(@TetheringType final int type,
             @NonNull final ResultReceiver receiver, final boolean showEntitlementUi) {
         final String callerPkg = mContext.getOpPackageName();
         Log.i(TAG, "getLatestTetheringEntitlementResult caller:" + callerPkg);
@@ -749,7 +850,7 @@
      * Callback for use with {@link registerTetheringEventCallback} to find out tethering
      * upstream status.
      */
-    public abstract static class TetheringEventCallback {
+    public interface TetheringEventCallback {
         /**
          * Called when tethering supported status changed.
          *
@@ -761,7 +862,7 @@
          *
          * @param supported The new supported status
          */
-        public void onTetheringSupported(boolean supported) {}
+        default void onTetheringSupported(boolean supported) {}
 
         /**
          * Called when tethering upstream changed.
@@ -772,7 +873,7 @@
          * @param network the {@link Network} of tethering upstream. Null means tethering doesn't
          * have any upstream.
          */
-        public void onUpstreamChanged(@Nullable Network network) {}
+        default void onUpstreamChanged(@Nullable Network network) {}
 
         /**
          * Called when there was a change in tethering interface regular expressions.
@@ -780,28 +881,30 @@
          * <p>This will be called immediately after the callback is registered, and may be called
          * multiple times later upon changes.
          * @param reg The new regular expressions.
-         * @deprecated Referencing interfaces by regular expressions is a deprecated mechanism.
+         *
+         * @hide
          */
-        @Deprecated
-        public void onTetherableInterfaceRegexpsChanged(@NonNull TetheringInterfaceRegexps reg) {}
+        @SystemApi(client = MODULE_LIBRARIES)
+        default void onTetherableInterfaceRegexpsChanged(@NonNull TetheringInterfaceRegexps reg) {}
 
         /**
-         * Called when there was a change in the list of tetherable interfaces.
+         * Called when there was a change in the list of tetherable interfaces. Tetherable
+         * interface means this interface is available and can be used for tethering.
          *
          * <p>This will be called immediately after the callback is registered, and may be called
          * multiple times later upon changes.
-         * @param interfaces The list of tetherable interfaces.
+         * @param interfaces The list of tetherable interface names.
          */
-        public void onTetherableInterfacesChanged(@NonNull List<String> interfaces) {}
+        default void onTetherableInterfacesChanged(@NonNull List<String> interfaces) {}
 
         /**
          * Called when there was a change in the list of tethered interfaces.
          *
          * <p>This will be called immediately after the callback is registered, and may be called
          * multiple times later upon changes.
-         * @param interfaces The list of tethered interfaces.
+         * @param interfaces The list of 0 or more String of currently tethered interface names.
          */
-        public void onTetheredInterfacesChanged(@NonNull List<String> interfaces) {}
+        default void onTetheredInterfacesChanged(@NonNull List<String> interfaces) {}
 
         /**
          * Called when an error occurred configuring tethering.
@@ -811,7 +914,7 @@
          * @param ifName Name of the interface.
          * @param error One of {@code TetheringManager#TETHER_ERROR_*}.
          */
-        public void onError(@NonNull String ifName, int error) {}
+        default void onError(@NonNull String ifName, @TetheringIfaceError int error) {}
 
         /**
          * Called when the list of tethered clients changes.
@@ -824,7 +927,7 @@
          * determine if they are still connected.
          * @param clients The new set of tethered clients; the collection is not ordered.
          */
-        public void onClientsChanged(@NonNull Collection<TetheredClient> clients) {}
+        default void onClientsChanged(@NonNull Collection<TetheredClient> clients) {}
 
         /**
          * Called when tethering offload status changes.
@@ -832,19 +935,20 @@
          * <p>This will be called immediately after the callback is registered.
          * @param status The offload status.
          */
-        public void onOffloadStatusChanged(@TetherOffloadStatus int status) {}
+        default void onOffloadStatusChanged(@TetherOffloadStatus int status) {}
     }
 
     /**
      * Regular expressions used to identify tethering interfaces.
-     * @deprecated Referencing interfaces by regular expressions is a deprecated mechanism.
+     * @hide
      */
-    @Deprecated
+    @SystemApi(client = MODULE_LIBRARIES)
     public static class TetheringInterfaceRegexps {
         private final String[] mTetherableBluetoothRegexs;
         private final String[] mTetherableUsbRegexs;
         private final String[] mTetherableWifiRegexs;
 
+        /** @hide */
         public TetheringInterfaceRegexps(@NonNull String[] tetherableBluetoothRegexs,
                 @NonNull String[] tetherableUsbRegexs, @NonNull String[] tetherableWifiRegexs) {
             mTetherableBluetoothRegexs = tetherableBluetoothRegexs.clone();
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl
index bf19d85..c0280d3 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl
@@ -25,6 +25,7 @@
 parcelable TetheringRequestParcel {
     int tetheringType;
     LinkAddress localIPv4Address;
+    LinkAddress staticClientAddress;
     boolean exemptFromEntitlementCheck;
     boolean showProvisioningUi;
 }
diff --git a/packages/Tethering/res/values-mcc204-mnc04/strings.xml b/packages/Tethering/res/values-mcc204-mnc04/strings.xml
new file mode 100644
index 0000000..6bc2e2a
--- /dev/null
+++ b/packages/Tethering/res/values-mcc204-mnc04/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <!-- String for no upstream notification title [CHAR LIMIT=200] -->
+    <string name="no_upstream_notification_title">Tethering &amp; Mobile Hotspot has no internet access</string>
+
+    <!-- String for cellular roaming notification title [CHAR LIMIT=200]  -->
+    <string name="upstream_roaming_notification_title">Roaming</string>
+    <!-- String for cellular roaming notification message [CHAR LIMIT=500]  -->
+    <string name="upstream_roaming_notification_message">You will be charged on a per MB basis for all data sent or received while using this service outside the Verizon Network. Please check our website for current international rates. To minimize charges, visit My Verizon periodically to monitor your usage, check your device settings to confirm which devices are connected, and consider using alternate data connections when available</string>
+    <!-- String for cellular roaming notification continue button [CHAR LIMIT=200]  -->
+    <string name="upstream_roaming_notification_continue_button">Continue</string>
+</resources>
\ No newline at end of file
diff --git a/packages/Tethering/res/values-mcc310-mnc004/strings.xml b/packages/Tethering/res/values-mcc310-mnc004/strings.xml
new file mode 100644
index 0000000..6bc2e2a
--- /dev/null
+++ b/packages/Tethering/res/values-mcc310-mnc004/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <!-- String for no upstream notification title [CHAR LIMIT=200] -->
+    <string name="no_upstream_notification_title">Tethering &amp; Mobile Hotspot has no internet access</string>
+
+    <!-- String for cellular roaming notification title [CHAR LIMIT=200]  -->
+    <string name="upstream_roaming_notification_title">Roaming</string>
+    <!-- String for cellular roaming notification message [CHAR LIMIT=500]  -->
+    <string name="upstream_roaming_notification_message">You will be charged on a per MB basis for all data sent or received while using this service outside the Verizon Network. Please check our website for current international rates. To minimize charges, visit My Verizon periodically to monitor your usage, check your device settings to confirm which devices are connected, and consider using alternate data connections when available</string>
+    <!-- String for cellular roaming notification continue button [CHAR LIMIT=200]  -->
+    <string name="upstream_roaming_notification_continue_button">Continue</string>
+</resources>
\ No newline at end of file
diff --git a/packages/Tethering/res/values-mcc311-mnc480/strings.xml b/packages/Tethering/res/values-mcc311-mnc480/strings.xml
new file mode 100644
index 0000000..6bc2e2a
--- /dev/null
+++ b/packages/Tethering/res/values-mcc311-mnc480/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <!-- String for no upstream notification title [CHAR LIMIT=200] -->
+    <string name="no_upstream_notification_title">Tethering &amp; Mobile Hotspot has no internet access</string>
+
+    <!-- String for cellular roaming notification title [CHAR LIMIT=200]  -->
+    <string name="upstream_roaming_notification_title">Roaming</string>
+    <!-- String for cellular roaming notification message [CHAR LIMIT=500]  -->
+    <string name="upstream_roaming_notification_message">You will be charged on a per MB basis for all data sent or received while using this service outside the Verizon Network. Please check our website for current international rates. To minimize charges, visit My Verizon periodically to monitor your usage, check your device settings to confirm which devices are connected, and consider using alternate data connections when available</string>
+    <!-- String for cellular roaming notification continue button [CHAR LIMIT=200]  -->
+    <string name="upstream_roaming_notification_continue_button">Continue</string>
+</resources>
\ No newline at end of file
diff --git a/packages/Tethering/res/values/strings.xml b/packages/Tethering/res/values/strings.xml
index ba98a66..d50884b 100644
--- a/packages/Tethering/res/values/strings.xml
+++ b/packages/Tethering/res/values/strings.xml
@@ -32,4 +32,14 @@
     Internet" settings page. That is currently the tether_settings_title_all string. -->
     <!-- String for tether notification channel name [CHAR LIMIT=200] -->
     <string name="notification_channel_tethering_status">Hotspot &amp; tethering status</string>
+
+    <!-- String for no upstream notification title [CHAR LIMIT=200] -->
+    <string name="no_upstream_notification_title"></string>
+
+    <!-- String for cellular roaming notification title [CHAR LIMIT=200]  -->
+    <string name="upstream_roaming_notification_title"></string>
+    <!-- String for cellular roaming notification message [CHAR LIMIT=500]  -->
+    <string name="upstream_roaming_notification_message"></string>
+    <!-- String for cellular roaming notification continue button [CHAR LIMIT=200]  -->
+    <string name="upstream_roaming_notification_continue_button"></string>
 </resources>
\ No newline at end of file
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index 6c0c432..c5478d2 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -35,6 +35,7 @@
 import android.net.RouteInfo;
 import android.net.TetheredClient;
 import android.net.TetheringManager;
+import android.net.TetheringRequestParcel;
 import android.net.dhcp.DhcpLeaseParcelable;
 import android.net.dhcp.DhcpServerCallbacks;
 import android.net.dhcp.DhcpServingParamsParcel;
@@ -243,6 +244,10 @@
     private IDhcpServer mDhcpServer;
     private RaParams mLastRaParams;
     private LinkAddress mIpv4Address;
+
+    private LinkAddress mStaticIpv4ServerAddr;
+    private LinkAddress mStaticIpv4ClientAddr;
+
     @NonNull
     private List<TetheredClient> mDhcpLeases = Collections.emptyList();
 
@@ -547,6 +552,8 @@
         // into calls to InterfaceController, shared with startIPv4().
         mInterfaceCtrl.clearIPv4Address();
         mIpv4Address = null;
+        mStaticIpv4ServerAddr = null;
+        mStaticIpv4ClientAddr = null;
     }
 
     private boolean configureIPv4(boolean enabled) {
@@ -557,7 +564,10 @@
         final Inet4Address srvAddr;
         int prefixLen = 0;
         try {
-            if (mInterfaceType == TetheringManager.TETHERING_USB
+            if (mStaticIpv4ServerAddr != null) {
+                srvAddr = (Inet4Address) mStaticIpv4ServerAddr.getAddress();
+                prefixLen = mStaticIpv4ServerAddr.getPrefixLength();
+            } else if (mInterfaceType == TetheringManager.TETHERING_USB
                     || mInterfaceType == TetheringManager.TETHERING_NCM) {
                 srvAddr = (Inet4Address) parseNumericAddress(USB_NEAR_IFACE_ADDR);
                 prefixLen = USB_PREFIX_LENGTH;
@@ -602,10 +612,6 @@
             return false;
         }
 
-        if (!configureDhcp(enabled, srvAddr, prefixLen)) {
-            return false;
-        }
-
         // Directly-connected route.
         final IpPrefix ipv4Prefix = new IpPrefix(mIpv4Address.getAddress(),
                 mIpv4Address.getPrefixLength());
@@ -617,7 +623,8 @@
             mLinkProperties.removeLinkAddress(mIpv4Address);
             mLinkProperties.removeRoute(route);
         }
-        return true;
+
+        return configureDhcp(enabled, srvAddr, prefixLen);
     }
 
     private String getRandomWifiIPv4Address() {
@@ -937,6 +944,13 @@
         mLinkProperties.setInterfaceName(mIfaceName);
     }
 
+    private void maybeConfigureStaticIp(final TetheringRequestParcel request) {
+        if (request == null) return;
+
+        mStaticIpv4ServerAddr = request.localIPv4Address;
+        mStaticIpv4ClientAddr = request.staticClientAddress;
+    }
+
     class InitialState extends State {
         @Override
         public void enter() {
@@ -951,9 +965,11 @@
                     mLastError = TetheringManager.TETHER_ERROR_NO_ERROR;
                     switch (message.arg1) {
                         case STATE_LOCAL_ONLY:
+                            maybeConfigureStaticIp((TetheringRequestParcel) message.obj);
                             transitionTo(mLocalHotspotState);
                             break;
                         case STATE_TETHERED:
+                            maybeConfigureStaticIp((TetheringRequestParcel) message.obj);
                             transitionTo(mTetheredState);
                             break;
                         default:
@@ -1038,7 +1054,7 @@
                 case CMD_START_TETHERING_ERROR:
                 case CMD_STOP_TETHERING_ERROR:
                 case CMD_SET_DNS_FORWARDERS_ERROR:
-                    mLastError = TetheringManager.TETHER_ERROR_MASTER_ERROR;
+                    mLastError = TetheringManager.TETHER_ERROR_INTERNAL_ERROR;
                     transitionTo(mInitialState);
                     break;
                 default:
@@ -1169,7 +1185,7 @@
                         } catch (RemoteException | ServiceSpecificException e) {
                             mLog.e("Exception enabling NAT: " + e.toString());
                             cleanupUpstream();
-                            mLastError = TetheringManager.TETHER_ERROR_ENABLE_NAT_ERROR;
+                            mLastError = TetheringManager.TETHER_ERROR_ENABLE_FORWARDING_ERROR;
                             transitionTo(mInitialState);
                             return true;
                         }
diff --git a/packages/Tethering/src/android/net/util/TetheringUtils.java b/packages/Tethering/src/android/net/util/TetheringUtils.java
index 5a6d5c1..dd67ddd 100644
--- a/packages/Tethering/src/android/net/util/TetheringUtils.java
+++ b/packages/Tethering/src/android/net/util/TetheringUtils.java
@@ -15,8 +15,11 @@
  */
 package android.net.util;
 
+import android.net.TetheringRequestParcel;
+
 import java.io.FileDescriptor;
 import java.net.SocketException;
+import java.util.Objects;
 
 /**
  * Native methods for tethering utilization.
@@ -38,4 +41,17 @@
     public static int uint16(short s) {
         return s & 0xffff;
     }
+
+    /** Check whether two TetheringRequestParcels are the same. */
+    public static boolean isTetheringRequestEquals(final TetheringRequestParcel request,
+            final TetheringRequestParcel otherRequest) {
+        if (request == otherRequest) return true;
+
+        return request != null && otherRequest != null
+                && request.tetheringType == otherRequest.tetheringType
+                && Objects.equals(request.localIPv4Address, otherRequest.localIPv4Address)
+                && Objects.equals(request.staticClientAddress, otherRequest.staticClientAddress)
+                && request.exemptFromEntitlementCheck == otherRequest.exemptFromEntitlementCheck
+                && request.showProvisioningUi == otherRequest.showProvisioningUi;
+    }
 }
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
index e81d6ac..bd60594f 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
@@ -25,7 +25,7 @@
 import static android.net.TetheringManager.TETHERING_WIFI;
 import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN;
 import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
-import static android.net.TetheringManager.TETHER_ERROR_PROVISION_FAILED;
+import static android.net.TetheringManager.TETHER_ERROR_PROVISIONING_FAILED;
 
 import android.app.AlarmManager;
 import android.app.PendingIntent;
@@ -579,7 +579,7 @@
         switch (value) {
             case TETHER_ERROR_ENTITLEMENT_UNKNOWN: return "TETHER_ERROR_ENTITLEMENT_UNKONWN";
             case TETHER_ERROR_NO_ERROR: return "TETHER_ERROR_NO_ERROR";
-            case TETHER_ERROR_PROVISION_FAILED: return "TETHER_ERROR_PROVISION_FAILED";
+            case TETHER_ERROR_PROVISIONING_FAILED: return "TETHER_ERROR_PROVISIONING_FAILED";
             default:
                 return String.format("UNKNOWN ERROR (%d)", value);
         }
@@ -592,7 +592,7 @@
             protected void onReceiveResult(int resultCode, Bundle resultData) {
                 int updatedCacheValue = updateEntitlementCacheValue(type, resultCode);
                 addDownstreamMapping(type, updatedCacheValue);
-                if (updatedCacheValue == TETHER_ERROR_PROVISION_FAILED && notifyFail) {
+                if (updatedCacheValue == TETHER_ERROR_PROVISIONING_FAILED && notifyFail) {
                     mListener.onUiEntitlementFailed(type);
                 }
                 if (receiver != null) receiver.send(updatedCacheValue, null);
@@ -635,8 +635,8 @@
             mEntitlementCacheValue.put(type, resultCode);
             return resultCode;
         } else {
-            mEntitlementCacheValue.put(type, TETHER_ERROR_PROVISION_FAILED);
-            return TETHER_ERROR_PROVISION_FAILED;
+            mEntitlementCacheValue.put(type, TETHER_ERROR_PROVISIONING_FAILED);
+            return TETHER_ERROR_PROVISIONING_FAILED;
         }
     }
 
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index 3d8dbab..8e2d4f4 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -39,11 +39,12 @@
 import static android.net.TetheringManager.TETHERING_USB;
 import static android.net.TetheringManager.TETHERING_WIFI;
 import static android.net.TetheringManager.TETHERING_WIFI_P2P;
-import static android.net.TetheringManager.TETHER_ERROR_MASTER_ERROR;
+import static android.net.TetheringManager.TETHER_ERROR_INTERNAL_ERROR;
 import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
 import static android.net.TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL;
 import static android.net.TetheringManager.TETHER_ERROR_UNAVAIL_IFACE;
 import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_IFACE;
+import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_TYPE;
 import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED;
 import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED;
 import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED;
@@ -92,6 +93,7 @@
 import android.net.util.InterfaceSet;
 import android.net.util.PrefixUtils;
 import android.net.util.SharedLog;
+import android.net.util.TetheringUtils;
 import android.net.util.VersionedBroadcastListener;
 import android.net.wifi.WifiClient;
 import android.net.wifi.WifiManager;
@@ -196,6 +198,11 @@
     private final SharedLog mLog = new SharedLog(TAG);
     private final RemoteCallbackList<ITetheringEventCallback> mTetheringEventCallbacks =
             new RemoteCallbackList<>();
+    // Currently active tethering requests per tethering type. Only one of each type can be
+    // requested at a time. After a tethering type is requested, the map keeps tethering parameters
+    // to be used after the interface comes up asynchronously.
+    private final SparseArray<TetheringRequestParcel> mActiveTetheringRequests =
+            new SparseArray<>();
 
     // used to synchronize public access to members
     private final Object mPublicSync;
@@ -487,14 +494,31 @@
     }
 
     void startTethering(final TetheringRequestParcel request, final IIntResultListener listener) {
-        mEntitlementMgr.startProvisioningIfNeeded(request.tetheringType,
-                request.showProvisioningUi);
-        enableTetheringInternal(request.tetheringType, true /* enabled */, listener);
+        mHandler.post(() -> {
+            final TetheringRequestParcel unfinishedRequest = mActiveTetheringRequests.get(
+                    request.tetheringType);
+            // If tethering is already enabled with a different request,
+            // disable before re-enabling.
+            if (unfinishedRequest != null
+                    && !TetheringUtils.isTetheringRequestEquals(unfinishedRequest, request)) {
+                enableTetheringInternal(request.tetheringType, false /* disabled */, null);
+                mEntitlementMgr.stopProvisioningIfNeeded(request.tetheringType);
+            }
+            mActiveTetheringRequests.put(request.tetheringType, request);
+
+            mEntitlementMgr.startProvisioningIfNeeded(request.tetheringType,
+                    request.showProvisioningUi);
+            enableTetheringInternal(request.tetheringType, true /* enabled */, listener);
+        });
     }
 
     void stopTethering(int type) {
-        enableTetheringInternal(type, false /* disabled */, null);
-        mEntitlementMgr.stopProvisioningIfNeeded(type);
+        mHandler.post(() -> {
+            mActiveTetheringRequests.remove(type);
+
+            enableTetheringInternal(type, false /* disabled */, null);
+            mEntitlementMgr.stopProvisioningIfNeeded(type);
+        });
     }
 
     /**
@@ -503,39 +527,45 @@
      */
     private void enableTetheringInternal(int type, boolean enable,
             final IIntResultListener listener) {
-        int result;
+        int result = TETHER_ERROR_NO_ERROR;
         switch (type) {
             case TETHERING_WIFI:
                 result = setWifiTethering(enable);
-                sendTetherResult(listener, result);
                 break;
             case TETHERING_USB:
                 result = setUsbTethering(enable);
-                sendTetherResult(listener, result);
                 break;
             case TETHERING_BLUETOOTH:
                 setBluetoothTethering(enable, listener);
                 break;
             case TETHERING_NCM:
                 result = setNcmTethering(enable);
-                sendTetherResult(listener, result);
                 break;
             case TETHERING_ETHERNET:
                 result = setEthernetTethering(enable);
-                sendTetherResult(listener, result);
                 break;
             default:
                 Log.w(TAG, "Invalid tether type.");
-                sendTetherResult(listener, TETHER_ERROR_UNKNOWN_IFACE);
+                result = TETHER_ERROR_UNKNOWN_TYPE;
+        }
+
+        // The result of Bluetooth tethering will be sent by #setBluetoothTethering.
+        if (type != TETHERING_BLUETOOTH) {
+            sendTetherResult(listener, result, type);
         }
     }
 
-    private void sendTetherResult(final IIntResultListener listener, int result) {
+    private void sendTetherResult(final IIntResultListener listener, final int result,
+            final int type) {
         if (listener != null) {
             try {
                 listener.onResult(result);
             } catch (RemoteException e) { }
         }
+
+        // If changing tethering fail, remove corresponding request
+        // no matter who trigger the start/stop.
+        if (result != TETHER_ERROR_NO_ERROR) mActiveTetheringRequests.remove(type);
     }
 
     private int setWifiTethering(final boolean enable) {
@@ -557,7 +587,7 @@
             Binder.restoreCallingIdentity(ident);
         }
 
-        return TETHER_ERROR_MASTER_ERROR;
+        return TETHER_ERROR_INTERNAL_ERROR;
     }
 
     private void setBluetoothTethering(final boolean enable, final IIntResultListener listener) {
@@ -565,7 +595,7 @@
         if (adapter == null || !adapter.isEnabled()) {
             Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: "
                     + (adapter == null));
-            sendTetherResult(listener, TETHER_ERROR_SERVICE_UNAVAIL);
+            sendTetherResult(listener, TETHER_ERROR_SERVICE_UNAVAIL, TETHERING_BLUETOOTH);
             return;
         }
 
@@ -593,8 +623,8 @@
                 // We should figure out a way to bubble up that failure instead of sending success.
                 final int result = (((BluetoothPan) proxy).isTetheringOn() == enable)
                         ? TETHER_ERROR_NO_ERROR
-                        : TETHER_ERROR_MASTER_ERROR;
-                sendTetherResult(listener, result);
+                        : TETHER_ERROR_INTERNAL_ERROR;
+                sendTetherResult(listener, result, TETHERING_BLUETOOTH);
                 adapter.closeProfileProxy(BluetoothProfile.PAN, proxy);
             }
         }, BluetoothProfile.PAN);
@@ -672,12 +702,18 @@
                 Log.e(TAG, "Tried to Tether an unavailable iface: " + iface + ", ignoring");
                 return TETHER_ERROR_UNAVAIL_IFACE;
             }
-            // NOTE: If a CMD_TETHER_REQUESTED message is already in the TISM's
-            // queue but not yet processed, this will be a no-op and it will not
-            // return an error.
+            // NOTE: If a CMD_TETHER_REQUESTED message is already in the TISM's queue but not yet
+            // processed, this will be a no-op and it will not return an error.
             //
-            // TODO: reexamine the threading and messaging model.
-            tetherState.ipServer.sendMessage(IpServer.CMD_TETHER_REQUESTED, requestedState);
+            // This code cannot race with untether() because they both synchronize on mPublicSync.
+            // TODO: reexamine the threading and messaging model to totally remove mPublicSync.
+            final int type = tetherState.ipServer.interfaceType();
+            final TetheringRequestParcel request = mActiveTetheringRequests.get(type, null);
+            if (request != null) {
+                mActiveTetheringRequests.delete(type);
+            }
+            tetherState.ipServer.sendMessage(IpServer.CMD_TETHER_REQUESTED, requestedState, 0,
+                    request);
             return TETHER_ERROR_NO_ERROR;
         }
     }
@@ -2145,7 +2181,7 @@
         // If TetherMasterSM is in ErrorState, TetherMasterSM stays there.
         // Thus we give a chance for TetherMasterSM to recover to InitialState
         // by sending CMD_CLEAR_ERROR
-        if (error == TETHER_ERROR_MASTER_ERROR) {
+        if (error == TETHER_ERROR_INTERNAL_ERROR) {
             mTetherMasterSM.sendMessage(TetherMasterSM.CMD_CLEAR_ERROR, who);
         }
         int which;
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
index 020b32a..c5329d8 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
@@ -33,6 +33,7 @@
 import android.net.ITetheringEventCallback;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
+import android.net.NetworkStack;
 import android.net.TetheringRequestParcel;
 import android.net.dhcp.DhcpServerCallbacks;
 import android.net.dhcp.DhcpServingParamsParcel;
@@ -364,8 +365,7 @@
                     IBinder connector;
                     try {
                         final long before = System.currentTimeMillis();
-                        while ((connector = (IBinder) mContext.getSystemService(
-                                Context.NETWORK_STACK_SERVICE)) == null) {
+                        while ((connector = NetworkStack.getService()) == null) {
                             if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) {
                                 Log.wtf(TAG, "Timeout, fail to get INetworkStackConnector");
                                 return null;
diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 948266d..3106e0e 100644
--- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -21,7 +21,7 @@
 import static android.net.TetheringManager.TETHERING_USB;
 import static android.net.TetheringManager.TETHERING_WIFI;
 import static android.net.TetheringManager.TETHERING_WIFI_P2P;
-import static android.net.TetheringManager.TETHER_ERROR_ENABLE_NAT_ERROR;
+import static android.net.TetheringManager.TETHER_ERROR_ENABLE_FORWARDING_ERROR;
 import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
 import static android.net.TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR;
 import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
@@ -448,7 +448,7 @@
         usbTeardownOrder.verify(mNetd, times(2)).interfaceSetCfg(
                 argThat(cfg -> IFACE_NAME.equals(cfg.ifName)));
         usbTeardownOrder.verify(mCallback).updateInterfaceState(
-                mIpServer, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR);
+                mIpServer, STATE_AVAILABLE, TETHER_ERROR_ENABLE_FORWARDING_ERROR);
         usbTeardownOrder.verify(mCallback).updateLinkProperties(
                 eq(mIpServer), mLinkPropertiesCaptor.capture());
         assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
diff --git a/packages/Tethering/tests/unit/src/android/net/util/TetheringUtilsTest.java b/packages/Tethering/tests/unit/src/android/net/util/TetheringUtilsTest.java
new file mode 100644
index 0000000..1499f3b
--- /dev/null
+++ b/packages/Tethering/tests/unit/src/android/net/util/TetheringUtilsTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.net.util;
+
+import static android.net.TetheringManager.TETHERING_USB;
+import static android.net.TetheringManager.TETHERING_WIFI;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.net.LinkAddress;
+import android.net.TetheringRequestParcel;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.MiscAssertsKt;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class TetheringUtilsTest {
+    private static final LinkAddress TEST_SERVER_ADDR = new LinkAddress("192.168.43.1/24");
+    private static final LinkAddress TEST_CLIENT_ADDR = new LinkAddress("192.168.43.5/24");
+    private TetheringRequestParcel mTetheringRequest;
+
+    @Before
+    public void setUp() {
+        mTetheringRequest = makeTetheringRequestParcel();
+    }
+
+    public TetheringRequestParcel makeTetheringRequestParcel() {
+        final TetheringRequestParcel request = new TetheringRequestParcel();
+        request.tetheringType = TETHERING_WIFI;
+        request.localIPv4Address = TEST_SERVER_ADDR;
+        request.staticClientAddress = TEST_CLIENT_ADDR;
+        request.exemptFromEntitlementCheck = false;
+        request.showProvisioningUi = true;
+        return request;
+    }
+
+    @Test
+    public void testIsTetheringRequestEquals() throws Exception {
+        TetheringRequestParcel request = makeTetheringRequestParcel();
+
+        assertTrue(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, mTetheringRequest));
+        assertTrue(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, request));
+        assertTrue(TetheringUtils.isTetheringRequestEquals(null, null));
+        assertFalse(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, null));
+        assertFalse(TetheringUtils.isTetheringRequestEquals(null, mTetheringRequest));
+
+        request = makeTetheringRequestParcel();
+        request.tetheringType = TETHERING_USB;
+        assertFalse(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, request));
+
+        request = makeTetheringRequestParcel();
+        request.localIPv4Address = null;
+        request.staticClientAddress = null;
+        assertFalse(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, request));
+
+        request = makeTetheringRequestParcel();
+        request.exemptFromEntitlementCheck = true;
+        assertFalse(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, request));
+
+        request = makeTetheringRequestParcel();
+        request.showProvisioningUi = false;
+        assertFalse(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, request));
+
+        MiscAssertsKt.assertFieldCountEquals(5, TetheringRequestParcel.class);
+    }
+}
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
index 3a1d4a6..0a7850b 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
@@ -21,7 +21,7 @@
 import static android.net.TetheringManager.TETHERING_WIFI;
 import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN;
 import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
-import static android.net.TetheringManager.TETHER_ERROR_PROVISION_FAILED;
+import static android.net.TetheringManager.TETHER_ERROR_PROVISIONING_FAILED;
 import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY;
 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
@@ -284,11 +284,11 @@
         assertEquals(0, mEnMgr.uiProvisionCount);
         mEnMgr.reset();
         // 3. No cache value and ui entitlement check is needed.
-        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED;
         receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
-                assertEquals(TETHER_ERROR_PROVISION_FAILED, resultCode);
+                assertEquals(TETHER_ERROR_PROVISIONING_FAILED, resultCode);
                 mCallbacklatch.countDown();
             }
         };
@@ -297,12 +297,13 @@
         callbackTimeoutHelper(mCallbacklatch);
         assertEquals(1, mEnMgr.uiProvisionCount);
         mEnMgr.reset();
-        // 4. Cache value is TETHER_ERROR_PROVISION_FAILED and don't need to run entitlement check.
+        // 4. Cache value is TETHER_ERROR_PROVISIONING_FAILED and don't need to run entitlement
+        // check.
         mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
         receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
-                assertEquals(TETHER_ERROR_PROVISION_FAILED, resultCode);
+                assertEquals(TETHER_ERROR_PROVISIONING_FAILED, resultCode);
                 mCallbacklatch.countDown();
             }
         };
@@ -311,7 +312,7 @@
         callbackTimeoutHelper(mCallbacklatch);
         assertEquals(0, mEnMgr.uiProvisionCount);
         mEnMgr.reset();
-        // 5. Cache value is TETHER_ERROR_PROVISION_FAILED and ui entitlement check is needed.
+        // 5. Cache value is TETHER_ERROR_PROVISIONING_FAILED and ui entitlement check is needed.
         mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
         receiver = new ResultReceiver(null) {
             @Override
@@ -364,7 +365,7 @@
     public void verifyPermissionResult() {
         setupForRequiredProvisioning();
         mEnMgr.notifyUpstream(true);
-        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED;
         mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
         mLooper.dispatchAll();
         assertFalse(mEnMgr.isCellularUpstreamPermitted());
@@ -380,15 +381,15 @@
     public void verifyPermissionIfAllNotApproved() {
         setupForRequiredProvisioning();
         mEnMgr.notifyUpstream(true);
-        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED;
         mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
         mLooper.dispatchAll();
         assertFalse(mEnMgr.isCellularUpstreamPermitted());
-        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED;
         mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
         mLooper.dispatchAll();
         assertFalse(mEnMgr.isCellularUpstreamPermitted());
-        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED;
         mEnMgr.startProvisioningIfNeeded(TETHERING_BLUETOOTH, true);
         mLooper.dispatchAll();
         assertFalse(mEnMgr.isCellularUpstreamPermitted());
@@ -403,7 +404,7 @@
         mLooper.dispatchAll();
         assertTrue(mEnMgr.isCellularUpstreamPermitted());
         mLooper.dispatchAll();
-        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED;
         mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
         mLooper.dispatchAll();
         assertTrue(mEnMgr.isCellularUpstreamPermitted());
@@ -465,7 +466,7 @@
         assertEquals(0, mEnMgr.silentProvisionCount);
         mEnMgr.reset();
         // 6. switch upstream back to mobile again
-        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED;
         mEnMgr.notifyUpstream(true);
         mLooper.dispatchAll();
         assertEquals(0, mEnMgr.uiProvisionCount);
@@ -477,7 +478,7 @@
     public void testCallStopTetheringWhenUiProvisioningFail() {
         setupForRequiredProvisioning();
         verify(mEntitlementFailedListener, times(0)).onUiEntitlementFailed(TETHERING_WIFI);
-        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED;
         mEnMgr.notifyUpstream(true);
         mLooper.dispatchAll();
         mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
index 820c852..60d7ad1 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
@@ -82,6 +82,7 @@
 import android.net.ConnectivityManager;
 import android.net.EthernetManager;
 import android.net.EthernetManager.TetheredInterfaceRequest;
+import android.net.IIntResultListener;
 import android.net.INetd;
 import android.net.ITetheringEventCallback;
 import android.net.InetAddresses;
@@ -499,10 +500,16 @@
         return new Tethering(mTetheringDependencies);
     }
 
-    private TetheringRequestParcel createTetheringRquestParcel(final int type) {
+    private TetheringRequestParcel createTetheringRequestParcel(final int type) {
+        return createTetheringRequestParcel(type, null, null);
+    }
+
+    private TetheringRequestParcel createTetheringRequestParcel(final int type,
+            final LinkAddress serverAddr, final LinkAddress clientAddr) {
         final TetheringRequestParcel request = new TetheringRequestParcel();
         request.tetheringType = type;
-        request.localIPv4Address = null;
+        request.localIPv4Address = serverAddr;
+        request.staticClientAddress = clientAddr;
         request.exemptFromEntitlementCheck = false;
         request.showProvisioningUi = false;
 
@@ -616,7 +623,7 @@
 
     private void prepareNcmTethering() {
         // Emulate startTethering(TETHERING_NCM) called
-        mTethering.startTethering(createTetheringRquestParcel(TETHERING_NCM), null);
+        mTethering.startTethering(createTetheringRequestParcel(TETHERING_NCM), null);
         mLooper.dispatchAll();
         verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_NCM);
 
@@ -629,7 +636,7 @@
                 .thenReturn(upstreamState);
 
         // Emulate pressing the USB tethering button in Settings UI.
-        mTethering.startTethering(createTetheringRquestParcel(TETHERING_USB), null);
+        mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB), null);
         mLooper.dispatchAll();
         verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
 
@@ -903,7 +910,7 @@
         when(mWifiManager.startTetheredHotspot(any(SoftApConfiguration.class))).thenReturn(true);
 
         // Emulate pressing the WiFi tethering button.
-        mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null);
+        mTethering.startTethering(createTetheringRequestParcel(TETHERING_WIFI), null);
         mLooper.dispatchAll();
         verify(mWifiManager, times(1)).startTetheredHotspot(null);
         verifyNoMoreInteractions(mWifiManager);
@@ -931,7 +938,7 @@
         when(mWifiManager.startTetheredHotspot(any(SoftApConfiguration.class))).thenReturn(true);
 
         // Emulate pressing the WiFi tethering button.
-        mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null);
+        mTethering.startTethering(createTetheringRequestParcel(TETHERING_WIFI), null);
         mLooper.dispatchAll();
         verify(mWifiManager, times(1)).startTetheredHotspot(null);
         verifyNoMoreInteractions(mWifiManager);
@@ -1008,7 +1015,7 @@
         doThrow(new RemoteException()).when(mNetd).ipfwdEnableForwarding(TETHERING_NAME);
 
         // Emulate pressing the WiFi tethering button.
-        mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null);
+        mTethering.startTethering(createTetheringRequestParcel(TETHERING_WIFI), null);
         mLooper.dispatchAll();
         verify(mWifiManager, times(1)).startTetheredHotspot(null);
         verifyNoMoreInteractions(mWifiManager);
@@ -1303,7 +1310,7 @@
         tetherState = callback.pollTetherStatesChanged();
         assertArrayEquals(tetherState.availableList, new String[] {TEST_WLAN_IFNAME});
 
-        mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null);
+        mTethering.startTethering(createTetheringRequestParcel(TETHERING_WIFI), null);
         sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
         mLooper.dispatchAll();
         tetherState = callback.pollTetherStatesChanged();
@@ -1398,10 +1405,10 @@
     public void testNoDuplicatedEthernetRequest() throws Exception {
         final TetheredInterfaceRequest mockRequest = mock(TetheredInterfaceRequest.class);
         when(mEm.requestTetheredInterface(any(), any())).thenReturn(mockRequest);
-        mTethering.startTethering(createTetheringRquestParcel(TETHERING_ETHERNET), null);
+        mTethering.startTethering(createTetheringRequestParcel(TETHERING_ETHERNET), null);
         mLooper.dispatchAll();
         verify(mEm, times(1)).requestTetheredInterface(any(), any());
-        mTethering.startTethering(createTetheringRquestParcel(TETHERING_ETHERNET), null);
+        mTethering.startTethering(createTetheringRequestParcel(TETHERING_ETHERNET), null);
         mLooper.dispatchAll();
         verifyNoMoreInteractions(mEm);
         mTethering.stopTethering(TETHERING_ETHERNET);
@@ -1580,6 +1587,86 @@
         assertTrue(element + " not found in " + collection, collection.contains(element));
     }
 
+    private class ResultListener extends IIntResultListener.Stub {
+        private final int mExpectedResult;
+        private boolean mHasResult = false;
+        ResultListener(final int expectedResult) {
+            mExpectedResult = expectedResult;
+        }
+
+        @Override
+        public void onResult(final int resultCode) {
+            mHasResult = true;
+            if (resultCode != mExpectedResult) {
+                fail("expected result: " + mExpectedResult + " but actual result: " + resultCode);
+            }
+        }
+
+        public void assertHasResult() {
+            if (!mHasResult) fail("No callback result");
+        }
+    }
+
+    @Test
+    public void testMultipleStartTethering() throws Exception {
+        final LinkAddress serverLinkAddr = new LinkAddress("192.168.20.1/24");
+        final LinkAddress clientLinkAddr = new LinkAddress("192.168.20.42/24");
+        final String serverAddr = "192.168.20.1";
+        final ResultListener firstResult = new ResultListener(TETHER_ERROR_NO_ERROR);
+        final ResultListener secondResult = new ResultListener(TETHER_ERROR_NO_ERROR);
+        final ResultListener thirdResult = new ResultListener(TETHER_ERROR_NO_ERROR);
+
+        // Enable USB tethering and check that Tethering starts USB.
+        mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB,
+                  null, null), firstResult);
+        mLooper.dispatchAll();
+        firstResult.assertHasResult();
+        verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
+        verifyNoMoreInteractions(mUsbManager);
+
+        // Enable USB tethering again with the same request and expect no change to USB.
+        mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB,
+                  null, null), secondResult);
+        mLooper.dispatchAll();
+        secondResult.assertHasResult();
+        verify(mUsbManager, never()).setCurrentFunctions(UsbManager.FUNCTION_NONE);
+        reset(mUsbManager);
+
+        // Enable USB tethering with a different request and expect that USB is stopped and
+        // started.
+        mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB,
+                  serverLinkAddr, clientLinkAddr), thirdResult);
+        mLooper.dispatchAll();
+        thirdResult.assertHasResult();
+        verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_NONE);
+        verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
+
+        // Expect that when USB comes up, the DHCP server is configured with the requested address.
+        mTethering.interfaceStatusChanged(TEST_USB_IFNAME, true);
+        sendUsbBroadcast(true, true, true, TETHERING_USB);
+        mLooper.dispatchAll();
+        verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks(
+                any(), any());
+        verify(mNetd).interfaceSetCfg(argThat(cfg -> serverAddr.equals(cfg.ipv4Addr)));
+    }
+
+    @Test
+    public void testRequestStaticServerIp() throws Exception {
+        final LinkAddress serverLinkAddr = new LinkAddress("192.168.20.1/24");
+        final LinkAddress clientLinkAddr = new LinkAddress("192.168.20.42/24");
+        final String serverAddr = "192.168.20.1";
+        mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB,
+                  serverLinkAddr, clientLinkAddr), null);
+        mLooper.dispatchAll();
+        verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
+        mTethering.interfaceStatusChanged(TEST_USB_IFNAME, true);
+        sendUsbBroadcast(true, true, true, TETHERING_USB);
+        mLooper.dispatchAll();
+        verify(mNetd).interfaceSetCfg(argThat(cfg -> serverAddr.equals(cfg.ipv4Addr)));
+
+        // TODO: test static client address.
+    }
+
     // TODO: Test that a request for hotspot mode doesn't interfere with an
     // already operating tethering mode interface.
 }
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
index 8a4a1c6..93bffe9 100644
--- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -164,6 +164,9 @@
                 }
                 if (DEBUG) Slog.v(TAG, "Storing wallpaper metadata");
                 backupFile(infoStage, data);
+            } else {
+                Slog.w(TAG, "Wallpaper metadata file doesn't exist: " +
+                        mWallpaperFile.getPath());
             }
             if (sysEligible && mWallpaperFile.exists()) {
                 if (sysChanged || !imageStage.exists()) {
@@ -173,6 +176,10 @@
                 if (DEBUG) Slog.v(TAG, "Storing system wallpaper image");
                 backupFile(imageStage, data);
                 prefs.edit().putInt(SYSTEM_GENERATION, sysGeneration).apply();
+            } else {
+                Slog.w(TAG, "Not backing up wallpaper as one of conditions is not "
+                        + "met: sysEligible = " + sysEligible + " wallpaperFileExists = "
+                        + mWallpaperFile.exists());
             }
 
             // If there's no lock wallpaper, then we have nothing to add to the backup.
@@ -181,7 +188,7 @@
                     if (DEBUG) Slog.v(TAG, "Removed lock wallpaper; deleting");
                     lockImageStage.delete();
                 }
-                if (DEBUG) Slog.v(TAG, "No lock paper set, add nothing to backup");
+                Slog.d(TAG, "No lockscreen wallpaper set, add nothing to backup");
                 prefs.edit().putInt(LOCK_GENERATION, lockGeneration).apply();
                 return;
             }
@@ -195,6 +202,12 @@
                 if (DEBUG) Slog.v(TAG, "Storing lock wallpaper image");
                 backupFile(lockImageStage, data);
                 prefs.edit().putInt(LOCK_GENERATION, lockGeneration).apply();
+            } else {
+                Slog.w(TAG, "Not backing up lockscreen wallpaper as one of conditions is not "
+                        + "met: lockEligible = " + lockEligible + " hasLockWallpaper = "
+                        + hasLockWallpaper + " lockWallpaperFileExists = "
+                        + mLockWallpaperFile.exists() + " quotaExceeded (last time) = "
+                        + mQuotaExceeded);
             }
         } catch (Exception e) {
             Slog.e(TAG, "Unable to back up wallpaper", e);
@@ -216,9 +229,7 @@
 
     @Override
     public void onQuotaExceeded(long backupDataBytes, long quotaBytes) {
-        if (DEBUG) {
-            Slog.i(TAG, "Quota exceeded (" + backupDataBytes + " vs " + quotaBytes + ')');
-        }
+        Slog.i(TAG, "Quota exceeded (" + backupDataBytes + " vs " + quotaBytes + ')');
         try (FileOutputStream f = new FileOutputStream(mQuotaFile)) {
             f.write(0);
         } catch (Exception e) {
@@ -230,9 +241,7 @@
     // then post-process in onRestoreFinished() to apply the new wallpaper.
     @Override
     public void onRestoreFinished() {
-        if (DEBUG) {
-            Slog.v(TAG, "onRestoreFinished()");
-        }
+        Slog.v(TAG, "onRestoreFinished()");
         final File filesDir = getFilesDir();
         final File infoStage = new File(filesDir, INFO_STAGE);
         final File imageStage = new File (filesDir, IMAGE_STAGE);
@@ -253,9 +262,7 @@
             // And reset to the wallpaper service we should be using
             ComponentName wpService = parseWallpaperComponent(infoStage, "wp");
             if (servicePackageExists(wpService)) {
-                if (DEBUG) {
-                    Slog.i(TAG, "Using wallpaper service " + wpService);
-                }
+                Slog.i(TAG, "Using wallpaper service " + wpService);
                 mWm.setWallpaperComponent(wpService, UserHandle.USER_SYSTEM);
                 if (!lockImageStage.exists()) {
                     // We have a live wallpaper and no static lock image,
@@ -273,9 +280,7 @@
         } catch (Exception e) {
             Slog.e(TAG, "Unable to restore wallpaper: " + e.getMessage());
         } finally {
-            if (DEBUG) {
-                Slog.v(TAG, "Restore finished; clearing backup bookkeeping");
-            }
+            Slog.v(TAG, "Restore finished; clearing backup bookkeeping");
             infoStage.delete();
             imageStage.delete();
             lockImageStage.delete();
@@ -295,14 +300,14 @@
             // relies on a priori knowledge of the wallpaper info file schema.
             Rect cropHint = parseCropHint(info, hintTag);
             if (cropHint != null) {
-                Slog.i(TAG, "Got restored wallpaper; applying which=" + which);
-                if (DEBUG) {
-                    Slog.v(TAG, "Restored crop hint " + cropHint);
-                }
+                Slog.i(TAG, "Got restored wallpaper; applying which=" + which
+                        + "; cropHint = " + cropHint);
                 try (FileInputStream in = new FileInputStream(stage)) {
                     mWm.setStream(in, cropHint.isEmpty() ? null : cropHint, true, which);
                 } finally {} // auto-closes 'in'
             }
+        } else {
+            Slog.d(TAG, "Restore data doesn't exist for file " + stage.getPath());
         }
     }
 
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index ad21075..260703d 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -3647,10 +3647,12 @@
     }
 
     private void updateAppOpsLocked(Host host, boolean visible) {
-        // The launcher must be at TOP.
-        final int procState = mActivityManagerInternal.getUidProcessState(host.id.uid);
-        if (procState > ActivityManager.PROCESS_STATE_TOP) {
-            return;
+        if (visible) {
+            final int procState = mActivityManagerInternal.getUidProcessState(host.id.uid);
+            if (procState > ActivityManager.PROCESS_STATE_TOP) {
+                // The launcher must be at TOP.
+                return;
+            }
         }
 
         final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index 53afa6e..b4b0641 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -37,7 +37,6 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.service.autofill.Dataset;
-import android.service.autofill.InlineAction;
 import android.service.autofill.augmented.AugmentedAutofillService;
 import android.service.autofill.augmented.IAugmentedAutofillService;
 import android.service.autofill.augmented.IFillCallback;
@@ -167,12 +166,12 @@
                             focusedId, focusedValue, requestTime, inlineSuggestionsRequest,
                             new IFillCallback.Stub() {
                                 @Override
-                                public void onSuccess(@Nullable List<Dataset> inlineSuggestionsData,
-                                        @Nullable List<InlineAction> inlineActions) {
+                                public void onSuccess(
+                                        @Nullable List<Dataset> inlineSuggestionsData) {
                                     mCallbacks.resetLastResponse();
                                     maybeRequestShowInlineSuggestions(sessionId,
                                             inlineSuggestionsRequest, inlineSuggestionsData,
-                                            inlineActions, focusedId, inlineSuggestionsCallback,
+                                            focusedId, inlineSuggestionsCallback,
                                             client, onErrorCallback, remoteRenderService);
                                     requestAutofill.complete(null);
                                 }
@@ -237,8 +236,7 @@
 
     private void maybeRequestShowInlineSuggestions(int sessionId,
             @Nullable InlineSuggestionsRequest request,
-            @Nullable List<Dataset> inlineSuggestionsData,
-            @Nullable List<InlineAction> inlineActions, @NonNull AutofillId focusedId,
+            @Nullable List<Dataset> inlineSuggestionsData, @NonNull AutofillId focusedId,
             @Nullable Function<InlineSuggestionsResponse, Boolean> inlineSuggestionsCallback,
             @NonNull IAutoFillManagerClient client, @NonNull Runnable onErrorCallback,
             @Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
@@ -251,7 +249,7 @@
 
         final InlineSuggestionsResponse inlineSuggestionsResponse =
                 InlineSuggestionFactory.createAugmentedInlineSuggestionsResponse(
-                        request, inlineSuggestionsData, inlineActions, focusedId,
+                        request, inlineSuggestionsData, focusedId,
                         dataset -> {
                             mCallbacks.logAugmentedAutofillSelected(sessionId,
                                     dataset.getId());
@@ -260,8 +258,13 @@
                                 final int size = fieldIds.size();
                                 final boolean hideHighlight = size == 1
                                         && fieldIds.get(0).equals(focusedId);
-                                client.autofill(sessionId, fieldIds, dataset.getFieldValues(),
-                                        hideHighlight);
+                                if (dataset.getAuthentication() != null) {
+                                    client.startIntentSender(dataset.getAuthentication(),
+                                            new Intent());
+                                } else {
+                                    client.autofill(sessionId, fieldIds, dataset.getFieldValues(),
+                                            hideHighlight);
+                                }
                             } catch (RemoteException e) {
                                 Slog.w(TAG, "Encounter exception autofilling the values");
                             }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index de31118..8032e9b 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -311,6 +311,10 @@
      */
     private final AssistDataReceiverImpl mAssistReceiver = new AssistDataReceiverImpl();
 
+    /**
+     * TODO(b/151867668): improve how asynchronous data dependencies are handled, without using
+     * CountDownLatch.
+     */
     private final class AssistDataReceiverImpl extends IAssistDataReceiver.Stub {
 
         @GuardedBy("mLock")
@@ -318,7 +322,7 @@
         @GuardedBy("mLock")
         private FillRequest mPendingFillRequest;
         @GuardedBy("mLock")
-        private CountDownLatch mCountDownLatch;
+        private CountDownLatch mCountDownLatch = new CountDownLatch(0);
 
         @Nullable Consumer<InlineSuggestionsRequest> newAutofillRequestLocked(
                 boolean isInlineRequest) {
@@ -327,6 +331,9 @@
             mPendingInlineSuggestionsRequest = null;
             return isInlineRequest ? (inlineSuggestionsRequest) -> {
                 synchronized (mLock) {
+                    if (mCountDownLatch.getCount() == 0) {
+                        return;
+                    }
                     mPendingInlineSuggestionsRequest = inlineSuggestionsRequest;
                     mCountDownLatch.countDown();
                     maybeRequestFillLocked();
@@ -335,8 +342,7 @@
         }
 
         void maybeRequestFillLocked() {
-            if (mCountDownLatch == null || mCountDownLatch.getCount() > 0
-                    || mPendingFillRequest == null) {
+            if (mCountDownLatch.getCount() > 0 || mPendingFillRequest == null) {
                 return;
             }
             if (mPendingInlineSuggestionsRequest != null) {
@@ -347,7 +353,6 @@
             mRemoteFillService.onFillRequest(mPendingFillRequest);
             mPendingInlineSuggestionsRequest = null;
             mPendingFillRequest = null;
-            mCountDownLatch = null;
         }
 
         @Override
@@ -447,9 +452,15 @@
                 request = new FillRequest(requestId, contexts, mClientState, flags,
                         /*inlineSuggestionsRequest=*/null);
 
-                mPendingFillRequest = request;
-                mCountDownLatch.countDown();
-                maybeRequestFillLocked();
+                if (mCountDownLatch.getCount() > 0) {
+                    mPendingFillRequest = request;
+                    mCountDownLatch.countDown();
+                    maybeRequestFillLocked();
+                } else {
+                    // TODO(b/151867668): ideally this case should not happen, but it was
+                    //  observed, we should figure out why and fix.
+                    mRemoteFillService.onFillRequest(request);
+                }
             }
 
             if (mActivityToken != null) {
@@ -2726,8 +2737,7 @@
 
         InlineSuggestionsResponse inlineSuggestionsResponse =
                 InlineSuggestionFactory.createInlineSuggestionsResponse(
-                        inlineSuggestionsRequest.get(),
-                        response, filterText, response.getInlineActions(), mCurrentViewId,
+                        inlineSuggestionsRequest.get(), response, filterText, mCurrentViewId,
                         this, () -> {
                             synchronized (mLock) {
                                 mInlineSuggestionSession.hideInlineSuggestionsUi(mCurrentViewId);
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
index 0ca9dd9..71d4ace 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
@@ -21,13 +21,11 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.IntentSender;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.service.autofill.Dataset;
 import android.service.autofill.FillResponse;
 import android.service.autofill.IInlineSuggestionUiCallback;
-import android.service.autofill.InlineAction;
 import android.service.autofill.InlinePresentation;
 import android.text.TextUtils;
 import android.util.Slog;
@@ -73,8 +71,7 @@
     @Nullable
     public static InlineSuggestionsResponse createInlineSuggestionsResponse(
             @NonNull InlineSuggestionsRequest request, @NonNull FillResponse response,
-            @Nullable String filterText, @Nullable List<InlineAction> inlineActions,
-            @NonNull AutofillId autofillId,
+            @Nullable String filterText, @NonNull AutofillId autofillId,
             @NonNull AutoFillUI.AutoFillUiCallback client, @NonNull Runnable onErrorCallback,
             @Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
         if (sDebug) Slog.d(TAG, "createInlineSuggestionsResponse called");
@@ -96,7 +93,7 @@
         final InlinePresentation inlineAuthentication =
                 response.getAuthentication() == null ? null : response.getInlinePresentation();
         return createInlineSuggestionsResponseInternal(/* isAugmented= */ false, request,
-                response.getDatasets(), filterText, inlineAuthentication, inlineActions, autofillId,
+                response.getDatasets(), filterText, inlineAuthentication, autofillId,
                 onErrorCallback, onClickFactory, remoteRenderService);
     }
 
@@ -107,15 +104,14 @@
     @Nullable
     public static InlineSuggestionsResponse createAugmentedInlineSuggestionsResponse(
             @NonNull InlineSuggestionsRequest request, @NonNull List<Dataset> datasets,
-            @Nullable List<InlineAction> inlineActions, @NonNull AutofillId autofillId,
+            @NonNull AutofillId autofillId,
             @NonNull InlineSuggestionUiCallback inlineSuggestionUiCallback,
             @NonNull Runnable onErrorCallback,
             @Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
         if (sDebug) Slog.d(TAG, "createAugmentedInlineSuggestionsResponse called");
         return createInlineSuggestionsResponseInternal(/* isAugmented= */ true, request,
                 datasets, /* filterText= */ null, /* inlineAuthentication= */ null,
-                inlineActions, autofillId, onErrorCallback,
-                (dataset, datasetIndex) ->
+                autofillId, onErrorCallback, (dataset, datasetIndex) ->
                         inlineSuggestionUiCallback.autofill(dataset), remoteRenderService);
     }
 
@@ -123,8 +119,7 @@
     private static InlineSuggestionsResponse createInlineSuggestionsResponseInternal(
             boolean isAugmented, @NonNull InlineSuggestionsRequest request,
             @Nullable List<Dataset> datasets, @Nullable String filterText,
-            @Nullable InlinePresentation inlineAuthentication,
-            @Nullable List<InlineAction> inlineActions, @NonNull AutofillId autofillId,
+            @Nullable InlinePresentation inlineAuthentication, @NonNull AutofillId autofillId,
             @NonNull Runnable onErrorCallback, @NonNull BiConsumer<Dataset, Integer> onClickFactory,
             @Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
 
@@ -167,16 +162,6 @@
 
             inlineSuggestions.add(inlineSuggestion);
         }
-        if (inlineActions != null) {
-            for (InlineAction inlineAction : inlineActions) {
-                final InlineSuggestion inlineActionSuggestion = createInlineAction(isAugmented,
-                        mergedInlinePresentation(request, 0, inlineAction.getInlinePresentation()),
-                        inlineAction.getAction(),
-                        remoteRenderService, onErrorCallback, request.getHostInputToken(),
-                        request.getHostDisplayId());
-                inlineSuggestions.add(inlineActionSuggestion);
-            }
-        }
         return new InlineSuggestionsResponse(inlineSuggestions);
     }
 
@@ -211,35 +196,6 @@
         return valueText.toLowerCase().startsWith(constraintLowerCase);
     }
 
-
-    private static InlineSuggestion createInlineAction(boolean isAugmented,
-            @NonNull InlinePresentation presentation,
-            @NonNull IntentSender action,
-            @Nullable RemoteInlineSuggestionRenderService remoteRenderService,
-            @NonNull Runnable onErrorCallback, @Nullable IBinder hostInputToken,
-            int displayId) {
-        final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo(
-                presentation.getInlinePresentationSpec(),
-                isAugmented ? InlineSuggestionInfo.SOURCE_PLATFORM
-                        : InlineSuggestionInfo.SOURCE_AUTOFILL,
-                presentation.getAutofillHints(), InlineSuggestionInfo.TYPE_ACTION,
-                presentation.isPinned());
-        final Runnable onClickAction = () -> {
-            try {
-                // TODO(b/150499490): route the intent to the client app to have it fired there,
-                //  so that it will appear as a part of the same task as the client app (similar
-                //  to the authentication flow).
-                action.sendIntent(null, 0, null, null, null);
-            } catch (IntentSender.SendIntentException e) {
-                onErrorCallback.run();
-                Slog.w(TAG, "Error sending inline action intent");
-            }
-        };
-        return new InlineSuggestion(inlineSuggestionInfo,
-                createInlineContentProvider(presentation, onClickAction, onErrorCallback,
-                        remoteRenderService, hostInputToken, displayId));
-    }
-
     private static InlineSuggestion createInlineSuggestion(boolean isAugmented,
             @NonNull Dataset dataset, int datasetIndex,
             @NonNull InlinePresentation inlinePresentation,
@@ -247,12 +203,15 @@
             @NonNull RemoteInlineSuggestionRenderService remoteRenderService,
             @NonNull Runnable onErrorCallback, @Nullable IBinder hostInputToken,
             int displayId) {
+        final String suggestionSource = isAugmented ? InlineSuggestionInfo.SOURCE_PLATFORM
+                : InlineSuggestionInfo.SOURCE_AUTOFILL;
+        final String suggestionType =
+                dataset.getAuthentication() == null ? InlineSuggestionInfo.TYPE_SUGGESTION
+                        : InlineSuggestionInfo.TYPE_ACTION;
         final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo(
-                inlinePresentation.getInlinePresentationSpec(),
-                isAugmented ? InlineSuggestionInfo.SOURCE_PLATFORM
-                        : InlineSuggestionInfo.SOURCE_AUTOFILL,
-                inlinePresentation.getAutofillHints(),
-                InlineSuggestionInfo.TYPE_SUGGESTION, inlinePresentation.isPinned());
+                inlinePresentation.getInlinePresentationSpec(), suggestionSource,
+                inlinePresentation.getAutofillHints(), suggestionType,
+                inlinePresentation.isPinned());
 
         final InlineSuggestion inlineSuggestion = new InlineSuggestion(inlineSuggestionInfo,
                 createInlineContentProvider(inlinePresentation,
@@ -270,7 +229,7 @@
         final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo(
                 inlinePresentation.getInlinePresentationSpec(),
                 InlineSuggestionInfo.SOURCE_AUTOFILL, inlinePresentation.getAutofillHints(),
-                InlineSuggestionInfo.TYPE_SUGGESTION, inlinePresentation.isPinned());
+                InlineSuggestionInfo.TYPE_ACTION, inlinePresentation.isPinned());
 
         return new InlineSuggestion(inlineSuggestionInfo,
                 createInlineContentProvider(inlinePresentation,
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 9fddafb..7d85966 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -66,7 +66,6 @@
     public static final int PACKAGE_CONFIGURATOR = 9;
     public static final int PACKAGE_INCIDENT_REPORT_APPROVER = 10;
     public static final int PACKAGE_APP_PREDICTOR = 11;
-    public static final int PACKAGE_TELEPHONY = 12;
     public static final int PACKAGE_WIFI = 13;
     public static final int PACKAGE_COMPANION = 14;
     public static final int PACKAGE_RETAIL_DEMO = 15;
@@ -124,7 +123,6 @@
         PACKAGE_CONFIGURATOR,
         PACKAGE_INCIDENT_REPORT_APPROVER,
         PACKAGE_APP_PREDICTOR,
-        PACKAGE_TELEPHONY,
         PACKAGE_WIFI,
         PACKAGE_COMPANION,
         PACKAGE_RETAIL_DEMO,
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index deae459..91dd1d5 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -110,6 +110,7 @@
 import android.net.PrivateDnsConfigParcel;
 import android.net.ProxyInfo;
 import android.net.RouteInfo;
+import android.net.RouteInfoParcel;
 import android.net.SocketKeepalive;
 import android.net.TetheringManager;
 import android.net.UidRange;
@@ -120,6 +121,7 @@
 import android.net.metrics.NetworkEvent;
 import android.net.netlink.InetDiagMessage;
 import android.net.shared.PrivateDnsConfig;
+import android.net.util.LinkPropertiesUtils.CompareOrUpdateResult;
 import android.net.util.LinkPropertiesUtils.CompareResult;
 import android.net.util.MultinetworkPolicyTracker;
 import android.net.util.NetdService;
@@ -232,6 +234,7 @@
 import java.util.StringJoiner;
 import java.util.TreeSet;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Function;
 
 /**
  * @hide
@@ -1666,7 +1669,7 @@
         if (newNc.getNetworkSpecifier() != null) {
             newNc.setNetworkSpecifier(newNc.getNetworkSpecifier().redact());
         }
-        newNc.setAdministratorUids(Collections.EMPTY_LIST);
+        newNc.setAdministratorUids(new int[0]);
 
         return newNc;
     }
@@ -1710,7 +1713,7 @@
         }
 
         if (checkSettingsPermission(callerPid, callerUid)) {
-            return lp.makeSensitiveFieldsParcelingCopy();
+            return new LinkProperties(lp, true /* parcelSensitiveFields */);
         }
 
         final LinkProperties newLp = new LinkProperties(lp);
@@ -1727,7 +1730,7 @@
             nc.setSingleUid(callerUid);
         }
         nc.setRequestorUidAndPackageName(callerUid, callerPackageName);
-        nc.setAdministratorUids(Collections.EMPTY_LIST);
+        nc.setAdministratorUids(new int[0]);
 
         // Clear owner UID; this can never come from an app.
         nc.setOwnerUid(INVALID_UID);
@@ -2237,14 +2240,9 @@
             if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
                 final NetworkInfo ni = intent.getParcelableExtra(
                         ConnectivityManager.EXTRA_NETWORK_INFO);
-                if (ni.getType() == ConnectivityManager.TYPE_MOBILE_SUPL) {
-                    intent.setAction(ConnectivityManager.CONNECTIVITY_ACTION_SUPL);
-                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-                } else {
-                    BroadcastOptions opts = BroadcastOptions.makeBasic();
-                    opts.setMaxManifestReceiverApiLevel(Build.VERSION_CODES.M);
-                    options = opts.toBundle();
-                }
+                final BroadcastOptions opts = BroadcastOptions.makeBasic();
+                opts.setMaxManifestReceiverApiLevel(Build.VERSION_CODES.M);
+                options = opts.toBundle();
                 final IBatteryStats bs = mDeps.getBatteryStatsService();
                 try {
                     bs.noteConnectivityChanged(intent.getIntExtra(
@@ -5951,15 +5949,49 @@
         }
     }
 
+    // TODO: move to frameworks/libs/net.
+    private RouteInfoParcel convertRouteInfo(RouteInfo route) {
+        final String nextHop;
+
+        switch (route.getType()) {
+            case RouteInfo.RTN_UNICAST:
+                if (route.hasGateway()) {
+                    nextHop = route.getGateway().getHostAddress();
+                } else {
+                    nextHop = INetd.NEXTHOP_NONE;
+                }
+                break;
+            case RouteInfo.RTN_UNREACHABLE:
+                nextHop = INetd.NEXTHOP_UNREACHABLE;
+                break;
+            case RouteInfo.RTN_THROW:
+                nextHop = INetd.NEXTHOP_THROW;
+                break;
+            default:
+                nextHop = INetd.NEXTHOP_NONE;
+                break;
+        }
+
+        final RouteInfoParcel rip = new RouteInfoParcel();
+        rip.ifName = route.getInterface();
+        rip.destination = route.getDestination().toString();
+        rip.nextHop = nextHop;
+        rip.mtu = route.getMtu();
+
+        return rip;
+    }
+
     /**
      * Have netd update routes from oldLp to newLp.
      * @return true if routes changed between oldLp and newLp
      */
     private boolean updateRoutes(LinkProperties newLp, LinkProperties oldLp, int netId) {
-        // Compare the route diff to determine which routes should be added and removed.
-        CompareResult<RouteInfo> routeDiff = new CompareResult<>(
+        Function<RouteInfo, IpPrefix> getDestination = (r) -> r.getDestination();
+        // compare the route diff to determine which routes have been updated
+        CompareOrUpdateResult<IpPrefix, RouteInfo> routeDiff = new CompareOrUpdateResult<>(
                 oldLp != null ? oldLp.getAllRoutes() : null,
-                newLp != null ? newLp.getAllRoutes() : null);
+                newLp != null ? newLp.getAllRoutes() : null,
+                getDestination);
 
         // add routes before removing old in case it helps with continuous connectivity
 
@@ -5968,10 +6000,10 @@
             if (route.hasGateway()) continue;
             if (VDBG || DDBG) log("Adding Route [" + route + "] to network " + netId);
             try {
-                mNMS.addRoute(netId, route);
+                mNetd.networkAddRouteParcel(netId, convertRouteInfo(route));
             } catch (Exception e) {
                 if ((route.getDestination().getAddress() instanceof Inet4Address) || VDBG) {
-                    loge("Exception in addRoute for non-gateway: " + e);
+                    loge("Exception in networkAddRouteParcel for non-gateway: " + e);
                 }
             }
         }
@@ -5979,10 +6011,10 @@
             if (!route.hasGateway()) continue;
             if (VDBG || DDBG) log("Adding Route [" + route + "] to network " + netId);
             try {
-                mNMS.addRoute(netId, route);
+                mNetd.networkAddRouteParcel(netId, convertRouteInfo(route));
             } catch (Exception e) {
                 if ((route.getGateway() instanceof Inet4Address) || VDBG) {
-                    loge("Exception in addRoute for gateway: " + e);
+                    loge("Exception in networkAddRouteParcel for gateway: " + e);
                 }
             }
         }
@@ -5990,12 +6022,22 @@
         for (RouteInfo route : routeDiff.removed) {
             if (VDBG || DDBG) log("Removing Route [" + route + "] from network " + netId);
             try {
-                mNMS.removeRoute(netId, route);
+                mNetd.networkRemoveRouteParcel(netId, convertRouteInfo(route));
             } catch (Exception e) {
-                loge("Exception in removeRoute: " + e);
+                loge("Exception in networkRemoveRouteParcel: " + e);
             }
         }
-        return !routeDiff.added.isEmpty() || !routeDiff.removed.isEmpty();
+
+        for (RouteInfo route : routeDiff.updated) {
+            if (VDBG || DDBG) log("Updating Route [" + route + "] from network " + netId);
+            try {
+                mNetd.networkUpdateRouteParcel(netId, convertRouteInfo(route));
+            } catch (Exception e) {
+                loge("Exception in networkUpdateRouteParcel: " + e);
+            }
+        }
+        return !routeDiff.added.isEmpty() || !routeDiff.removed.isEmpty()
+                || !routeDiff.updated.isEmpty();
     }
 
     private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId) {
@@ -7864,7 +7906,7 @@
 
     private void clearNetworkCapabilitiesUids(@NonNull NetworkCapabilities nc) {
         nc.setUids(null);
-        nc.setAdministratorUids(Collections.EMPTY_LIST);
+        nc.setAdministratorUids(new int[0]);
         nc.setOwnerUid(Process.INVALID_UID);
     }
 
@@ -7911,8 +7953,9 @@
         }
 
         // Administrator UIDs also contains the Owner UID
-        if (nai.networkCapabilities.getAdministratorUids().contains(callbackUid)) {
-            return true;
+        final int[] administratorUids = nai.networkCapabilities.getAdministratorUids();
+        for (final int uid : administratorUids) {
+            if (uid == callbackUid) return true;
         }
 
         return false;
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 5a056d3..a767347 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -4139,19 +4139,6 @@
             boolean hasLegacy = mIAppOpsService.checkOperation(OP_LEGACY_STORAGE,
                     uid, packageName) == MODE_ALLOWED;
 
-            // Hack(b/147137425): we have to honor hasRequestedLegacyExternalStorage for a short
-            // while to enable 2 cases.
-            // 1) Apps that want to be in scoped storage in R, but want to opt out in Q devices,
-            // because they want to use raw file paths, would fail until fuse is enabled by default.
-            // 2) Test apps that target current sdk will fail. They would fail even after fuse is
-            // enabled, but we are fixing it with b/142395442. We are not planning to enable
-            // fuse by default until b/142395442 is fixed.
-            if (!hasLegacy && !mIsFuseEnabled) {
-                ApplicationInfo ai = mIPackageManager.getApplicationInfo(packageName,
-                        0, UserHandle.getUserId(uid));
-                hasLegacy = (ai != null && ai.hasRequestedLegacyExternalStorage());
-            }
-
             if (hasLegacy && hasWrite) {
                 return Zygote.MOUNT_EXTERNAL_WRITE;
             } else if (hasLegacy && hasRead) {
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index f772a4a..81a1372 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -53,7 +53,6 @@
 import java.net.NetworkInterface;
 import java.net.SocketException;
 import java.util.ArrayList;
-import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -250,7 +249,7 @@
         nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
         nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
         nc.setNetworkSpecifier(new StringNetworkSpecifier(iface));
-        nc.setAdministratorUids(intArrayToList(administratorUids));
+        nc.setAdministratorUids(administratorUids);
         if (!isMetered) {
             nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
         }
@@ -293,14 +292,6 @@
         return new TestNetworkAgent(looper, context, ni, nc, lp, callingUid, binder);
     }
 
-    private List<Integer> intArrayToList(@NonNull int[] array) {
-        final List<Integer> list = new ArrayList<>(array.length);
-        for (final int i : array) {
-            list.add(i);
-        }
-        return list;
-    }
-
     /**
      * Sets up a Network with extremely limited privileges, guarded by the MANAGE_TEST_NETWORKS
      * permission.
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ebca1f7..a458498 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -579,6 +579,13 @@
     static final String EXTRA_DESCRIPTION = "android.intent.extra.DESCRIPTION";
     static final String EXTRA_BUGREPORT_TYPE = "android.intent.extra.BUGREPORT_TYPE";
 
+    /**
+     * The maximum number of bytes that {@link #setProcessStateSummary} accepts.
+     *
+     * @see {@link android.app.ActivityManager#setProcessStateSummary(byte[])}
+     */
+    static final int MAX_STATE_DATA_SIZE = 128;
+
     /** All system services */
     SystemServiceManager mSystemServiceManager;
 
@@ -3202,7 +3209,7 @@
         return mAtmInternal.compatibilityInfoForPackage(ai);
     }
 
-    private void enforceNotIsolatedCaller(String caller) {
+    /* package */ void enforceNotIsolatedCaller(String caller) {
         if (UserHandle.isIsolated(Binder.getCallingUid())) {
             throw new SecurityException("Isolated process not allowed to call " + caller);
         }
@@ -3887,6 +3894,18 @@
     public static File dumpStackTraces(ArrayList<Integer> firstPids,
             ProcessCpuTracker processCpuTracker, SparseArray<Boolean> lastPids,
             ArrayList<Integer> nativePids, StringWriter logExceptionCreatingFile) {
+        return dumpStackTraces(firstPids, processCpuTracker, lastPids, nativePids,
+                logExceptionCreatingFile, null);
+    }
+
+    /**
+     * @param firstPidOffsets Optional, when it's set, it receives the start/end offset
+     *                        of the very first pid to be dumped.
+     */
+    /* package */ static File dumpStackTraces(ArrayList<Integer> firstPids,
+            ProcessCpuTracker processCpuTracker, SparseArray<Boolean> lastPids,
+            ArrayList<Integer> nativePids, StringWriter logExceptionCreatingFile,
+            long[] firstPidOffsets) {
         ArrayList<Integer> extraPids = null;
 
         Slog.i(TAG, "dumpStackTraces pids=" + lastPids + " nativepids=" + nativePids);
@@ -3938,12 +3957,22 @@
             return null;
         }
 
-        dumpStackTraces(tracesFile.getAbsolutePath(), firstPids, nativePids, extraPids);
+        Pair<Long, Long> offsets = dumpStackTraces(
+                tracesFile.getAbsolutePath(), firstPids, nativePids, extraPids);
+        if (firstPidOffsets != null) {
+            if (offsets == null) {
+                firstPidOffsets[0] = firstPidOffsets[1] = -1;
+            } else {
+                firstPidOffsets[0] = offsets.first; // Start offset to the ANR trace file
+                firstPidOffsets[1] = offsets.second; // End offset to the ANR trace file
+            }
+        }
         return tracesFile;
     }
 
     @GuardedBy("ActivityManagerService.class")
     private static SimpleDateFormat sAnrFileDateFormat;
+    static final String ANR_FILE_PREFIX = "anr_";
 
     private static synchronized File createAnrDumpFile(File tracesDir) throws IOException {
         if (sAnrFileDateFormat == null) {
@@ -3951,7 +3980,7 @@
         }
 
         final String formattedDate = sAnrFileDateFormat.format(new Date());
-        final File anrFile = new File(tracesDir, "anr_" + formattedDate);
+        final File anrFile = new File(tracesDir, ANR_FILE_PREFIX + formattedDate);
 
         if (anrFile.createNewFile()) {
             FileUtils.setPermissions(anrFile.getAbsolutePath(), 0600, -1, -1); // -rw-------
@@ -4020,7 +4049,10 @@
         return SystemClock.elapsedRealtime() - timeStart;
     }
 
-    public static void dumpStackTraces(String tracesFile, ArrayList<Integer> firstPids,
+    /**
+     * @return The start/end offset of the trace of the very first PID
+     */
+    public static Pair<Long, Long> dumpStackTraces(String tracesFile, ArrayList<Integer> firstPids,
             ArrayList<Integer> nativePids, ArrayList<Integer> extraPids) {
 
         Slog.i(TAG, "Dumping to " + tracesFile);
@@ -4032,21 +4064,39 @@
         // We must complete all stack dumps within 20 seconds.
         long remainingTime = 20 * 1000;
 
+        // As applications are usually interested with the ANR stack traces, but we can't share with
+        // them the stack traces other than their own stacks. So after the very first PID is
+        // dumped, remember the current file size.
+        long firstPidStart = -1;
+        long firstPidEnd = -1;
+
         // First collect all of the stacks of the most important pids.
         if (firstPids != null) {
             int num = firstPids.size();
             for (int i = 0; i < num; i++) {
-                Slog.i(TAG, "Collecting stacks for pid " + firstPids.get(i));
-                final long timeTaken = dumpJavaTracesTombstoned(firstPids.get(i), tracesFile,
+                final int pid = firstPids.get(i);
+                // We don't copy ANR traces from the system_server intentionally.
+                final boolean firstPid = i == 0 && MY_PID != pid;
+                File tf = null;
+                if (firstPid) {
+                    tf = new File(tracesFile);
+                    firstPidStart = tf.exists() ? tf.length() : 0;
+                }
+
+                Slog.i(TAG, "Collecting stacks for pid " + pid);
+                final long timeTaken = dumpJavaTracesTombstoned(pid, tracesFile,
                                                                 remainingTime);
 
                 remainingTime -= timeTaken;
                 if (remainingTime <= 0) {
-                    Slog.e(TAG, "Aborting stack trace dump (current firstPid=" + firstPids.get(i) +
-                           "); deadline exceeded.");
-                    return;
+                    Slog.e(TAG, "Aborting stack trace dump (current firstPid=" + pid
+                            + "); deadline exceeded.");
+                    return firstPidStart >= 0 ? new Pair<>(firstPidStart, firstPidEnd) : null;
                 }
 
+                if (firstPid) {
+                    firstPidEnd = tf.length();
+                }
                 if (DEBUG_ANR) {
                     Slog.d(TAG, "Done with pid " + firstPids.get(i) + " in " + timeTaken + "ms");
                 }
@@ -4068,7 +4118,7 @@
                 if (remainingTime <= 0) {
                     Slog.e(TAG, "Aborting stack trace dump (current native pid=" + pid +
                         "); deadline exceeded.");
-                    return;
+                    return firstPidStart >= 0 ? new Pair<>(firstPidStart, firstPidEnd) : null;
                 }
 
                 if (DEBUG_ANR) {
@@ -4088,7 +4138,7 @@
                 if (remainingTime <= 0) {
                     Slog.e(TAG, "Aborting stack trace dump (current extra pid=" + pid +
                             "); deadline exceeded.");
-                    return;
+                    return firstPidStart >= 0 ? new Pair<>(firstPidStart, firstPidEnd) : null;
                 }
 
                 if (DEBUG_ANR) {
@@ -4097,6 +4147,7 @@
             }
         }
         Slog.i(TAG, "Done dumping");
+        return firstPidStart >= 0 ? new Pair<>(firstPidStart, firstPidEnd) : null;
     }
 
     @Override
@@ -10280,6 +10331,15 @@
         return new ParceledListSlice<ApplicationExitInfo>(results);
     }
 
+    @Override
+    public void setProcessStateSummary(@Nullable byte[] state) {
+        if (state != null && state.length > MAX_STATE_DATA_SIZE) {
+            throw new IllegalArgumentException("Data size is too large");
+        }
+        mProcessList.mAppExitInfoTracker.setProcessStateSummary(Binder.getCallingUid(),
+                Binder.getCallingPid(), state);
+    }
+
     /**
      * Check if the calling process has the permission to dump given package,
      * throw SecurityException if it doesn't have the permission.
@@ -10287,7 +10347,7 @@
      * @return The UID of the given package, or {@link android.os.Process#INVALID_UID}
      *         if the package is not found.
      */
-    private int enforceDumpPermissionForPackage(String packageName, int userId, int callingUid,
+    int enforceDumpPermissionForPackage(String packageName, int userId, int callingUid,
             String function) {
         long identity = Binder.clearCallingIdentity();
         int uid = Process.INVALID_UID;
diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java
index 028a059..0c3d02d 100644
--- a/services/core/java/com/android/server/am/AppExitInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java
@@ -17,23 +17,31 @@
 package com.android.server.am;
 
 import static android.app.ActivityManager.RunningAppProcessInfo.procStateToImportance;
+import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
 import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
 
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 
+import android.annotation.Nullable;
 import android.app.ApplicationExitInfo;
 import android.app.ApplicationExitInfo.Reason;
 import android.app.ApplicationExitInfo.SubReason;
+import android.app.IAppTraceRetriever;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.icu.text.SimpleDateFormat;
+import android.os.Binder;
+import android.os.FileUtils;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.system.OsConstants;
@@ -52,12 +60,17 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.ProcessMap;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.IoThread;
 import com.android.server.ServiceThread;
 import com.android.server.SystemServiceManager;
 
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -68,6 +81,10 @@
 import java.util.concurrent.TimeUnit;
 import java.util.function.BiConsumer;
 import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.zip.GZIPOutputStream;
 
 /**
  * A class to manage all the {@link android.app.ApplicationExitInfo} records.
@@ -80,16 +97,21 @@
      */
     private static final long APP_EXIT_INFO_PERSIST_INTERVAL = TimeUnit.MINUTES.toMillis(30);
 
-    /** These are actions that the forEachPackage should take after each iteration */
+    /** These are actions that the forEach* should take after each iteration */
     private static final int FOREACH_ACTION_NONE = 0;
-    private static final int FOREACH_ACTION_REMOVE_PACKAGE = 1;
+    private static final int FOREACH_ACTION_REMOVE_ITEM = 1;
     private static final int FOREACH_ACTION_STOP_ITERATION = 2;
 
     private static final int APP_EXIT_RAW_INFO_POOL_SIZE = 8;
 
     @VisibleForTesting
+    static final String APP_EXIT_STORE_DIR = "procexitstore";
+
+    @VisibleForTesting
     static final String APP_EXIT_INFO_FILE = "procexitinfo";
 
+    private static final String APP_TRACE_FILE_SUFFIX = ".gz";
+
     private final Object mLock = new Object();
 
     /**
@@ -153,6 +175,13 @@
     final ArrayList<ApplicationExitInfo> mTmpInfoList2 = new ArrayList<ApplicationExitInfo>();
 
     /**
+     * The path to the directory which includes the historical proc exit info file
+     * as specified in {@link #mProcExitInfoFile}, as well as the associated trace files.
+     */
+    @VisibleForTesting
+    File mProcExitStoreDir;
+
+    /**
      * The path to the historical proc exit info file, persisted in the storage.
      */
     @VisibleForTesting
@@ -176,6 +205,35 @@
     final AppExitInfoExternalSource mAppExitInfoSourceLmkd =
             new AppExitInfoExternalSource("lmkd", ApplicationExitInfo.REASON_LOW_MEMORY);
 
+    /**
+     * The active per-UID/PID state data set by
+     * {@link android.app.ActivityManager#setProcessStateSummary};
+     * these state data are to be "claimed" when its process dies, by then the data will be moved
+     * from this list to the new instance of ApplicationExitInfo.
+     *
+     * <p> The mapping here is UID -> PID -> state </p>
+     *
+     * @see android.app.ActivityManager#setProcessStateSummary(byte[])
+     */
+    @GuardedBy("mLock")
+    final SparseArray<SparseArray<byte[]>> mActiveAppStateSummary = new SparseArray<>();
+
+    /**
+     * The active per-UID/PID trace file when an ANR occurs but the process hasn't been killed yet,
+     * each record is a path to the actual trace file;  these files are to be "claimed"
+     * when its process dies, by then the "ownership" of the files will be transferred
+     * from this list to the new instance of ApplicationExitInfo.
+     *
+     * <p> The mapping here is UID -> PID -> file </p>
+     */
+    @GuardedBy("mLock")
+    final SparseArray<SparseArray<File>> mActiveAppTraces = new SparseArray<>();
+
+    /**
+     * The implementation of the interface IAppTraceRetriever.
+     */
+    final AppTraceRetriever mAppTraceRetriever = new AppTraceRetriever();
+
     AppExitInfoTracker() {
         mData = new ProcessMap<AppExitInfoContainer>();
         mRawRecordsPool = new SynchronizedPool<ApplicationExitInfo>(APP_EXIT_RAW_INFO_POOL_SIZE);
@@ -187,7 +245,13 @@
                 THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
         thread.start();
         mKillHandler = new KillHandler(thread.getLooper());
-        mProcExitInfoFile = new File(SystemServiceManager.ensureSystemDir(), APP_EXIT_INFO_FILE);
+
+        mProcExitStoreDir = new File(SystemServiceManager.ensureSystemDir(), APP_EXIT_STORE_DIR);
+        if (!FileUtils.createDir(mProcExitStoreDir)) {
+            Slog.e(TAG, "Unable to create " + mProcExitStoreDir);
+            return;
+        }
+        mProcExitInfoFile = new File(mProcExitStoreDir, APP_EXIT_INFO_FILE);
 
         mAppExitInfoHistoryListSize = service.mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_app_exit_info_history_list_size);
@@ -304,7 +368,7 @@
                         + "(" + raw.getPid() + "/u" + raw.getRealUid() + ")");
             }
 
-            ApplicationExitInfo info = getExitInfo(raw.getPackageName(),
+            ApplicationExitInfo info = getExitInfoLocked(raw.getPackageName(),
                     raw.getPackageUid(), raw.getPid());
 
             // query zygote and lmkd to get the exit info, and clear the saved info
@@ -312,7 +376,7 @@
                     raw.getPid(), raw.getRealUid());
             Pair<Long, Object> lmkd = mAppExitInfoSourceLmkd.remove(
                     raw.getPid(), raw.getRealUid());
-            mIsolatedUidRecords.removeIsolatedUid(raw.getRealUid());
+            mIsolatedUidRecords.removeIsolatedUidLocked(raw.getRealUid());
 
             if (info == null) {
                 info = addExitInfoLocked(raw);
@@ -333,7 +397,7 @@
     @VisibleForTesting
     @GuardedBy("mLock")
     void handleNoteAppKillLocked(final ApplicationExitInfo raw) {
-        ApplicationExitInfo info = getExitInfo(
+        ApplicationExitInfo info = getExitInfoLocked(
                 raw.getPackageName(), raw.getPackageUid(), raw.getPid());
 
         if (info == null) {
@@ -359,7 +423,7 @@
         final String[] packages = raw.getPackageList();
         final int uid = raw.getPackageUid();
         for (int i = 0; i < packages.length; i++) {
-            addExitInfoInner(packages[i], uid, info);
+            addExitInfoInnerLocked(packages[i], uid, info);
         }
 
         schedulePersistProcessExitInfo(false);
@@ -400,39 +464,37 @@
      *
      * @return true if a recond is updated
      */
-    private boolean updateExitInfoIfNecessary(int pid, int uid, Integer status, Integer reason) {
-        synchronized (mLock) {
-            if (UserHandle.isIsolated(uid)) {
-                Integer k = mIsolatedUidRecords.getUidByIsolatedUid(uid);
-                if (k != null) {
-                    uid = k;
-                }
-            }
-            ArrayList<ApplicationExitInfo> tlist = mTmpInfoList;
-            tlist.clear();
-            final int targetUid = uid;
-            forEachPackage((packageName, records) -> {
-                AppExitInfoContainer container = records.get(targetUid);
-                if (container == null) {
-                    return FOREACH_ACTION_NONE;
-                }
-                tlist.clear();
-                container.getExitInfoLocked(pid, 1, tlist);
-                if (tlist.size() == 0) {
-                    return FOREACH_ACTION_NONE;
-                }
-                ApplicationExitInfo info = tlist.get(0);
-                if (info.getRealUid() != targetUid) {
-                    tlist.clear();
-                    return FOREACH_ACTION_NONE;
-                }
-                // Okay found it, update its reason.
-                updateExistingExitInfoRecordLocked(info, status, reason);
-
-                return FOREACH_ACTION_STOP_ITERATION;
-            });
-            return tlist.size() > 0;
+    @GuardedBy("mLock")
+    private boolean updateExitInfoIfNecessaryLocked(
+            int pid, int uid, Integer status, Integer reason) {
+        Integer k = mIsolatedUidRecords.getUidByIsolatedUid(uid);
+        if (k != null) {
+            uid = k;
         }
+        ArrayList<ApplicationExitInfo> tlist = mTmpInfoList;
+        tlist.clear();
+        final int targetUid = uid;
+        forEachPackageLocked((packageName, records) -> {
+            AppExitInfoContainer container = records.get(targetUid);
+            if (container == null) {
+                return FOREACH_ACTION_NONE;
+            }
+            tlist.clear();
+            container.getExitInfoLocked(pid, 1, tlist);
+            if (tlist.size() == 0) {
+                return FOREACH_ACTION_NONE;
+            }
+            ApplicationExitInfo info = tlist.get(0);
+            if (info.getRealUid() != targetUid) {
+                tlist.clear();
+                return FOREACH_ACTION_NONE;
+            }
+            // Okay found it, update its reason.
+            updateExistingExitInfoRecordLocked(info, status, reason);
+
+            return FOREACH_ACTION_STOP_ITERATION;
+        });
+        return tlist.size() > 0;
     }
 
     /**
@@ -441,38 +503,43 @@
     @VisibleForTesting
     void getExitInfo(final String packageName, final int filterUid,
             final int filterPid, final int maxNum, final ArrayList<ApplicationExitInfo> results) {
-        synchronized (mLock) {
-            boolean emptyPackageName = TextUtils.isEmpty(packageName);
-            if (!emptyPackageName) {
-                // fast path
-                AppExitInfoContainer container = mData.get(packageName, filterUid);
-                if (container != null) {
-                    container.getExitInfoLocked(filterPid, maxNum, results);
-                }
-            } else {
-                // slow path
-                final ArrayList<ApplicationExitInfo> list = mTmpInfoList2;
-                list.clear();
-                // get all packages
-                forEachPackage((name, records) -> {
-                    AppExitInfoContainer container = records.get(filterUid);
+        long identity = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                boolean emptyPackageName = TextUtils.isEmpty(packageName);
+                if (!emptyPackageName) {
+                    // fast path
+                    AppExitInfoContainer container = mData.get(packageName, filterUid);
                     if (container != null) {
-                        mTmpInfoList.clear();
-                        results.addAll(container.toListLocked(mTmpInfoList, filterPid));
+                        container.getExitInfoLocked(filterPid, maxNum, results);
                     }
-                    return AppExitInfoTracker.FOREACH_ACTION_NONE;
-                });
+                } else {
+                    // slow path
+                    final ArrayList<ApplicationExitInfo> list = mTmpInfoList2;
+                    list.clear();
+                    // get all packages
+                    forEachPackageLocked((name, records) -> {
+                        AppExitInfoContainer container = records.get(filterUid);
+                        if (container != null) {
+                            mTmpInfoList.clear();
+                            results.addAll(container.toListLocked(mTmpInfoList, filterPid));
+                        }
+                        return AppExitInfoTracker.FOREACH_ACTION_NONE;
+                    });
 
-                Collections.sort(list, (a, b) -> (int) (b.getTimestamp() - a.getTimestamp()));
-                int size = list.size();
-                if (maxNum > 0) {
-                    size = Math.min(size, maxNum);
+                    Collections.sort(list, (a, b) -> (int) (b.getTimestamp() - a.getTimestamp()));
+                    int size = list.size();
+                    if (maxNum > 0) {
+                        size = Math.min(size, maxNum);
+                    }
+                    for (int i = 0; i < size; i++) {
+                        results.add(list.get(i));
+                    }
+                    list.clear();
                 }
-                for (int i = 0; i < size; i++) {
-                    results.add(list.get(i));
-                }
-                list.clear();
             }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
         }
     }
 
@@ -480,17 +547,16 @@
      * Return the first matching exit info record, for internal use, the parameters are not supposed
      * to be empty.
      */
-    private ApplicationExitInfo getExitInfo(final String packageName,
+    @GuardedBy("mLock")
+    private ApplicationExitInfo getExitInfoLocked(final String packageName,
             final int filterUid, final int filterPid) {
-        synchronized (mLock) {
-            ArrayList<ApplicationExitInfo> list = mTmpInfoList;
-            list.clear();
-            getExitInfo(packageName, filterUid, filterPid, 1, list);
+        ArrayList<ApplicationExitInfo> list = mTmpInfoList;
+        list.clear();
+        getExitInfo(packageName, filterUid, filterPid, 1, list);
 
-            ApplicationExitInfo info = list.size() > 0 ? list.get(0) : null;
-            list.clear();
-            return info;
-        }
+        ApplicationExitInfo info = list.size() > 0 ? list.get(0) : null;
+        list.clear();
+        return info;
     }
 
     @VisibleForTesting
@@ -498,8 +564,10 @@
         mAppExitInfoSourceZygote.removeByUserId(userId);
         mAppExitInfoSourceLmkd.removeByUserId(userId);
         mIsolatedUidRecords.removeByUserId(userId);
-        removeByUserId(userId);
-        schedulePersistProcessExitInfo(true);
+        synchronized (mLock) {
+            removeByUserIdLocked(userId);
+            schedulePersistProcessExitInfo(true);
+        }
     }
 
     @VisibleForTesting
@@ -507,13 +575,16 @@
         if (packageName != null) {
             final boolean removeUid = TextUtils.isEmpty(
                     mService.mPackageManagerInt.getNameForUid(uid));
-            if (removeUid) {
-                mAppExitInfoSourceZygote.removeByUid(uid, allUsers);
-                mAppExitInfoSourceLmkd.removeByUid(uid, allUsers);
-                mIsolatedUidRecords.removeAppUid(uid, allUsers);
+            synchronized (mLock) {
+                if (removeUid) {
+                    mAppExitInfoSourceZygote.removeByUidLocked(uid, allUsers);
+                    mAppExitInfoSourceLmkd.removeByUidLocked(uid, allUsers);
+                    mIsolatedUidRecords.removeAppUid(uid, allUsers);
+                }
+                removePackageLocked(packageName, uid, removeUid,
+                        allUsers ? UserHandle.USER_ALL : UserHandle.getUserId(uid));
+                schedulePersistProcessExitInfo(true);
             }
-            removePackage(packageName, allUsers ? UserHandle.USER_ALL : UserHandle.getUserId(uid));
-            schedulePersistProcessExitInfo(true);
         }
     }
 
@@ -593,6 +664,7 @@
             }
         }
         synchronized (mLock) {
+            pruneAnrTracesIfNecessaryLocked();
             mAppExitInfoLoaded = true;
         }
     }
@@ -634,7 +706,7 @@
             ProtoOutputStream proto = new ProtoOutputStream(out);
             proto.write(AppsExitInfoProto.LAST_UPDATE_TIMESTAMP, now);
             synchronized (mLock) {
-                forEachPackage((packageName, records) -> {
+                forEachPackageLocked((packageName, records) -> {
                     long token = proto.start(AppsExitInfoProto.PACKAGES);
                     proto.write(AppsExitInfoProto.Package.PACKAGE_NAME, packageName);
                     int uidArraySize = records.size();
@@ -688,6 +760,9 @@
                 mProcExitInfoFile.delete();
             }
             mData.getMap().clear();
+            mActiveAppStateSummary.clear();
+            mActiveAppTraces.clear();
+            pruneAnrTracesIfNecessaryLocked();
         }
     }
 
@@ -695,15 +770,15 @@
      * Helper function for shell command
      */
     void clearHistoryProcessExitInfo(String packageName, int userId) {
-        synchronized (mLock) {
-            if (TextUtils.isEmpty(packageName)) {
-                if (userId == UserHandle.USER_ALL) {
-                    mData.getMap().clear();
-                } else {
-                    removeByUserId(userId);
-                }
-            } else {
-                removePackage(packageName, userId);
+        if (TextUtils.isEmpty(packageName)) {
+            synchronized (mLock) {
+                removeByUserIdLocked(userId);
+            }
+        } else {
+            final int uid = mService.mPackageManagerInt.getPackageUid(packageName,
+                    PackageManager.MATCH_ALL, userId);
+            synchronized (mLock) {
+                removePackageLocked(packageName, uid, true, userId);
             }
         }
         schedulePersistProcessExitInfo(true);
@@ -716,7 +791,7 @@
             pw.println("Last Timestamp of Persistence Into Persistent Storage: "
                     + sdf.format(new Date(mLastAppExitInfoPersistTimestamp)));
             if (TextUtils.isEmpty(packageName)) {
-                forEachPackage((name, records) -> {
+                forEachPackageLocked((name, records) -> {
                     dumpHistoryProcessExitInfoLocked(pw, "  ", name, records, sdf);
                     return AppExitInfoTracker.FOREACH_ACTION_NONE;
                 });
@@ -741,86 +816,108 @@
         }
     }
 
-    private void addExitInfoInner(String packageName, int userId, ApplicationExitInfo info) {
-        synchronized (mLock) {
-            AppExitInfoContainer container = mData.get(packageName, userId);
-            if (container == null) {
-                container = new AppExitInfoContainer(mAppExitInfoHistoryListSize);
-                if (UserHandle.isIsolated(info.getRealUid())) {
-                    Integer k = mIsolatedUidRecords.getUidByIsolatedUid(info.getRealUid());
-                    if (k != null) {
-                        container.mUid = k;
-                    }
-                } else {
-                    container.mUid = info.getRealUid();
+    @GuardedBy("mLock")
+    private void addExitInfoInnerLocked(String packageName, int userId, ApplicationExitInfo info) {
+        AppExitInfoContainer container = mData.get(packageName, userId);
+        if (container == null) {
+            container = new AppExitInfoContainer(mAppExitInfoHistoryListSize);
+            if (UserHandle.isIsolated(info.getRealUid())) {
+                Integer k = mIsolatedUidRecords.getUidByIsolatedUid(info.getRealUid());
+                if (k != null) {
+                    container.mUid = k;
                 }
-                mData.put(packageName, userId, container);
+            } else {
+                container.mUid = info.getRealUid();
             }
-            container.addExitInfoLocked(info);
+            mData.put(packageName, userId, container);
         }
+        container.addExitInfoLocked(info);
     }
 
-    private void forEachPackage(
+    @GuardedBy("mLocked")
+    private void forEachPackageLocked(
             BiFunction<String, SparseArray<AppExitInfoContainer>, Integer> callback) {
         if (callback != null) {
-            synchronized (mLock) {
-                ArrayMap<String, SparseArray<AppExitInfoContainer>> map = mData.getMap();
-                for (int i = map.size() - 1; i >= 0; i--) {
-                    switch (callback.apply(map.keyAt(i), map.valueAt(i))) {
-                        case FOREACH_ACTION_REMOVE_PACKAGE:
-                            map.removeAt(i);
-                            break;
-                        case FOREACH_ACTION_STOP_ITERATION:
-                            i = 0;
-                            break;
-                        case FOREACH_ACTION_NONE:
-                        default:
-                            break;
-                    }
-                }
-            }
-        }
-    }
-
-    private void removePackage(String packageName, int userId) {
-        synchronized (mLock) {
-            if (userId == UserHandle.USER_ALL) {
-                mData.getMap().remove(packageName);
-            } else {
-                ArrayMap<String, SparseArray<AppExitInfoContainer>> map =
-                        mData.getMap();
-                SparseArray<AppExitInfoContainer> array = map.get(packageName);
-                if (array == null) {
-                    return;
-                }
-                for (int i = array.size() - 1; i >= 0; i--) {
-                    if (UserHandle.getUserId(array.keyAt(i)) == userId) {
-                        array.removeAt(i);
+            ArrayMap<String, SparseArray<AppExitInfoContainer>> map = mData.getMap();
+            for (int i = map.size() - 1; i >= 0; i--) {
+                switch (callback.apply(map.keyAt(i), map.valueAt(i))) {
+                    case FOREACH_ACTION_REMOVE_ITEM:
+                        final SparseArray<AppExitInfoContainer> records = map.valueAt(i);
+                        for (int j = records.size() - 1; j >= 0; j--) {
+                            records.valueAt(j).destroyLocked();
+                        }
+                        map.removeAt(i);
                         break;
-                    }
-                }
-                if (array.size() == 0) {
-                    map.remove(packageName);
+                    case FOREACH_ACTION_STOP_ITERATION:
+                        i = 0;
+                        break;
+                    case FOREACH_ACTION_NONE:
+                    default:
+                        break;
                 }
             }
         }
     }
 
-    private void removeByUserId(final int userId) {
-        if (userId == UserHandle.USER_ALL) {
-            synchronized (mLock) {
-                mData.getMap().clear();
+    @GuardedBy("mLocked")
+    private void removePackageLocked(String packageName, int uid, boolean removeUid, int userId) {
+        if (removeUid) {
+            mActiveAppStateSummary.remove(uid);
+            final int idx = mActiveAppTraces.indexOfKey(uid);
+            if (idx >= 0) {
+                final SparseArray<File> array = mActiveAppTraces.valueAt(idx);
+                for (int i = array.size() - 1; i >= 0; i--) {
+                    array.valueAt(i).delete();
+                }
+                mActiveAppTraces.removeAt(idx);
             }
+        }
+        ArrayMap<String, SparseArray<AppExitInfoContainer>> map = mData.getMap();
+        SparseArray<AppExitInfoContainer> array = map.get(packageName);
+        if (array == null) {
             return;
         }
-        forEachPackage((packageName, records) -> {
+        if (userId == UserHandle.USER_ALL) {
+            for (int i = array.size() - 1; i >= 0; i--) {
+                array.valueAt(i).destroyLocked();
+            }
+            mData.getMap().remove(packageName);
+        } else {
+            for (int i = array.size() - 1; i >= 0; i--) {
+                if (UserHandle.getUserId(array.keyAt(i)) == userId) {
+                    array.valueAt(i).destroyLocked();
+                    array.removeAt(i);
+                    break;
+                }
+            }
+            if (array.size() == 0) {
+                map.remove(packageName);
+            }
+        }
+    }
+
+    @GuardedBy("mLocked")
+    private void removeByUserIdLocked(final int userId) {
+        if (userId == UserHandle.USER_ALL) {
+            mData.getMap().clear();
+            mActiveAppStateSummary.clear();
+            mActiveAppTraces.clear();
+            pruneAnrTracesIfNecessaryLocked();
+            return;
+        }
+        removeFromSparse2dArray(mActiveAppStateSummary,
+                (v) -> UserHandle.getUserId(v) == userId, null, null);
+        removeFromSparse2dArray(mActiveAppTraces,
+                (v) -> UserHandle.getUserId(v) == userId, null, (v) -> v.delete());
+        forEachPackageLocked((packageName, records) -> {
             for (int i = records.size() - 1; i >= 0; i--) {
                 if (UserHandle.getUserId(records.keyAt(i)) == userId) {
+                    records.valueAt(i).destroyLocked();
                     records.removeAt(i);
                     break;
                 }
             }
-            return records.size() == 0 ? FOREACH_ACTION_REMOVE_PACKAGE : FOREACH_ACTION_NONE;
+            return records.size() == 0 ? FOREACH_ACTION_REMOVE_ITEM : FOREACH_ACTION_NONE;
         });
     }
 
@@ -862,6 +959,262 @@
     }
 
     /**
+     * Called from {@link ActivityManagerService#setProcessStateSummary}.
+     */
+    @VisibleForTesting
+    void setProcessStateSummary(int uid, final int pid, final byte[] data) {
+        synchronized (mLock) {
+            Integer k = mIsolatedUidRecords.getUidByIsolatedUid(uid);
+            if (k != null) {
+                uid = k;
+            }
+            putToSparse2dArray(mActiveAppStateSummary, uid, pid, data, SparseArray::new, null);
+        }
+    }
+
+    @VisibleForTesting
+    @Nullable byte[] getProcessStateSummary(int uid, final int pid) {
+        synchronized (mLock) {
+            Integer k = mIsolatedUidRecords.getUidByIsolatedUid(uid);
+            if (k != null) {
+                uid = k;
+            }
+            int index = mActiveAppStateSummary.indexOfKey(uid);
+            if (index < 0) {
+                return null;
+            }
+            return mActiveAppStateSummary.valueAt(index).get(pid);
+        }
+    }
+
+    /**
+     * Called from ProcessRecord when an ANR occurred and the ANR trace is taken.
+     */
+    void scheduleLogAnrTrace(final int pid, final int uid, final String[] packageList,
+            final File traceFile, final long startOff, final long endOff) {
+        mKillHandler.sendMessage(PooledLambda.obtainMessage(
+                this::handleLogAnrTrace, pid, uid, packageList,
+                traceFile, startOff, endOff));
+    }
+
+    /**
+     * Copy and compress the given ANR trace file
+     */
+    @VisibleForTesting
+    void handleLogAnrTrace(final int pid, int uid, final String[] packageList,
+            final File traceFile, final long startOff, final long endOff) {
+        if (!traceFile.exists() || ArrayUtils.isEmpty(packageList)) {
+            return;
+        }
+        final long size = traceFile.length();
+        final long length = endOff - startOff;
+        if (startOff >= size || endOff > size || length <= 0) {
+            return;
+        }
+
+        final File outFile = new File(mProcExitStoreDir, traceFile.getName()
+                + APP_TRACE_FILE_SUFFIX);
+        // Copy & compress
+        if (copyToGzFile(traceFile, outFile, startOff, length)) {
+            // Wrote successfully.
+            synchronized (mLock) {
+                Integer k = mIsolatedUidRecords.getUidByIsolatedUid(uid);
+                if (k != null) {
+                    uid = k;
+                }
+                if (DEBUG_PROCESSES) {
+                    Slog.i(TAG, "Stored ANR traces of " + pid + "/u" + uid + " in " + outFile);
+                }
+                boolean pending = true;
+                // Unlikely but possible: the app has died
+                for (int i = 0; i < packageList.length; i++) {
+                    final AppExitInfoContainer container = mData.get(packageList[i], uid);
+                    // Try to see if we could append this trace to an existing record
+                    if (container != null && container.appendTraceIfNecessaryLocked(pid, outFile)) {
+                        // Okay someone took it
+                        pending = false;
+                    }
+                }
+                if (pending) {
+                    // Save it into a temporary list for later use (when the app dies).
+                    putToSparse2dArray(mActiveAppTraces, uid, pid, outFile,
+                            SparseArray::new, (v) -> v.delete());
+                }
+            }
+        }
+    }
+
+    /**
+     * Copy the given portion of the file into a gz file.
+     *
+     * @param inFile The source file.
+     * @param outFile The destination file, which will be compressed in gzip format.
+     * @param start The start offset where the copy should start from.
+     * @param length The number of bytes that should be copied.
+     * @return If the copy was successful or not.
+     */
+    private static boolean copyToGzFile(final File inFile, final File outFile,
+            final long start, final long length) {
+        long remaining = length;
+        try (
+            BufferedInputStream in = new BufferedInputStream(new FileInputStream(inFile));
+            GZIPOutputStream out = new GZIPOutputStream(new BufferedOutputStream(
+                    new FileOutputStream(outFile)))) {
+            final byte[] buffer = new byte[8192];
+            in.skip(start);
+            while (remaining > 0) {
+                int t = in.read(buffer, 0, (int) Math.min(buffer.length, remaining));
+                if (t < 0) {
+                    break;
+                }
+                out.write(buffer, 0, t);
+                remaining -= t;
+            }
+        } catch (IOException e) {
+            if (DEBUG_PROCESSES) {
+                Slog.e(TAG, "Error in copying ANR trace from " + inFile + " to " + outFile, e);
+            }
+            return false;
+        }
+        return remaining == 0 && outFile.exists();
+    }
+
+    /**
+     * In case there is any orphan ANR trace file, remove it.
+     */
+    @GuardedBy("mLock")
+    private void pruneAnrTracesIfNecessaryLocked() {
+        final ArraySet<String> allFiles = new ArraySet();
+        final File[] files = mProcExitStoreDir.listFiles((f) -> {
+            final String name = f.getName();
+            boolean trace = name.startsWith(ActivityManagerService.ANR_FILE_PREFIX)
+                    && name.endsWith(APP_TRACE_FILE_SUFFIX);
+            if (trace) {
+                allFiles.add(name);
+            }
+            return trace;
+        });
+        if (ArrayUtils.isEmpty(files)) {
+            return;
+        }
+        // Find out the owners from the existing records
+        forEachPackageLocked((name, records) -> {
+            for (int i = records.size() - 1; i >= 0; i--) {
+                final AppExitInfoContainer container = records.valueAt(i);
+                container.forEachRecordLocked((pid, info) -> {
+                    final File traceFile = info.getTraceFile();
+                    if (traceFile != null) {
+                        allFiles.remove(traceFile.getName());
+                    }
+                    return FOREACH_ACTION_NONE;
+                });
+            }
+            return AppExitInfoTracker.FOREACH_ACTION_NONE;
+        });
+        // See if there is any active process owns it.
+        forEachSparse2dArray(mActiveAppTraces, (v) -> allFiles.remove(v.getName()));
+
+        // Remove orphan traces if nobody claims it.
+        for (int i = allFiles.size() - 1; i >= 0; i--) {
+            (new File(mProcExitStoreDir, allFiles.valueAt(i))).delete();
+        }
+    }
+
+    /**
+     * A utility function to add the given value to the given 2d SparseArray
+     */
+    private static <T extends SparseArray<U>, U> void putToSparse2dArray(final SparseArray<T> array,
+            final int outerKey, final int innerKey, final U value, final Supplier<T> newInstance,
+            final Consumer<U> actionToOldValue) {
+        int idx = array.indexOfKey(outerKey);
+        T innerArray = null;
+        if (idx < 0) {
+            innerArray = newInstance.get();
+            array.put(outerKey, innerArray);
+        } else {
+            innerArray = array.valueAt(idx);
+        }
+        idx = innerArray.indexOfKey(innerKey);
+        if (idx >= 0) {
+            if (actionToOldValue != null) {
+                actionToOldValue.accept(innerArray.valueAt(idx));
+            }
+            innerArray.setValueAt(idx, value);
+        } else {
+            innerArray.put(innerKey, value);
+        }
+    }
+
+    /**
+     * A utility function to iterate through the given 2d SparseArray
+     */
+    private static <T extends SparseArray<U>, U> void forEachSparse2dArray(
+            final SparseArray<T> array, final Consumer<U> action) {
+        if (action != null) {
+            for (int i = array.size() - 1; i >= 0; i--) {
+                T innerArray = array.valueAt(i);
+                if (innerArray == null) {
+                    continue;
+                }
+                for (int j = innerArray.size() - 1; j >= 0; j--) {
+                    action.accept(innerArray.valueAt(j));
+                }
+            }
+        }
+    }
+
+    /**
+     * A utility function to remove elements from the given 2d SparseArray
+     */
+    private static <T extends SparseArray<U>, U> void removeFromSparse2dArray(
+            final SparseArray<T> array, final Predicate<Integer> outerPredicate,
+            final Predicate<Integer> innerPredicate, final Consumer<U> action) {
+        for (int i = array.size() - 1; i >= 0; i--) {
+            if (outerPredicate == null || outerPredicate.test(array.keyAt(i))) {
+                final T innerArray = array.valueAt(i);
+                if (innerArray == null) {
+                    continue;
+                }
+                for (int j = innerArray.size() - 1; j >= 0; j--) {
+                    if (innerPredicate == null || innerPredicate.test(innerArray.keyAt(j))) {
+                        if (action != null) {
+                            action.accept(innerArray.valueAt(j));
+                        }
+                        innerArray.removeAt(j);
+                    }
+                }
+                if (innerArray.size() == 0) {
+                    array.removeAt(i);
+                }
+            }
+        }
+    }
+
+    /**
+     * A utility function to find and remove elements from the given 2d SparseArray.
+     */
+    private static <T extends SparseArray<U>, U> U findAndRemoveFromSparse2dArray(
+            final SparseArray<T> array, final int outerKey, final int innerKey) {
+        final int idx = array.indexOfKey(outerKey);
+        if (idx >= 0) {
+            T p = array.valueAt(idx);
+            if (p == null) {
+                return null;
+            }
+            final int innerIdx = p.indexOfKey(innerKey);
+            if (innerIdx >= 0) {
+                final U ret = p.valueAt(innerIdx);
+                p.removeAt(innerIdx);
+                if (p.size() == 0) {
+                    array.removeAt(idx);
+                }
+                return ret;
+            }
+        }
+        return null;
+    }
+
+    /**
      * A container class of {@link android.app.ApplicationExitInfo}
      */
     final class AppExitInfoContainer {
@@ -934,10 +1287,68 @@
                     }
                 }
                 if (oldestIndex >= 0) {
+                    final File traceFile = mInfos.valueAt(oldestIndex).getTraceFile();
+                    if (traceFile != null) {
+                        traceFile.delete();
+                    }
                     mInfos.removeAt(oldestIndex);
                 }
             }
-            mInfos.append(info.getPid(), info);
+            // Claim the state information if there is any
+            final int uid = info.getPackageUid();
+            final int pid = info.getPid();
+            info.setProcessStateSummary(findAndRemoveFromSparse2dArray(
+                    mActiveAppStateSummary, uid, pid));
+            info.setTraceFile(findAndRemoveFromSparse2dArray(mActiveAppTraces, uid, pid));
+            info.setAppTraceRetriever(mAppTraceRetriever);
+            mInfos.append(pid, info);
+        }
+
+        @GuardedBy("mLock")
+        boolean appendTraceIfNecessaryLocked(final int pid, final File traceFile) {
+            final ApplicationExitInfo r = mInfos.get(pid);
+            if (r != null) {
+                r.setTraceFile(traceFile);
+                r.setAppTraceRetriever(mAppTraceRetriever);
+                return true;
+            }
+            return false;
+        }
+
+        @GuardedBy("mLock")
+        void destroyLocked() {
+            for (int i = mInfos.size() - 1; i >= 0; i--) {
+                ApplicationExitInfo ai = mInfos.valueAt(i);
+                final File traceFile = ai.getTraceFile();
+                if (traceFile != null) {
+                    traceFile.delete();
+                }
+                ai.setTraceFile(null);
+                ai.setAppTraceRetriever(null);
+            }
+        }
+
+        @GuardedBy("mLock")
+        void forEachRecordLocked(final BiFunction<Integer, ApplicationExitInfo, Integer> callback) {
+            if (callback != null) {
+                for (int i = mInfos.size() - 1; i >= 0; i--) {
+                    switch (callback.apply(mInfos.keyAt(i), mInfos.valueAt(i))) {
+                        case FOREACH_ACTION_REMOVE_ITEM:
+                            final File traceFile = mInfos.valueAt(i).getTraceFile();
+                            if (traceFile != null) {
+                                traceFile.delete();
+                            }
+                            mInfos.removeAt(i);
+                            break;
+                        case FOREACH_ACTION_STOP_ITERATION:
+                            i = 0;
+                            break;
+                        case FOREACH_ACTION_NONE:
+                        default:
+                            break;
+                    }
+                }
+            }
         }
 
         @GuardedBy("mLock")
@@ -1033,6 +1444,7 @@
             }
         }
 
+        @GuardedBy("mLock")
         Integer getUidByIsolatedUid(int isolatedUid) {
             if (UserHandle.isIsolated(isolatedUid)) {
                 synchronized (mLock) {
@@ -1053,6 +1465,7 @@
             }
         }
 
+        @VisibleForTesting
         void removeAppUid(int uid, boolean allUsers) {
             synchronized (mLock) {
                 if (allUsers) {
@@ -1071,23 +1484,22 @@
             }
         }
 
-        int removeIsolatedUid(int isolatedUid) {
+        @GuardedBy("mLock")
+        int removeIsolatedUidLocked(int isolatedUid) {
             if (!UserHandle.isIsolated(isolatedUid)) {
                 return isolatedUid;
             }
-            synchronized (mLock) {
-                int uid = mIsolatedUidToUidMap.get(isolatedUid, -1);
-                if (uid == -1) {
-                    return isolatedUid;
-                }
-                mIsolatedUidToUidMap.remove(isolatedUid);
-                ArraySet<Integer> set = mUidToIsolatedUidMap.get(uid);
-                if (set != null) {
-                    set.remove(isolatedUid);
-                }
-                // let the ArraySet stay in the mUidToIsolatedUidMap even if it's empty
-                return uid;
+            int uid = mIsolatedUidToUidMap.get(isolatedUid, -1);
+            if (uid == -1) {
+                return isolatedUid;
             }
+            mIsolatedUidToUidMap.remove(isolatedUid);
+            ArraySet<Integer> set = mUidToIsolatedUidMap.get(uid);
+            if (set != null) {
+                set.remove(isolatedUid);
+            }
+            // let the ArraySet stay in the mUidToIsolatedUidMap even if it's empty
+            return uid;
         }
 
         void removeByUserId(int userId) {
@@ -1193,33 +1605,29 @@
             mPresetReason = reason;
         }
 
-        void add(int pid, int uid, Object extra) {
-            if (UserHandle.isIsolated(uid)) {
-                Integer k = mIsolatedUidRecords.getUidByIsolatedUid(uid);
-                if (k != null) {
-                    uid = k;
-                }
+        @GuardedBy("mLock")
+        private void addLocked(int pid, int uid, Object extra) {
+            Integer k = mIsolatedUidRecords.getUidByIsolatedUid(uid);
+            if (k != null) {
+                uid = k;
             }
 
-            synchronized (mLock) {
-                SparseArray<Pair<Long, Object>> array = mData.get(uid);
-                if (array == null) {
-                    array = new SparseArray<Pair<Long, Object>>();
-                    mData.put(uid, array);
-                }
-                array.put(pid, new Pair<Long, Object>(System.currentTimeMillis(), extra));
+            SparseArray<Pair<Long, Object>> array = mData.get(uid);
+            if (array == null) {
+                array = new SparseArray<Pair<Long, Object>>();
+                mData.put(uid, array);
             }
+            array.put(pid, new Pair<Long, Object>(System.currentTimeMillis(), extra));
         }
 
+        @VisibleForTesting
         Pair<Long, Object> remove(int pid, int uid) {
-            if (UserHandle.isIsolated(uid)) {
+            synchronized (mLock) {
                 Integer k = mIsolatedUidRecords.getUidByIsolatedUid(uid);
                 if (k != null) {
                     uid = k;
                 }
-            }
 
-            synchronized (mLock) {
                 SparseArray<Pair<Long, Object>> array = mData.get(uid);
                 if (array != null) {
                     Pair<Long, Object> p = array.get(pid);
@@ -1228,8 +1636,8 @@
                         return isFresh(p.first) ? p : null;
                     }
                 }
+                return null;
             }
-            return null;
         }
 
         void removeByUserId(int userId) {
@@ -1250,7 +1658,8 @@
             }
         }
 
-        void removeByUid(int uid, boolean allUsers) {
+        @GuardedBy("mLock")
+        void removeByUidLocked(int uid, boolean allUsers) {
             if (UserHandle.isIsolated(uid)) {
                 Integer k = mIsolatedUidRecords.getUidByIsolatedUid(uid);
                 if (k != null) {
@@ -1260,17 +1669,13 @@
 
             if (allUsers) {
                 uid = UserHandle.getAppId(uid);
-                synchronized (mLock) {
-                    for (int i = mData.size() - 1; i >= 0; i--) {
-                        if (UserHandle.getAppId(mData.keyAt(i)) == uid) {
-                            mData.removeAt(i);
-                        }
+                for (int i = mData.size() - 1; i >= 0; i--) {
+                    if (UserHandle.getAppId(mData.keyAt(i)) == uid) {
+                        mData.removeAt(i);
                     }
                 }
             } else {
-                synchronized (mLock) {
-                    mData.remove(uid);
-                }
+                mData.remove(uid);
             }
         }
 
@@ -1292,12 +1697,12 @@
 
             // Unlikely but possible: the record has been created
             // Let's update it if we could find a ApplicationExitInfo record
-            if (!updateExitInfoIfNecessary(pid, uid, status, mPresetReason)) {
-                add(pid, uid, status);
-            }
-
-            // Notify any interesed party regarding the lmkd kills
             synchronized (mLock) {
+                if (!updateExitInfoIfNecessaryLocked(pid, uid, status, mPresetReason)) {
+                    addLocked(pid, uid, status);
+                }
+
+                // Notify any interesed party regarding the lmkd kills
                 final BiConsumer<Integer, Integer> listener = mProcDiedListener;
                 if (listener != null) {
                     mService.mHandler.post(()-> listener.accept(pid, uid));
@@ -1305,4 +1710,51 @@
             }
         }
     }
+
+    /**
+     * The implementation to the IAppTraceRetriever interface.
+     */
+    @VisibleForTesting
+    class AppTraceRetriever extends IAppTraceRetriever.Stub {
+        @Override
+        public ParcelFileDescriptor getTraceFileDescriptor(final String packageName,
+                final int uid, final int pid) {
+            mService.enforceNotIsolatedCaller("getTraceFileDescriptor");
+
+            if (TextUtils.isEmpty(packageName)) {
+                throw new IllegalArgumentException("Invalid package name");
+            }
+            final int callingPid = Binder.getCallingPid();
+            final int callingUid = Binder.getCallingUid();
+            final int callingUserId = UserHandle.getCallingUserId();
+            final int userId = UserHandle.getUserId(uid);
+
+            mService.mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
+                    ALLOW_NON_FULL, "getTraceFileDescriptor", null);
+            if (mService.enforceDumpPermissionForPackage(packageName, userId,
+                    callingUid, "getTraceFileDescriptor") != Process.INVALID_UID) {
+                synchronized (mLock) {
+                    final ApplicationExitInfo info = getExitInfoLocked(packageName, uid, pid);
+                    if (info == null) {
+                        return null;
+                    }
+                    final File traceFile = info.getTraceFile();
+                    if (traceFile == null) {
+                        return null;
+                    }
+                    final long identity = Binder.clearCallingIdentity();
+                    try {
+                        // The fd will be closed after being written into Parcel
+                        return ParcelFileDescriptor.open(traceFile,
+                                ParcelFileDescriptor.MODE_READ_ONLY);
+                    } catch (FileNotFoundException e) {
+                        return null;
+                    } finally {
+                        Binder.restoreCallingIdentity(identity);
+                    }
+                }
+            }
+            return null;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 16a7c6b..0f9d61f 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -71,7 +71,6 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManagerInternal;
-import android.content.pm.ProcessInfo;
 import android.content.res.Resources;
 import android.graphics.Point;
 import android.net.LocalSocket;
@@ -99,7 +98,6 @@
 import android.system.Os;
 import android.text.TextUtils;
 import android.util.ArrayMap;
-import android.util.ArraySet;
 import android.util.EventLog;
 import android.util.LongSparseArray;
 import android.util.Pair;
@@ -138,10 +136,8 @@
 import java.util.Arrays;
 import java.util.BitSet;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 /**
  * Activity manager code dealing with processes.
@@ -512,13 +508,6 @@
      */
     private final int[] mZygoteSigChldMessage = new int[3];
 
-    interface LmkdKillListener {
-        /**
-         * Called when there is a process kill by lmkd.
-         */
-        void onLmkdKillOccurred(int pid, int uid);
-    }
-
     final class IsolatedUidRange {
         @VisibleForTesting
         public final int mFirstUid;
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index e7f66bb..eec7519 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1621,9 +1621,11 @@
         // For background ANRs, don't pass the ProcessCpuTracker to
         // avoid spending 1/2 second collecting stats to rank lastPids.
         StringWriter tracesFileException = new StringWriter();
+        // To hold the start and end offset to the ANR trace file respectively.
+        final long[] offsets = new long[2];
         File tracesFile = ActivityManagerService.dumpStackTraces(firstPids,
                 (isSilentAnr()) ? null : processCpuTracker, (isSilentAnr()) ? null : lastPids,
-                nativePids, tracesFileException);
+                nativePids, tracesFileException, offsets);
 
         if (isMonitorCpuUsage()) {
             mService.updateCpuStatsNow();
@@ -1641,6 +1643,10 @@
         if (tracesFile == null) {
             // There is no trace file, so dump (only) the alleged culprit's threads to the log
             Process.sendSignal(pid, Process.SIGNAL_QUIT);
+        } else if (offsets[1] > 0) {
+            // We've dumped into the trace file successfully
+            mService.mProcessList.mAppExitInfoTracker.scheduleLogAnrTrace(
+                    pid, uid, getPackageList(), tracesFile, offsets[0], offsets[1]);
         }
 
         FrameworkStatsLog.write(FrameworkStatsLog.ANR_OCCURRED, uid, processName,
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index a7125b4..343b4ba 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2218,19 +2218,23 @@
 
     /**
      * Returns whether the given user requires credential entry at this time. This is used to
-     * intercept activity launches for work apps when the Work Challenge is present.
+     * intercept activity launches for locked work apps due to work challenge being triggered
+     * or when the profile user is yet to be unlocked.
      */
     protected boolean shouldConfirmCredentials(@UserIdInt int userId) {
-        synchronized (mLock) {
-            if (mStartedUsers.get(userId) == null) {
-                return false;
-            }
-        }
-        if (!mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
+        if (getStartedUserState(userId) == null) {
             return false;
         }
-        final KeyguardManager km = mInjector.getKeyguardManager();
-        return km.isDeviceLocked(userId) && km.isDeviceSecure(userId);
+        if (!getUserInfo(userId).isManagedProfile()) {
+            return false;
+        }
+        if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
+            final KeyguardManager km = mInjector.getKeyguardManager();
+            return km.isDeviceLocked(userId) && km.isDeviceSecure(userId);
+        } else {
+            // For unified challenge, need to confirm credential if user is RUNNING_LOCKED.
+            return isUserRunning(userId, ActivityManager.FLAG_AND_LOCKED);
+        }
     }
 
     boolean isLockScreenDisabled(@UserIdInt int userId) {
diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
index 04c792a..d548871 100644
--- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
+++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
@@ -25,6 +25,7 @@
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkPolicy.LIMIT_DISABLED;
 import static android.net.NetworkPolicy.WARNING_DISABLED;
+import static android.net.NetworkTemplate.NETWORK_TYPE_ALL;
 import static android.provider.Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES;
 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
@@ -220,7 +221,7 @@
             mNetworkTemplate = new NetworkTemplate(
                     NetworkTemplate.MATCH_MOBILE, subscriberId, new String[] { subscriberId },
                     null, NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
-                    NetworkStats.DEFAULT_NETWORK_NO);
+                    NetworkStats.DEFAULT_NETWORK_NO, NETWORK_TYPE_ALL);
             mUsageCallback = new UsageCallback() {
                 @Override
                 public void onThresholdReached(int networkType, String subscriberId) {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index caf2914..173dfc2 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1868,8 +1868,11 @@
                 mNetIdToSubId.put(state.network.netId, parseSubId(state));
             }
             if (state.networkInfo != null && state.networkInfo.isConnected()) {
+                // Policies matched by NPMS only match by subscriber ID or by ssid. Thus subtype
+                // in the object created here is never used and its value doesn't matter, so use
+                // NETWORK_TYPE_UNKNOWN.
                 final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state,
-                        true);
+                        true, TelephonyManager.NETWORK_TYPE_UNKNOWN /* subType */);
                 identified.put(state, ident);
             }
         }
@@ -3087,17 +3090,38 @@
     private void enforceSubscriptionPlanValidity(SubscriptionPlan[] plans) {
         // nothing to check if no plans
         if (plans.length == 0) {
+            Log.d(TAG, "Received empty plans list. Clearing existing SubscriptionPlans.");
             return;
         }
 
-        final ArraySet<Integer> applicableNetworkTypes = new ArraySet<Integer>();
-        boolean allNetworks = false;
-        for (SubscriptionPlan plan : plans) {
-            if (plan.getNetworkTypes() == null) {
-                allNetworks = true;
+        final int[] allNetworkTypes = TelephonyManager.getAllNetworkTypes();
+        final ArraySet<Integer> allNetworksSet = new ArraySet<>();
+        addAll(allNetworksSet, allNetworkTypes);
+
+        final ArraySet<Integer> applicableNetworkTypes = new ArraySet<>();
+        boolean hasGeneralPlan = false;
+        for (int i = 0; i < plans.length; i++) {
+            final int[] planNetworkTypes = plans[i].getNetworkTypes();
+            final ArraySet<Integer> planNetworksSet = new ArraySet<>();
+            for (int j = 0; j < planNetworkTypes.length; j++) {
+                // ensure all network types are valid
+                if (allNetworksSet.contains(planNetworkTypes[j])) {
+                    // ensure no duplicate network types in the same SubscriptionPlan
+                    if (!planNetworksSet.add(planNetworkTypes[j])) {
+                        throw new IllegalArgumentException(
+                                "Subscription plan contains duplicate network types.");
+                    }
+                } else {
+                    throw new IllegalArgumentException("Invalid network type: "
+                            + planNetworkTypes[j]);
+                }
+            }
+
+            if (planNetworkTypes.length == allNetworkTypes.length) {
+                hasGeneralPlan = true;
             } else {
-                final int[] networkTypes = plan.getNetworkTypes();
-                if (!addAll(applicableNetworkTypes, networkTypes)) {
+                // ensure no network type applies to multiple plans
+                if (!addAll(applicableNetworkTypes, planNetworkTypes)) {
                     throw new IllegalArgumentException(
                             "Multiple subscription plans defined for a single network type.");
                 }
@@ -3105,7 +3129,7 @@
         }
 
         // ensure at least one plan applies for every network type
-        if (!allNetworks) {
+        if (!hasGeneralPlan) {
             throw new IllegalArgumentException(
                     "No generic subscription plan that applies to all network types.");
         }
@@ -3114,12 +3138,12 @@
     /**
      * Adds all of the {@code elements} to the {@code set}.
      *
-     * @return {@code false} if any element is not added because the set already have the value.
+     * @return {@code false} if any element is not added because the set already has the value.
      */
-    private static boolean addAll(@NonNull Set<Integer> set, @NonNull int... elements) {
+    private static boolean addAll(@NonNull ArraySet<Integer> set, @NonNull int... elements) {
         boolean result = true;
-        for (int element : elements) {
-            result &= set.add(element);
+        for (int i = 0; i < elements.length; i++) {
+            result &= set.add(elements[i]);
         }
         return result;
     }
@@ -3329,6 +3353,7 @@
      * existing plans; it simply lets the debug package define new plans.
      */
     void setSubscriptionPlansOwner(int subId, String packageName) {
+        mContext.enforceCallingOrSelfPermission(NETWORK_SETTINGS, TAG);
         SystemProperties.set(PROP_SUB_PLAN_OWNER + "." + subId, packageName);
     }
 
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 10136b3..d8264b3 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -27,6 +27,7 @@
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
 import static android.net.ConnectivityManager.isNetworkTypeMobile;
+import static android.net.NetworkIdentity.SUBTYPE_COMBINED;
 import static android.net.NetworkStack.checkNetworkStackPermission;
 import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
 import static android.net.NetworkStats.IFACE_ALL;
@@ -45,10 +46,12 @@
 import static android.net.NetworkStatsHistory.FIELD_ALL;
 import static android.net.NetworkTemplate.buildTemplateMobileWildcard;
 import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
+import static android.net.NetworkTemplate.getCollapsedRatType;
 import static android.net.TrafficStats.KB_IN_BYTES;
 import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.os.Trace.TRACE_TAG_NETWORK;
 import static android.provider.Settings.Global.NETSTATS_AUGMENT_ENABLED;
+import static android.provider.Settings.Global.NETSTATS_COMBINE_SUBTYPE_ENABLED;
 import static android.provider.Settings.Global.NETSTATS_DEV_BUCKET_DURATION;
 import static android.provider.Settings.Global.NETSTATS_DEV_DELETE_AGE;
 import static android.provider.Settings.Global.NETSTATS_DEV_PERSIST_BYTES;
@@ -64,6 +67,9 @@
 import static android.provider.Settings.Global.NETSTATS_UID_TAG_DELETE_AGE;
 import static android.provider.Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES;
 import static android.provider.Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE;
+import static android.telephony.PhoneStateListener.LISTEN_NONE;
+import static android.telephony.PhoneStateListener.LISTEN_SERVICE_STATE;
+import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
@@ -109,6 +115,7 @@
 import android.os.DropBoxManager;
 import android.os.Environment;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.INetworkManagementService;
@@ -125,6 +132,8 @@
 import android.provider.Settings.Global;
 import android.service.NetworkInterfaceProto;
 import android.service.NetworkStatsServiceDumpProto;
+import android.telephony.PhoneStateListener;
+import android.telephony.ServiceState;
 import android.telephony.SubscriptionPlan;
 import android.telephony.TelephonyManager;
 import android.text.format.DateUtils;
@@ -157,6 +166,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
+import java.util.concurrent.Executor;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 
@@ -173,6 +183,7 @@
     private static final int MSG_PERFORM_POLL = 1;
     // Perform polling, persist network, and register the global alert again.
     private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 2;
+    private static final int MSG_UPDATE_IFACES = 3;
 
     /** Flags to control detail level of poll event. */
     private static final int FLAG_PERSIST_NETWORK = 0x1;
@@ -229,12 +240,20 @@
      * Settings that can be changed externally.
      */
     public interface NetworkStatsSettings {
-        public long getPollInterval();
-        public long getPollDelay();
-        public boolean getSampleEnabled();
-        public boolean getAugmentEnabled();
+        long getPollInterval();
+        long getPollDelay();
+        boolean getSampleEnabled();
+        boolean getAugmentEnabled();
+        /**
+         * When enabled, all mobile data is reported under {@link NetworkIdentity#SUBTYPE_COMBINED}.
+         * When disabled, mobile data is broken down by a granular subtype representative of the
+         * actual subtype. {@see NetworkTemplate#getCollapsedRatType}.
+         * Enabling this decreases the level of detail but saves performance, disk space and
+         * amount of data logged.
+         */
+        boolean getCombineSubtypeEnabled();
 
-        public static class Config {
+        class Config {
             public final long bucketDuration;
             public final long rotateAgeMillis;
             public final long deleteAgeMillis;
@@ -246,16 +265,16 @@
             }
         }
 
-        public Config getDevConfig();
-        public Config getXtConfig();
-        public Config getUidConfig();
-        public Config getUidTagConfig();
+        Config getDevConfig();
+        Config getXtConfig();
+        Config getUidConfig();
+        Config getUidTagConfig();
 
-        public long getGlobalAlertBytes(long def);
-        public long getDevPersistBytes(long def);
-        public long getXtPersistBytes(long def);
-        public long getUidPersistBytes(long def);
-        public long getUidTagPersistBytes(long def);
+        long getGlobalAlertBytes(long def);
+        long getDevPersistBytes(long def);
+        long getXtPersistBytes(long def);
+        long getUidPersistBytes(long def);
+        long getUidTagPersistBytes(long def);
     }
 
     private final Object mStatsLock = new Object();
@@ -280,6 +299,11 @@
     @GuardedBy("mStatsLock")
     private Network[] mDefaultNetworks = new Network[0];
 
+    /** Last states of all networks sent from ConnectivityService. */
+    @GuardedBy("mStatsLock")
+    @Nullable
+    private NetworkState[] mLastNetworkStates = null;
+
     private final DropBoxNonMonotonicObserver mNonMonotonicObserver =
             new DropBoxNonMonotonicObserver();
 
@@ -355,6 +379,12 @@
                     performPoll(FLAG_PERSIST_ALL);
                     break;
                 }
+                case MSG_UPDATE_IFACES: {
+                    // If no cached states, ignore.
+                    if (mLastNetworkStates == null) break;
+                    updateIfaces(mDefaultNetworks, mLastNetworkStates, mActiveIface);
+                    break;
+                }
                 case MSG_PERFORM_POLL_REGISTER_ALERT: {
                     performPoll(FLAG_PERSIST_NETWORK);
                     registerGlobalAlert();
@@ -407,6 +437,7 @@
         final HandlerThread handlerThread = mDeps.makeHandlerThread();
         handlerThread.start();
         mHandler = new NetworkStatsHandler(handlerThread.getLooper());
+        mPhoneListener = new NetworkTypeListener(new HandlerExecutor(mHandler));
     }
 
     /**
@@ -486,6 +517,13 @@
         mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime,
                 mSettings.getPollInterval(), pollIntent);
 
+        // TODO: 1. listen to changes from all subscriptions.
+        //       2. listen to settings changed to support dynamically enable/disable.
+        // watch for networkType changes
+        if (!mSettings.getCombineSubtypeEnabled()) {
+            mTeleManager.listen(mPhoneListener, LISTEN_SERVICE_STATE);
+        }
+
         registerGlobalAlert();
     }
 
@@ -506,6 +544,8 @@
         mContext.unregisterReceiver(mUserReceiver);
         mContext.unregisterReceiver(mShutdownReceiver);
 
+        mTeleManager.listen(mPhoneListener, LISTEN_NONE);
+
         final long currentTime = mClock.millis();
 
         // persist any pending stats
@@ -1156,6 +1196,38 @@
         }
     };
 
+    /**
+     * Receiver that watches for {@link TelephonyManager} changes, such as
+     * transitioning between Radio Access Technology(RAT) types.
+     */
+    @NonNull
+    private final NetworkTypeListener mPhoneListener;
+
+    class NetworkTypeListener extends PhoneStateListener {
+        private volatile int mLastCollapsedRatType = NETWORK_TYPE_UNKNOWN;
+
+        NetworkTypeListener(@NonNull Executor executor) {
+            super(executor);
+        }
+
+        @Override
+        public void onServiceStateChanged(@NonNull ServiceState ss) {
+            final int networkType = ss.getDataNetworkType();
+            final int collapsedRatType = getCollapsedRatType(networkType);
+            if (collapsedRatType == mLastCollapsedRatType) return;
+
+            if (LOGD) {
+                Log.d(TAG, "subtype changed for mobile: "
+                        + mLastCollapsedRatType + " -> " + collapsedRatType);
+            }
+            // Protect service from frequently updating. Remove pending messages if any.
+            mHandler.removeMessages(MSG_UPDATE_IFACES);
+            mLastCollapsedRatType = collapsedRatType;
+            mHandler.sendMessageDelayed(
+                    mHandler.obtainMessage(MSG_UPDATE_IFACES), mSettings.getPollDelay());
+        }
+    }
+
     private void updateIfaces(
             Network[] defaultNetworks,
             NetworkState[] networkStates,
@@ -1177,7 +1249,8 @@
      * they are combined under a single {@link NetworkIdentitySet}.
      */
     @GuardedBy("mStatsLock")
-    private void updateIfacesLocked(Network[] defaultNetworks, NetworkState[] states) {
+    private void updateIfacesLocked(@Nullable Network[] defaultNetworks,
+            @NonNull NetworkState[] states) {
         if (!mSystemReady) return;
         if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
 
@@ -1197,13 +1270,18 @@
             mDefaultNetworks = defaultNetworks;
         }
 
+        mLastNetworkStates = states;
+
+        final boolean combineSubtypeEnabled = mSettings.getCombineSubtypeEnabled();
         final ArraySet<String> mobileIfaces = new ArraySet<>();
         for (NetworkState state : states) {
             if (state.networkInfo.isConnected()) {
                 final boolean isMobile = isNetworkTypeMobile(state.networkInfo.getType());
                 final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, state.network);
+                final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED
+                        : getSubTypeForState(state);
                 final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state,
-                        isDefault);
+                        isDefault, subType);
 
                 // Traffic occurring on the base interface is always counted for
                 // both total usage and UID details.
@@ -1264,6 +1342,20 @@
         mMobileIfaces = mobileIfaces.toArray(new String[mobileIfaces.size()]);
     }
 
+    /**
+     * For networks with {@code TRANSPORT_CELLULAR}, get subType that was obtained through
+     * {@link PhoneStateListener}. Otherwise, return 0 given that other networks with different
+     * transport types do not actually fill this value.
+     */
+    private int getSubTypeForState(@NonNull NetworkState state) {
+        if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+            return 0;
+        }
+
+        // TODO: return different subType for different subscriptions.
+        return mPhoneListener.mLastCollapsedRatType;
+    }
+
     private static <K> NetworkIdentitySet findOrCreateNetworkIdentitySet(
             ArrayMap<K, NetworkIdentitySet> map, K key) {
         NetworkIdentitySet ident = map.get(key);
@@ -1617,6 +1709,12 @@
                 return;
             }
 
+            pw.println("Configs:");
+            pw.increaseIndent();
+            pw.printPair(NETSTATS_COMBINE_SUBTYPE_ENABLED, mSettings.getCombineSubtypeEnabled());
+            pw.println();
+            pw.decreaseIndent();
+
             pw.println("Active interfaces:");
             pw.increaseIndent();
             for (int i = 0; i < mActiveIfaces.size(); i++) {
@@ -2045,6 +2143,10 @@
             return getGlobalBoolean(NETSTATS_AUGMENT_ENABLED, true);
         }
         @Override
+        public boolean getCombineSubtypeEnabled() {
+            return getGlobalBoolean(NETSTATS_COMBINE_SUBTYPE_ENABLED, false);
+        }
+        @Override
         public Config getDevConfig() {
             return new Config(getGlobalLong(NETSTATS_DEV_BUCKET_DURATION, HOUR_IN_MILLIS),
                     getGlobalLong(NETSTATS_DEV_ROTATE_AGE, 15 * DAY_IN_MILLIS),
diff --git a/services/core/java/com/android/server/pm/DataLoaderManagerService.java b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
index 8eb773a..09baf6e 100644
--- a/services/core/java/com/android/server/pm/DataLoaderManagerService.java
+++ b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
@@ -213,7 +213,7 @@
 
         void destroy() {
             try {
-                mDataLoader.destroy();
+                mDataLoader.destroy(mId);
             } catch (RemoteException ignored) {
             }
             mContext.unbindService(this);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 45a25a0..348a4cb 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1487,6 +1487,18 @@
         return e;
     }
 
+    private void onDataLoaderUnrecoverable() {
+        final PackageManagerService packageManagerService = mPm;
+        final String packageName = mPackageName;
+        mHandler.post(() -> {
+            if (packageManagerService.deletePackageX(packageName,
+                    PackageManager.VERSION_CODE_HIGHEST, UserHandle.USER_SYSTEM,
+                    PackageManager.DELETE_ALL_USERS) != PackageManager.DELETE_SUCCEEDED) {
+                Slog.e(TAG, "Failed to uninstall package with failed dataloader: " + packageName);
+            }
+        });
+    }
+
     /**
      * If session should be sealed, then it's sealed to prevent further modification.
      * If the session can't be sealed then it's destroyed.
@@ -2564,11 +2576,20 @@
         IDataLoaderStatusListener listener = new IDataLoaderStatusListener.Stub() {
             @Override
             public void onStatusChanged(int dataLoaderId, int status) {
-                try {
-                    if (status == IDataLoaderStatusListener.DATA_LOADER_DESTROYED) {
+                switch (status) {
+                    case IDataLoaderStatusListener.DATA_LOADER_STOPPED:
+                    case IDataLoaderStatusListener.DATA_LOADER_DESTROYED:
                         return;
-                    }
+                    case IDataLoaderStatusListener.DATA_LOADER_UNRECOVERABLE:
+                        onDataLoaderUnrecoverable();
+                        return;
+                }
 
+                if (mDestroyed || mDataLoaderFinished) {
+                    return;
+                }
+
+                try {
                     IDataLoader dataLoader = dataLoaderManager.getDataLoader(dataLoaderId);
                     if (dataLoader == null) {
                         mDataLoaderFinished = true;
@@ -2583,12 +2604,13 @@
                             if (manualStartAndDestroy) {
                                 // IncrementalFileStorages will call start after all files are
                                 // created in IncFS.
-                                dataLoader.start();
+                                dataLoader.start(dataLoaderId);
                             }
                             break;
                         }
                         case IDataLoaderStatusListener.DATA_LOADER_STARTED: {
                             dataLoader.prepareImage(
+                                    dataLoaderId,
                                     addedFiles.toArray(
                                             new InstallationFileParcel[addedFiles.size()]),
                                     removedFiles.toArray(new String[removedFiles.size()]));
@@ -2603,7 +2625,7 @@
                                 dispatchStreamValidateAndCommit();
                             }
                             if (manualStartAndDestroy) {
-                                dataLoader.destroy();
+                                dataLoader.destroy(dataLoaderId);
                             }
                             break;
                         }
@@ -2613,7 +2635,7 @@
                                     new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
                                             "Failed to prepare image."));
                             if (manualStartAndDestroy) {
-                                dataLoader.destroy();
+                                dataLoader.destroy(dataLoaderId);
                             }
                             break;
                         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 24ebd32..09e4e60 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1548,7 +1548,6 @@
     final @Nullable String mConfiguratorPackage;
     final @Nullable String mAppPredictionServicePackage;
     final @Nullable String mIncidentReportApproverPackage;
-    final @Nullable String[] mTelephonyPackages;
     final @Nullable String mServicesExtensionPackageName;
     final @Nullable String mSharedSystemSharedLibraryPackageName;
     final @Nullable String mRetailDemoPackage;
@@ -3181,7 +3180,6 @@
             mConfiguratorPackage = getDeviceConfiguratorPackageName();
             mAppPredictionServicePackage = getAppPredictionServicePackageName();
             mIncidentReportApproverPackage = getIncidentReportApproverPackageName();
-            mTelephonyPackages = getTelephonyPackageNames();
             mRetailDemoPackage = getRetailDemoPackageName();
 
             // Now that we know all of the shared libraries, update all clients to have
@@ -19939,16 +19937,6 @@
     }
 
     @Override
-    public String[] getTelephonyPackageNames() {
-        String names = mContext.getString(R.string.config_telephonyPackages);
-        String[] telephonyPackageNames = null;
-        if (!TextUtils.isEmpty(names)) {
-            telephonyPackageNames = names.trim().split(",");
-        }
-        return ensureSystemPackageNames(telephonyPackageNames);
-    }
-
-    @Override
     public String getContentCaptureServicePackageName() {
         final String flattenedContentCaptureService =
                 mContext.getString(R.string.config_defaultContentCaptureService);
@@ -23335,8 +23323,6 @@
                     return filterOnlySystemPackages(mIncidentReportApproverPackage);
                 case PackageManagerInternal.PACKAGE_APP_PREDICTOR:
                     return filterOnlySystemPackages(mAppPredictionServicePackage);
-                case PackageManagerInternal.PACKAGE_TELEPHONY:
-                    return filterOnlySystemPackages(mTelephonyPackages);
                 case PackageManagerInternal.PACKAGE_COMPANION:
                     return filterOnlySystemPackages("com.android.companiondevicemanager");
                 case PackageManagerInternal.PACKAGE_RETAIL_DEMO:
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index f8e5082..1d7d038 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -277,9 +277,6 @@
     public boolean isAppPredictor() {
         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_APP_PREDICTOR) != 0;
     }
-    public boolean isTelephony() {
-        return (protectionLevel & PermissionInfo.PROTECTION_FLAG_TELEPHONY) != 0;
-    }
     public boolean isCompanion() {
         return (protectionLevel & PermissionInfo.PROTECTION_FLAG_COMPANION) != 0;
     }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 46f121d..5d6eaf2 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -3464,13 +3464,6 @@
                 // Special permissions for the system app predictor.
                 allowed = true;
             }
-            if (!allowed && bp.isTelephony()
-                    && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
-                        PackageManagerInternal.PACKAGE_TELEPHONY, UserHandle.USER_SYSTEM),
-                    pkg.getPackageName())) {
-                // Special permissions for the system telephony apps.
-                allowed = true;
-            }
             if (!allowed && bp.isCompanion()
                     && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
                         PackageManagerInternal.PACKAGE_COMPANION, UserHandle.USER_SYSTEM),
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
index 1292f6c..63048f6 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
@@ -252,8 +252,21 @@
      * @param permission The permission to check.
      */
     void enforcePermission(String permission) {
-        mContext.enforceCallingOrSelfPermission(permission,
-                String.format("Caller must have the %s permission.", permission));
+        final int status = PermissionChecker.checkCallingOrSelfPermissionForPreflight(mContext,
+                permission);
+        switch (status) {
+            case PermissionChecker.PERMISSION_GRANTED:
+                return;
+            case PermissionChecker.PERMISSION_HARD_DENIED:
+                throw new SecurityException(
+                        String.format("Caller must have the %s permission.", permission));
+            case PermissionChecker.PERMISSION_SOFT_DENIED:
+                throw new ServiceSpecificException(Status.TEMPORARY_PERMISSION_DENIED,
+                        String.format("Caller must have the %s permission.", permission));
+            default:
+                throw new InternalServerError(
+                        new RuntimeException("Unexpected perimission check result."));
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index fd275d8..f1f5bfe 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -1292,7 +1292,7 @@
     int pullSystemUptime(int atomTag, List<StatsEvent> pulledData) {
         StatsEvent e = StatsEvent.newBuilder()
                 .setAtomId(atomTag)
-                .writeLong(SystemClock.elapsedRealtime())
+                .writeLong(SystemClock.uptimeMillis())
                 .build();
         pulledData.add(e);
         return StatsManager.PULL_SUCCESS;
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
index 57b6ec9..fc52584 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -25,6 +25,8 @@
 import android.content.Context;
 import android.database.ContentObserver;
 import android.os.Handler;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
 import android.provider.Settings;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -133,5 +135,13 @@
                 android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE,
                 "suggest manual time and time zone");
     }
+
+    @Override
+    public void onShellCommand(FileDescriptor in, FileDescriptor out,
+            FileDescriptor err, String[] args, ShellCallback callback,
+            ResultReceiver resultReceiver) {
+        (new TimeZoneDetectorShellCommand(this)).exec(
+                this, in, out, err, args, callback, resultReceiver);
+    }
 }
 
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
new file mode 100644
index 0000000..b051bab
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2020 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.timezonedetector;
+
+import android.app.timezonedetector.ManualTimeZoneSuggestion;
+import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
+import android.os.ShellCommand;
+
+import java.io.PrintWriter;
+
+/** Implemented the shell command interface for {@link TimeZoneDetectorService}. */
+class TimeZoneDetectorShellCommand extends ShellCommand {
+
+    private final TimeZoneDetectorService mInterface;
+
+    TimeZoneDetectorShellCommand(TimeZoneDetectorService timeZoneDetectorService) {
+        mInterface = timeZoneDetectorService;
+    }
+
+    @Override
+    public int onCommand(String cmd) {
+        if (cmd == null) {
+            return handleDefaultCommands(cmd);
+        }
+
+        switch (cmd) {
+            case "suggestTelephonyTimeZone":
+                return runSuggestTelephonyTimeZone();
+            case "suggestManualTimeZone":
+                return runSuggestManualTimeZone();
+            default: {
+                return handleDefaultCommands(cmd);
+            }
+        }
+    }
+
+    private int runSuggestTelephonyTimeZone() {
+        final PrintWriter pw = getOutPrintWriter();
+        try {
+            TelephonyTimeZoneSuggestion suggestion = null;
+            String opt;
+            while ((opt = getNextArg()) != null) {
+                if ("--suggestion".equals(opt)) {
+                    suggestion = TelephonyTimeZoneSuggestion.parseCommandLineArg(this);
+                } else {
+                    pw.println("Error: Unknown option: " + opt);
+                    return 1;
+                }
+            }
+            if (suggestion == null) {
+                pw.println("Error: suggestion not specified");
+                return 1;
+            }
+            mInterface.suggestTelephonyTimeZone(suggestion);
+            pw.println("Suggestion " + suggestion + " injected.");
+            return 0;
+        } catch (RuntimeException e) {
+            pw.println(e.toString());
+            return 1;
+        }
+    }
+
+    private int runSuggestManualTimeZone() {
+        final PrintWriter pw = getOutPrintWriter();
+        try {
+            ManualTimeZoneSuggestion suggestion = null;
+            String opt;
+            while ((opt = getNextArg()) != null) {
+                if ("--suggestion".equals(opt)) {
+                    suggestion = ManualTimeZoneSuggestion.parseCommandLineArg(this);
+                } else {
+                    pw.println("Error: Unknown option: " + opt);
+                    return 1;
+                }
+            }
+            if (suggestion == null) {
+                pw.println("Error: suggestion not specified");
+                return 1;
+            }
+            mInterface.suggestManualTimeZone(suggestion);
+            pw.println("Suggestion " + suggestion + " injected.");
+            return 0;
+        } catch (RuntimeException e) {
+            pw.println(e.toString());
+            return 1;
+        }
+    }
+
+    @Override
+    public void onHelp() {
+        final PrintWriter pw = getOutPrintWriter();
+        pw.println("Time Zone Detector (time_zone_detector) commands:");
+        pw.println("  help");
+        pw.println("    Print this help text.");
+        pw.println("  suggestTelephonyTimeZone");
+        pw.println("    --suggestion <telephony suggestion opts>");
+        pw.println("  suggestManualTimeZone");
+        pw.println("    --suggestion <manual suggestion opts>");
+        pw.println();
+        ManualTimeZoneSuggestion.printCommandLineOpts(pw);
+        pw.println();
+        TelephonyTimeZoneSuggestion.printCommandLineOpts(pw);
+        pw.println();
+    }
+}
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
index 25585b3..7047a9e 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -100,6 +100,7 @@
                 @NonNull IResourcesReclaimListener listener, @NonNull int[] clientId)
                 throws RemoteException {
             enforceTrmAccessPermission("registerClientProfile");
+            enforceTunerAccessPermission("registerClientProfile");
             if (profile == null) {
                 throw new RemoteException("ResourceClientProfile can't be null");
             }
diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
index 1009771..57b6024 100644
--- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
@@ -178,7 +178,7 @@
             // before issuing the work challenge.
             return true;
         }
-        return interceptWorkProfileChallengeIfNeeded();
+        return interceptLockedManagedProfileIfNeeded();
     }
 
     private boolean hasCrossProfileAnimation() {
@@ -296,7 +296,7 @@
         return true;
     }
 
-    private boolean interceptWorkProfileChallengeIfNeeded() {
+    private boolean interceptLockedManagedProfileIfNeeded() {
         final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(mAInfo, mUserId);
         if (interceptingIntent == null) {
             return false;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index c7a1391..14ca7cb 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -27,8 +27,10 @@
 import static android.app.ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
 import static android.app.ActivityManager.START_SUCCESS;
 import static android.app.ActivityManager.START_TASK_TO_FRONT;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.WaitResult.LAUNCH_STATE_COLD;
 import static android.app.WaitResult.LAUNCH_STATE_HOT;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -167,6 +169,8 @@
 
     // The display to launch the activity onto, barring any strong reason to do otherwise.
     private int mPreferredDisplayId;
+    // The windowing mode to apply to the root task, if possible
+    private int mPreferredWindowingMode;
 
     private Task mInTask;
     @VisibleForTesting
@@ -538,6 +542,7 @@
         mStartFlags = starter.mStartFlags;
         mSourceRecord = starter.mSourceRecord;
         mPreferredDisplayId = starter.mPreferredDisplayId;
+        mPreferredWindowingMode = starter.mPreferredWindowingMode;
 
         mInTask = starter.mInTask;
         mAddingToTask = starter.mAddingToTask;
@@ -1493,8 +1498,6 @@
         setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
                 voiceInteractor, restrictedBgActivity);
 
-        final int preferredWindowingMode = mLaunchParams.mWindowingMode;
-
         computeLaunchingTaskFlags();
 
         computeSourceStack();
@@ -1564,6 +1567,14 @@
 
         if (!mAvoidMoveToFront && mDoResume) {
             mTargetStack.moveToFront("reuseOrNewTask");
+            if (mOptions != null) {
+                if (mPreferredWindowingMode != WINDOWING_MODE_UNDEFINED) {
+                    mTargetStack.setWindowingMode(mPreferredWindowingMode);
+                }
+                if (mOptions.getTaskAlwaysOnTop()) {
+                    mTargetStack.setAlwaysOnTop(true);
+                }
+            }
         }
 
         mService.mUgmInternal.grantUriPermissionFromIntent(mCallingUid, mStartActivity.packageName,
@@ -1627,7 +1638,7 @@
         // Update the recent tasks list immediately when the activity starts
         mSupervisor.mRecentTasks.add(mStartActivity.getTask());
         mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(),
-                preferredWindowingMode, mPreferredDisplayId, mTargetStack);
+                mPreferredWindowingMode, mPreferredDisplayId, mTargetStack);
 
         return START_SUCCESS;
     }
@@ -1680,9 +1691,10 @@
 
         mSupervisor.getLaunchParamsController().calculate(targetTask, r.info.windowLayout, r,
                 sourceRecord, mOptions, PHASE_BOUNDS, mLaunchParams);
-        mPreferredDisplayId =
-                mLaunchParams.hasPreferredDisplay() ? mLaunchParams.mPreferredDisplayId
-                        : DEFAULT_DISPLAY;
+        mPreferredDisplayId = mLaunchParams.hasPreferredDisplay()
+                ? mLaunchParams.mPreferredDisplayId
+                : DEFAULT_DISPLAY;
+        mPreferredWindowingMode = mLaunchParams.mWindowingMode;
     }
 
     private int isAllowedToStart(ActivityRecord r, boolean newTask, Task targetTask) {
@@ -2006,6 +2018,7 @@
         mStartFlags = 0;
         mSourceRecord = null;
         mPreferredDisplayId = INVALID_DISPLAY;
+        mPreferredWindowingMode = WINDOWING_MODE_UNDEFINED;
 
         mInTask = null;
         mAddingToTask = false;
@@ -2054,9 +2067,10 @@
         // after we located a reusable task (which might be resided in another display).
         mSupervisor.getLaunchParamsController().calculate(inTask, r.info.windowLayout, r,
                 sourceRecord, options, PHASE_DISPLAY, mLaunchParams);
-        mPreferredDisplayId =
-                mLaunchParams.hasPreferredDisplay() ? mLaunchParams.mPreferredDisplayId
-                        : DEFAULT_DISPLAY;
+        mPreferredDisplayId = mLaunchParams.hasPreferredDisplay()
+                ? mLaunchParams.mPreferredDisplayId
+                : DEFAULT_DISPLAY;
+        mPreferredWindowingMode = mLaunchParams.mWindowingMode;
 
         mLaunchMode = r.launchMode;
 
@@ -2098,7 +2112,7 @@
         }
 
         if (mOptions != null) {
-            if (mOptions.getLaunchTaskId() != -1 && mOptions.getTaskOverlay()) {
+            if (mOptions.getLaunchTaskId() != INVALID_TASK_ID && mOptions.getTaskOverlay()) {
                 r.setTaskOverlay(true);
                 if (!mOptions.canTaskOverlayResume()) {
                     final Task task = mRootWindowContainer.anyTaskForId(
@@ -2291,6 +2305,15 @@
      * if not or an ActivityRecord with the task into which the new activity should be added.
      */
     private Task getReusableTask() {
+        // If a target task is specified, try to reuse that one
+        if (mOptions != null && mOptions.getLaunchTaskId() != INVALID_TASK_ID) {
+            Task launchTask = mRootWindowContainer.anyTaskForId(mOptions.getLaunchTaskId());
+            if (launchTask != null) {
+                return launchTask;
+            }
+            return null;
+        }
+
         // We may want to try to place the new activity in to an existing task.  We always
         // do this if the target activity is singleTask or singleInstance; we will also do
         // this if NEW_TASK has been requested, and there is not an additional qualifier telling
@@ -2304,12 +2327,7 @@
         // same component, then instead of launching bring that one to the front.
         putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
         ActivityRecord intentActivity = null;
-        if (mOptions != null && mOptions.getLaunchTaskId() != -1) {
-            Task launchTask = mRootWindowContainer.anyTaskForId(mOptions.getLaunchTaskId());
-            if (launchTask != null) {
-                return launchTask;
-            }
-        } else if (putIntoExistingTask) {
+        if (putIntoExistingTask) {
             if (LAUNCH_SINGLE_INSTANCE == mLaunchMode) {
                 // There can be one and only one instance of single instance activity in the
                 // history, and it is always in its own unique task, so we do a special search.
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index ee36db9..a4bdfb3 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.view.InsetsState.ITYPE_CAPTION_BAR;
 import static android.view.InsetsState.ITYPE_IME;
@@ -87,7 +88,8 @@
         final InsetsSourceProvider provider = target.getControllableInsetProvider();
         final @InternalInsetsType int type = provider != null
                 ? provider.getSource().getType() : ITYPE_INVALID;
-        return getInsetsForTypeAndWindowingMode(type, target.getWindowingMode());
+        return getInsetsForTypeAndWindowingMode(type, target.getWindowingMode(),
+                target.isAlwaysOnTop());
     }
 
     InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) {
@@ -95,7 +97,9 @@
         final WindowToken token = mDisplayContent.getWindowToken(attrs.token);
         final @WindowingMode int windowingMode = token != null
                 ? token.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
-        return getInsetsForTypeAndWindowingMode(type, windowingMode);
+        final boolean alwaysOnTop = token != null
+                ? token.isAlwaysOnTop() : false;
+        return getInsetsForTypeAndWindowingMode(type, windowingMode, alwaysOnTop);
     }
 
     private static @InternalInsetsType int getInsetsTypeForWindowType(int type) {
@@ -113,7 +117,7 @@
 
     /** @see #getInsetsForDispatch */
     private InsetsState getInsetsForTypeAndWindowingMode(@InternalInsetsType int type,
-            @WindowingMode int windowingMode) {
+            @WindowingMode int windowingMode, boolean isAlwaysOnTop) {
         InsetsState state = mState;
 
         if (type != ITYPE_INVALID) {
@@ -147,7 +151,8 @@
             }
         }
 
-        if (WindowConfiguration.isFloating(windowingMode)) {
+        if (WindowConfiguration.isFloating(windowingMode)
+                || (windowingMode == WINDOWING_MODE_MULTI_WINDOW && isAlwaysOnTop)) {
             state = new InsetsState(state);
             state.removeSource(ITYPE_STATUS_BAR);
             state.removeSource(ITYPE_NAVIGATION_BAR);
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 8f09f3f..cc52cb4 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -231,7 +231,8 @@
         }
     }
 
-    void unregisterTaskOrganizer(ITaskOrganizer organizer) {
+    @Override
+    public void unregisterTaskOrganizer(ITaskOrganizer organizer) {
         final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
         state.unlinkDeath();
         if (mTaskOrganizersForWindowingMode.get(state.mWindowingMode) == state) {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 9a92832..a1902bb 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -2476,9 +2476,12 @@
 
     boolean prepareForSync(BLASTSyncEngine.TransactionReadyListener waitingListener,
             int waitingId) {
-        boolean willSync = false;
-        if (!isVisible()) {
-            return willSync;
+        boolean willSync = true;
+
+        // If we are invisible, no need to sync, likewise if we are already engaged in a sync,
+        // we can't support overlapping syncs on a single container yet.
+        if (!isVisible() || mWaitingListener != null) {
+            return false;
         }
         mUsingBLASTSyncTransaction = true;
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index eb18678..83fff28 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -186,6 +186,7 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.WorkSource;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.service.vr.IVrManager;
 import android.service.vr.IVrStateCallbacks;
@@ -1167,7 +1168,9 @@
         mAnimator = new WindowAnimator(this);
         mRoot = new RootWindowContainer(this);
 
-        mUseBLAST = true;
+        mUseBLAST = DeviceConfig.getBoolean(
+                    DeviceConfig.NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT,
+                    WM_USE_BLAST_ADAPTER_FLAG, false);
 
         mWindowPlacerLocked = new WindowSurfacePlacer(this);
         mTaskSnapshotController = new TaskSnapshotController(this);
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 336934e..822f383 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -1448,13 +1448,13 @@
 
     SET(BasebandCn0DbHz, measurement_V2_1->basebandCN0DbHz);
 
-    if (measurement_V2_1->flags & GnssMeasurementFlags::HAS_RECEIVER_ISB) {
-        SET(ReceiverInterSignalBiasNanos, measurement_V2_1->receiverInterSignalBiasNs);
+    if (measurement_V2_1->flags & GnssMeasurementFlags::HAS_FULL_ISB) {
+        SET(FullInterSignalBiasNanos, measurement_V2_1->fullInterSignalBiasNs);
     }
 
-    if (measurement_V2_1->flags & GnssMeasurementFlags::HAS_RECEIVER_ISB_UNCERTAINTY) {
-        SET(ReceiverInterSignalBiasUncertaintyNanos,
-            measurement_V2_1->receiverInterSignalBiasUncertaintyNs);
+    if (measurement_V2_1->flags & GnssMeasurementFlags::HAS_FULL_ISB_UNCERTAINTY) {
+        SET(FullInterSignalBiasUncertaintyNanos,
+            measurement_V2_1->fullInterSignalBiasUncertaintyNs);
     }
 
     if (measurement_V2_1->flags & GnssMeasurementFlags::HAS_SATELLITE_ISB) {
diff --git a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
index 29b2cd6..5f0c8fe3 100644
--- a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
+++ b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
@@ -598,6 +598,9 @@
     // IFS callbacks.
     void onPendingReads(dataloader::PendingReads pendingReads) final {
         std::lock_guard lock{mOutFdLock};
+        if (mOutFd < 0) {
+            return;
+        }
         CHECK(mIfs);
         for (auto&& pendingRead : pendingReads) {
             const android::dataloader::FileId& fileId = pendingRead.id;
@@ -611,13 +614,9 @@
                       android::incfs::toString(fileId).c_str());
                 continue;
             }
-            if (mRequestedFiles.insert(fileIdx).second) {
-                if (!sendRequest(mOutFd, PREFETCH, fileIdx, blockIdx)) {
-                    ALOGE("Failed to request prefetch for fileid=%s. Ignore.",
-                          android::incfs::toString(fileId).c_str());
-                    mRequestedFiles.erase(fileIdx);
-                    mStatusListener->reportStatus(DATA_LOADER_NO_CONNECTION);
-                }
+            if (mRequestedFiles.insert(fileIdx).second &&
+                !sendRequest(mOutFd, PREFETCH, fileIdx, blockIdx)) {
+                mRequestedFiles.erase(fileIdx);
             }
             sendRequest(mOutFd, BLOCK_MISSING, fileIdx, blockIdx);
         }
@@ -634,7 +633,7 @@
             }
             if (res < 0) {
                 ALOGE("Failed to poll. Abort.");
-                mStatusListener->reportStatus(DATA_LOADER_NO_CONNECTION);
+                mStatusListener->reportStatus(DATA_LOADER_UNRECOVERABLE);
                 break;
             }
             if (res == mEventFd) {
@@ -644,7 +643,7 @@
             }
             if (!readChunk(inout, data)) {
                 ALOGE("Failed to read a message. Abort.");
-                mStatusListener->reportStatus(DATA_LOADER_NO_CONNECTION);
+                mStatusListener->reportStatus(DATA_LOADER_UNRECOVERABLE);
                 break;
             }
             auto remainingData = std::span(data);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index fc9044a..6ab5303 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1076,6 +1076,7 @@
         private static final String TAG_PROFILE_OFF_DEADLINE = "profile-off-deadline";
         private static final String TAG_ALWAYS_ON_VPN_PACKAGE = "vpn-package";
         private static final String TAG_ALWAYS_ON_VPN_LOCKDOWN = "vpn-lockdown";
+        private static final String TAG_COMMON_CRITERIA_MODE = "common-criteria-mode";
         DeviceAdminInfo info;
 
 
@@ -1206,7 +1207,7 @@
 
         public String mAlwaysOnVpnPackage;
         public boolean mAlwaysOnVpnLockdown;
-
+        boolean mCommonCriteriaMode;
 
         ActiveAdmin(DeviceAdminInfo _info, boolean parent) {
             info = _info;
@@ -1454,6 +1455,9 @@
             if (mAlwaysOnVpnLockdown) {
                 writeAttributeValueToXml(out, TAG_ALWAYS_ON_VPN_LOCKDOWN, mAlwaysOnVpnLockdown);
             }
+            if (mCommonCriteriaMode) {
+                writeAttributeValueToXml(out, TAG_COMMON_CRITERIA_MODE, mCommonCriteriaMode);
+            }
         }
 
         void writeTextToXml(XmlSerializer out, String tag, String text) throws IOException {
@@ -1704,6 +1708,9 @@
                 } else if (TAG_ALWAYS_ON_VPN_LOCKDOWN.equals(tag)) {
                     mAlwaysOnVpnLockdown = Boolean.parseBoolean(
                             parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_COMMON_CRITERIA_MODE.equals(tag)) {
+                    mCommonCriteriaMode = Boolean.parseBoolean(
+                            parser.getAttributeValue(null, ATTR_VALUE));
                 } else {
                     Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
                     XmlUtils.skipCurrentTag(parser);
@@ -1940,6 +1947,8 @@
             pw.println(mAlwaysOnVpnPackage);
             pw.print("mAlwaysOnVpnLockdown=");
             pw.println(mAlwaysOnVpnLockdown);
+            pw.print("mCommonCriteriaMode=");
+            pw.println(mCommonCriteriaMode);
         }
     }
 
@@ -15606,28 +15615,38 @@
     }
 
     @Override
-    public void setCommonCriteriaModeEnabled(ComponentName admin, boolean enabled) {
+    public void setCommonCriteriaModeEnabled(ComponentName who, boolean enabled) {
+        final int userId = mInjector.userHandleGetCallingUserId();
         synchronized (getLockObject()) {
-            getActiveAdminForCallerLocked(admin,
+            final ActiveAdmin admin = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER);
+            admin.mCommonCriteriaMode = enabled;
+            saveSettingsLocked(userId);
         }
-        mInjector.binderWithCleanCallingIdentity(
-                () -> mInjector.settingsGlobalPutInt(Settings.Global.COMMON_CRITERIA_MODE,
-                        enabled ? 1 : 0));
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_COMMON_CRITERIA_MODE)
-                .setAdmin(admin)
+                .setAdmin(who)
                 .setBoolean(enabled)
                 .write();
     }
 
     @Override
-    public boolean isCommonCriteriaModeEnabled(ComponentName admin) {
-        synchronized (getLockObject()) {
-            getActiveAdminForCallerLocked(admin,
-                    DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER);
+    public boolean isCommonCriteriaModeEnabled(ComponentName who) {
+        if (who != null) {
+            synchronized (getLockObject()) {
+                final ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                        DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER);
+                return admin.mCommonCriteriaMode;
+            }
         }
-        return mInjector.settingsGlobalGetInt(Settings.Global.COMMON_CRITERIA_MODE, 0) != 0;
+        // Return aggregated state if caller is not admin (who == null).
+        synchronized (getLockObject()) {
+            // Only DO or COPE PO can turn on CC mode, so take a shortcut here and only look at
+            // their ActiveAdmin, instead of iterating through all admins.
+            final ActiveAdmin admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked(
+                    UserHandle.USER_SYSTEM);
+            return admin != null ? admin.mCommonCriteriaMode : false;
+        }
     }
 
     @Override
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 4da0091..ed85b93 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -941,7 +941,7 @@
     if (!dataloader) {
         return false;
     }
-    status = dataloader->start();
+    status = dataloader->start(mountId);
     if (!status.isOk()) {
         return false;
     }
@@ -1170,6 +1170,10 @@
             // If one lib file fails to be created, abort others as well
             break;
         }
+        // If it is a zero-byte file, skip data writing
+        if (uncompressedLen == 0) {
+            continue;
+        }
 
         // Write extracted data to new file
         std::vector<uint8_t> libData(uncompressedLen);
@@ -1248,14 +1252,6 @@
     }
 
     switch (newStatus) {
-        case IDataLoaderStatusListener::DATA_LOADER_NO_CONNECTION: {
-            // TODO(b/150411019): handle data loader connection loss
-            break;
-        }
-        case IDataLoaderStatusListener::DATA_LOADER_CONNECTION_OK: {
-            // TODO(b/150411019): handle data loader connection loss
-            break;
-        }
         case IDataLoaderStatusListener::DATA_LOADER_CREATED: {
             if (startRequested) {
                 incrementalService.startDataLoader(mountId);
@@ -1277,6 +1273,10 @@
         case IDataLoaderStatusListener::DATA_LOADER_IMAGE_NOT_READY: {
             break;
         }
+        case IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE: {
+            // Nothing for now. Rely on externalListener to handle this.
+            break;
+        }
         default: {
             LOG(WARNING) << "Unknown data loader status: " << newStatus
                          << " for mount: " << mountId;
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 6002226..f5b88d9 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -100,10 +100,11 @@
                           const sp<IDataLoaderStatusListener>&) override {
         return binder::Status::ok();
     }
-    binder::Status start() override { return binder::Status::ok(); }
-    binder::Status stop() override { return binder::Status::ok(); }
-    binder::Status destroy() override { return binder::Status::ok(); }
-    binder::Status prepareImage(const std::vector<InstallationFileParcel>&,
+    binder::Status start(int32_t) override { return binder::Status::ok(); }
+    binder::Status stop(int32_t) override { return binder::Status::ok(); }
+    binder::Status destroy(int32_t) override { return binder::Status::ok(); }
+    binder::Status prepareImage(int32_t,
+                                const std::vector<InstallationFileParcel>&,
                                 const std::vector<std::string>&) override {
         return binder::Status::ok();
     }
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
index efe8119..23381ff 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
@@ -46,6 +46,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManagerInternal;
 import android.os.Debug;
+import android.os.FileUtils;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Process;
@@ -55,6 +56,7 @@
 import android.text.TextUtils;
 import android.util.Pair;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
 import com.android.server.appop.AppOpsService;
@@ -71,10 +73,17 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
+import java.util.Random;
+import java.util.zip.GZIPInputStream;
 
 /**
  * Test class for {@link android.app.ApplicationExitInfo}.
@@ -119,6 +128,8 @@
         setFieldValue(AppExitInfoTracker.class, mAppExitInfoTracker, "mAppExitInfoSourceLmkd",
                 spy(mAppExitInfoTracker.new AppExitInfoExternalSource("lmkd",
                 ApplicationExitInfo.REASON_LOW_MEMORY)));
+        setFieldValue(AppExitInfoTracker.class, mAppExitInfoTracker, "mAppTraceRetriever",
+                spy(mAppExitInfoTracker.new AppTraceRetriever()));
         setFieldValue(ProcessList.class, mProcessList, "mAppExitInfoTracker", mAppExitInfoTracker);
         mInjector = new TestInjector(mContext);
         mAms = new ActivityManagerService(mInjector, mServiceThreadRule.getThread());
@@ -169,6 +180,11 @@
     public void testApplicationExitInfo() throws Exception {
         mAppExitInfoTracker.clearProcessExitInfo(true);
         mAppExitInfoTracker.mAppExitInfoLoaded = true;
+        mAppExitInfoTracker.mProcExitStoreDir = new File(mContext.getFilesDir(),
+                AppExitInfoTracker.APP_EXIT_STORE_DIR);
+        assertTrue(FileUtils.createDir(mAppExitInfoTracker.mProcExitStoreDir));
+        mAppExitInfoTracker.mProcExitInfoFile = new File(mAppExitInfoTracker.mProcExitStoreDir,
+                AppExitInfoTracker.APP_EXIT_INFO_FILE);
 
         // Test application calls System.exit()
         doNothing().when(mAppExitInfoTracker).schedulePersistProcessExitInfo(anyBoolean());
@@ -188,6 +204,10 @@
         final long app1Rss3 = 45680;
         final String app1ProcessName = "com.android.test.stub1:process";
         final String app1PackageName = "com.android.test.stub1";
+        final byte[] app1Cookie1 = {(byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04,
+                (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08};
+        final byte[] app1Cookie2 = {(byte) 0x08, (byte) 0x07, (byte) 0x06, (byte) 0x05,
+                (byte) 0x04, (byte) 0x03, (byte) 0x02, (byte) 0x01};
 
         final long now1 = System.currentTimeMillis();
         ProcessRecord app = makeProcessRecord(
@@ -204,6 +224,9 @@
 
         // Case 1: basic System.exit() test
         int exitCode = 5;
+        mAppExitInfoTracker.setProcessStateSummary(app1Uid, app1Pid1, app1Cookie1);
+        assertTrue(ArrayUtils.equals(mAppExitInfoTracker.getProcessStateSummary(app1Uid,
+                app1Pid1), app1Cookie1, app1Cookie1.length));
         doReturn(new Pair<Long, Object>(now1, Integer.valueOf(makeExitStatus(exitCode))))
                 .when(mAppExitInfoTracker.mAppExitInfoSourceZygote)
                 .remove(anyInt(), anyInt());
@@ -235,6 +258,10 @@
                 IMPORTANCE_CACHED,                    // importance
                 null);                                // description
 
+        assertTrue(ArrayUtils.equals(info.getProcessStateSummary(), app1Cookie1,
+                app1Cookie1.length));
+        assertEquals(info.getTraceInputStream(), null);
+
         // Case 2: create another app1 process record with a different pid
         sleep(1);
         final long now2 = System.currentTimeMillis();
@@ -250,6 +277,12 @@
                 app1ProcessName,        // processName
                 app1PackageName);       // packageName
         exitCode = 6;
+
+        mAppExitInfoTracker.setProcessStateSummary(app1Uid, app1Pid2, app1Cookie1);
+        // Override with a different cookie
+        mAppExitInfoTracker.setProcessStateSummary(app1Uid, app1Pid2, app1Cookie2);
+        assertTrue(ArrayUtils.equals(mAppExitInfoTracker.getProcessStateSummary(app1Uid,
+                app1Pid2), app1Cookie2, app1Cookie2.length));
         doReturn(new Pair<Long, Object>(now2, Integer.valueOf(makeExitStatus(exitCode))))
                 .when(mAppExitInfoTracker.mAppExitInfoSourceZygote)
                 .remove(anyInt(), anyInt());
@@ -280,6 +313,12 @@
                 IMPORTANCE_SERVICE,                   // importance
                 null);                                // description
 
+        assertTrue(ArrayUtils.equals(info.getProcessStateSummary(), app1Cookie2,
+                app1Cookie2.length));
+        info = list.get(1);
+        assertTrue(ArrayUtils.equals(info.getProcessStateSummary(), app1Cookie1,
+                app1Cookie1.length));
+
         // Case 3: Create an instance of app1 with different user, and died because of SIGKILL
         sleep(1);
         final long now3 = System.currentTimeMillis();
@@ -702,9 +741,19 @@
                 app1PackageName);             // packageName
 
         mAppExitInfoTracker.mIsolatedUidRecords.addIsolatedUid(app1IsolatedUid2User2, app1UidUser2);
+
+        // Pretent it gets an ANR trace too (although the reason here should be REASON_ANR)
+        final File traceFile = new File(mContext.getFilesDir(), "anr_original.txt");
+        final int traceSize = 10240;
+        final int traceStart = 1024;
+        final int traceEnd = 8192;
+        createRandomFile(traceFile, traceSize);
+        assertEquals(traceSize, traceFile.length());
+        mAppExitInfoTracker.handleLogAnrTrace(app.pid, app.uid, app.getPackageList(),
+                traceFile, traceStart, traceEnd);
+
         noteAppKill(app, ApplicationExitInfo.REASON_OTHER,
                 ApplicationExitInfo.SUBREASON_TOO_MANY_EMPTY, app1Description2);
-
         updateExitInfo(app);
         list.clear();
         mAppExitInfoTracker.getExitInfo(app1PackageName, app1UidUser2, app1Pid2User2, 1, list);
@@ -729,6 +778,10 @@
                 IMPORTANCE_CACHED,                            // importance
                 app1Description2);                            // description
 
+        // Verify if the traceFile get copied into the records correctly.
+        verifyTraceFile(traceFile, traceStart, info.getTraceFile(), 0, traceEnd - traceStart);
+        traceFile.delete();
+        info.getTraceFile().delete();
 
         // Case 9: User2 gets removed
         sleep(1);
@@ -801,8 +854,6 @@
         mAppExitInfoTracker.getExitInfo(null, app1Uid, 0, 0, original);
         assertTrue(original.size() > 0);
 
-        mAppExitInfoTracker.mProcExitInfoFile = new File(mContext.getFilesDir(),
-                AppExitInfoTracker.APP_EXIT_INFO_FILE);
         mAppExitInfoTracker.persistProcessExitInfo();
         assertTrue(mAppExitInfoTracker.mProcExitInfoFile.exists());
 
@@ -836,6 +887,37 @@
         }
     }
 
+    private static void createRandomFile(File file, int size) throws IOException {
+        try (BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file))) {
+            Random random = new Random();
+            byte[] buf = random.ints('a', 'z').limit(size).collect(
+                    StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
+                    .toString().getBytes();
+            out.write(buf);
+        }
+    }
+
+    private static void verifyTraceFile(File originFile, int originStart, File traceFile,
+            int traceStart, int length) throws IOException {
+        assertTrue(originFile.exists());
+        assertTrue(traceFile.exists());
+        assertTrue(originStart < originFile.length());
+        try (GZIPInputStream traceIn = new GZIPInputStream(new FileInputStream(traceFile));
+            BufferedInputStream originIn = new BufferedInputStream(
+                    new FileInputStream(originFile))) {
+            assertEquals(traceStart, traceIn.skip(traceStart));
+            assertEquals(originStart, originIn.skip(originStart));
+            byte[] buf1 = new byte[8192];
+            byte[] buf2 = new byte[8192];
+            while (length > 0) {
+                int len = traceIn.read(buf1, 0, Math.min(buf1.length, length));
+                assertEquals(len, originIn.read(buf2, 0, len));
+                assertTrue(ArrayUtils.equals(buf1, buf2, len));
+                length -= len;
+            }
+        }
+    }
+
     private ProcessRecord makeProcessRecord(int pid, int uid, int packageUid, Integer definingUid,
             int connectionGroup, int procState, long pss, long rss,
             String processName, String packageName) {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index d038d6c..f57b5f2 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -5990,26 +5990,29 @@
     public void testSetCommonCriteriaMode_asDeviceOwner() throws Exception {
         setDeviceOwner();
 
-        dpm.setCommonCriteriaModeEnabled(admin1, true);
-        verify(getServices().settings).settingsGlobalPutInt(
-                Settings.Global.COMMON_CRITERIA_MODE, 1);
+        assertFalse(dpm.isCommonCriteriaModeEnabled(admin1));
+        assertFalse(dpm.isCommonCriteriaModeEnabled(null));
 
-        when(getServices().settings.settingsGlobalGetInt(Settings.Global.COMMON_CRITERIA_MODE, 0))
-                .thenReturn(1);
+        dpm.setCommonCriteriaModeEnabled(admin1, true);
+
         assertTrue(dpm.isCommonCriteriaModeEnabled(admin1));
+        assertTrue(dpm.isCommonCriteriaModeEnabled(null));
     }
 
     public void testSetCommonCriteriaMode_asPoOfOrgOwnedDevice() throws Exception {
-        setupProfileOwner();
-        configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
+        final int managedProfileUserId = 15;
+        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
+        addManagedProfile(admin1, managedProfileAdminUid, admin1);
+        configureProfileOwnerOfOrgOwnedDevice(admin1, managedProfileUserId);
+        mContext.binder.callingUid = managedProfileAdminUid;
+
+        assertFalse(dpm.isCommonCriteriaModeEnabled(admin1));
+        assertFalse(dpm.isCommonCriteriaModeEnabled(null));
 
         dpm.setCommonCriteriaModeEnabled(admin1, true);
-        verify(getServices().settings).settingsGlobalPutInt(
-                Settings.Global.COMMON_CRITERIA_MODE, 1);
 
-        when(getServices().settings.settingsGlobalGetInt(Settings.Global.COMMON_CRITERIA_MODE, 0))
-                .thenReturn(1);
         assertTrue(dpm.isCommonCriteriaModeEnabled(admin1));
+        assertTrue(dpm.isCommonCriteriaModeEnabled(null));
     }
 
     public void testCanProfileOwnerResetPasswordWhenLocked_nonDirectBootAwarePo()
diff --git a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
index 2e60866..bbfc5ab 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
@@ -1275,25 +1275,8 @@
                     true /* valid */, true /* installed */));
 
         runWebViewBootPreparationOnMainSync();
-
         checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation phase */);
 
-        mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
-                WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0 /* userId */);
-        mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
-                WebViewUpdateService.PACKAGE_ADDED_REPLACED, 1 /* userId */);
-        mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
-                WebViewUpdateService.PACKAGE_ADDED_REPLACED, 2 /* userId */);
-        // package still has the same update-time so we shouldn't run preparation here
-        Mockito.verify(mTestSystemImpl, Mockito.times(1)).onWebViewProviderChanged(
-                Mockito.argThat(new IsPackageInfoWithName(primaryPackage)));
-
-        // Ensure we can still load the package
-        WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
-        assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
-        assertEquals(primaryPackage, response.packageInfo.packageName);
-
-
         mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
                     true /* valid */, true /* installed */, null /* signatures */,
                     20 /* lastUpdateTime*/ ));
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
index c449049..2acb647 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
@@ -51,6 +51,7 @@
         opts.setLaunchTaskId(Integer.MAX_VALUE);
         opts.setLockTaskEnabled(true);
         opts.setRotationAnimationHint(ROTATION_ANIMATION_ROTATE);
+        opts.setTaskAlwaysOnTop(true);
         opts.setTaskOverlay(true, true);
         opts.setSplitScreenCreateMode(SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT);
         Bundle optsBundle = opts.toBundle();
@@ -67,6 +68,7 @@
         assertEquals(Integer.MAX_VALUE, restoredOpts.getLaunchTaskId());
         assertTrue(restoredOpts.getLockTaskMode());
         assertEquals(ROTATION_ANIMATION_ROTATE, restoredOpts.getRotationAnimationHint());
+        assertTrue(restoredOpts.getTaskAlwaysOnTop());
         assertTrue(restoredOpts.getTaskOverlay());
         assertTrue(restoredOpts.canTaskOverlayResume());
         assertEquals(SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
index af04f76..fc256b0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
@@ -246,7 +246,7 @@
     }
 
     @Test
-    public void testWorkChallenge() {
+    public void testLockedManagedProfile() {
         // GIVEN that the user the activity is starting as is currently locked
         when(mAmInternal.shouldConfirmCredentials(TEST_USER_ID)).thenReturn(true);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index a380ece..bfb126f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.view.InsetsState.ITYPE_IME;
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
@@ -131,6 +132,21 @@
     }
 
     @Test
+    public void testStripForDispatch_multiwindow_alwaysOnTop() {
+        final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
+        final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
+        final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+
+        getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
+        getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
+        app.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        app.setAlwaysOnTop(true);
+
+        assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_STATUS_BAR));
+        assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_NAVIGATION_BAR));
+    }
+
+    @Test
     public void testImeForDispatch() {
         final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
         final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
index 8019e9d..71c837e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -550,6 +550,9 @@
         final Task task = createTaskInStack(stackController1, 0 /* userId */);
         final ITaskOrganizer organizer = registerMockOrganizer();
 
+        spyOn(task);
+        doReturn(true).when(task).isVisible();
+
         BLASTSyncEngine bse = new BLASTSyncEngine();
 
         BLASTSyncEngine.TransactionReadyListener transactionListener =
@@ -564,6 +567,35 @@
     }
 
     @Test
+    public void testOverlappingBLASTCallback() throws RemoteException {
+        final ActivityStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
+        final Task task = createTaskInStack(stackController1, 0 /* userId */);
+        final ITaskOrganizer organizer = registerMockOrganizer();
+
+        spyOn(task);
+        doReturn(true).when(task).isVisible();
+        final WindowState w = createAppWindow(task, TYPE_APPLICATION, "Enlightened Window");
+        makeWindowVisible(w);
+
+        BLASTSyncEngine bse = new BLASTSyncEngine();
+
+        BLASTSyncEngine.TransactionReadyListener transactionListener =
+            mock(BLASTSyncEngine.TransactionReadyListener.class);
+
+        int id = bse.startSyncSet(transactionListener);
+        assertEquals(true, bse.addToSyncSet(id, task));
+        bse.setReady(id);
+
+        int id2 = bse.startSyncSet(transactionListener);
+        // We should be rejected from the second sync since we are already
+        // in one.
+        assertEquals(false, bse.addToSyncSet(id2, task));
+        w.finishDrawing(null);
+        assertEquals(true, bse.addToSyncSet(id2, task));
+        bse.setReady(id2);
+    }
+
+    @Test
     public void testBLASTCallbackWithWindow() {
         final ActivityStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
         final Task task = createTaskInStack(stackController1, 0 /* userId */);
diff --git a/telephony/api/system-current.txt b/telephony/api/system-current.txt
index a49d3d53..11568f1 100644
--- a/telephony/api/system-current.txt
+++ b/telephony/api/system-current.txt
@@ -878,14 +878,10 @@
     field public static final String ACTION_EMERGENCY_CALLBACK_MODE_CHANGED = "android.intent.action.EMERGENCY_CALLBACK_MODE_CHANGED";
     field public static final String ACTION_EMERGENCY_CALL_STATE_CHANGED = "android.intent.action.EMERGENCY_CALL_STATE_CHANGED";
     field public static final String ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE = "com.android.omadm.service.CONFIGURATION_UPDATE";
-    field public static final String ACTION_SERVICE_PROVIDERS_UPDATED = "android.telephony.action.SERVICE_PROVIDERS_UPDATED";
     field public static final String ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS = "android.telephony.action.SHOW_NOTICE_ECM_BLOCK_OTHERS";
     field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED";
     field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED";
     field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED";
-    field public static final int CARD_POWER_DOWN = 0; // 0x0
-    field public static final int CARD_POWER_UP = 1; // 0x1
-    field public static final int CARD_POWER_UP_PASS_THROUGH = 2; // 0x2
     field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe
     field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
     field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
@@ -896,7 +892,6 @@
     field public static final String EXTRA_APN_PROTOCOL_INT = "apnProtoInt";
     field @Deprecated public static final String EXTRA_APN_TYPE = "apnType";
     field public static final String EXTRA_APN_TYPE_INT = "apnTypeInt";
-    field public static final String EXTRA_DATA_SPN = "android.telephony.extra.DATA_SPN";
     field public static final String EXTRA_DEFAULT_NETWORK_AVAILABLE = "defaultNetworkAvailable";
     field public static final String EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE = "android.telephony.extra.DEFAULT_SUBSCRIPTION_SELECT_TYPE";
     field public static final int EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_ALL = 4; // 0x4
@@ -909,16 +904,12 @@
     field public static final String EXTRA_PCO_VALUE = "pcoValue";
     field public static final String EXTRA_PHONE_IN_ECM_STATE = "android.telephony.extra.PHONE_IN_ECM_STATE";
     field public static final String EXTRA_PHONE_IN_EMERGENCY_CALL = "android.telephony.extra.PHONE_IN_EMERGENCY_CALL";
-    field public static final String EXTRA_PLMN = "android.telephony.extra.PLMN";
     field public static final String EXTRA_REDIRECTION_URL = "redirectionUrl";
-    field public static final String EXTRA_SHOW_PLMN = "android.telephony.extra.SHOW_PLMN";
-    field public static final String EXTRA_SHOW_SPN = "android.telephony.extra.SHOW_SPN";
     field public static final String EXTRA_SIM_COMBINATION_NAMES = "android.telephony.extra.SIM_COMBINATION_NAMES";
     field public static final String EXTRA_SIM_COMBINATION_WARNING_TYPE = "android.telephony.extra.SIM_COMBINATION_WARNING_TYPE";
     field public static final int EXTRA_SIM_COMBINATION_WARNING_TYPE_DUAL_CDMA = 1; // 0x1
     field public static final int EXTRA_SIM_COMBINATION_WARNING_TYPE_NONE = 0; // 0x0
     field public static final String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE";
-    field public static final String EXTRA_SPN = "android.telephony.extra.SPN";
     field public static final String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL";
     field public static final String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING";
     field public static final int INVALID_EMERGENCY_NUMBER_DB_VERSION = -1; // 0xffffffff
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index b897725..f0f9721 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -437,8 +437,9 @@
     /**
      * Returns whether the caller can read phone numbers.
      *
-     * <p>Besides apps with the ability to read phone state per {@link #checkReadPhoneState}, the
-     * default SMS app and apps with READ_SMS or READ_PHONE_NUMBERS can also read phone numbers.
+     * <p>Besides apps with the ability to read phone state per {@link #checkReadPhoneState}
+     * (only prior to R), the default SMS app and apps with READ_SMS or READ_PHONE_NUMBERS
+     * can also read phone numbers.
      */
     public static boolean checkCallingOrSelfReadPhoneNumber(
             Context context, int subId, String callingPackage, @Nullable String callingFeatureId,
@@ -451,8 +452,9 @@
     /**
      * Returns whether the caller can read phone numbers.
      *
-     * <p>Besides apps with the ability to read phone state per {@link #checkReadPhoneState}, the
-     * default SMS app and apps with READ_SMS or READ_PHONE_NUMBERS can also read phone numbers.
+     * <p>Besides apps with the ability to read phone state per {@link #checkReadPhoneState}
+     * (only prior to R), the default SMS app and apps with READ_SMS or READ_PHONE_NUMBERS
+     * can also read phone numbers.
      */
     @VisibleForTesting
     public static boolean checkReadPhoneNumber(
@@ -468,12 +470,15 @@
         // NOTE(b/73308711): If an app has one of the following AppOps bits explicitly revoked, they
         // will be denied access, even if they have another permission and AppOps bit if needed.
 
-        // First, check if we can read the phone state.
+        // First, check if we can read the phone state and the SDK version is below R.
         try {
-            return checkReadPhoneState(
-                    context, subId, pid, uid, callingPackage, callingFeatureId,
-                    message);
-        } catch (SecurityException readPhoneStateSecurityException) {
+            ApplicationInfo info = context.getPackageManager().getApplicationInfoAsUser(
+                    callingPackage, 0, UserHandle.getUserHandleForUid(Binder.getCallingUid()));
+            if (info.targetSdkVersion <= Build.VERSION_CODES.Q) {
+                return checkReadPhoneState(
+                        context, subId, pid, uid, callingPackage, callingFeatureId, message);
+            }
+        } catch (SecurityException | PackageManager.NameNotFoundException e) {
         }
         // Can be read with READ_SMS too.
         try {
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index 28cc7d0..b8a74d2 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -571,6 +571,19 @@
     public @interface PreciseDisconnectCauses {
     }
 
+    /**
+     * Carrier Privilege Status.
+     */
+    @IntDef(prefix = { "CARRIER_PRIVILEGE_STATUS_" }, value = {
+        TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS,
+        TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS,
+        TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED,
+        TelephonyManager.CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CarrierPrivilegeStatus {
+    }
+
     @IntDef({
             Connection.AUDIO_CODEC_NONE,
             Connection.AUDIO_CODEC_AMR,
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 5339fb9..d6f5bb2 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -71,6 +71,7 @@
 import android.telecom.TelecomManager;
 import android.telephony.Annotation.ApnType;
 import android.telephony.Annotation.CallState;
+import android.telephony.Annotation.CarrierPrivilegeStatus;
 import android.telephony.Annotation.NetworkType;
 import android.telephony.Annotation.RadioPowerState;
 import android.telephony.Annotation.SimActivationState;
@@ -1035,7 +1036,9 @@
             "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING";
 
     /**
-     * Broadcast intent that indicates multi-SIM configuration is changed. For example, it changed
+     * Broadcast action to be received by Broadcast receivers.
+     *
+     * Indicates multi-SIM configuration is changed. For example, it changed
      * from single SIM capable to dual-SIM capable (DSDS or DSDA) or triple-SIM mode.
      *
      * It doesn't indicate how many subscriptions are actually active, or which states SIMs are,
@@ -1278,7 +1281,6 @@
      * <p>Note: this is a protected intent that can only be sent by the system.
      * @hide
      */
-    @SystemApi
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_SERVICE_PROVIDERS_UPDATED =
             "android.telephony.action.SERVICE_PROVIDERS_UPDATED";
@@ -1288,7 +1290,6 @@
      * whether the PLMN should be shown.
      * @hide
      */
-    @SystemApi
     public static final String EXTRA_SHOW_PLMN = "android.telephony.extra.SHOW_PLMN";
 
     /**
@@ -1296,7 +1297,6 @@
      * the operator name of the registered network.
      * @hide
      */
-    @SystemApi
     public static final String EXTRA_PLMN = "android.telephony.extra.PLMN";
 
     /**
@@ -1304,7 +1304,6 @@
      * whether the PLMN should be shown.
      * @hide
      */
-    @SystemApi
     public static final String EXTRA_SHOW_SPN = "android.telephony.extra.SHOW_SPN";
 
     /**
@@ -1312,7 +1311,6 @@
      * the service provider name.
      * @hide
      */
-    @SystemApi
     public static final String EXTRA_SPN = "android.telephony.extra.SPN";
 
     /**
@@ -1320,7 +1318,6 @@
      * the service provider name for data service.
      * @hide
      */
-    @SystemApi
     public static final String EXTRA_DATA_SPN = "android.telephony.extra.DATA_SPN";
 
     /**
@@ -4327,14 +4324,18 @@
 
     /**
      * Returns the phone number string for line 1, for example, the MSISDN
-     * for a GSM phone. Return null if it is unavailable.
+     * for a GSM phone for a particular subscription. Return null if it is unavailable.
+     * <p>
+     * The default SMS app can also use this.
      *
      * <p>Requires Permission:
-     *     {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE},
      *     {@link android.Manifest.permission#READ_SMS READ_SMS},
      *     {@link android.Manifest.permission#READ_PHONE_NUMBERS READ_PHONE_NUMBERS},
      *     that the caller is the default SMS app,
-     *     or that the caller has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *     or that the caller has carrier privileges (see {@link #hasCarrierPrivileges})
+     *     for any API level.
+     *     {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *     for apps targeting SDK API level 29 and below.
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges or default SMS app
     @RequiresPermission(anyOf = {
@@ -4352,6 +4353,15 @@
      * <p>
      * The default SMS app can also use this.
      *
+     * <p>Requires Permission:
+     *     {@link android.Manifest.permission#READ_SMS READ_SMS},
+     *     {@link android.Manifest.permission#READ_PHONE_NUMBERS READ_PHONE_NUMBERS},
+     *     that the caller is the default SMS app,
+     *     or that the caller has carrier privileges (see {@link #hasCarrierPrivileges})
+     *     for any API level.
+     *     {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *     for apps targeting SDK API level 29 and below.
+     *
      * @param subId whose phone number for line 1 is returned
      * @hide
      */
@@ -4532,25 +4542,50 @@
     }
 
     /**
-     * Returns the MSISDN string.
-     * for a GSM phone. Return null if it is unavailable.
+     * Returns the MSISDN string for a GSM phone. Return null if it is unavailable.
+     *
+     * <p>Requires Permission:
+     *     {@link android.Manifest.permission#READ_SMS READ_SMS},
+     *     {@link android.Manifest.permission#READ_PHONE_NUMBERS READ_PHONE_NUMBERS},
+     *     that the caller is the default SMS app,
+     *     or that the caller has carrier privileges (see {@link #hasCarrierPrivileges})
+     *     for any API level.
+     *     {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *     for apps targeting SDK API level 29 and below.
      *
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.READ_PHONE_STATE,
+            android.Manifest.permission.READ_SMS,
+            android.Manifest.permission.READ_PHONE_NUMBERS
+    })
     @UnsupportedAppUsage
     public String getMsisdn() {
         return getMsisdn(getSubId());
     }
 
     /**
-     * Returns the MSISDN string.
-     * for a GSM phone. Return null if it is unavailable.
+     * Returns the MSISDN string for a GSM phone. Return null if it is unavailable.
      *
      * @param subId for which msisdn is returned
+     *
+     * <p>Requires Permission:
+     *     {@link android.Manifest.permission#READ_SMS READ_SMS},
+     *     {@link android.Manifest.permission#READ_PHONE_NUMBERS READ_PHONE_NUMBERS},
+     *     that the caller is the default SMS app,
+     *     or that the caller has carrier privileges (see {@link #hasCarrierPrivileges})
+     *     for any API level.
+     *     {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *     for apps targeting SDK API level 29 and below.
+     *
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.READ_PHONE_STATE,
+            android.Manifest.permission.READ_SMS,
+            android.Manifest.permission.READ_PHONE_NUMBERS
+    })
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getMsisdn(int subId) {
         try {
@@ -9708,14 +9743,12 @@
      * Powers down the SIM. SIM must be up prior.
      * @hide
      */
-    @SystemApi
     public static final int CARD_POWER_DOWN = 0;
 
     /**
      * Powers up the SIM normally. SIM must be down prior.
      * @hide
      */
-    @SystemApi
     public static final int CARD_POWER_UP = 1;
 
     /**
@@ -9733,7 +9766,6 @@
      * is NOT persistent across boots. On reboot, SIM will power up normally.
      * @hide
      */
-    @SystemApi
     public static final int CARD_POWER_UP_PASS_THROUGH = 2;
 
     /**
@@ -11162,8 +11194,6 @@
                 retVal = telephony.isDataEnabled(subId);
         } catch (RemoteException e) {
             Log.e(TAG, "Error isDataConnectionAllowed", e);
-        } catch (NullPointerException e) {
-            return false;
         }
         return retVal;
     }
@@ -12450,7 +12480,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public int getCarrierPrivilegeStatus(int uid) {
+    public @CarrierPrivilegeStatus int getCarrierPrivilegeStatus(int uid) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
diff --git a/tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java b/tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java
index ae20cae..629b6c7 100644
--- a/tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java
+++ b/tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java
@@ -98,7 +98,8 @@
         mDevice = getDevice();
 
         String apkVerityMode = mDevice.getProperty("ro.apk_verity.mode");
-        assumeTrue(APK_VERITY_STANDARD_MODE.equals(apkVerityMode));
+        assumeTrue(mDevice.getLaunchApiLevel() >= 30
+                || APK_VERITY_STANDARD_MODE.equals(apkVerityMode));
 
         mKeyId = expectRemoteCommandToSucceed(
                 "mini-keyctl padd asymmetric fsv_test .fs-verity < " + CERT_PATH).trim();
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index da45d9a..2f9a1c8 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -71,6 +71,7 @@
     // with the app launch
     private static final String KEY_REQUIRED_ACCOUNTS = "required_accounts";
     private static final String KEY_APPS = "apps";
+    private static final String KEY_IORAP_TRIAL_LAUNCH = "iorap_trial_launch";
     private static final String KEY_TRIAL_LAUNCH = "trial_launch";
     private static final String KEY_LAUNCH_ITERATIONS = "launch_iterations";
     private static final String KEY_LAUNCH_ORDER = "launch_order";
@@ -98,6 +99,9 @@
     private static final int BEFORE_KILL_APP_SLEEP_TIMEOUT = 1000; // 1s before killing
     private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 3000; // 3s between launching apps
     private static final int PROFILE_SAVE_SLEEP_TIMEOUT = 1000; // Allow 1s for the profile to save
+    private static final int IORAP_TRACE_DURATION_TIMEOUT = 7000; // Allow 7s for trace to complete.
+    private static final int IORAP_TRIAL_LAUNCH_ITERATIONS = 3;  // min 3 launches to merge traces.
+    private static final int IORAP_COMPILE_CMD_TIMEOUT = 600;  // in seconds: 10 minutes
     private static final String LAUNCH_SUB_DIRECTORY = "launch_logs";
     private static final String LAUNCH_FILE = "applaunch.txt";
     private static final String TRACE_SUB_DIRECTORY = "atrace_logs";
@@ -106,6 +110,9 @@
     private static final String DEFAULT_TRACE_BUFFER_SIZE = "20000";
     private static final String DEFAULT_TRACE_DUMP_INTERVAL = "10";
     private static final String TRIAL_LAUNCH = "TRIAL_LAUNCH";
+    private static final String IORAP_TRIAL_LAUNCH = "IORAP_TRIAL_LAUNCH";
+    private static final String IORAP_TRIAL_LAUNCH_FIRST = "IORAP_TRIAL_LAUNCH_FIRST";
+    private static final String IORAP_TRIAL_LAUNCH_LAST = "IORAP_TRIAL_LAUNCH_LAST";
     private static final String DELIMITER = ",";
     private static final String DROP_CACHE_SCRIPT = "/data/local/tmp/dropCache.sh";
     private static final String APP_LAUNCH_CMD = "am start -W -n";
@@ -119,6 +126,10 @@
     private static final String LAUNCH_ORDER_CYCLIC = "cyclic";
     private static final String LAUNCH_ORDER_SEQUENTIAL = "sequential";
     private static final String COMPILE_CMD = "cmd package compile -f -m %s %s";
+    private static final String IORAP_COMPILE_CMD = "cmd jobscheduler run -f android 283673059";
+    private static final String IORAP_MAINTENANCE_CMD =
+            "iorap.cmd.maintenance --purge-package %s /data/misc/iorapd/sqlite.db";
+    private static final String IORAP_DUMPSYS_CMD = "dumpsys iorapd";
     private static final String SPEED_PROFILE_FILTER = "speed-profile";
     private static final String VERIFY_FILTER = "verify";
     private static final String LAUNCH_SCRIPT_NAME = "appLaunch";
@@ -138,6 +149,7 @@
     private Bundle mResult = new Bundle();
     private Set<String> mRequiredAccounts;
     private boolean mTrialLaunch = false;
+    private boolean mIorapTrialLaunch = false;
     private BufferedWriter mBufferedWriter = null;
     private boolean mSimplePerfAppOnly = false;
     private String[] mCompilerFilters = null;
@@ -145,6 +157,13 @@
     private boolean mCycleCleanUp = false;
     private boolean mTraceAll = false;
     private boolean mIterationCycle = false;
+
+    enum IorapStatus {
+        UNDEFINED,
+        ENABLED,
+        DISABLED
+    }
+    private IorapStatus mIorapStatus = IorapStatus.UNDEFINED;
     private long mCycleTime = 0;
     private StringBuilder mCycleTimes = new StringBuilder();
 
@@ -243,7 +262,10 @@
             setLaunchOrder();
 
             for (LaunchOrder launch : mLaunchOrderList) {
-                dropCache();
+                toggleIorapStatus(launch.getIorapEnabled());
+                dropCache(/*override*/false);
+
+                Log.v(TAG, "Launch reason: " + launch.getLaunchReason());
 
                 // App launch times for trial launch will not be used for final
                 // launch time calculations.
@@ -289,6 +311,43 @@
                               compileApp(launch.getCompilerFilter(), appPkgName));
                     }
                 }
+                else if (launch.getLaunchReason().startsWith(IORAP_TRIAL_LAUNCH)) {
+                    mIterationCycle = false;
+
+                    // In the "applaunch.txt" file, iorap-trial launches is referenced using
+                    // "IORAP_TRIAL_LAUNCH" or "IORAP_TRIAL_LAUNCH_LAST"
+                    Intent startIntent = mNameToIntent.get(launch.getApp());
+                    if (startIntent == null) {
+                        Log.w(TAG, "App does not exist: " + launch.getApp());
+                        mResult.putString(mNameToResultKey.get(launch.getApp()),
+                            "App does not exist");
+                        continue;
+                    }
+                    String appPkgName = startIntent.getComponent().getPackageName();
+
+                    if (launch.getLaunchReason().equals(IORAP_TRIAL_LAUNCH_FIRST)) {
+                        // delete any iorap-traces associated with this package.
+                        purgeIorapPackage(appPkgName);
+                    }
+                    dropCache(/*override*/true);  // iorap-trial runs must have drop cache.
+
+                    AppLaunchResult launchResult =
+                        startApp(launch.getApp(), launch.getLaunchReason());
+                    if (launchResult.mLaunchTime < 0) {
+                        addLaunchResult(launch, new AppLaunchResult());
+                        // simply pass the app if launch isn't successful
+                        // error should have already been logged by startApp
+                        continue;
+                    }
+                    // wait for slightly more than 5s (iorapd.perfetto.trace_duration_ms) for the trace buffers to complete.
+                    sleep(IORAP_TRACE_DURATION_TIMEOUT);
+
+                    if (launch.getLaunchReason().equals(IORAP_TRIAL_LAUNCH_LAST)) {
+                        // run the iorap job scheduler and wait for iorap to compile fully.
+                        assertTrue(String.format("Not able to iorap-compile the app : %s", appPkgName),
+                                compileAppForIorap(appPkgName));
+                    }
+                }
 
                 // App launch times used for final calculation
                 else if (launch.getLaunchReason().contains(LAUNCH_ITERATION_PREFIX)) {
@@ -440,6 +499,74 @@
     }
 
     /**
+     * Compile the app package using compilerFilter and return true or false
+     * based on status of the compilation command.
+     */
+    private boolean compileAppForIorap(String appPkgName) throws IOException {
+        getInstrumentation().getUiAutomation().
+                executeShellCommand(IORAP_COMPILE_CMD);
+
+        for (int i = 0; i < IORAP_COMPILE_CMD_TIMEOUT; ++i) {
+            IorapCompilationStatus status = waitForIorapCompiled(appPkgName);
+            if (status == IorapCompilationStatus.COMPLETE) {
+                return true;
+            } else if (status == IorapCompilationStatus.INSUFFICIENT_TRACES) {
+                return false;
+            } // else INCOMPLETE. keep asking iorapd if it's done yet.
+            sleep(1000);
+        }
+
+        return false;
+    }
+
+    enum IorapCompilationStatus {
+        INCOMPLETE,
+        COMPLETE,
+        INSUFFICIENT_TRACES,
+    }
+    private IorapCompilationStatus waitForIorapCompiled(String appPkgName) throws IOException {
+        try (ParcelFileDescriptor result = getInstrumentation().getUiAutomation().
+                executeShellCommand(IORAP_DUMPSYS_CMD);
+                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
+                        new FileInputStream(result.getFileDescriptor())))) {
+            String line;
+            String prevLine = "";
+            while ((line = bufferedReader.readLine()) != null) {
+                // Match the indented VersionedComponentName string.
+                // "  com.google.android.deskclock/com.android.deskclock.DeskClock@62000712"
+                // Note: spaces are meaningful here.
+                if (prevLine.contains("  " + appPkgName) && prevLine.contains("@")) {
+                    // pre-requisite:
+                    // Compiled Status: Raw traces pending compilation (3)
+                    if (line.contains("Compiled Status: Usable compiled trace")) {
+                        return IorapCompilationStatus.COMPLETE;
+                    } else if (line.contains("Compiled Status: ") &&
+                            line.contains("more traces for compilation")) {
+                        //      Compiled Status: Need 1 more traces for compilation
+                        // No amount of waiting will help here because there were
+                        // insufficient traces made.
+                        return IorapCompilationStatus.INSUFFICIENT_TRACES;
+                    }
+                }
+
+                prevLine = line;
+            }
+            return IorapCompilationStatus.INCOMPLETE;
+        }
+    }
+
+    private String makeReasonForIorapTrialLaunch(int launchCount) {
+        String reason = IORAP_TRIAL_LAUNCH;
+        if (launchCount == 0) {
+            reason = IORAP_TRIAL_LAUNCH_FIRST;
+        }
+        if (launchCount == IORAP_TRIAL_LAUNCH_ITERATIONS - 1) {
+            reason = IORAP_TRIAL_LAUNCH_LAST;
+        }
+        return reason;
+    }
+
+    /**
      * If launch order is "cyclic" then apps will be launched one after the
      * other for each iteration count.
      * If launch order is "sequential" then each app will be launched for given number
@@ -450,20 +577,31 @@
             for (String compilerFilter : mCompilerFilters) {
                 if (mTrialLaunch) {
                     for (String app : mNameToResultKey.keySet()) {
-                        mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH));
+                        mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH, /*iorapEnabled*/false));
+                    }
+                }
+                if (mIorapTrialLaunch) {
+                    for (int launchCount = 0; launchCount < IORAP_TRIAL_LAUNCH_ITERATIONS; ++launchCount) {
+                        for (String app : mNameToResultKey.keySet()) {
+                            String reason = makeReasonForIorapTrialLaunch(launchCount);
+                            mLaunchOrderList.add(
+                                    new LaunchOrder(app, compilerFilter,
+                                            reason,
+                                            /*iorapEnabled*/true));
+                        }
                     }
                 }
                 for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
                     for (String app : mNameToResultKey.keySet()) {
                         mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
-                                  String.format(LAUNCH_ITERATION, launchCount)));
+                                  String.format(LAUNCH_ITERATION, launchCount), mIorapTrialLaunch));
                     }
                 }
                 if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
                     for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
                         for (String app : mNameToResultKey.keySet()) {
                             mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
-                                      String.format(TRACE_ITERATION, traceCount)));
+                                      String.format(TRACE_ITERATION, traceCount), mIorapTrialLaunch));
                         }
                     }
                 }
@@ -472,16 +610,25 @@
             for (String compilerFilter : mCompilerFilters) {
                 for (String app : mNameToResultKey.keySet()) {
                     if (mTrialLaunch) {
-                        mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH));
+                        mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH, /*iorapEnabled*/false));
+                    }
+                    if (mIorapTrialLaunch) {
+                        for (int launchCount = 0; launchCount < IORAP_TRIAL_LAUNCH_ITERATIONS; ++launchCount) {
+                            String reason = makeReasonForIorapTrialLaunch(launchCount);
+                            mLaunchOrderList.add(
+                                    new LaunchOrder(app, compilerFilter,
+                                            reason,
+                                            /*iorapEnabled*/true));
+                        }
                     }
                     for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
                         mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
-                                String.format(LAUNCH_ITERATION, launchCount)));
+                                String.format(LAUNCH_ITERATION, launchCount), mIorapTrialLaunch));
                     }
                     if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
                         for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
                             mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
-                                    String.format(TRACE_ITERATION, traceCount)));
+                                    String.format(TRACE_ITERATION, traceCount), mIorapTrialLaunch));
                         }
                     }
                 }
@@ -491,14 +638,92 @@
         }
     }
 
-    private void dropCache() {
-        if (mDropCache) {
+    private void dropCache(boolean override) {
+        if (mDropCache || override) {
             assertNotNull("Issue in dropping the cache",
                     getInstrumentation().getUiAutomation()
                             .executeShellCommand(DROP_CACHE_SCRIPT));
         }
     }
 
+    // [[ $(adb shell whoami) == "root" ]]
+    private boolean checkIfRoot() throws IOException {
+        String total = "";
+        try (ParcelFileDescriptor result = getInstrumentation().getUiAutomation().
+                executeShellCommand("whoami");
+                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
+                        new FileInputStream(result.getFileDescriptor())))) {
+            String line;
+            while ((line = bufferedReader.readLine()) != null) {
+                total = total + line;
+            }
+        }
+        return total.contains("root");
+    }
+
+    // Delete all db rows and files associated with a package in iorapd.
+    // Effectively deletes any raw or compiled trace files, unoptimizing the package in iorap.
+    private void purgeIorapPackage(String packageName) {
+        try {
+            if (!checkIfRoot()) {
+                throw new AssertionError("must be root to toggle iorapd; try adb root?");
+            }
+        } catch (IOException e) {
+            throw new AssertionError(e);
+        }
+
+        getInstrumentation().getUiAutomation()
+                .executeShellCommand("stop iorapd");
+        sleep(100);  // give iorapd enough time to stop.
+        getInstrumentation().getUiAutomation()
+                .executeShellCommand(String.format(IORAP_MAINTENANCE_CMD, packageName));
+        Log.v(TAG, "Executed: " + String.format(IORAP_MAINTENANCE_CMD, packageName));
+        getInstrumentation().getUiAutomation()
+                .executeShellCommand("start iorapd");
+        sleep(2000);  // give iorapd enough time to start up.
+    }
+
+    /**
+     * Toggle iorapd-based readahead and trace-collection.
+     * If iorapd is already enabled and enable is true, does nothing.
+     * If iorapd is already disabled and enable is false, does nothing.
+     */
+    private void toggleIorapStatus(boolean enable) {
+        boolean currentlyEnabled = false;
+        Log.v(TAG, "toggleIorapStatus " + Boolean.toString(enable));
+
+        // Do nothing if we are already enabled or disabled.
+        if (mIorapStatus == IorapStatus.ENABLED && enable) {
+            return;
+        } else if (mIorapStatus == IorapStatus.DISABLED && !enable) {
+            return;
+        }
+
+        try {
+            if (!checkIfRoot()) {
+                throw new AssertionError("must be root to toggle iorapd; try adb root?");
+            }
+        } catch (IOException e) {
+            throw new AssertionError(e);
+        }
+
+        getInstrumentation().getUiAutomation()
+                .executeShellCommand("stop iorapd");
+        getInstrumentation().getUiAutomation()
+                .executeShellCommand(String.format("setprop iorapd.perfetto.enable %b", enable));
+        getInstrumentation().getUiAutomation()
+                .executeShellCommand(String.format("setprop iorapd.readahead.enable %b", enable));
+        getInstrumentation().getUiAutomation()
+                .executeShellCommand("start iorapd");
+        sleep(2000);  // give enough time for iorapd to start back up.
+
+        if (enable) {
+            mIorapStatus = IorapStatus.ENABLED;
+        } else {
+            mIorapStatus = IorapStatus.DISABLED;
+        }
+    }
+
     private void parseArgs(Bundle args) {
         mNameToResultKey = new LinkedHashMap<String, String>();
         mNameToLaunchTime = new HashMap<>();
@@ -562,6 +787,8 @@
         mCycleCleanUp = Boolean.parseBoolean(args.getString(KEY_CYCLE_CLEAN));
         mTraceAll = Boolean.parseBoolean(args.getString(KEY_TRACE_ALL));
         mTrialLaunch = mTrialLaunch || Boolean.parseBoolean(args.getString(KEY_TRIAL_LAUNCH));
+        mIorapTrialLaunch = mIorapTrialLaunch ||
+                Boolean.parseBoolean(args.getString(KEY_IORAP_TRIAL_LAUNCH));
 
         if (mSimplePerfCmd != null && mSimplePerfAppOnly) {
             Log.w(TAG, String.format("Passing both %s and %s is not supported, ignoring %s",
@@ -740,11 +967,13 @@
         private String mApp;
         private String mCompilerFilter;
         private String mLaunchReason;
+        private boolean mIorapEnabled;
 
-        LaunchOrder(String app, String compilerFilter, String launchReason){
+        LaunchOrder(String app, String compilerFilter, String launchReason, boolean iorapEnabled) {
             mApp = app;
             mCompilerFilter = compilerFilter;
             mLaunchReason = launchReason;
+            mIorapEnabled = iorapEnabled;
         }
 
         public String getApp() {
@@ -766,6 +995,14 @@
         public void setLaunchReason(String launchReason) {
             mLaunchReason = launchReason;
         }
+
+        public void setIorapEnabled(boolean iorapEnabled) {
+            mIorapEnabled = iorapEnabled;
+        }
+
+        public boolean getIorapEnabled() {
+            return mIorapEnabled;
+        }
     }
 
     private class AppLaunchResult {
diff --git a/tests/RollbackTest/RollbackTest.xml b/tests/RollbackTest/RollbackTest.xml
index f2c0f86..269cec1 100644
--- a/tests/RollbackTest/RollbackTest.xml
+++ b/tests/RollbackTest/RollbackTest.xml
@@ -18,6 +18,12 @@
     <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
         <option name="test-file-name" value="RollbackTest.apk" />
     </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es package &quot;com.google.android.gms.platformconfigurator&quot; --es user '\\*' --esa flags &quot;ModuleConfig__immediate_commit_packages&quot; --esa types &quot;bytes&quot; --esa values &quot;CgA=&quot; com.google.android.gms" />
+        <option name="run-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es package &quot;com.google.android.gms.platformconfigurator&quot; --es user '\\*' --esa flags &quot;ModuleConfig__versioned_immediate_commit_packages&quot; --esa types &quot;bytes&quot; --esa values &quot;Cm5vdGFwYWNrYWdlOgA=&quot; com.google.android.gms" />
+        <option name="teardown-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es action delete --es package &quot;com.google.android.gms.platformconfigurator&quot; --es user '\*' --esa flag &quot;ModuleConfig__immediate_commit_packages&quot; com.google.android.gms" />
+        <option name="teardown-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es action delete --es package &quot;com.google.android.gms.platformconfigurator&quot; --es user '\*' --esa flag &quot;ModuleConfig__versioned_immediate_commit_packages&quot; com.google.android.gms" />
+    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.tests.rollback" />
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
diff --git a/tests/net/common/Android.bp b/tests/net/common/Android.bp
index e44d460..46d680f 100644
--- a/tests/net/common/Android.bp
+++ b/tests/net/common/Android.bp
@@ -20,6 +20,7 @@
     name: "FrameworksNetCommonTests",
     srcs: ["java/**/*.java", "java/**/*.kt"],
     static_libs: [
+        "androidx.core_core",
         "androidx.test.rules",
         "junit",
         "mockito-target-minus-junit4",
diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java
index 48b65e5..2b5720a 100644
--- a/tests/net/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/common/java/android/net/LinkPropertiesTest.java
@@ -29,12 +29,19 @@
 
 import android.net.LinkProperties.ProvisioningChange;
 import android.net.util.LinkPropertiesUtils.CompareResult;
+import android.os.Build;
 import android.system.OsConstants;
 import android.util.ArraySet;
 
+import androidx.core.os.BuildCompat;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -50,6 +57,9 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class LinkPropertiesTest {
+    @Rule
+    public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
+
     private static final InetAddress ADDRV4 = address("75.208.6.1");
     private static final InetAddress ADDRV6 = address("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
     private static final InetAddress DNS1 = address("75.208.7.1");
@@ -76,13 +86,23 @@
     private static final LinkAddress LINKADDRV6 = new LinkAddress(ADDRV6, 128);
     private static final LinkAddress LINKADDRV6LINKLOCAL = new LinkAddress("fe80::1/64");
     private static final Uri CAPPORT_API_URL = Uri.parse("https://test.example.com/capportapi");
-    private static final CaptivePortalData CAPPORT_DATA = new CaptivePortalData.Builder()
-            .setVenueInfoUrl(Uri.parse("https://test.example.com/venue")).build();
+
+    // CaptivePortalData cannot be in a constant as it does not exist on Q.
+    // The test runner also crashes when scanning for tests if it is a return type.
+    private static Object getCaptivePortalData() {
+        return new CaptivePortalData.Builder()
+                .setVenueInfoUrl(Uri.parse("https://test.example.com/venue")).build();
+    }
 
     private static InetAddress address(String addrString) {
         return InetAddresses.parseNumericAddress(addrString);
     }
 
+    private static boolean isAtLeastR() {
+        // BuildCompat.isAtLeastR is documented to return false on release SDKs (including R)
+        return Build.VERSION.SDK_INT > Build.VERSION_CODES.Q || BuildCompat.isAtLeastR();
+    }
+
     private void checkEmpty(final LinkProperties lp) {
         assertEquals(0, lp.getAllInterfaceNames().size());
         assertEquals(0, lp.getAllAddresses().size());
@@ -98,14 +118,17 @@
         assertNull(lp.getHttpProxy());
         assertNull(lp.getTcpBufferSizes());
         assertNull(lp.getNat64Prefix());
-        assertNull(lp.getDhcpServerAddress());
         assertFalse(lp.isProvisioned());
         assertFalse(lp.isIpv4Provisioned());
         assertFalse(lp.isIpv6Provisioned());
         assertFalse(lp.isPrivateDnsActive());
-        assertFalse(lp.isWakeOnLanSupported());
-        assertNull(lp.getCaptivePortalApiUrl());
-        assertNull(lp.getCaptivePortalData());
+
+        if (isAtLeastR()) {
+            assertNull(lp.getDhcpServerAddress());
+            assertFalse(lp.isWakeOnLanSupported());
+            assertNull(lp.getCaptivePortalApiUrl());
+            assertNull(lp.getCaptivePortalData());
+        }
     }
 
     private LinkProperties makeTestObject() {
@@ -127,10 +150,12 @@
         lp.setMtu(MTU);
         lp.setTcpBufferSizes(TCP_BUFFER_SIZES);
         lp.setNat64Prefix(new IpPrefix("2001:db8:0:64::/96"));
-        lp.setDhcpServerAddress(DHCPSERVER);
-        lp.setWakeOnLanSupported(true);
-        lp.setCaptivePortalApiUrl(CAPPORT_API_URL);
-        lp.setCaptivePortalData(CAPPORT_DATA);
+        if (isAtLeastR()) {
+            lp.setDhcpServerAddress(DHCPSERVER);
+            lp.setWakeOnLanSupported(true);
+            lp.setCaptivePortalApiUrl(CAPPORT_API_URL);
+            lp.setCaptivePortalData((CaptivePortalData) getCaptivePortalData());
+        }
         return lp;
     }
 
@@ -169,14 +194,19 @@
         assertTrue(source.isIdenticalTcpBufferSizes(target));
         assertTrue(target.isIdenticalTcpBufferSizes(source));
 
-        assertTrue(source.isIdenticalWakeOnLan(target));
-        assertTrue(target.isIdenticalWakeOnLan(source));
+        if (isAtLeastR()) {
+            assertTrue(source.isIdenticalDhcpServerAddress(target));
+            assertTrue(source.isIdenticalDhcpServerAddress(source));
 
-        assertTrue(source.isIdenticalCaptivePortalApiUrl(target));
-        assertTrue(target.isIdenticalCaptivePortalApiUrl(source));
+            assertTrue(source.isIdenticalWakeOnLan(target));
+            assertTrue(target.isIdenticalWakeOnLan(source));
 
-        assertTrue(source.isIdenticalCaptivePortalData(target));
-        assertTrue(target.isIdenticalCaptivePortalData(source));
+            assertTrue(source.isIdenticalCaptivePortalApiUrl(target));
+            assertTrue(target.isIdenticalCaptivePortalApiUrl(source));
+
+            assertTrue(source.isIdenticalCaptivePortalData(target));
+            assertTrue(target.isIdenticalCaptivePortalData(source));
+        }
 
         // Check result of equals().
         assertTrue(source.equals(target));
@@ -943,8 +973,7 @@
         assertEquals(new ArraySet<>(expectRemoved), (new ArraySet<>(result.removed)));
     }
 
-    @Test
-    public void testLinkPropertiesParcelable() throws Exception {
+    private static LinkProperties makeLinkPropertiesForParceling() {
         LinkProperties source = new LinkProperties();
         source.setInterfaceName(NAME);
 
@@ -978,17 +1007,29 @@
 
         source.setNat64Prefix(new IpPrefix("2001:db8:1:2:64:64::/96"));
 
-        source.setWakeOnLanSupported(true);
-        source.setCaptivePortalApiUrl(CAPPORT_API_URL);
-        source.setCaptivePortalData(CAPPORT_DATA);
-
-        source.setDhcpServerAddress((Inet4Address) GATEWAY1);
-
         final LinkProperties stacked = new LinkProperties();
         stacked.setInterfaceName("test-stacked");
         source.addStackedLink(stacked);
 
-        assertParcelSane(source.makeSensitiveFieldsParcelingCopy(), 18 /* fieldCount */);
+        return source;
+    }
+
+    @Test @IgnoreAfter(Build.VERSION_CODES.Q)
+    public void testLinkPropertiesParcelable_Q() throws Exception {
+        final LinkProperties source = makeLinkPropertiesForParceling();
+        assertParcelSane(source, 14 /* fieldCount */);
+    }
+
+    @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+    public void testLinkPropertiesParcelable() throws Exception {
+        final LinkProperties source = makeLinkPropertiesForParceling();
+
+        source.setWakeOnLanSupported(true);
+        source.setCaptivePortalApiUrl(CAPPORT_API_URL);
+        source.setCaptivePortalData((CaptivePortalData) getCaptivePortalData());
+        source.setDhcpServerAddress((Inet4Address) GATEWAY1);
+        assertParcelSane(new LinkProperties(source, true /* parcelSensitiveFields */),
+                18 /* fieldCount */);
 
         // Verify that without using a sensitiveFieldsParcelingCopy, sensitive fields are cleared.
         final LinkProperties sanitized = new LinkProperties(source);
@@ -997,7 +1038,8 @@
         assertEquals(sanitized, parcelingRoundTrip(source));
     }
 
-    @Test
+    // Parceling of the scope was broken until Q-QPR2
+    @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
     public void testLinkLocalDnsServerParceling() throws Exception {
         final String strAddress = "fe80::1%lo";
         final LinkProperties lp = new LinkProperties();
@@ -1120,7 +1162,7 @@
         assertFalse(lp.isPrivateDnsActive());
     }
 
-    @Test
+    @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
     public void testDhcpServerAddress() {
         final LinkProperties lp = makeTestObject();
         assertEquals(DHCPSERVER, lp.getDhcpServerAddress());
@@ -1129,7 +1171,7 @@
         assertNull(lp.getDhcpServerAddress());
     }
 
-    @Test
+    @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
     public void testWakeOnLanSupported() {
         final LinkProperties lp = makeTestObject();
         assertTrue(lp.isWakeOnLanSupported());
@@ -1138,7 +1180,7 @@
         assertFalse(lp.isWakeOnLanSupported());
     }
 
-    @Test
+    @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
     public void testCaptivePortalApiUrl() {
         final LinkProperties lp = makeTestObject();
         assertEquals(CAPPORT_API_URL, lp.getCaptivePortalApiUrl());
@@ -1147,10 +1189,10 @@
         assertNull(lp.getCaptivePortalApiUrl());
     }
 
-    @Test
+    @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
     public void testCaptivePortalData() {
         final LinkProperties lp = makeTestObject();
-        assertEquals(CAPPORT_DATA, lp.getCaptivePortalData());
+        assertEquals(getCaptivePortalData(), lp.getCaptivePortalData());
 
         lp.clear();
         assertNull(lp.getCaptivePortalData());
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index efea91a..9fe1883 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -48,9 +48,11 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import android.os.Build;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.ArraySet;
 
+import androidx.core.os.BuildCompat;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
@@ -64,6 +66,13 @@
     private static final String TEST_SSID = "TEST_SSID";
     private static final String DIFFERENT_TEST_SSID = "DIFFERENT_TEST_SSID";
 
+    private boolean isAtLeastR() {
+        // BuildCompat.isAtLeastR() is used to check the Android version before releasing Android R.
+        // Build.VERSION.SDK_INT > Build.VERSION_CODES.Q is used to check the Android version after
+        // releasing Android R.
+        return BuildCompat.isAtLeastR() || Build.VERSION.SDK_INT > Build.VERSION_CODES.Q;
+    }
+
     @Test
     public void testMaybeMarkCapabilitiesRestricted() {
         // verify EIMS is restricted
@@ -269,25 +278,36 @@
             .setUids(uids)
             .addCapability(NET_CAPABILITY_EIMS)
             .addCapability(NET_CAPABILITY_NOT_METERED);
-        netCap.setOwnerUid(123);
+        if (isAtLeastR()) {
+            netCap.setOwnerUid(123);
+        }
         assertParcelingIsLossless(netCap);
         netCap.setSSID(TEST_SSID);
-        assertParcelSane(netCap, 15);
+        testParcelSane(netCap);
     }
 
     @Test
     public void testParcelNetworkCapabilitiesWithRequestorUidAndPackageName() {
         final NetworkCapabilities netCap = new NetworkCapabilities()
                 .addCapability(NET_CAPABILITY_INTERNET)
-                .setRequestorUid(9304)
-                .setRequestorPackageName("com.android.test")
                 .addCapability(NET_CAPABILITY_EIMS)
                 .addCapability(NET_CAPABILITY_NOT_METERED);
+        if (isAtLeastR()) {
+            netCap.setRequestorPackageName("com.android.test");
+            netCap.setRequestorUid(9304);
+        }
         assertParcelingIsLossless(netCap);
         netCap.setSSID(TEST_SSID);
-        assertParcelSane(netCap, 15);
+        testParcelSane(netCap);
     }
 
+    private void testParcelSane(NetworkCapabilities cap) {
+        if (isAtLeastR()) {
+            assertParcelSane(cap, 15);
+        } else {
+            assertParcelSane(cap, 11);
+        }
+    }
 
     @Test
     public void testOemPaid() {
diff --git a/tests/net/java/android/net/NetworkTemplateTest.kt b/tests/net/java/android/net/NetworkTemplateTest.kt
new file mode 100644
index 0000000..5dd0fda
--- /dev/null
+++ b/tests/net/java/android/net/NetworkTemplateTest.kt
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2020 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.net
+
+import android.content.Context
+import android.net.ConnectivityManager.TYPE_MOBILE
+import android.net.ConnectivityManager.TYPE_WIFI
+import android.net.NetworkIdentity.SUBTYPE_COMBINED
+import android.net.NetworkIdentity.buildNetworkIdentity
+import android.net.NetworkStats.DEFAULT_NETWORK_ALL
+import android.net.NetworkStats.METERED_ALL
+import android.net.NetworkStats.ROAMING_ALL
+import android.net.NetworkTemplate.MATCH_MOBILE
+import android.net.NetworkTemplate.MATCH_WIFI
+import android.net.NetworkTemplate.NETWORK_TYPE_ALL
+import android.net.NetworkTemplate.buildTemplateMobileWithRatType
+import android.telephony.TelephonyManager
+import com.android.testutils.assertParcelSane
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.mock
+import org.mockito.MockitoAnnotations
+import kotlin.test.assertFalse
+import kotlin.test.assertNotEquals
+import kotlin.test.assertTrue
+
+private const val TEST_IMSI1 = "imsi1"
+private const val TEST_IMSI2 = "imsi2"
+private const val TEST_SSID1 = "ssid1"
+
+@RunWith(JUnit4::class)
+class NetworkTemplateTest {
+    private val mockContext = mock(Context::class.java)
+
+    private fun buildMobileNetworkState(subscriberId: String): NetworkState =
+            buildNetworkState(TYPE_MOBILE, subscriberId = subscriberId)
+    private fun buildWifiNetworkState(ssid: String): NetworkState =
+            buildNetworkState(TYPE_WIFI, ssid = ssid)
+
+    private fun buildNetworkState(
+        type: Int,
+        subscriberId: String? = null,
+        ssid: String? = null
+    ): NetworkState {
+        val info = mock(NetworkInfo::class.java)
+        doReturn(type).`when`(info).type
+        doReturn(NetworkInfo.State.CONNECTED).`when`(info).state
+        val lp = LinkProperties()
+        val caps = NetworkCapabilities().apply {
+            setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false)
+            setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true)
+        }
+        return NetworkState(info, lp, caps, mock(Network::class.java), subscriberId, ssid)
+    }
+
+    private fun NetworkTemplate.assertMatches(ident: NetworkIdentity) =
+            assertTrue(matches(ident), "$this does not match $ident")
+
+    private fun NetworkTemplate.assertDoesNotMatch(ident: NetworkIdentity) =
+            assertFalse(matches(ident), "$this should match $ident")
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+    }
+
+    @Test
+    fun testRatTypeGroupMatches() {
+        val stateMobile = buildMobileNetworkState(TEST_IMSI1)
+        // Build UMTS template that matches mobile identities with RAT in the same
+        // group with any IMSI. See {@link NetworkTemplate#getCollapsedRatType}.
+        val templateUmts = buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UMTS)
+        // Build normal template that matches mobile identities with any RAT and IMSI.
+        val templateAll = buildTemplateMobileWithRatType(null, NETWORK_TYPE_ALL)
+        // Build template with UNKNOWN RAT that matches mobile identities with RAT that
+        // cannot be determined.
+        val templateUnknown =
+                buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UNKNOWN)
+
+        val identUmts = buildNetworkIdentity(
+                mockContext, stateMobile, false, TelephonyManager.NETWORK_TYPE_UMTS)
+        val identHsdpa = buildNetworkIdentity(
+                mockContext, stateMobile, false, TelephonyManager.NETWORK_TYPE_HSDPA)
+        val identLte = buildNetworkIdentity(
+                mockContext, stateMobile, false, TelephonyManager.NETWORK_TYPE_LTE)
+        val identCombined = buildNetworkIdentity(
+                mockContext, stateMobile, false, SUBTYPE_COMBINED)
+        val identImsi2 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI2),
+                false, TelephonyManager.NETWORK_TYPE_UMTS)
+        val identWifi = buildNetworkIdentity(
+                mockContext, buildWifiNetworkState(TEST_SSID1), true, 0)
+
+        // Assert that identity with the same RAT matches.
+        templateUmts.assertMatches(identUmts)
+        templateAll.assertMatches(identUmts)
+        templateUnknown.assertDoesNotMatch(identUmts)
+        // Assert that identity with the RAT within the same group matches.
+        templateUmts.assertMatches(identHsdpa)
+        templateAll.assertMatches(identHsdpa)
+        templateUnknown.assertDoesNotMatch(identHsdpa)
+        // Assert that identity with the RAT out of the same group only matches template with
+        // NETWORK_TYPE_ALL.
+        templateUmts.assertDoesNotMatch(identLte)
+        templateAll.assertMatches(identLte)
+        templateUnknown.assertDoesNotMatch(identLte)
+        // Assert that identity with combined RAT only matches with template with NETWORK_TYPE_ALL
+        // and NETWORK_TYPE_UNKNOWN.
+        templateUmts.assertDoesNotMatch(identCombined)
+        templateAll.assertMatches(identCombined)
+        templateUnknown.assertMatches(identCombined)
+        // Assert that identity with different IMSI matches.
+        templateUmts.assertMatches(identImsi2)
+        templateAll.assertMatches(identImsi2)
+        templateUnknown.assertDoesNotMatch(identImsi2)
+        // Assert that wifi identity does not match.
+        templateUmts.assertDoesNotMatch(identWifi)
+        templateAll.assertDoesNotMatch(identWifi)
+        templateUnknown.assertDoesNotMatch(identWifi)
+    }
+
+    @Test
+    fun testParcelUnparcel() {
+        val templateMobile = NetworkTemplate(MATCH_MOBILE, TEST_IMSI1, null, null, METERED_ALL,
+                ROAMING_ALL, DEFAULT_NETWORK_ALL, TelephonyManager.NETWORK_TYPE_LTE)
+        val templateWifi = NetworkTemplate(MATCH_WIFI, null, null, TEST_SSID1, METERED_ALL,
+                ROAMING_ALL, DEFAULT_NETWORK_ALL, 0)
+        assertParcelSane(templateMobile, 8)
+        assertParcelSane(templateWifi, 8)
+    }
+
+    // Verify NETWORK_TYPE_ALL does not conflict with TelephonyManager#NETWORK_TYPE_* constants.
+    @Test
+    fun testNetworkTypeAll() {
+        for (ratType in TelephonyManager.getAllNetworkTypes()) {
+            assertNotEquals(NETWORK_TYPE_ALL, ratType)
+        }
+    }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 44216e8..4bfb51b 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -25,7 +25,6 @@
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN;
 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
-import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_SUPL;
 import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
 import static android.net.ConnectivityManager.EXTRA_NETWORK_TYPE;
 import static android.net.ConnectivityManager.NETID_UNSET;
@@ -175,6 +174,7 @@
 import android.net.ProxyInfo;
 import android.net.ResolverParamsParcel;
 import android.net.RouteInfo;
+import android.net.RouteInfoParcel;
 import android.net.SocketKeepalive;
 import android.net.UidRange;
 import android.net.Uri;
@@ -427,7 +427,6 @@
         public Object getSystemService(String name) {
             if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm;
             if (Context.NOTIFICATION_SERVICE.equals(name)) return mNotificationManager;
-            if (Context.NETWORK_STACK_SERVICE.equals(name)) return mNetworkStack;
             if (Context.USER_SERVICE.equals(name)) return mUserManager;
             if (Context.ALARM_SERVICE.equals(name)) return mAlarmManager;
             if (Context.LOCATION_SERVICE.equals(name)) return mLocationManager;
@@ -1374,7 +1373,6 @@
             @NonNull final Predicate<Intent> filter) {
         final ConditionVariable cv = new ConditionVariable();
         final IntentFilter intentFilter = new IntentFilter(CONNECTIVITY_ACTION);
-        intentFilter.addAction(CONNECTIVITY_ACTION_SUPL);
         final BroadcastReceiver receiver = new BroadcastReceiver() {
                     private int remaining = count;
                     public void onReceive(Context context, Intent intent) {
@@ -1422,56 +1420,28 @@
         final NetworkRequest legacyRequest = new NetworkRequest(legacyCaps, TYPE_MOBILE_SUPL,
                 ConnectivityManager.REQUEST_ID_UNSET, NetworkRequest.Type.REQUEST);
 
-        // Send request and check that the legacy broadcast for SUPL is sent correctly.
+        // File request, withdraw it and make sure no broadcast is sent
+        final ConditionVariable cv2 = registerConnectivityBroadcast(1);
         final TestNetworkCallback callback = new TestNetworkCallback();
-        final ConditionVariable cv2 = registerConnectivityBroadcastThat(1,
-                intent -> intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) == TYPE_MOBILE_SUPL);
         mCm.requestNetwork(legacyRequest, callback);
         callback.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
-        waitFor(cv2);
-
-        // File another request, withdraw it and make sure no broadcast is sent
-        final ConditionVariable cv3 = registerConnectivityBroadcast(1);
-        final TestNetworkCallback callback2 = new TestNetworkCallback();
-        mCm.requestNetwork(legacyRequest, callback2);
-        callback2.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
-        mCm.unregisterNetworkCallback(callback2);
-        assertFalse(cv3.block(800)); // 800ms long enough to at least flake if this is sent
+        mCm.unregisterNetworkCallback(callback);
+        assertFalse(cv2.block(800)); // 800ms long enough to at least flake if this is sent
         // As the broadcast did not fire, the receiver was not unregistered. Do this now.
         mServiceContext.clearRegisteredReceivers();
 
-        // Withdraw the request and check that the broadcast for disconnection is sent.
-        final ConditionVariable cv4 = registerConnectivityBroadcastThat(1, intent ->
-                !((NetworkInfo) intent.getExtra(EXTRA_NETWORK_INFO, -1)).isConnected()
-                        && intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) == TYPE_MOBILE_SUPL);
-        mCm.unregisterNetworkCallback(callback);
-        waitFor(cv4);
-
-        // Re-file the request and expect the connected broadcast again
-        final ConditionVariable cv5 = registerConnectivityBroadcastThat(1,
-                intent -> intent.getIntExtra(EXTRA_NETWORK_TYPE, -1) == TYPE_MOBILE_SUPL);
-        final TestNetworkCallback callback3 = new TestNetworkCallback();
-        mCm.requestNetwork(legacyRequest, callback3);
-        callback3.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
-        waitFor(cv5);
-
-        // Disconnect the network and expect two disconnected broadcasts, one for SUPL and one
-        // for mobile. Use a small hack to check that both have been sent, but the order is
-        // not contractual.
+        // Disconnect the network and expect mobile disconnected broadcast. Use a small hack to
+        // check that has been sent.
         final AtomicBoolean vanillaAction = new AtomicBoolean(false);
-        final AtomicBoolean suplAction = new AtomicBoolean(false);
-        final ConditionVariable cv6 = registerConnectivityBroadcastThat(2, intent -> {
+        final ConditionVariable cv3 = registerConnectivityBroadcastThat(1, intent -> {
             if (intent.getAction().equals(CONNECTIVITY_ACTION)) {
                 vanillaAction.set(true);
-            } else if (intent.getAction().equals(CONNECTIVITY_ACTION_SUPL)) {
-                suplAction.set(true);
             }
             return !((NetworkInfo) intent.getExtra(EXTRA_NETWORK_INFO, -1)).isConnected();
         });
         mCellNetworkAgent.disconnect();
-        waitFor(cv6);
+        waitFor(cv3);
         assertTrue(vanillaAction.get());
-        assertTrue(suplAction.get());
     }
 
     @Test
@@ -6064,6 +6034,7 @@
             verify(mBatteryStatsService).noteNetworkInterfaceType(stackedLp.getInterfaceName(),
                     TYPE_MOBILE);
         }
+        reset(mMockNetd);
 
         // Add ipv4 address, expect that clatd and prefix discovery are stopped and stacked
         // linkproperties are cleaned up.
@@ -6115,7 +6086,6 @@
         networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
         verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kNat64Prefix.toString());
 
-
         // Clat iface comes up. Expect stacked link to be added.
         clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
         networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
@@ -6701,17 +6671,45 @@
         }
     }
 
+    private void assertRouteInfoParcelMatches(RouteInfo route, RouteInfoParcel parcel) {
+        assertEquals(route.getDestination().toString(), parcel.destination);
+        assertEquals(route.getInterface(), parcel.ifName);
+        assertEquals(route.getMtu(), parcel.mtu);
+
+        switch (route.getType()) {
+            case RouteInfo.RTN_UNICAST:
+                if (route.hasGateway()) {
+                    assertEquals(route.getGateway().getHostAddress(), parcel.nextHop);
+                } else {
+                    assertEquals(INetd.NEXTHOP_NONE, parcel.nextHop);
+                }
+                break;
+            case RouteInfo.RTN_UNREACHABLE:
+                assertEquals(INetd.NEXTHOP_UNREACHABLE, parcel.nextHop);
+                break;
+            case RouteInfo.RTN_THROW:
+                assertEquals(INetd.NEXTHOP_THROW, parcel.nextHop);
+                break;
+            default:
+                assertEquals(INetd.NEXTHOP_NONE, parcel.nextHop);
+                break;
+        }
+    }
+
     private void assertRoutesAdded(int netId, RouteInfo... routes) throws Exception {
-        InOrder inOrder = inOrder(mNetworkManagementService);
+        ArgumentCaptor<RouteInfoParcel> captor = ArgumentCaptor.forClass(RouteInfoParcel.class);
+        verify(mMockNetd, times(routes.length)).networkAddRouteParcel(eq(netId), captor.capture());
         for (int i = 0; i < routes.length; i++) {
-            inOrder.verify(mNetworkManagementService).addRoute(eq(netId), eq(routes[i]));
+            assertRouteInfoParcelMatches(routes[i], captor.getAllValues().get(i));
         }
     }
 
     private void assertRoutesRemoved(int netId, RouteInfo... routes) throws Exception {
-        InOrder inOrder = inOrder(mNetworkManagementService);
+        ArgumentCaptor<RouteInfoParcel> captor = ArgumentCaptor.forClass(RouteInfoParcel.class);
+        verify(mMockNetd, times(routes.length)).networkRemoveRouteParcel(eq(netId),
+                captor.capture());
         for (int i = 0; i < routes.length; i++) {
-            inOrder.verify(mNetworkManagementService).removeRoute(eq(netId), eq(routes[i]));
+            assertRouteInfoParcelMatches(routes[i], captor.getAllValues().get(i));
         }
     }
 
@@ -6851,7 +6849,7 @@
     @Test
     public void testCheckConnectivityDiagnosticsPermissionsNetworkAdministrator() throws Exception {
         final NetworkCapabilities nc = new NetworkCapabilities();
-        nc.setAdministratorUids(Arrays.asList(Process.myUid()));
+        nc.setAdministratorUids(new int[] {Process.myUid()});
         final NetworkAgentInfo naiWithUid =
                 new NetworkAgentInfo(
                         null, null, null, null, null, nc, 0, mServiceContext, null, null,
@@ -6873,7 +6871,7 @@
     public void testCheckConnectivityDiagnosticsPermissionsFails() throws Exception {
         final NetworkCapabilities nc = new NetworkCapabilities();
         nc.setOwnerUid(Process.myUid());
-        nc.setAdministratorUids(Arrays.asList(Process.myUid()));
+        nc.setAdministratorUids(new int[] {Process.myUid()});
         final NetworkAgentInfo naiWithUid =
                 new NetworkAgentInfo(
                         null, null, null, null, null, nc, 0, mServiceContext, null, null,
@@ -6926,7 +6924,7 @@
                 argThat(report -> {
                     final NetworkCapabilities nc = report.getNetworkCapabilities();
                     return nc.getUids() == null
-                            && nc.getAdministratorUids().isEmpty()
+                            && nc.getAdministratorUids().length == 0
                             && nc.getOwnerUid() == Process.INVALID_UID;
                 }));
     }
@@ -6947,7 +6945,7 @@
                 argThat(report -> {
                     final NetworkCapabilities nc = report.getNetworkCapabilities();
                     return nc.getUids() == null
-                            && nc.getAdministratorUids().isEmpty()
+                            && nc.getAdministratorUids().length == 0
                             && nc.getOwnerUid() == Process.INVALID_UID;
                 }));
     }
@@ -6977,4 +6975,60 @@
         verify(mConnectivityDiagnosticsCallback)
                 .onNetworkConnectivityReported(eq(n), eq(noConnectivity));
     }
+
+    @Test
+    public void testRouteAddDeleteUpdate() throws Exception {
+        final NetworkRequest request = new NetworkRequest.Builder().build();
+        final TestNetworkCallback networkCallback = new TestNetworkCallback();
+        mCm.registerNetworkCallback(request, networkCallback);
+        mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+        reset(mMockNetd);
+        mCellNetworkAgent.connect(false);
+        networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
+        final int netId = mCellNetworkAgent.getNetwork().netId;
+
+        final String iface = "rmnet_data0";
+        final InetAddress gateway = InetAddress.getByName("fe80::5678");
+        RouteInfo direct = RouteInfo.makeHostRoute(gateway, iface);
+        RouteInfo rio1 = new RouteInfo(new IpPrefix("2001:db8:1::/48"), gateway, iface);
+        RouteInfo rio2 = new RouteInfo(new IpPrefix("2001:db8:2::/48"), gateway, iface);
+        RouteInfo defaultRoute = new RouteInfo((IpPrefix) null, gateway, iface);
+        RouteInfo defaultWithMtu = new RouteInfo(null, gateway, iface, RouteInfo.RTN_UNICAST,
+                                                 1280 /* mtu */);
+
+        // Send LinkProperties and check that we ask netd to add routes.
+        LinkProperties lp = new LinkProperties();
+        lp.setInterfaceName(iface);
+        lp.addRoute(direct);
+        lp.addRoute(rio1);
+        lp.addRoute(defaultRoute);
+        mCellNetworkAgent.sendLinkProperties(lp);
+        networkCallback.expectLinkPropertiesThat(mCellNetworkAgent, x -> x.getRoutes().size() == 3);
+
+        assertRoutesAdded(netId, direct, rio1, defaultRoute);
+        reset(mMockNetd);
+
+        // Send updated LinkProperties and check that we ask netd to add, remove, update routes.
+        assertTrue(lp.getRoutes().contains(defaultRoute));
+        lp.removeRoute(rio1);
+        lp.addRoute(rio2);
+        lp.addRoute(defaultWithMtu);
+        // Ensure adding the same route with a different MTU replaces the previous route.
+        assertFalse(lp.getRoutes().contains(defaultRoute));
+        assertTrue(lp.getRoutes().contains(defaultWithMtu));
+
+        mCellNetworkAgent.sendLinkProperties(lp);
+        networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
+                x -> x.getRoutes().contains(rio2));
+
+        assertRoutesRemoved(netId, rio1);
+        assertRoutesAdded(netId, rio2);
+
+        ArgumentCaptor<RouteInfoParcel> captor = ArgumentCaptor.forClass(RouteInfoParcel.class);
+        verify(mMockNetd).networkUpdateRouteParcel(eq(netId), captor.capture());
+        assertRouteInfoParcelMatches(defaultWithMtu, captor.getValue());
+
+
+        mCm.unregisterNetworkCallback(networkCallback);
+    }
 }
diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
index 8f90f13..551498f 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
@@ -319,33 +319,33 @@
             assertEntry(18322, 75, 15031, 75, history.getValues(i++, null));
             assertEntry(527798, 761, 78570, 652, history.getValues(i++, null));
             assertEntry(527797, 760, 78570, 651, history.getValues(i++, null));
-            assertEntry(10747, 50, 16838, 55, history.getValues(i++, null));
-            assertEntry(10747, 49, 16838, 54, history.getValues(i++, null));
+            assertEntry(10747, 50, 16839, 55, history.getValues(i++, null));
+            assertEntry(10747, 49, 16837, 54, history.getValues(i++, null));
             assertEntry(89191, 151, 18021, 140, history.getValues(i++, null));
             assertEntry(89190, 150, 18020, 139, history.getValues(i++, null));
-            assertEntry(3821, 22, 4525, 26, history.getValues(i++, null));
-            assertEntry(3820, 22, 4524, 26, history.getValues(i++, null));
-            assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
-            assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
-            assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
-            assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
+            assertEntry(3821, 23, 4525, 26, history.getValues(i++, null));
+            assertEntry(3820, 21, 4524, 26, history.getValues(i++, null));
+            assertEntry(91686, 159, 18576, 146, history.getValues(i++, null));
+            assertEntry(91685, 159, 18574, 146, history.getValues(i++, null));
+            assertEntry(8289, 36, 6864, 39, history.getValues(i++, null));
+            assertEntry(8289, 34, 6862, 37, history.getValues(i++, null));
             assertEntry(113914, 174, 18364, 157, history.getValues(i++, null));
             assertEntry(113913, 173, 18364, 157, history.getValues(i++, null));
-            assertEntry(11378, 49, 9261, 49, history.getValues(i++, null));
-            assertEntry(11377, 48, 9261, 49, history.getValues(i++, null));
-            assertEntry(201765, 328, 41808, 291, history.getValues(i++, null));
-            assertEntry(201765, 328, 41807, 290, history.getValues(i++, null));
-            assertEntry(106106, 218, 39917, 201, history.getValues(i++, null));
-            assertEntry(106105, 217, 39917, 201, history.getValues(i++, null));
+            assertEntry(11378, 49, 9261, 50, history.getValues(i++, null));
+            assertEntry(11377, 48, 9261, 48, history.getValues(i++, null));
+            assertEntry(201766, 328, 41808, 291, history.getValues(i++, null));
+            assertEntry(201764, 328, 41807, 290, history.getValues(i++, null));
+            assertEntry(106106, 219, 39918, 202, history.getValues(i++, null));
+            assertEntry(106105, 216, 39916, 200, history.getValues(i++, null));
             assertEquals(history.size(), i);
 
             // Slice from middle should be untouched
             history = getHistory(collection, plan, TIME_B - HOUR_IN_MILLIS,
                     TIME_B + HOUR_IN_MILLIS); i = 0;
-            assertEntry(3821, 22, 4525, 26, history.getValues(i++, null));
-            assertEntry(3820, 22, 4524, 26, history.getValues(i++, null));
-            assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
-            assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
+            assertEntry(3821, 23, 4525, 26, history.getValues(i++, null));
+            assertEntry(3820, 21, 4524, 26, history.getValues(i++, null));
+            assertEntry(91686, 159, 18576, 146, history.getValues(i++, null));
+            assertEntry(91685, 159, 18574, 146, history.getValues(i++, null));
             assertEquals(history.size(), i);
         }
 
@@ -373,25 +373,25 @@
             assertEntry(527797, 760, 78570, 651, history.getValues(i++, null));
             // Cycle point; start data normalization
             assertEntry(7507, 0, 11763, 0, history.getValues(i++, null));
-            assertEntry(7507, 0, 11763, 0, history.getValues(i++, null));
+            assertEntry(7507, 0, 11762, 0, history.getValues(i++, null));
             assertEntry(62309, 0, 12589, 0, history.getValues(i++, null));
             assertEntry(62309, 0, 12588, 0, history.getValues(i++, null));
             assertEntry(2669, 0, 3161, 0, history.getValues(i++, null));
             assertEntry(2668, 0, 3160, 0, history.getValues(i++, null));
             // Anchor point; end data normalization
-            assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
-            assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
-            assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
-            assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
+            assertEntry(91686, 159, 18576, 146, history.getValues(i++, null));
+            assertEntry(91685, 159, 18574, 146, history.getValues(i++, null));
+            assertEntry(8289, 36, 6864, 39, history.getValues(i++, null));
+            assertEntry(8289, 34, 6862, 37, history.getValues(i++, null));
             assertEntry(113914, 174, 18364, 157, history.getValues(i++, null));
             assertEntry(113913, 173, 18364, 157, history.getValues(i++, null));
             // Cycle point
-            assertEntry(11378, 49, 9261, 49, history.getValues(i++, null));
-            assertEntry(11377, 48, 9261, 49, history.getValues(i++, null));
-            assertEntry(201765, 328, 41808, 291, history.getValues(i++, null));
-            assertEntry(201765, 328, 41807, 290, history.getValues(i++, null));
-            assertEntry(106106, 218, 39917, 201, history.getValues(i++, null));
-            assertEntry(106105, 217, 39917, 201, history.getValues(i++, null));
+            assertEntry(11378, 49, 9261, 50, history.getValues(i++, null));
+            assertEntry(11377, 48, 9261, 48, history.getValues(i++, null));
+            assertEntry(201766, 328, 41808, 291, history.getValues(i++, null));
+            assertEntry(201764, 328, 41807, 290, history.getValues(i++, null));
+            assertEntry(106106, 219, 39918, 202, history.getValues(i++, null));
+            assertEntry(106105, 216, 39916, 200, history.getValues(i++, null));
             assertEquals(history.size(), i);
 
             // Slice from middle should be augmented
@@ -399,8 +399,8 @@
                     TIME_B + HOUR_IN_MILLIS); i = 0;
             assertEntry(2669, 0, 3161, 0, history.getValues(i++, null));
             assertEntry(2668, 0, 3160, 0, history.getValues(i++, null));
-            assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
-            assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
+            assertEntry(91686, 159, 18576, 146, history.getValues(i++, null));
+            assertEntry(91685, 159, 18574, 146, history.getValues(i++, null));
             assertEquals(history.size(), i);
         }
 
@@ -427,34 +427,34 @@
             assertEntry(527798, 761, 78570, 652, history.getValues(i++, null));
             assertEntry(527797, 760, 78570, 651, history.getValues(i++, null));
             // Cycle point; start data normalization
-            assertEntry(15015, 0, 23526, 0, history.getValues(i++, null));
-            assertEntry(15015, 0, 23526, 0, history.getValues(i++, null));
+            assertEntry(15015, 0, 23527, 0, history.getValues(i++, null));
+            assertEntry(15015, 0, 23524, 0, history.getValues(i++, null));
             assertEntry(124619, 0, 25179, 0, history.getValues(i++, null));
             assertEntry(124618, 0, 25177, 0, history.getValues(i++, null));
             assertEntry(5338, 0, 6322, 0, history.getValues(i++, null));
             assertEntry(5337, 0, 6320, 0, history.getValues(i++, null));
             // Anchor point; end data normalization
-            assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
-            assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
-            assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
-            assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
+            assertEntry(91686, 159, 18576, 146, history.getValues(i++, null));
+            assertEntry(91685, 159, 18574, 146, history.getValues(i++, null));
+            assertEntry(8289, 36, 6864, 39, history.getValues(i++, null));
+            assertEntry(8289, 34, 6862, 37, history.getValues(i++, null));
             assertEntry(113914, 174, 18364, 157, history.getValues(i++, null));
             assertEntry(113913, 173, 18364, 157, history.getValues(i++, null));
             // Cycle point
-            assertEntry(11378, 49, 9261, 49, history.getValues(i++, null));
-            assertEntry(11377, 48, 9261, 49, history.getValues(i++, null));
-            assertEntry(201765, 328, 41808, 291, history.getValues(i++, null));
-            assertEntry(201765, 328, 41807, 290, history.getValues(i++, null));
-            assertEntry(106106, 218, 39917, 201, history.getValues(i++, null));
-            assertEntry(106105, 217, 39917, 201, history.getValues(i++, null));
+            assertEntry(11378, 49, 9261, 50, history.getValues(i++, null));
+            assertEntry(11377, 48, 9261, 48, history.getValues(i++, null));
+            assertEntry(201766, 328, 41808, 291, history.getValues(i++, null));
+            assertEntry(201764, 328, 41807, 290, history.getValues(i++, null));
+            assertEntry(106106, 219, 39918, 202, history.getValues(i++, null));
+            assertEntry(106105, 216, 39916, 200, history.getValues(i++, null));
 
             // Slice from middle should be augmented
             history = getHistory(collection, plan, TIME_B - HOUR_IN_MILLIS,
                     TIME_B + HOUR_IN_MILLIS); i = 0;
             assertEntry(5338, 0, 6322, 0, history.getValues(i++, null));
             assertEntry(5337, 0, 6320, 0, history.getValues(i++, null));
-            assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
-            assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
+            assertEntry(91686, 159, 18576, 146, history.getValues(i++, null));
+            assertEntry(91685, 159, 18574, 146, history.getValues(i++, null));
             assertEquals(history.size(), i);
         }
     }
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index b346c92..6e63313 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -42,6 +42,7 @@
 import static android.net.NetworkStats.UID_ALL;
 import static android.net.NetworkStatsHistory.FIELD_ALL;
 import static android.net.NetworkTemplate.buildTemplateMobileAll;
+import static android.net.NetworkTemplate.buildTemplateMobileWithRatType;
 import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
 import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.net.TrafficStats.UID_REMOVED;
@@ -60,11 +61,13 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.AlarmManager;
 import android.app.usage.NetworkStatsManager;
 import android.content.Context;
@@ -92,6 +95,8 @@
 import android.os.Messenger;
 import android.os.PowerManager;
 import android.os.SimpleClock;
+import android.telephony.PhoneStateListener;
+import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 
 import androidx.test.InstrumentationRegistry;
@@ -163,11 +168,14 @@
     private @Mock NetworkStatsSettings mSettings;
     private @Mock IBinder mBinder;
     private @Mock AlarmManager mAlarmManager;
+    private @Mock TelephonyManager mTelephonyManager;
     private HandlerThread mHandlerThread;
 
     private NetworkStatsService mService;
     private INetworkStatsSession mSession;
     private INetworkManagementEventObserver mNetworkObserver;
+    @Nullable
+    private PhoneStateListener mPhoneStateListener;
 
     private final Clock mClock = new SimpleClock(ZoneOffset.UTC) {
         @Override
@@ -195,7 +203,7 @@
         mHandlerThread = new HandlerThread("HandlerThread");
         final NetworkStatsService.Dependencies deps = makeDependencies();
         mService = new NetworkStatsService(mServiceContext, mNetManager, mAlarmManager, wakeLock,
-                mClock, mServiceContext.getSystemService(TelephonyManager.class), mSettings,
+                mClock, mTelephonyManager, mSettings,
                 mStatsFactory, new NetworkStatsObservers(), mStatsDir, getBaseDir(mStatsDir), deps);
 
         mElapsedRealtime = 0L;
@@ -216,6 +224,12 @@
                 ArgumentCaptor.forClass(INetworkManagementEventObserver.class);
         verify(mNetManager).registerObserver(networkObserver.capture());
         mNetworkObserver = networkObserver.getValue();
+
+        // Capture the phone state listener that created by service.
+        final ArgumentCaptor<PhoneStateListener> phoneStateListenerCaptor =
+                ArgumentCaptor.forClass(PhoneStateListener.class);
+        verify(mTelephonyManager).listen(phoneStateListenerCaptor.capture(), anyInt());
+        mPhoneStateListener = phoneStateListenerCaptor.getValue();
     }
 
     @NonNull
@@ -534,7 +548,7 @@
     }
 
     @Test
-    public void testUid3g4gCombinedByTemplate() throws Exception {
+    public void testUid3gWimaxCombinedByTemplate() throws Exception {
         // pretend that network comes online
         expectDefaultSettings();
         NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)};
@@ -558,10 +572,10 @@
         assertUidTotal(sTemplateImsi1, UID_RED, 1024L, 8L, 1024L, 8L, 5);
 
 
-        // now switch over to 4g network
+        // now switch over to wimax network
         incrementCurrentTime(HOUR_IN_MILLIS);
         expectDefaultSettings();
-        states = new NetworkState[] {buildMobile4gState(TEST_IFACE2)};
+        states = new NetworkState[] {buildWimaxState(TEST_IFACE2)};
         expectNetworkStatsSummary(buildEmptyStats());
         expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
                 .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
@@ -589,6 +603,89 @@
     }
 
     @Test
+    public void testMobileStatsByRatType() throws Exception {
+        final NetworkTemplate template3g =
+                buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UMTS);
+        final NetworkTemplate template4g =
+                buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_LTE);
+        final NetworkTemplate template5g =
+                buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_NR);
+        final NetworkState[] states = new NetworkState[]{buildMobile3gState(IMSI_1)};
+
+        // 3G network comes online.
+        expectNetworkStatsSummary(buildEmptyStats());
+        expectNetworkStatsUidDetail(buildEmptyStats());
+
+        setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_UMTS);
+        mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+                new VpnInfo[0]);
+
+        // Create some traffic.
+        incrementCurrentTime(MINUTE_IN_MILLIS);
+        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+                .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
+                        12L, 18L, 14L, 1L, 0L)));
+        forcePollAndWaitForIdle();
+
+        // Verify 3g templates gets stats.
+        assertUidTotal(sTemplateImsi1, UID_RED, 12L, 18L, 14L, 1L, 0);
+        assertUidTotal(template3g, UID_RED, 12L, 18L, 14L, 1L, 0);
+        assertUidTotal(template4g, UID_RED, 0L, 0L, 0L, 0L, 0);
+        assertUidTotal(template5g, UID_RED, 0L, 0L, 0L, 0L, 0);
+
+        // 4G network comes online.
+        incrementCurrentTime(MINUTE_IN_MILLIS);
+        setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_LTE);
+        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+                // Append more traffic on existing 3g stats entry.
+                .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
+                        16L, 22L, 17L, 2L, 0L))
+                // Add entry that is new on 4g.
+                .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE,
+                        33L, 27L, 8L, 10L, 1L)));
+        forcePollAndWaitForIdle();
+
+        // Verify ALL_MOBILE template gets all. 3g template counters do not increase.
+        assertUidTotal(sTemplateImsi1, UID_RED, 49L, 49L, 25L, 12L, 1);
+        assertUidTotal(template3g, UID_RED, 12L, 18L, 14L, 1L, 0);
+        // Verify 4g template counts appended stats on existing entry and newly created entry.
+        assertUidTotal(template4g, UID_RED, 4L + 33L, 4L + 27L, 3L + 8L, 1L + 10L, 1);
+        // Verify 5g template doesn't get anything since no traffic is generated on 5g.
+        assertUidTotal(template5g, UID_RED, 0L, 0L, 0L, 0L, 0);
+
+        // 5g network comes online.
+        incrementCurrentTime(MINUTE_IN_MILLIS);
+        setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_NR);
+        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
+                // Existing stats remains.
+                .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
+                        16L, 22L, 17L, 2L, 0L))
+                .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE,
+                        33L, 27L, 8L, 10L, 1L))
+                // Add some traffic on 5g.
+                .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
+                5L, 13L, 31L, 9L, 2L)));
+        forcePollAndWaitForIdle();
+
+        // Verify ALL_MOBILE template gets all.
+        assertUidTotal(sTemplateImsi1, UID_RED, 54L, 62L, 56L, 21L, 3);
+        // 3g/4g template counters do not increase.
+        assertUidTotal(template3g, UID_RED, 12L, 18L, 14L, 1L, 0);
+        assertUidTotal(template4g, UID_RED, 4L + 33L, 4L + 27L, 3L + 8L, 1L + 10L, 1);
+        // Verify 5g template gets the 5g count.
+        assertUidTotal(template5g, UID_RED, 5L, 13L, 31L, 9L, 2);
+    }
+
+    // TODO: support per IMSI state
+    private void setMobileRatTypeAndWaitForIdle(int ratType) {
+        final ServiceState mockSs = mock(ServiceState.class);
+        when(mockSs.getDataNetworkType()).thenReturn(ratType);
+        mPhoneStateListener.onServiceStateChanged(mockSs);
+
+        HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
+    }
+
+    @Test
     public void testSummaryForAllUid() throws Exception {
         // pretend that network comes online
         expectDefaultSettings();
@@ -1197,6 +1294,7 @@
         when(mSettings.getPollInterval()).thenReturn(HOUR_IN_MILLIS);
         when(mSettings.getPollDelay()).thenReturn(0L);
         when(mSettings.getSampleEnabled()).thenReturn(true);
+        when(mSettings.getCombineSubtypeEnabled()).thenReturn(false);
 
         final Config config = new Config(bucketDuration, deleteAge, deleteAge);
         when(mSettings.getDevConfig()).thenReturn(config);
@@ -1242,6 +1340,7 @@
         final NetworkCapabilities capabilities = new NetworkCapabilities();
         capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, !isMetered);
         capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
+        capabilities.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
         return new NetworkState(info, prop, capabilities, WIFI_NETWORK, null, TEST_SSID);
     }
 
@@ -1259,10 +1358,11 @@
         final NetworkCapabilities capabilities = new NetworkCapabilities();
         capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
         capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, !isRoaming);
+        capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
         return new NetworkState(info, prop, capabilities, MOBILE_NETWORK, subscriberId, null);
     }
 
-    private static NetworkState buildMobile4gState(String iface) {
+    private static NetworkState buildWimaxState(@NonNull String iface) {
         final NetworkInfo info = new NetworkInfo(TYPE_WIMAX, 0, null, null);
         info.setDetailedState(DetailedState.CONNECTED, null, null);
         final LinkProperties prop = new LinkProperties();
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 70c2741..fbafa07 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -46,6 +46,7 @@
         // TODO(b/146011398) package android.net.wifi is now split amongst 2 jars: framework.jar and
         // framework-wifi.jar. This is not a good idea, should move WifiNetworkScoreCache
         // to a separate package.
+        "java/android/net/wifi/SoftApConfToXmlMigrationUtil.java",
         "java/android/net/wifi/WifiNetworkScoreCache.java",
         "java/android/net/wifi/WifiMigration.java",
         "java/android/net/wifi/nl80211/*.java",
diff --git a/wifi/java/android/net/wifi/SoftApConfToXmlMigrationUtil.java b/wifi/java/android/net/wifi/SoftApConfToXmlMigrationUtil.java
new file mode 100755
index 0000000..c5472ce
--- /dev/null
+++ b/wifi/java/android/net/wifi/SoftApConfToXmlMigrationUtil.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2020 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.net.wifi;
+
+import static android.os.Environment.getDataMiscDirectory;
+
+import android.annotation.Nullable;
+import android.net.MacAddress;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Utility class to convert the legacy softap.conf file format to the new XML format.
+ * Note:
+ * <li>This should be modified by the OEM if they want to migrate configuration for existing
+ * devices for new softap features supported by AOSP in Android 11.
+ * For ex: client allowlist/blocklist feature was already supported by some OEM's before Android 10
+ * while AOSP only supported it in Android 11. </li>
+ * <li>Most of this class was copied over from WifiApConfigStore class in Android 10 and
+ * SoftApStoreData class in Android 11</li>
+ * @hide
+ */
+public final class SoftApConfToXmlMigrationUtil {
+    private static final String TAG = "SoftApConfToXmlMigrationUtil";
+
+    /**
+     * Directory to read the wifi config store files from under.
+     */
+    private static final String LEGACY_WIFI_STORE_DIRECTORY_NAME = "wifi";
+    /**
+     * The legacy Softap config file which contained key/value pairs.
+     */
+    private static final String LEGACY_AP_CONFIG_FILE = "softap.conf";
+
+    /**
+     * Pre-apex wifi shared folder.
+     */
+    private static File getLegacyWifiSharedDirectory() {
+        return new File(getDataMiscDirectory(), LEGACY_WIFI_STORE_DIRECTORY_NAME);
+    }
+
+    /* @hide constants copied from WifiConfiguration */
+    /**
+     * 2GHz band.
+     */
+    private static final int WIFICONFIG_AP_BAND_2GHZ = 0;
+    /**
+     * 5GHz band.
+     */
+    private static final int WIFICONFIG_AP_BAND_5GHZ = 1;
+    /**
+     * Device is allowed to choose the optimal band (2Ghz or 5Ghz) based on device capability,
+     * operating country code and current radio conditions.
+     */
+    private static final int WIFICONFIG_AP_BAND_ANY = -1;
+    /**
+     * Convert band from WifiConfiguration into SoftApConfiguration
+     *
+     * @param wifiConfigBand band encoded as WIFICONFIG_AP_BAND_xxxx
+     * @return band as encoded as SoftApConfiguration.BAND_xxx
+     */
+    @VisibleForTesting
+    public static int convertWifiConfigBandToSoftApConfigBand(int wifiConfigBand) {
+        switch (wifiConfigBand) {
+            case WIFICONFIG_AP_BAND_2GHZ:
+                return SoftApConfiguration.BAND_2GHZ;
+            case WIFICONFIG_AP_BAND_5GHZ:
+                return SoftApConfiguration.BAND_5GHZ;
+            case WIFICONFIG_AP_BAND_ANY:
+                return SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ;
+            default:
+                return SoftApConfiguration.BAND_2GHZ;
+        }
+    }
+
+    /**
+     * Load AP configuration from legacy persistent storage.
+     * Note: This is deprecated and only used for migrating data once on reboot.
+     */
+    private static SoftApConfiguration loadFromLegacyFile(InputStream fis) {
+        SoftApConfiguration config = null;
+        DataInputStream in = null;
+        try {
+            SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder();
+            in = new DataInputStream(new BufferedInputStream(fis));
+
+            int version = in.readInt();
+            if (version < 1 || version > 3) {
+                Log.e(TAG, "Bad version on hotspot configuration file");
+                return null;
+            }
+            configBuilder.setSsid(in.readUTF());
+
+            if (version >= 2) {
+                int band = in.readInt();
+                int channel = in.readInt();
+                if (channel == 0) {
+                    configBuilder.setBand(
+                            convertWifiConfigBandToSoftApConfigBand(band));
+                } else {
+                    configBuilder.setChannel(channel,
+                            convertWifiConfigBandToSoftApConfigBand(band));
+                }
+            }
+            if (version >= 3) {
+                configBuilder.setHiddenSsid(in.readBoolean());
+            }
+            int authType = in.readInt();
+            if (authType == WifiConfiguration.KeyMgmt.WPA2_PSK) {
+                configBuilder.setPassphrase(in.readUTF(),
+                        SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+            }
+            config = configBuilder.build();
+        } catch (IOException e) {
+            Log.e(TAG, "Error reading hotspot configuration ",  e);
+            config = null;
+        } catch (IllegalArgumentException ie) {
+            Log.e(TAG, "Invalid hotspot configuration ", ie);
+            config = null;
+        } finally {
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (IOException e) {
+                    Log.e(TAG, "Error closing hotspot configuration during read", e);
+                }
+            }
+        }
+        // NOTE: OEM's should add their customized parsing code here.
+        return config;
+    }
+
+    // This is the version that Android 11 released with.
+    private static final int CONFIG_STORE_DATA_VERSION = 3;
+
+    private static final String XML_TAG_DOCUMENT_HEADER = "WifiConfigStoreData";
+    private static final String XML_TAG_VERSION = "Version";
+    private static final String XML_TAG_SECTION_HEADER_SOFTAP = "SoftAp";
+    private static final String XML_TAG_SSID = "SSID";
+    private static final String XML_TAG_BSSID = "Bssid";
+    private static final String XML_TAG_CHANNEL = "Channel";
+    private static final String XML_TAG_HIDDEN_SSID = "HiddenSSID";
+    private static final String XML_TAG_SECURITY_TYPE = "SecurityType";
+    private static final String XML_TAG_AP_BAND = "ApBand";
+    private static final String XML_TAG_PASSPHRASE = "Passphrase";
+    private static final String XML_TAG_MAX_NUMBER_OF_CLIENTS = "MaxNumberOfClients";
+    private static final String XML_TAG_AUTO_SHUTDOWN_ENABLED = "AutoShutdownEnabled";
+    private static final String XML_TAG_SHUTDOWN_TIMEOUT_MILLIS = "ShutdownTimeoutMillis";
+    private static final String XML_TAG_CLIENT_CONTROL_BY_USER = "ClientControlByUser";
+    private static final String XML_TAG_BLOCKED_CLIENT_LIST = "BlockedClientList";
+    private static final String XML_TAG_ALLOWED_CLIENT_LIST = "AllowedClientList";
+    public static final String XML_TAG_CLIENT_MACADDRESS = "ClientMacAddress";
+
+    private static byte[] convertConfToXml(SoftApConfiguration softApConf) {
+        try {
+            final XmlSerializer out = new FastXmlSerializer();
+            final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+            out.setOutput(outputStream, StandardCharsets.UTF_8.name());
+
+            // Header for the XML file.
+            out.startDocument(null, true);
+            out.startTag(null, XML_TAG_DOCUMENT_HEADER);
+            XmlUtils.writeValueXml(CONFIG_STORE_DATA_VERSION, XML_TAG_VERSION, out);
+            out.startTag(null, XML_TAG_SECTION_HEADER_SOFTAP);
+
+            // SoftAp conf
+            XmlUtils.writeValueXml(softApConf.getSsid(), XML_TAG_SSID, out);
+            if (softApConf.getBssid() != null) {
+                XmlUtils.writeValueXml(softApConf.getBssid().toString(), XML_TAG_BSSID, out);
+            }
+            XmlUtils.writeValueXml(softApConf.getBand(), XML_TAG_AP_BAND, out);
+            XmlUtils.writeValueXml(softApConf.getChannel(), XML_TAG_CHANNEL, out);
+            XmlUtils.writeValueXml(softApConf.isHiddenSsid(), XML_TAG_HIDDEN_SSID, out);
+            XmlUtils.writeValueXml(softApConf.getSecurityType(), XML_TAG_SECURITY_TYPE, out);
+            if (softApConf.getSecurityType() != SoftApConfiguration.SECURITY_TYPE_OPEN) {
+                XmlUtils.writeValueXml(softApConf.getPassphrase(), XML_TAG_PASSPHRASE, out);
+            }
+            XmlUtils.writeValueXml(softApConf.getMaxNumberOfClients(),
+                    XML_TAG_MAX_NUMBER_OF_CLIENTS, out);
+            XmlUtils.writeValueXml(softApConf.isClientControlByUserEnabled(),
+                    XML_TAG_CLIENT_CONTROL_BY_USER, out);
+            XmlUtils.writeValueXml(softApConf.isAutoShutdownEnabled(),
+                    XML_TAG_AUTO_SHUTDOWN_ENABLED, out);
+            XmlUtils.writeValueXml(softApConf.getShutdownTimeoutMillis(),
+                    XML_TAG_SHUTDOWN_TIMEOUT_MILLIS, out);
+            out.startTag(null, XML_TAG_BLOCKED_CLIENT_LIST);
+            for (MacAddress mac: softApConf.getBlockedClientList()) {
+                XmlUtils.writeValueXml(mac.toString(), XML_TAG_CLIENT_MACADDRESS, out);
+            }
+            out.endTag(null, XML_TAG_BLOCKED_CLIENT_LIST);
+            out.startTag(null, XML_TAG_ALLOWED_CLIENT_LIST);
+            for (MacAddress mac: softApConf.getAllowedClientList()) {
+                XmlUtils.writeValueXml(mac.toString(), XML_TAG_CLIENT_MACADDRESS, out);
+            }
+            out.endTag(null, XML_TAG_ALLOWED_CLIENT_LIST);
+
+            // Footer for the XML file.
+            out.endTag(null, XML_TAG_SECTION_HEADER_SOFTAP);
+            out.endTag(null, XML_TAG_DOCUMENT_HEADER);
+            out.endDocument();
+
+            return outputStream.toByteArray();
+        } catch (IOException | XmlPullParserException e) {
+            Log.e(TAG, "Failed to convert softap conf to XML", e);
+            return null;
+        }
+    }
+
+    private SoftApConfToXmlMigrationUtil() { }
+
+    /**
+     * Read the legacy /data/misc/wifi/softap.conf file format and convert to the new XML
+     * format understood by WifiConfigStore.
+     * Note: Used for unit testing.
+     */
+    @VisibleForTesting
+    @Nullable
+    public static InputStream convert(InputStream fis) {
+        SoftApConfiguration softApConf = loadFromLegacyFile(fis);
+        if (softApConf == null) return null;
+
+        byte[] xmlBytes = convertConfToXml(softApConf);
+        if (xmlBytes == null) return null;
+
+        return new ByteArrayInputStream(xmlBytes);
+    }
+
+    /**
+     * Read the legacy /data/misc/wifi/softap.conf file format and convert to the new XML
+     * format understood by WifiConfigStore.
+     */
+    @Nullable
+    public static InputStream convert() {
+        File file = new File(getLegacyWifiSharedDirectory(), LEGACY_AP_CONFIG_FILE);
+        FileInputStream fis = null;
+        try {
+            fis = new FileInputStream(file);
+        } catch (FileNotFoundException e) {
+            return null;
+        }
+        if (fis == null) return null;
+        return convert(fis);
+    }
+
+    /**
+     * Remove the legacy /data/misc/wifi/softap.conf file.
+     */
+    @Nullable
+    public static void remove() {
+        File file = new File(getLegacyWifiSharedDirectory(), LEGACY_AP_CONFIG_FILE);
+        file.delete();
+    }
+}
diff --git a/wifi/java/android/net/wifi/WifiMigration.java b/wifi/java/android/net/wifi/WifiMigration.java
index f2a1aec..666d72d 100755
--- a/wifi/java/android/net/wifi/WifiMigration.java
+++ b/wifi/java/android/net/wifi/WifiMigration.java
@@ -95,7 +95,7 @@
     private static final SparseArray<String> STORE_ID_TO_FILE_NAME =
             new SparseArray<String>() {{
                 put(STORE_FILE_SHARED_GENERAL, "WifiConfigStore.xml");
-                put(STORE_FILE_SHARED_SOFTAP, "softap.conf");
+                put(STORE_FILE_SHARED_SOFTAP, "WifiConfigStoreSoftAp.xml");
                 put(STORE_FILE_USER_GENERAL, "WifiConfigStore.xml");
                 put(STORE_FILE_USER_NETWORK_SUGGESTIONS, "WifiConfigStoreNetworkSuggestions.xml");
             }};
@@ -176,6 +176,13 @@
             // OEMs should do conversions necessary here before returning the stream.
             return getSharedAtomicFile(storeFileId).openRead();
         } catch (FileNotFoundException e) {
+            // Special handling for softap.conf.
+            // Note: OEM devices upgrading from Q -> R will only have the softap.conf file.
+            // Test devices running previous R builds however may have already migrated to the
+            // XML format. So, check for that above before falling back to check for legacy file.
+            if (storeFileId == STORE_FILE_SHARED_SOFTAP) {
+                return SoftApConfToXmlMigrationUtil.convert();
+            }
             return null;
         }
     }
@@ -191,7 +198,18 @@
         if (storeFileId != STORE_FILE_SHARED_GENERAL && storeFileId !=  STORE_FILE_SHARED_SOFTAP) {
             throw new IllegalArgumentException("Invalid shared store file id");
         }
-        getSharedAtomicFile(storeFileId).delete();
+        AtomicFile file = getSharedAtomicFile(storeFileId);
+        if (file.exists()) {
+            file.delete();
+            return;
+        }
+        // Special handling for softap.conf.
+        // Note: OEM devices upgrading from Q -> R will only have the softap.conf file.
+        // Test devices running previous R builds however may have already migrated to the
+        // XML format. So, check for that above before falling back to check for legacy file.
+        if (storeFileId == STORE_FILE_SHARED_SOFTAP) {
+            SoftApConfToXmlMigrationUtil.remove();
+        }
     }
 
     /**
@@ -258,7 +276,10 @@
             throw new IllegalArgumentException("Invalid user store file id");
         }
         Objects.requireNonNull(userHandle);
-        getUserAtomicFile(storeFileId, userHandle.getIdentifier()).delete();
+        AtomicFile file = getUserAtomicFile(storeFileId, userHandle.getIdentifier());
+        if (file.exists()) {
+            file.delete();
+        }
     }
 
     /**
diff --git a/wifi/tests/src/android/net/wifi/SoftApConfToXmlMigrationUtilTest.java b/wifi/tests/src/android/net/wifi/SoftApConfToXmlMigrationUtilTest.java
new file mode 100644
index 0000000..f49f387
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/SoftApConfToXmlMigrationUtilTest.java
@@ -0,0 +1,199 @@
+/*
+ * 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.net.wifi;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Unit tests for {@link android.net.wifi.SoftApConfToXmlMigrationUtilTest}.
+ */
+@SmallTest
+public class SoftApConfToXmlMigrationUtilTest {
+    private static final String TEST_SSID = "SSID";
+    private static final String TEST_PASSPHRASE = "TestPassphrase";
+    private static final int TEST_CHANNEL = 0;
+    private static final boolean TEST_HIDDEN = false;
+    private static final int TEST_BAND = SoftApConfiguration.BAND_5GHZ;
+    private static final int TEST_SECURITY = SoftApConfiguration.SECURITY_TYPE_WPA2_PSK;
+
+    private static final String TEST_EXPECTED_XML_STRING =
+            "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+                    + "<WifiConfigStoreData>\n"
+                    + "<int name=\"Version\" value=\"3\" />\n"
+                    + "<SoftAp>\n"
+                    + "<string name=\"SSID\">" + TEST_SSID + "</string>\n"
+                    + "<int name=\"ApBand\" value=\"" + TEST_BAND + "\" />\n"
+                    + "<int name=\"Channel\" value=\"" + TEST_CHANNEL + "\" />\n"
+                    + "<boolean name=\"HiddenSSID\" value=\"" + TEST_HIDDEN + "\" />\n"
+                    + "<int name=\"SecurityType\" value=\"" + TEST_SECURITY + "\" />\n"
+                    + "<string name=\"Passphrase\">" + TEST_PASSPHRASE + "</string>\n"
+                    + "<int name=\"MaxNumberOfClients\" value=\"0\" />\n"
+                    + "<boolean name=\"ClientControlByUser\" value=\"false\" />\n"
+                    + "<boolean name=\"AutoShutdownEnabled\" value=\"true\" />\n"
+                    + "<long name=\"ShutdownTimeoutMillis\" value=\"0\" />\n"
+                    + "<BlockedClientList />\n"
+                    + "<AllowedClientList />\n"
+                    + "</SoftAp>\n"
+                    + "</WifiConfigStoreData>\n";
+
+    private byte[] createLegacyApConfFile(WifiConfiguration config) throws Exception {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        DataOutputStream out = new DataOutputStream(outputStream);
+        out.writeInt(3);
+        out.writeUTF(config.SSID);
+        out.writeInt(config.apBand);
+        out.writeInt(config.apChannel);
+        out.writeBoolean(config.hiddenSSID);
+        int authType = config.getAuthType();
+        out.writeInt(authType);
+        if (authType != WifiConfiguration.KeyMgmt.NONE) {
+            out.writeUTF(config.preSharedKey);
+        }
+        out.close();
+        return outputStream.toByteArray();
+    }
+
+    /**
+     * Generate a SoftApConfiguration based on the specified parameters.
+     */
+    private SoftApConfiguration setupApConfig(
+            String ssid, String preSharedKey, int keyManagement, int band, int channel,
+            boolean hiddenSSID) {
+        SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder();
+        configBuilder.setSsid(ssid);
+        configBuilder.setPassphrase(preSharedKey, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+        if (channel == 0) {
+            configBuilder.setBand(band);
+        } else {
+            configBuilder.setChannel(channel, band);
+        }
+        configBuilder.setHiddenSsid(hiddenSSID);
+        return configBuilder.build();
+    }
+
+    /**
+     * Generate a WifiConfiguration based on the specified parameters.
+     */
+    private WifiConfiguration setupWifiConfigurationApConfig(
+            String ssid, String preSharedKey, int keyManagement, int band, int channel,
+            boolean hiddenSSID) {
+        WifiConfiguration config = new WifiConfiguration();
+        config.SSID = ssid;
+        config.preSharedKey = preSharedKey;
+        config.allowedKeyManagement.set(keyManagement);
+        config.apBand = band;
+        config.apChannel = channel;
+        config.hiddenSSID = hiddenSSID;
+        return config;
+    }
+
+    /**
+     * Asserts that the WifiConfigurations equal to SoftApConfiguration.
+     * This only compares the elements saved
+     * for softAp used.
+     */
+    public static void assertWifiConfigurationEqualSoftApConfiguration(
+            WifiConfiguration backup, SoftApConfiguration restore) {
+        assertEquals(backup.SSID, restore.getSsid());
+        assertEquals(backup.BSSID, restore.getBssid());
+        assertEquals(SoftApConfToXmlMigrationUtil.convertWifiConfigBandToSoftApConfigBand(
+                backup.apBand),
+                restore.getBand());
+        assertEquals(backup.apChannel, restore.getChannel());
+        assertEquals(backup.preSharedKey, restore.getPassphrase());
+        if (backup.getAuthType() == WifiConfiguration.KeyMgmt.WPA2_PSK) {
+            assertEquals(SoftApConfiguration.SECURITY_TYPE_WPA2_PSK, restore.getSecurityType());
+        } else {
+            assertEquals(SoftApConfiguration.SECURITY_TYPE_OPEN, restore.getSecurityType());
+        }
+        assertEquals(backup.hiddenSSID, restore.isHiddenSsid());
+    }
+
+    /**
+     * Note: This is a copy of {@link AtomicFile#readFully()} modified to use the passed in
+     * {@link InputStream} which was returned using {@link AtomicFile#openRead()}.
+     */
+    private static byte[] readFully(InputStream stream) throws IOException {
+        try {
+            int pos = 0;
+            int avail = stream.available();
+            byte[] data = new byte[avail];
+            while (true) {
+                int amt = stream.read(data, pos, data.length - pos);
+                if (amt <= 0) {
+                    return data;
+                }
+                pos += amt;
+                avail = stream.available();
+                if (avail > data.length - pos) {
+                    byte[] newData = new byte[pos + avail];
+                    System.arraycopy(data, 0, newData, 0, pos);
+                    data = newData;
+                }
+            }
+        } finally {
+            stream.close();
+        }
+    }
+
+    /**
+     * Tests conversion from legacy .conf file to XML file format.
+     */
+    @Test
+    public void testConversion() throws Exception {
+        WifiConfiguration backupConfig = setupWifiConfigurationApConfig(
+                TEST_SSID,    /* SSID */
+                TEST_PASSPHRASE,       /* preshared key */
+                WifiConfiguration.KeyMgmt.WPA2_PSK,   /* key management */
+                1,                 /* AP band (5GHz) */
+                TEST_CHANNEL,                /* AP channel */
+                TEST_HIDDEN            /* Hidden SSID */);
+        SoftApConfiguration expectedConfig = setupApConfig(
+                TEST_SSID,           /* SSID */
+                TEST_PASSPHRASE,              /* preshared key */
+                SoftApConfiguration.SECURITY_TYPE_WPA2_PSK,   /* security type */
+                SoftApConfiguration.BAND_5GHZ, /* AP band (5GHz) */
+                TEST_CHANNEL,                       /* AP channel */
+                TEST_HIDDEN            /* Hidden SSID */);
+
+        assertWifiConfigurationEqualSoftApConfiguration(backupConfig, expectedConfig);
+
+        byte[] confBytes = createLegacyApConfFile(backupConfig);
+        assertNotNull(confBytes);
+
+        InputStream xmlStream = SoftApConfToXmlMigrationUtil.convert(
+                new ByteArrayInputStream(confBytes));
+
+        byte[] xmlBytes = readFully(xmlStream);
+        assertNotNull(xmlBytes);
+
+        assertEquals(TEST_EXPECTED_XML_STRING, new String(xmlBytes));
+    }
+
+}