Merge "Fix issue with white and black themes"
diff --git a/Android.bp b/Android.bp
index c47b747..9493733 100644
--- a/Android.bp
+++ b/Android.bp
@@ -916,6 +916,7 @@
         ":ipconnectivity-proto-src",
         ":libstats_atom_enum_protos",
         ":libstats_internal_protos",
+        ":statsd_internal_protos",
         "cmds/am/proto/instrumentation_data.proto",
         "cmds/statsd/src/**/*.proto",
         "core/proto/**/*.proto",
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..4f89f7d
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,24 @@
+# This top-level list should remain narrowly defined as team leads; individual
+# teams are strongly encouraged to define narrower OWNERS files at deeper
+# levels within the source tree; see OWNERS.md for more details
+dsandler@android.com
+dsandler@google.com
+hackbod@android.com
+hackbod@google.com
+jsharkey@android.com
+jsharkey@google.com
+michaelwr@google.com
+nandana@google.com
+narayan@google.com
+ogunwale@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
+yamasani@google.com
+
+# Support bulk translation updates
+per-file */res*/values*/*.xml = byi@google.com
+
+per-file Android.bp = file:platform/build/soong:/OWNERS
+per-file Android.mk = file:platform/build/soong:/OWNERS
+per-file ApiDocs.bp = file:platform/build/soong:/OWNERS
+per-file StubLibraries.bp = file:platform/build/soong:/OWNERS
diff --git a/OWNERS.md b/OWNERS.md
new file mode 100644
index 0000000..6428c59
--- /dev/null
+++ b/OWNERS.md
@@ -0,0 +1,34 @@
+As general background, `OWNERS` files expedite code reviews by helping code
+authors quickly find relevant reviewers, and they also ensure that stakeholders
+are involved in code changes in their areas.
+
+The structure of `frameworks/base/` is unique among Android repositories, and
+it's evolved into a complex interleaved structure over the years.  Because of
+this structure, the best place to authoritatively define `OWNERS` can vary
+wildly, but here are some common patterns:
+
+* `core/java/` contains source that is included in the base classpath, and as
+such it's where most APIs are defined:
+  * `core/java/android/app/`
+  * `core/java/android/content/`
+* `services/core/` contains most system services, and these directories
+typically have more granularity than `core/java/`, since they can be refactored
+without API changes:
+  * `services/core/java/com/android/server/net/`
+  * `services/core/java/com/android/server/wm/`
+* `services/` contains several system services that have been isolated from the
+main `services/core/` project:
+  * `services/appwidget/`
+  * `services/midi/`
+* `apex/` contains Mainline modules:
+  * `apex/jobscheduler/`
+  * `apex/permission/`
+* Finally, some teams may have dedicated top-level directories:
+  * `media/`
+  * `wifi/`
+
+Area maintainers are strongly encouraged to list people in a single
+authoritative `OWNERS` file in **exactly one** location.  Then, other paths
+should reference that single authoritative `OWNERS` file using an include
+directive.  This approach ensures that updates are applied consistently across
+the tree, reducing maintenance burden.
diff --git a/ZYGOTE_OWNERS b/ZYGOTE_OWNERS
new file mode 100644
index 0000000..90a185b
--- /dev/null
+++ b/ZYGOTE_OWNERS
@@ -0,0 +1,5 @@
+calin@google.com
+chriswailes@google.com
+maco@google.com
+narayan@google.com
+ngeoffray@google.com
diff --git a/apct-tests/perftests/OWNERS b/apct-tests/perftests/OWNERS
new file mode 100644
index 0000000..a060ad9
--- /dev/null
+++ b/apct-tests/perftests/OWNERS
@@ -0,0 +1,2 @@
+timmurray@google.com
+philipcuadra@google.com
diff --git a/apct-tests/perftests/autofill/OWNERS b/apct-tests/perftests/autofill/OWNERS
new file mode 100644
index 0000000..c52751d
--- /dev/null
+++ b/apct-tests/perftests/autofill/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/autofill/OWNERS
diff --git a/apct-tests/perftests/blobstore/OWNERS b/apct-tests/perftests/blobstore/OWNERS
new file mode 100644
index 0000000..65bb6b8
--- /dev/null
+++ b/apct-tests/perftests/blobstore/OWNERS
@@ -0,0 +1 @@
+include /apex/blobstore/OWNERS
diff --git a/apct-tests/perftests/contentcapture/OWNERS b/apct-tests/perftests/contentcapture/OWNERS
new file mode 100644
index 0000000..a28e00a
--- /dev/null
+++ b/apct-tests/perftests/contentcapture/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/contentcapture/OWNERS
diff --git a/apct-tests/perftests/core/apps/overlay/OWNERS b/apct-tests/perftests/core/apps/overlay/OWNERS
new file mode 100644
index 0000000..afb98d4
--- /dev/null
+++ b/apct-tests/perftests/core/apps/overlay/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/content/om/OWNERS
diff --git a/apct-tests/perftests/core/src/android/accounts/OWNERS b/apct-tests/perftests/core/src/android/accounts/OWNERS
new file mode 100644
index 0000000..df1b4f4
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/accounts/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/accounts/OWNERS
diff --git a/apct-tests/perftests/core/src/android/database/OWNERS b/apct-tests/perftests/core/src/android/database/OWNERS
new file mode 100644
index 0000000..bb9a2ca
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/database/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/database/OWNERS
diff --git a/apct-tests/perftests/inputmethod/OWNERS b/apct-tests/perftests/inputmethod/OWNERS
new file mode 100644
index 0000000..5deb2ce
--- /dev/null
+++ b/apct-tests/perftests/inputmethod/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/inputmethod/OWNERS
diff --git a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfRunPrecondition.java b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfRunPrecondition.java
index fc48fd5..4bfcade 100644
--- a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfRunPrecondition.java
+++ b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfRunPrecondition.java
@@ -16,134 +16,8 @@
 
 package android.inputmethod;
 
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.inputmethod.ImePerfTestBase.executeShellCommand;
-import static android.inputmethod.ImePerfTestBase.runWithShellPermissionIdentity;
-
-import android.app.ActivityManager;
-import android.app.ActivityManager.RunningAppProcessInfo;
-import android.app.ActivityTaskManager;
-import android.content.Context;
-import android.inputmethod.ImePerfTestBase.SettingsSession;
-import android.os.BatteryManager;
-import android.os.Bundle;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.util.Log;
-import android.view.WindowManagerPolicyConstants;
-
-import androidx.test.platform.app.InstrumentationRegistry;
-
-import com.android.internal.policy.PhoneWindow;
-
-import org.junit.runner.Description;
-import org.junit.runner.Result;
-import org.junit.runner.notification.RunListener;
-
-import java.util.List;
+import android.perftests.utils.WindowPerfRunPreconditionBase;
 
 /** Prepare the preconditions before running performance test. */
-public class ImePerfRunPrecondition extends RunListener {
-    private static final String TAG = ImePerfRunPrecondition.class.getSimpleName();
-
-    private static final String ARGUMENT_LOG_ONLY = "log";
-    private static final String ARGUMENT_KILL_BACKGROUND = "kill-bg";
-    private static final String ARGUMENT_PROFILING_ITERATIONS = "profiling-iterations";
-    private static final String ARGUMENT_PROFILING_SAMPLING = "profiling-sampling";
-    private static final String DEFAULT_PROFILING_ITERATIONS = "10";
-    private static final String DEFAULT_PROFILING_SAMPLING_US = "10";
-    private static final long KILL_BACKGROUND_WAIT_MS = 3000;
-
-    /** The requested iterations to run with method profiling. */
-    static int sProfilingIterations;
-
-    /** The interval of sample profiling in microseconds. */
-    static int sSamplingIntervalUs;
-
-    private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
-    private long mWaitPreconditionDoneMs = 500;
-
-    private final SettingsSession<Integer> mStayOnWhilePluggedInSetting = new SettingsSession<>(
-            Settings.Global.getInt(mContext.getContentResolver(),
-                    Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0),
-            value -> executeShellCommand(String.format("settings put global %s %d",
-                    Settings.Global.STAY_ON_WHILE_PLUGGED_IN, value)));
-
-    private final SettingsSession<Integer> mNavigationModeSetting = new SettingsSession<>(
-            mContext.getResources().getInteger(
-                    com.android.internal.R.integer.config_navBarInteractionMode),
-            value -> {
-                final String navOverlay;
-                switch (value) {
-                    case WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL:
-                    default:
-                        navOverlay = WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
-                        break;
-                }
-                executeShellCommand("cmd overlay enable-exclusive " + navOverlay);
-            });
-
-    /** It only executes once before all tests. */
-    @Override
-    public void testRunStarted(Description description) {
-        final Bundle arguments = InstrumentationRegistry.getArguments();
-        // If true, it only logs the method names without running.
-        final boolean skip = Boolean.parseBoolean(arguments.getString(ARGUMENT_LOG_ONLY, "false"));
-        Log.i(TAG, "arguments=" + arguments);
-        if (skip) {
-            return;
-        }
-        sProfilingIterations = Integer.parseInt(
-                arguments.getString(ARGUMENT_PROFILING_ITERATIONS, DEFAULT_PROFILING_ITERATIONS));
-        sSamplingIntervalUs = Integer.parseInt(
-                arguments.getString(ARGUMENT_PROFILING_SAMPLING, DEFAULT_PROFILING_SAMPLING_US));
-
-        // Use same navigation mode (gesture navigation) across all devices and tests
-        // for consistency.
-        mNavigationModeSetting.set(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL);
-        // Keep the device awake during testing.
-        mStayOnWhilePluggedInSetting.set(BatteryManager.BATTERY_PLUGGED_ANY);
-
-        runWithShellPermissionIdentity(() -> {
-            final ActivityTaskManager atm = mContext.getSystemService(ActivityTaskManager.class);
-            atm.removeAllVisibleRecentTasks();
-            atm.removeRootTasksWithActivityTypes(new int[] { ACTIVITY_TYPE_STANDARD,
-                    ACTIVITY_TYPE_ASSISTANT, ACTIVITY_TYPE_RECENTS, ACTIVITY_TYPE_UNDEFINED });
-        });
-        PhoneWindow.sendCloseSystemWindows(mContext, "ImePerfTests");
-
-        if (Boolean.parseBoolean(arguments.getString(ARGUMENT_KILL_BACKGROUND))) {
-            runWithShellPermissionIdentity(this::killBackgroundProcesses);
-            mWaitPreconditionDoneMs = KILL_BACKGROUND_WAIT_MS;
-        }
-        // Wait a while for the precondition setup to complete.
-        SystemClock.sleep(mWaitPreconditionDoneMs);
-    }
-
-    private void killBackgroundProcesses() {
-        Log.i(TAG, "Killing background processes...");
-        final ActivityManager am = mContext.getSystemService(ActivityManager.class);
-        final List<RunningAppProcessInfo> processes = am.getRunningAppProcesses();
-        if (processes == null) {
-            return;
-        }
-        for (RunningAppProcessInfo processInfo : processes) {
-            if (processInfo.importanceReasonCode == RunningAppProcessInfo.REASON_UNKNOWN
-                    && processInfo.importance > RunningAppProcessInfo.IMPORTANCE_SERVICE) {
-                for (String pkg : processInfo.pkgList) {
-                    am.forceStopPackage(pkg);
-                }
-            }
-        }
-    }
-
-    /** It only executes once after all tests. */
-    @Override
-    public void testRunFinished(Result result) {
-        mNavigationModeSetting.close();
-        mStayOnWhilePluggedInSetting.close();
-    }
+public class ImePerfRunPrecondition extends WindowPerfRunPreconditionBase {
 }
diff --git a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java
index 2b7af2f..689fb36 100644
--- a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java
+++ b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java
@@ -29,7 +29,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.inputmethodservice.InputMethodService;
-import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.SystemClock;
 import android.perftests.utils.ManualBenchmarkState;
@@ -420,23 +419,20 @@
                 });
     }
 
-    private void startAsyncAtrace() throws IOException {
+    private void startAsyncAtrace() {
         mIsTraceStarted = true;
         // IMF uses 'wm' component for trace in InputMethodService, InputMethodManagerService,
         // WindowManagerService and 'view' for client window (InsetsController).
         // TODO(b/167947940): Consider a separate input_method atrace
-        UI_AUTOMATION.executeShellCommand("atrace -b 32768 --async_start wm view");
-        // Avoid atrace isn't ready immediately.
-        SystemClock.sleep(TimeUnit.NANOSECONDS.toMillis(TIME_1_S_IN_NS));
+        startAsyncAtrace("wm view");
     }
 
     private void stopAsyncAtrace() {
         if (!mIsTraceStarted) {
             return;
         }
-        final ParcelFileDescriptor pfd = UI_AUTOMATION.executeShellCommand("atrace --async_stop");
         mIsTraceStarted = false;
-        final InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+        final InputStream inputStream = stopAsyncAtraceWithStream();
         try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
             String line;
             while ((line = reader.readLine()) != null) {
diff --git a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTestBase.java b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTestBase.java
index 1a861d7..f70d79c 100644
--- a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTestBase.java
+++ b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTestBase.java
@@ -18,135 +18,21 @@
 
 import static android.perftests.utils.PerfTestActivity.INTENT_EXTRA_ADD_EDIT_TEXT;
 
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import android.app.KeyguardManager;
-import android.app.UiAutomation;
-import android.content.Context;
 import android.content.Intent;
-import android.os.ParcelFileDescriptor;
-import android.os.PowerManager;
 import android.perftests.utils.PerfTestActivity;
+import android.perftests.utils.WindowPerfTestBase;
 
-
-import androidx.test.rule.ActivityTestRule;
-
-import org.junit.BeforeClass;
-
-import java.io.ByteArrayOutputStream;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.Objects;
-import java.util.function.Consumer;
-
-public class ImePerfTestBase {
-    static final UiAutomation UI_AUTOMATION = getInstrumentation().getUiAutomation();
-    static final long NANOS_PER_S = 1000L * 1000 * 1000;
-    static final long TIME_1_S_IN_NS = 1 * NANOS_PER_S;
+public class ImePerfTestBase extends WindowPerfTestBase {
     static final long TIMEOUT_1_S_IN_MS = 1 * 1000L;
 
-    @BeforeClass
-    public static void setUpOnce() {
-        final Context context = getInstrumentation().getContext();
-
-        if (!context.getSystemService(PowerManager.class).isInteractive()
-                || context.getSystemService(KeyguardManager.class).isKeyguardLocked()) {
-            executeShellCommand("input keyevent KEYCODE_WAKEUP");
-            executeShellCommand("wm dismiss-keyguard");
-        }
-        context.startActivity(new Intent(Intent.ACTION_MAIN)
-                .addCategory(Intent.CATEGORY_HOME).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
-    }
-
-    /**
-     * Executes shell command with reading the output. It may also used to block until the current
-     * command is completed.
-     */
-    static ByteArrayOutputStream executeShellCommand(String command) {
-        final ParcelFileDescriptor pfd = UI_AUTOMATION.executeShellCommand(command);
-        final byte[] buf = new byte[512];
-        final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
-        int bytesRead;
-        try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
-            while ((bytesRead = fis.read(buf)) != -1) {
-                bytes.write(buf, 0, bytesRead);
-            }
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-        return bytes;
-    }
-
-    /** Returns how many iterations should run with method tracing. */
-    static int getProfilingIterations() {
-        return ImePerfRunPrecondition.sProfilingIterations;
-    }
-
-    static void runWithShellPermissionIdentity(Runnable runnable) {
-        UI_AUTOMATION.adoptShellPermissionIdentity();
-        try {
-            runnable.run();
-        } finally {
-            UI_AUTOMATION.dropShellPermissionIdentity();
-        }
-    }
-
-    static class SettingsSession<T> implements AutoCloseable {
-        private final Consumer<T> mSetter;
-        private final T mOriginalValue;
-        private boolean mChanged;
-
-        SettingsSession(T originalValue, Consumer<T> setter) {
-            mOriginalValue = originalValue;
-            mSetter = setter;
-        }
-
-        void set(T value) {
-            if (Objects.equals(value, mOriginalValue)) {
-                mChanged = false;
-                return;
-            }
-            mSetter.accept(value);
-            mChanged = true;
-        }
-
-        @Override
-        public void close() {
-            if (mChanged) {
-                mSetter.accept(mOriginalValue);
-            }
-        }
-    }
-
-    /**
-     * Provides an activity that keeps screen on and is able to wait for a stable lifecycle stage.
-     */
-    static class PerfTestActivityRule extends ActivityTestRule<PerfTestActivity> {
-        private final Intent mStartIntent =
-                new Intent(getInstrumentation().getTargetContext(), PerfTestActivity.class);
-
-        PerfTestActivityRule() {
-            this(false /* launchActivity */);
-        }
-
-        PerfTestActivityRule(boolean launchActivity) {
-            super(PerfTestActivity.class, false /* initialTouchMode */, launchActivity);
-        }
-
-        @Override
-        protected Intent getActivityIntent() {
-            return mStartIntent;
-        }
+    /** Provides an activity that contains an edit text view.*/
+    static class PerfTestActivityRule extends PerfTestActivityRuleBase {
 
         @Override
         public PerfTestActivity launchActivity(Intent intent) {
             intent.putExtra(INTENT_EXTRA_ADD_EDIT_TEXT, true);
             return super.launchActivity(intent);
         }
-
-        PerfTestActivity launchActivity() {
-            return launchActivity(mStartIntent);
-        }
     }
 
     static String[] buildArray(String[]... arrays) {
diff --git a/apct-tests/perftests/packagemanager/OWNERS b/apct-tests/perftests/packagemanager/OWNERS
new file mode 100644
index 0000000..d825dfd
--- /dev/null
+++ b/apct-tests/perftests/packagemanager/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/OWNERS
diff --git a/apct-tests/perftests/textclassifier/OWNERS b/apct-tests/perftests/textclassifier/OWNERS
new file mode 100644
index 0000000..46b3cb8
--- /dev/null
+++ b/apct-tests/perftests/textclassifier/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/textclassifier/OWNERS
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/WindowPerfRunPreconditionBase.java b/apct-tests/perftests/utils/src/android/perftests/utils/WindowPerfRunPreconditionBase.java
new file mode 100644
index 0000000..8d2ac02
--- /dev/null
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/WindowPerfRunPreconditionBase.java
@@ -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.perftests.utils;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.perftests.utils.WindowPerfTestBase.executeShellCommand;
+import static android.perftests.utils.WindowPerfTestBase.runWithShellPermissionIdentity;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningAppProcessInfo;
+import android.app.ActivityTaskManager;
+import android.content.Context;
+import android.os.BatteryManager;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.perftests.utils.WindowPerfTestBase.SettingsSession;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.WindowManagerPolicyConstants;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.internal.policy.PhoneWindow;
+
+import org.junit.runner.Description;
+import org.junit.runner.Result;
+import org.junit.runner.notification.RunListener;
+
+import java.util.List;
+
+/** Prepare the preconditions before running performance test. */
+public class WindowPerfRunPreconditionBase extends RunListener {
+    protected final String mTag = getClass().getSimpleName();
+
+    private static final String ARGUMENT_LOG_ONLY = "log";
+    private static final String ARGUMENT_KILL_BACKGROUND = "kill-bg";
+    private static final String ARGUMENT_PROFILING_ITERATIONS = "profiling-iterations";
+    private static final String ARGUMENT_PROFILING_SAMPLING = "profiling-sampling";
+    private static final String DEFAULT_PROFILING_ITERATIONS = "0";
+    private static final String DEFAULT_PROFILING_SAMPLING_US = "10";
+    private static final long KILL_BACKGROUND_WAIT_MS = 3000;
+
+    /** The requested iterations to run with method profiling. */
+    static int sProfilingIterations;
+
+    /** The interval of sample profiling in microseconds. */
+    static int sSamplingIntervalUs;
+
+    private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
+    private long mWaitPreconditionDoneMs = 500;
+
+    private final SettingsSession<Integer> mStayOnWhilePluggedInSetting = new SettingsSession<>(
+            Settings.Global.getInt(mContext.getContentResolver(),
+                    Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0),
+            value -> executeShellCommand(String.format("settings put global %s %d",
+                    Settings.Global.STAY_ON_WHILE_PLUGGED_IN, value)));
+
+    private final SettingsSession<Integer> mNavigationModeSetting = new SettingsSession<>(
+            mContext.getResources().getInteger(
+                    com.android.internal.R.integer.config_navBarInteractionMode),
+            value -> {
+                final String navOverlay;
+                switch (value) {
+                    case WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON:
+                        navOverlay = WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY;
+                        break;
+                    case WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON:
+                        navOverlay = WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
+                        break;
+                    case WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL:
+                    default:
+                        navOverlay = WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
+                        break;
+                }
+                executeShellCommand("cmd overlay enable-exclusive " + navOverlay);
+            });
+
+    /** It only executes once before all tests. */
+    @Override
+    public void testRunStarted(Description description) {
+        final Bundle arguments = InstrumentationRegistry.getArguments();
+        // If true, it only logs the method names without running.
+        final boolean skip = Boolean.parseBoolean(arguments.getString(ARGUMENT_LOG_ONLY, "false"));
+        Log.i(mTag, "arguments=" + arguments);
+        if (skip) {
+            return;
+        }
+        sProfilingIterations = Integer.parseInt(
+                arguments.getString(ARGUMENT_PROFILING_ITERATIONS, DEFAULT_PROFILING_ITERATIONS));
+        sSamplingIntervalUs = Integer.parseInt(
+                arguments.getString(ARGUMENT_PROFILING_SAMPLING, DEFAULT_PROFILING_SAMPLING_US));
+
+        // Use same navigation mode (gesture navigation) across all devices and tests
+        // for consistency.
+        mNavigationModeSetting.set(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL);
+        // Keep the device awake during testing.
+        mStayOnWhilePluggedInSetting.set(BatteryManager.BATTERY_PLUGGED_ANY);
+
+        runWithShellPermissionIdentity(() -> {
+            final ActivityTaskManager atm = mContext.getSystemService(ActivityTaskManager.class);
+            atm.removeAllVisibleRecentTasks();
+            atm.removeRootTasksWithActivityTypes(new int[] { ACTIVITY_TYPE_STANDARD,
+                    ACTIVITY_TYPE_ASSISTANT, ACTIVITY_TYPE_RECENTS, ACTIVITY_TYPE_UNDEFINED });
+        });
+        PhoneWindow.sendCloseSystemWindows(mContext, mTag);
+
+        if (Boolean.parseBoolean(arguments.getString(ARGUMENT_KILL_BACKGROUND))) {
+            runWithShellPermissionIdentity(this::killBackgroundProcesses);
+            mWaitPreconditionDoneMs = KILL_BACKGROUND_WAIT_MS;
+        }
+        // Wait a while for the precondition setup to complete.
+        SystemClock.sleep(mWaitPreconditionDoneMs);
+    }
+
+    private void killBackgroundProcesses() {
+        Log.i(mTag, "Killing background processes...");
+        final ActivityManager am = mContext.getSystemService(ActivityManager.class);
+        final List<RunningAppProcessInfo> processes = am.getRunningAppProcesses();
+        if (processes == null) {
+            return;
+        }
+        for (RunningAppProcessInfo processInfo : processes) {
+            if (processInfo.importanceReasonCode == RunningAppProcessInfo.REASON_UNKNOWN
+                    && processInfo.importance > RunningAppProcessInfo.IMPORTANCE_SERVICE) {
+                for (String pkg : processInfo.pkgList) {
+                    am.forceStopPackage(pkg);
+                }
+            }
+        }
+    }
+
+    /** It only executes once after all tests. */
+    @Override
+    public void testRunFinished(Result result) {
+        mNavigationModeSetting.close();
+        mStayOnWhilePluggedInSetting.close();
+    }
+}
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/WindowPerfTestBase.java b/apct-tests/perftests/utils/src/android/perftests/utils/WindowPerfTestBase.java
new file mode 100644
index 0000000..ca59137
--- /dev/null
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/WindowPerfTestBase.java
@@ -0,0 +1,193 @@
+/*
+ * 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.perftests.utils;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import android.app.KeyguardManager;
+import android.app.UiAutomation;
+import android.content.Context;
+import android.content.Intent;
+import android.os.ParcelFileDescriptor;
+import android.os.PowerManager;
+import android.os.SystemClock;
+
+import androidx.test.rule.ActivityTestRule;
+
+import org.junit.After;
+import org.junit.BeforeClass;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+/** The base class for window related performance tests. */
+public class WindowPerfTestBase {
+    public static final long NANOS_PER_S = 1000L * 1000 * 1000;
+    public static final long TIME_1_S_IN_NS = 1 * NANOS_PER_S;
+
+    static boolean sIsProfilingMethod;
+
+    @BeforeClass
+    public static void setUpOnce() {
+        final Context context = getInstrumentation().getContext();
+
+        if (!context.getSystemService(PowerManager.class).isInteractive()
+                || context.getSystemService(KeyguardManager.class).isKeyguardLocked()) {
+            executeShellCommand("input keyevent KEYCODE_WAKEUP");
+            executeShellCommand("wm dismiss-keyguard");
+        }
+        context.startActivity(new Intent(Intent.ACTION_MAIN)
+                .addCategory(Intent.CATEGORY_HOME).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+    }
+
+    @After
+    public void tearDown() {
+        // Make sure that profiling is stopped if test fails.
+        if (sIsProfilingMethod) {
+            stopProfiling();
+        }
+    }
+
+    public static UiAutomation getUiAutomation() {
+        return getInstrumentation().getUiAutomation();
+    }
+
+    public static void startAsyncAtrace(String tags) {
+        getUiAutomation().executeShellCommand("atrace -b 32768 --async_start " + tags);
+        // Avoid atrace isn't ready immediately.
+        SystemClock.sleep(TimeUnit.NANOSECONDS.toMillis(TIME_1_S_IN_NS));
+    }
+
+    public static InputStream stopAsyncAtraceWithStream() {
+        return new ParcelFileDescriptor.AutoCloseInputStream(
+                getUiAutomation().executeShellCommand("atrace --async_stop"));
+    }
+
+    /** Starts method tracing on system server. */
+    public static void startProfiling(File basePath, String outFileName) {
+        if (!basePath.exists()) {
+            executeShellCommand("mkdir -p " + basePath);
+        }
+        final String samplingArg = WindowPerfRunPreconditionBase.sSamplingIntervalUs > 0
+                ? ("--sampling " + WindowPerfRunPreconditionBase.sSamplingIntervalUs)
+                : "";
+        executeShellCommand("am profile start " + samplingArg + " system "
+                + new File(basePath, outFileName));
+        sIsProfilingMethod = true;
+    }
+
+    /** Stops method tracing of system server. */
+    public static void stopProfiling() {
+        executeShellCommand("am profile stop system");
+        sIsProfilingMethod = false;
+    }
+
+    public static boolean sIsProfilingMethod() {
+        return sIsProfilingMethod;
+    }
+
+    /** Returns how many iterations should run with method tracing. */
+    public static int getProfilingIterations() {
+        return WindowPerfRunPreconditionBase.sProfilingIterations;
+    }
+
+    /**
+     * Executes shell command with reading the output. It may also used to block until the current
+     * command is completed.
+     */
+    public static ByteArrayOutputStream executeShellCommand(String command) {
+        final ParcelFileDescriptor pfd = getUiAutomation().executeShellCommand(command);
+        final byte[] buf = new byte[512];
+        final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+        int bytesRead;
+        try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
+            while ((bytesRead = fis.read(buf)) != -1) {
+                bytes.write(buf, 0, bytesRead);
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        return bytes;
+    }
+
+    public static void runWithShellPermissionIdentity(Runnable runnable) {
+        getUiAutomation().adoptShellPermissionIdentity();
+        try {
+            runnable.run();
+        } finally {
+            getUiAutomation().dropShellPermissionIdentity();
+        }
+    }
+
+    public static class SettingsSession<T> implements AutoCloseable {
+        private final Consumer<T> mSetter;
+        private final T mOriginalValue;
+        private boolean mChanged;
+
+        public SettingsSession(T originalValue, Consumer<T> setter) {
+            mOriginalValue = originalValue;
+            mSetter = setter;
+        }
+
+        public void set(T value) {
+            if (Objects.equals(value, mOriginalValue)) {
+                mChanged = false;
+                return;
+            }
+            mSetter.accept(value);
+            mChanged = true;
+        }
+
+        @Override
+        public void close() {
+            if (mChanged) {
+                mSetter.accept(mOriginalValue);
+            }
+        }
+    }
+
+    /**
+     * Provides the {@link PerfTestActivity} with an associated customizable intent.
+     */
+    public static class PerfTestActivityRuleBase extends ActivityTestRule<PerfTestActivity> {
+        protected final Intent mStartIntent =
+                new Intent(getInstrumentation().getTargetContext(), PerfTestActivity.class);
+
+        public PerfTestActivityRuleBase() {
+            this(false /* launchActivity */);
+        }
+
+        public PerfTestActivityRuleBase(boolean launchActivity) {
+            super(PerfTestActivity.class, false /* initialTouchMode */, launchActivity);
+        }
+
+        @Override
+        public Intent getActivityIntent() {
+            return mStartIntent;
+        }
+
+        public PerfTestActivity launchActivity() {
+            return launchActivity(mStartIntent);
+        }
+    }
+}
diff --git a/apct-tests/perftests/windowmanager/OWNERS b/apct-tests/perftests/windowmanager/OWNERS
new file mode 100644
index 0000000..0862c05
--- /dev/null
+++ b/apct-tests/perftests/windowmanager/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java
index 5c09ec2..bccef53 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/InternalWindowOperationPerfTest.java
@@ -18,7 +18,6 @@
 
 import static android.perftests.utils.ManualBenchmarkState.StatsReport;
 
-import android.os.ParcelFileDescriptor;
 import android.os.SystemClock;
 import android.perftests.utils.ManualBenchmarkState;
 import android.perftests.utils.ManualBenchmarkState.ManualBenchmarkTest;
@@ -37,7 +36,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.util.concurrent.TimeUnit;
 
 /** Measure the performance of internal methods in window manager service by trace tag. */
 @LargeTest
@@ -85,7 +83,7 @@
 
         while (state.keepRunning(measuredTimeNs)) {
             if (!mIsTraceStarted && !mIsProfiling && !state.isWarmingUp()) {
-                startAsyncAtrace();
+                startAsyncAtrace("wm");
                 mIsTraceStarted = true;
             }
             final long startTime = SystemClock.elapsedRealtimeNanos();
@@ -108,15 +106,8 @@
         Log.i(TAG, String.valueOf(mTraceMarkParser));
     }
 
-    private void startAsyncAtrace() throws IOException {
-        sUiAutomation.executeShellCommand("atrace -b 32768 --async_start wm");
-        // Avoid atrace isn't ready immediately.
-        SystemClock.sleep(TimeUnit.NANOSECONDS.toMillis(TIME_1_S_IN_NS));
-    }
-
     private void stopAsyncAtrace() {
-        final ParcelFileDescriptor pfd = sUiAutomation.executeShellCommand("atrace --async_stop");
-        final InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+        final InputStream inputStream = stopAsyncAtraceWithStream();
         try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
             String line;
             while ((line = reader.readLine()) != null) {
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
index 833cc0f..2aea61f 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
@@ -96,7 +96,7 @@
     @BeforeClass
     public static void setUpClass() {
         // Get the permission to invoke startRecentsActivity.
-        sUiAutomation.adoptShellPermissionIdentity();
+        getUiAutomation().adoptShellPermissionIdentity();
 
         final Context context = getInstrumentation().getContext();
         final PackageManager pm = context.getPackageManager();
@@ -129,7 +129,7 @@
             ActivityManager.resumeAppSwitches();
         } catch (RemoteException ignored) {
         }
-        sUiAutomation.dropShellPermissionIdentity();
+        getUiAutomation().dropShellPermissionIdentity();
     }
 
     @Before
@@ -233,7 +233,7 @@
 
             // Ensure the animation callback is done.
             Assume.assumeTrue(recentsSemaphore.tryAcquire(
-                    sIsProfilingMethod ? 10 * TIME_5_S_IN_NS : TIME_5_S_IN_NS,
+                    sIsProfilingMethod() ? 10 * TIME_5_S_IN_NS : TIME_5_S_IN_NS,
                     TimeUnit.NANOSECONDS));
         }
     }
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
index 2960603..9403e8b 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
@@ -54,12 +54,12 @@
     @BeforeClass
     public static void setUpClass() {
         // Get the permission to use most window types.
-        sUiAutomation.adoptShellPermissionIdentity();
+        getUiAutomation().adoptShellPermissionIdentity();
     }
 
     @AfterClass
     public static void tearDownClass() {
-        sUiAutomation.dropShellPermissionIdentity();
+        getUiAutomation().dropShellPermissionIdentity();
     }
 
     /** The last customized iterations will provide the information of method profiling. */
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java
index b51a9a8..4b1982f 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java
@@ -19,36 +19,21 @@
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
 import android.app.Activity;
-import android.app.KeyguardManager;
-import android.app.UiAutomation;
-import android.content.Context;
 import android.content.Intent;
-import android.os.ParcelFileDescriptor;
-import android.os.PowerManager;
 import android.perftests.utils.PerfTestActivity;
+import android.perftests.utils.WindowPerfTestBase;
 
-import androidx.test.rule.ActivityTestRule;
 import androidx.test.runner.lifecycle.ActivityLifecycleCallback;
 import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry;
 import androidx.test.runner.lifecycle.Stage;
 
-import org.junit.After;
-import org.junit.BeforeClass;
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
 
-import java.io.ByteArrayOutputStream;
 import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.Objects;
 import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
 
-public class WindowManagerPerfTestBase {
-    static final UiAutomation sUiAutomation = getInstrumentation().getUiAutomation();
-    static final long NANOS_PER_S = 1000L * 1000 * 1000;
-    static final long TIME_1_S_IN_NS = 1 * NANOS_PER_S;
+public class WindowManagerPerfTestBase extends WindowPerfTestBase {
     static final long TIME_5_S_IN_NS = 5 * NANOS_PER_S;
 
     /**
@@ -58,121 +43,21 @@
      */
     static final File BASE_OUT_PATH = new File("/data/local/tmp/WmPerfTests");
 
-    static boolean sIsProfilingMethod;
-
-    @BeforeClass
-    public static void setUpOnce() {
-        final Context context = getInstrumentation().getContext();
-
-        if (!context.getSystemService(PowerManager.class).isInteractive()
-                || context.getSystemService(KeyguardManager.class).isKeyguardLocked()) {
-            executeShellCommand("input keyevent KEYCODE_WAKEUP");
-            executeShellCommand("wm dismiss-keyguard");
-        }
-        context.startActivity(new Intent(Intent.ACTION_MAIN)
-                .addCategory(Intent.CATEGORY_HOME).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
-    }
-
-    @After
-    public void tearDown() {
-        // Make sure that profiling is stopped if test fails.
-        if (sIsProfilingMethod) {
-            stopProfiling();
-        }
+    static void startProfiling(String outFileName) {
+        startProfiling(BASE_OUT_PATH, outFileName);
     }
 
     /**
-     * Executes shell command with reading the output. It may also used to block until the current
-     * command is completed.
+     * Provides an activity that is able to wait for a stable lifecycle stage.
      */
-    static ByteArrayOutputStream executeShellCommand(String command) {
-        final ParcelFileDescriptor pfd = sUiAutomation.executeShellCommand(command);
-        final byte[] buf = new byte[512];
-        final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
-        int bytesRead;
-        try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
-            while ((bytesRead = fis.read(buf)) != -1) {
-                bytes.write(buf, 0, bytesRead);
-            }
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-        return bytes;
-    }
-
-    /** Starts method tracing on system server. */
-    static void startProfiling(String subPath) {
-        if (!BASE_OUT_PATH.exists()) {
-            executeShellCommand("mkdir -p " + BASE_OUT_PATH);
-        }
-        final String samplingArg = WmPerfRunListener.sSamplingIntervalUs > 0
-                ? ("--sampling " + WmPerfRunListener.sSamplingIntervalUs)
-                : "";
-        executeShellCommand("am profile start " + samplingArg + " system "
-                + new File(BASE_OUT_PATH, subPath));
-        sIsProfilingMethod = true;
-    }
-
-    static void stopProfiling() {
-        executeShellCommand("am profile stop system");
-        sIsProfilingMethod = false;
-    }
-
-    /** Returns how many iterations should run with method tracing. */
-    static int getProfilingIterations() {
-        return WmPerfRunListener.sProfilingIterations;
-    }
-
-    static void runWithShellPermissionIdentity(Runnable runnable) {
-        sUiAutomation.adoptShellPermissionIdentity();
-        try {
-            runnable.run();
-        } finally {
-            sUiAutomation.dropShellPermissionIdentity();
-        }
-    }
-
-    static class SettingsSession<T> implements AutoCloseable {
-        private final Consumer<T> mSetter;
-        private final T mOriginalValue;
-        private boolean mChanged;
-
-        SettingsSession(T originalValue, Consumer<T> setter) {
-            mOriginalValue = originalValue;
-            mSetter = setter;
-        }
-
-        void set(T value) {
-            if (Objects.equals(value, mOriginalValue)) {
-                mChanged = false;
-                return;
-            }
-            mSetter.accept(value);
-            mChanged = true;
-        }
-
-        @Override
-        public void close() {
-            if (mChanged) {
-                mSetter.accept(mOriginalValue);
-            }
-        }
-    }
-
-    /**
-     * Provides an activity that keeps screen on and is able to wait for a stable lifecycle stage.
-     */
-    static class PerfTestActivityRule extends ActivityTestRule<PerfTestActivity> {
-        private final Intent mStartIntent =
-                new Intent(getInstrumentation().getTargetContext(), PerfTestActivity.class);
+    static class PerfTestActivityRule extends PerfTestActivityRuleBase {
         private final LifecycleListener mLifecycleListener = new LifecycleListener();
 
         PerfTestActivityRule() {
-            this(false /* launchActivity */);
         }
 
         PerfTestActivityRule(boolean launchActivity) {
-            super(PerfTestActivity.class, false /* initialTouchMode */, launchActivity);
+            super(launchActivity);
         }
 
         @Override
@@ -191,21 +76,12 @@
         }
 
         @Override
-        protected Intent getActivityIntent() {
-            return mStartIntent;
-        }
-
-        @Override
         public PerfTestActivity launchActivity(Intent intent) {
             final PerfTestActivity activity = super.launchActivity(intent);
             mLifecycleListener.setTargetActivity(activity);
             return activity;
         }
 
-        PerfTestActivity launchActivity() {
-            return launchActivity(mStartIntent);
-        }
-
         void waitForIdleSync(Stage state) {
             mLifecycleListener.waitForIdleSync(state);
         }
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java b/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java
index a9d5716..2b0801a 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/WmPerfRunListener.java
@@ -16,138 +16,8 @@
 
 package android.wm;
 
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.wm.WindowManagerPerfTestBase.executeShellCommand;
-import static android.wm.WindowManagerPerfTestBase.runWithShellPermissionIdentity;
-
-import android.app.ActivityManager;
-import android.app.ActivityManager.RunningAppProcessInfo;
-import android.app.ActivityTaskManager;
-import android.content.Context;
-import android.os.BatteryManager;
-import android.os.Bundle;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.util.Log;
-import android.view.WindowManagerPolicyConstants;
-import android.wm.WindowManagerPerfTestBase.SettingsSession;
-
-import androidx.test.platform.app.InstrumentationRegistry;
-
-import com.android.internal.policy.PhoneWindow;
-
-import org.junit.runner.Description;
-import org.junit.runner.Result;
-import org.junit.runner.notification.RunListener;
-
-import java.util.List;
+import android.perftests.utils.WindowPerfRunPreconditionBase;
 
 /** Prepare the preconditions before running performance test. */
-public class WmPerfRunListener extends RunListener {
-    private static final String TAG = WmPerfRunListener.class.getSimpleName();
-
-    private static final String ARGUMENT_LOG_ONLY = "log";
-    private static final String ARGUMENT_KILL_BACKGROUND = "kill-bg";
-    private static final String ARGUMENT_PROFILING_ITERATIONS = "profiling-iterations";
-    private static final String ARGUMENT_PROFILING_SAMPLING = "profiling-sampling";
-    private static final String DEFAULT_PROFILING_ITERATIONS = "0";
-    private static final String DEFAULT_PROFILING_SAMPLING_US = "10";
-    private static final long KILL_BACKGROUND_WAIT_MS = 3000;
-
-    /** The requested iterations to run with method profiling. */
-    static int sProfilingIterations;
-
-    /** The interval of sample profiling in microseconds. */
-    static int sSamplingIntervalUs;
-
-    private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
-    private long mWaitPreconditionDoneMs = 500;
-
-    private final SettingsSession<Integer> mStayOnWhilePluggedInSetting = new SettingsSession<>(
-            Settings.Global.getInt(mContext.getContentResolver(),
-                    Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0),
-            value -> executeShellCommand(String.format("settings put global %s %d",
-                    Settings.Global.STAY_ON_WHILE_PLUGGED_IN, value)));
-
-    private final SettingsSession<Integer> mNavigationModeSetting = new SettingsSession<>(
-            mContext.getResources().getInteger(
-                    com.android.internal.R.integer.config_navBarInteractionMode),
-            value -> {
-                final String navOverlay;
-                switch (value) {
-                    case WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON:
-                        navOverlay = WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY;
-                        break;
-                    case WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON:
-                        navOverlay = WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
-                        break;
-                    case WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL:
-                    default:
-                        navOverlay = WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
-                        break;
-                }
-                executeShellCommand("cmd overlay enable-exclusive " + navOverlay);
-            });
-
-    /** It only executes once before all tests. */
-    @Override
-    public void testRunStarted(Description description) {
-        final Bundle arguments = InstrumentationRegistry.getArguments();
-        // If true, it only logs the method names without running.
-        final boolean skip = Boolean.parseBoolean(arguments.getString(ARGUMENT_LOG_ONLY, "false"));
-        Log.i(TAG, "arguments=" + arguments);
-        if (skip) {
-            return;
-        }
-        sProfilingIterations = Integer.parseInt(
-                arguments.getString(ARGUMENT_PROFILING_ITERATIONS, DEFAULT_PROFILING_ITERATIONS));
-        sSamplingIntervalUs = Integer.parseInt(
-                arguments.getString(ARGUMENT_PROFILING_SAMPLING, DEFAULT_PROFILING_SAMPLING_US));
-
-        // Use gesture navigation for consistency.
-        mNavigationModeSetting.set(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL);
-        // Keep the device awake during testing.
-        mStayOnWhilePluggedInSetting.set(BatteryManager.BATTERY_PLUGGED_ANY);
-
-        runWithShellPermissionIdentity(() -> {
-            final ActivityTaskManager atm = mContext.getSystemService(ActivityTaskManager.class);
-            atm.removeAllVisibleRecentTasks();
-            atm.removeRootTasksWithActivityTypes(new int[] { ACTIVITY_TYPE_STANDARD,
-                    ACTIVITY_TYPE_ASSISTANT, ACTIVITY_TYPE_RECENTS, ACTIVITY_TYPE_UNDEFINED });
-        });
-        PhoneWindow.sendCloseSystemWindows(mContext, "WmPerfTests");
-
-        if (Boolean.parseBoolean(arguments.getString(ARGUMENT_KILL_BACKGROUND))) {
-            runWithShellPermissionIdentity(this::killBackgroundProcesses);
-            mWaitPreconditionDoneMs = KILL_BACKGROUND_WAIT_MS;
-        }
-        // Wait a while for the precondition setup to complete.
-        SystemClock.sleep(mWaitPreconditionDoneMs);
-    }
-
-    private void killBackgroundProcesses() {
-        final ActivityManager am = mContext.getSystemService(ActivityManager.class);
-        final List<RunningAppProcessInfo> processes = am.getRunningAppProcesses();
-        if (processes == null) {
-            return;
-        }
-        for (RunningAppProcessInfo processInfo : processes) {
-            if (processInfo.importanceReasonCode == RunningAppProcessInfo.REASON_UNKNOWN
-                    && processInfo.importance > RunningAppProcessInfo.IMPORTANCE_SERVICE) {
-                for (String pkg : processInfo.pkgList) {
-                    am.forceStopPackage(pkg);
-                }
-            }
-        }
-    }
-
-    /** It only executes once after all tests. */
-    @Override
-    public void testRunFinished(Result result) {
-        mNavigationModeSetting.close();
-        mStayOnWhilePluggedInSetting.close();
-    }
+public class WmPerfRunListener extends WindowPerfRunPreconditionBase {
 }
diff --git a/apex/Android.bp b/apex/Android.bp
index 0a535a8..4e80acb 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -15,6 +15,7 @@
 mainline_stubs_args =
     "--error UnhiddenSystemApi " +
     "--hide BroadcastBehavior " +
+    "--hide CallbackInterface " +
     "--hide DeprecationMismatch " +
     "--hide HiddenSuperclass " +
     "--hide HiddenTypedefConstant " +
diff --git a/apex/appsearch/OWNERS b/apex/appsearch/OWNERS
new file mode 100644
index 0000000..ce0c212
--- /dev/null
+++ b/apex/appsearch/OWNERS
@@ -0,0 +1 @@
+sudheersai@google.com
diff --git a/apex/appsearch/framework/api/current.txt b/apex/appsearch/framework/api/current.txt
index 2be873c..380c646 100644
--- a/apex/appsearch/framework/api/current.txt
+++ b/apex/appsearch/framework/api/current.txt
@@ -1,6 +1,27 @@
 // Signature format: 2.0
 package android.app.appsearch {
 
+  public final class AppSearchBatchResult<KeyType, ValueType> {
+    method @NonNull public java.util.Map<KeyType,android.app.appsearch.AppSearchResult<ValueType>> getFailures();
+    method @NonNull public java.util.Map<KeyType,ValueType> getSuccesses();
+    method public boolean isSuccess();
+  }
+
+  public final class AppSearchResult<ValueType> {
+    method @Nullable public String getErrorMessage();
+    method public int getResultCode();
+    method @Nullable public ValueType getResultValue();
+    method public boolean isSuccess();
+    field public static final int RESULT_INTERNAL_ERROR = 2; // 0x2
+    field public static final int RESULT_INVALID_ARGUMENT = 3; // 0x3
+    field public static final int RESULT_INVALID_SCHEMA = 7; // 0x7
+    field public static final int RESULT_IO_ERROR = 4; // 0x4
+    field public static final int RESULT_NOT_FOUND = 6; // 0x6
+    field public static final int RESULT_OK = 0; // 0x0
+    field public static final int RESULT_OUT_OF_SPACE = 5; // 0x5
+    field public static final int RESULT_UNKNOWN_ERROR = 1; // 0x1
+  }
+
   public final class AppSearchSchema {
     method @NonNull public java.util.List<android.app.appsearch.AppSearchSchema.PropertyConfig> getProperties();
     method @NonNull public String getSchemaType();
@@ -85,6 +106,43 @@
     method @NonNull public BuilderType setTtlMillis(long);
   }
 
+  public final class GetByUriRequest {
+    method @NonNull public String getNamespace();
+    method @NonNull public java.util.Set<java.lang.String> getUris();
+  }
+
+  public static final class GetByUriRequest.Builder {
+    ctor public GetByUriRequest.Builder();
+    method @NonNull public android.app.appsearch.GetByUriRequest.Builder addUri(@NonNull java.lang.String...);
+    method @NonNull public android.app.appsearch.GetByUriRequest.Builder addUri(@NonNull java.util.Collection<java.lang.String>);
+    method @NonNull public android.app.appsearch.GetByUriRequest build();
+    method @NonNull public android.app.appsearch.GetByUriRequest.Builder setNamespace(@NonNull String);
+  }
+
+  public final class PutDocumentsRequest {
+    method @NonNull public java.util.List<android.app.appsearch.GenericDocument> getDocuments();
+  }
+
+  public static final class PutDocumentsRequest.Builder {
+    ctor public PutDocumentsRequest.Builder();
+    method @NonNull public android.app.appsearch.PutDocumentsRequest.Builder addGenericDocument(@NonNull android.app.appsearch.GenericDocument...);
+    method @NonNull public android.app.appsearch.PutDocumentsRequest.Builder addGenericDocument(@NonNull java.util.Collection<android.app.appsearch.GenericDocument>);
+    method @NonNull public android.app.appsearch.PutDocumentsRequest build();
+  }
+
+  public final class RemoveByUriRequest {
+    method @NonNull public String getNamespace();
+    method @NonNull public java.util.Set<java.lang.String> getUris();
+  }
+
+  public static final class RemoveByUriRequest.Builder {
+    ctor public RemoveByUriRequest.Builder();
+    method @NonNull public android.app.appsearch.RemoveByUriRequest.Builder addUri(@NonNull java.lang.String...);
+    method @NonNull public android.app.appsearch.RemoveByUriRequest.Builder addUri(@NonNull java.util.Collection<java.lang.String>);
+    method @NonNull public android.app.appsearch.RemoveByUriRequest build();
+    method @NonNull public android.app.appsearch.RemoveByUriRequest.Builder setNamespace(@NonNull String);
+  }
+
   public final class SearchResult {
     method @NonNull public android.app.appsearch.GenericDocument getDocument();
     method @NonNull public java.util.List<android.app.appsearch.SearchResult.MatchInfo> getMatches();
@@ -139,5 +197,18 @@
     method @NonNull public android.app.appsearch.SearchSpec.Builder setTermMatch(int);
   }
 
+  public final class SetSchemaRequest {
+    method @NonNull public java.util.Set<android.app.appsearch.AppSearchSchema> getSchemas();
+    method public boolean isForceOverride();
+  }
+
+  public static final class SetSchemaRequest.Builder {
+    ctor public SetSchemaRequest.Builder();
+    method @NonNull public android.app.appsearch.SetSchemaRequest.Builder addSchema(@NonNull android.app.appsearch.AppSearchSchema...);
+    method @NonNull public android.app.appsearch.SetSchemaRequest.Builder addSchema(@NonNull java.util.Collection<android.app.appsearch.AppSearchSchema>);
+    method @NonNull public android.app.appsearch.SetSchemaRequest build();
+    method @NonNull public android.app.appsearch.SetSchemaRequest.Builder setForceOverride(boolean);
+  }
+
 }
 
diff --git a/apex/appsearch/framework/java/android/app/TEST_MAPPING b/apex/appsearch/framework/java/TEST_MAPPING
similarity index 100%
rename from apex/appsearch/framework/java/android/app/TEST_MAPPING
rename to apex/appsearch/framework/java/TEST_MAPPING
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java
index 98daa66..97cfe36 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java
@@ -33,7 +33,6 @@
  *
  * @param <KeyType> The type of the keys for {@link #getSuccesses} and {@link #getFailures}.
  * @param <ValueType> The type of result objects associated with the keys.
- * @hide
  */
 public final class AppSearchBatchResult<KeyType, ValueType> implements Parcelable {
     @NonNull private final Map<KeyType, ValueType> mSuccesses;
@@ -51,6 +50,7 @@
         mFailures = Collections.unmodifiableMap(in.readHashMap(/*loader=*/ null));
     }
 
+    /** @hide */
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeMap(mSuccesses);
@@ -100,11 +100,14 @@
         return "{\n  successes: " + mSuccesses + "\n  failures: " + mFailures + "\n}";
     }
 
+    /** @hide */
     @Override
     public int describeContents() {
         return 0;
     }
 
+    /** @hide */
+    @NonNull
     public static final Creator<AppSearchBatchResult> CREATOR =
             new Creator<AppSearchBatchResult>() {
         @NonNull
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
index 5fd45ea..442ca7b 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
@@ -224,7 +224,11 @@
         }
         AndroidFuture<AppSearchResult> future = new AndroidFuture<>();
         try {
-            mService.setSchema(DEFAULT_DATABASE_NAME, schemaBundles, request.isForceOverride(),
+            mService.setSchema(
+                    DEFAULT_DATABASE_NAME,
+                    schemaBundles,
+                    new ArrayList<>(request.getSchemasNotPlatformSurfaceable()),
+                    request.isForceOverride(),
                     new IAppSearchResultCallback.Stub() {
                         public void onResult(AppSearchResult result) {
                             future.complete(result);
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java
index 6e2ed70..76225e4 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java
@@ -32,7 +32,6 @@
  * Information about the success or failure of an AppSearch call.
  *
  * @param <ValueType> The type of result object for successful calls.
- * @hide
  */
 public final class AppSearchResult<ValueType> implements Parcelable {
     /**
@@ -107,6 +106,7 @@
         mErrorMessage = in.readString();
     }
 
+    /** @hide */
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeInt(mResultCode);
@@ -181,13 +181,15 @@
         return "[FAILURE(" + mResultCode + ")]: " + mErrorMessage;
     }
 
+    /** @hide */
     @Override
     public int describeContents() {
         return 0;
     }
 
-    public static final Creator<AppSearchResult> CREATOR =
-            new Creator<AppSearchResult>() {
+    /** @hide */
+    @NonNull
+    public static final Creator<AppSearchResult> CREATOR = new Creator<AppSearchResult>() {
         @NonNull
         @Override
         public AppSearchResult createFromParcel(@NonNull Parcel in) {
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java
deleted file mode 100644
index 2db74a8..0000000
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- * 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.appsearch;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SuppressLint;
-import android.app.appsearch.exceptions.IllegalSchemaException;
-import android.os.Bundle;
-import android.util.ArraySet;
-
-import com.android.internal.util.Preconditions;
-
-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.Set;
-
-/**
- * The AppSearch Schema for a particular type of document.
- *
- * <p>For example, an e-mail message or a music recording could be a schema type.
- *
- * <p>The schema consists of type information, properties, and config (like tokenization type).
- *
- * @see AppSearchManager#setSchema
- */
-public final class AppSearchSchema {
-    private static final String SCHEMA_TYPE_FIELD = "schemaType";
-    private static final String PROPERTIES_FIELD = "properties";
-
-    private final Bundle mBundle;
-
-    /** @hide */
-    public AppSearchSchema(@NonNull Bundle bundle) {
-        Preconditions.checkNotNull(bundle);
-        mBundle = bundle;
-    }
-
-    /**
-     * Returns the {@link Bundle} populated by this builder.
-     *
-     * @hide
-     */
-    @NonNull
-    public Bundle getBundle() {
-        return mBundle;
-    }
-
-    @Override
-    public String toString() {
-        return mBundle.toString();
-    }
-
-    /** Returns the name of this schema type, e.g. Email. */
-    @NonNull
-    public String getSchemaType() {
-        return mBundle.getString(SCHEMA_TYPE_FIELD, "");
-    }
-
-    /**
-     * Returns the list of {@link PropertyConfig}s that are part of this schema.
-     *
-     * <p>This method creates a new list when called.
-     */
-    @NonNull
-    public List<PropertyConfig> getProperties() {
-        ArrayList<Bundle> propertyBundles =
-                mBundle.getParcelableArrayList(AppSearchSchema.PROPERTIES_FIELD);
-        if (propertyBundles.isEmpty()) {
-            return Collections.emptyList();
-        }
-        List<PropertyConfig> ret = new ArrayList<>(propertyBundles.size());
-        for (int i = 0; i < propertyBundles.size(); i++) {
-            ret.add(new PropertyConfig(propertyBundles.get(i)));
-        }
-        return ret;
-    }
-
-    /** Builder for {@link AppSearchSchema objects}. */
-    public static final class Builder {
-        private final String mTypeName;
-        private final ArrayList<Bundle> mPropertyBundles = new ArrayList<>();
-        private final Set<String> mPropertyNames = new ArraySet<>();
-        private boolean mBuilt = false;
-
-        /** Creates a new {@link AppSearchSchema.Builder}. */
-        public Builder(@NonNull String typeName) {
-            Preconditions.checkNotNull(typeName);
-            mTypeName = typeName;
-        }
-
-        /** Adds a property to the given type. */
-        // TODO(b/171360120): MissingGetterMatchingBuilder expects a method called getPropertys, but
-        //  we provide the (correct) method getProperties. Once the bug referenced in this TODO is
-        //  fixed, remove this SuppressLint.
-        @SuppressLint("MissingGetterMatchingBuilder")
-        @NonNull
-        public AppSearchSchema.Builder addProperty(@NonNull PropertyConfig propertyConfig) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            Preconditions.checkNotNull(propertyConfig);
-            String name = propertyConfig.getName();
-            if (!mPropertyNames.add(name)) {
-                throw new IllegalSchemaException("Property defined more than once: " + name);
-            }
-            mPropertyBundles.add(propertyConfig.mBundle);
-            return this;
-        }
-
-        /**
-         * Constructs a new {@link AppSearchSchema} from the contents of this builder.
-         *
-         * <p>After calling this method, the builder must no longer be used.
-         */
-        @NonNull
-        public AppSearchSchema build() {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            Bundle bundle = new Bundle();
-            bundle.putString(AppSearchSchema.SCHEMA_TYPE_FIELD, mTypeName);
-            bundle.putParcelableArrayList(AppSearchSchema.PROPERTIES_FIELD, mPropertyBundles);
-            mBuilt = true;
-            return new AppSearchSchema(bundle);
-        }
-    }
-
-    /**
-     * Configuration for a single property (field) of a document type.
-     *
-     * <p>For example, an {@code EmailMessage} would be a type and the {@code subject} would be a
-     * property.
-     */
-    public static final class PropertyConfig {
-        private static final String NAME_FIELD = "name";
-        private static final String DATA_TYPE_FIELD = "dataType";
-        private static final String SCHEMA_TYPE_FIELD = "schemaType";
-        private static final String CARDINALITY_FIELD = "cardinality";
-        private static final String INDEXING_TYPE_FIELD = "indexingType";
-        private static final String TOKENIZER_TYPE_FIELD = "tokenizerType";
-
-        /**
-         * Physical data-types of the contents of the property.
-         *
-         * @hide
-         */
-        // NOTE: The integer values of these constants must match the proto enum constants in
-        // com.google.android.icing.proto.PropertyConfigProto.DataType.Code.
-        @IntDef(
-                value = {
-                    DATA_TYPE_STRING,
-                    DATA_TYPE_INT64,
-                    DATA_TYPE_DOUBLE,
-                    DATA_TYPE_BOOLEAN,
-                    DATA_TYPE_BYTES,
-                    DATA_TYPE_DOCUMENT,
-                })
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface DataType {}
-
-        public static final int DATA_TYPE_STRING = 1;
-        public static final int DATA_TYPE_INT64 = 2;
-        public static final int DATA_TYPE_DOUBLE = 3;
-        public static final int DATA_TYPE_BOOLEAN = 4;
-
-        /** Unstructured BLOB. */
-        public static final int DATA_TYPE_BYTES = 5;
-
-        /**
-         * Indicates that the property is itself a {@link GenericDocument}, making it part of a
-         * hierarchical schema. Any property using this DataType MUST have a valid {@link
-         * PropertyConfig#getSchemaType}.
-         */
-        public static final int DATA_TYPE_DOCUMENT = 6;
-
-        /**
-         * The cardinality of the property (whether it is required, optional or repeated).
-         *
-         * @hide
-         */
-        // NOTE: The integer values of these constants must match the proto enum constants in
-        // com.google.android.icing.proto.PropertyConfigProto.Cardinality.Code.
-        @IntDef(
-                value = {
-                    CARDINALITY_REPEATED,
-                    CARDINALITY_OPTIONAL,
-                    CARDINALITY_REQUIRED,
-                })
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface Cardinality {}
-
-        /** Any number of items (including zero) [0...*]. */
-        public static final int CARDINALITY_REPEATED = 1;
-
-        /** Zero or one value [0,1]. */
-        public static final int CARDINALITY_OPTIONAL = 2;
-
-        /** Exactly one value [1]. */
-        public static final int CARDINALITY_REQUIRED = 3;
-
-        /**
-         * Encapsulates the configurations on how AppSearch should query/index these terms.
-         *
-         * @hide
-         */
-        @IntDef(
-                value = {
-                    INDEXING_TYPE_NONE,
-                    INDEXING_TYPE_EXACT_TERMS,
-                    INDEXING_TYPE_PREFIXES,
-                })
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface IndexingType {}
-
-        /**
-         * Content in this property will not be tokenized or indexed.
-         *
-         * <p>Useful if the data type is not made up of terms (e.g. {@link
-         * PropertyConfig#DATA_TYPE_DOCUMENT} or {@link PropertyConfig#DATA_TYPE_BYTES} type). None
-         * of the properties inside the nested property will be indexed regardless of the value of
-         * {@code indexingType} for the nested properties.
-         */
-        public static final int INDEXING_TYPE_NONE = 0;
-
-        /**
-         * Content in this property should only be returned for queries matching the exact tokens
-         * appearing in this property.
-         *
-         * <p>Ex. A property with "fool" should NOT match a query for "foo".
-         */
-        public static final int INDEXING_TYPE_EXACT_TERMS = 1;
-
-        /**
-         * Content in this property should be returned for queries that are either exact matches or
-         * query matches of the tokens appearing in this property.
-         *
-         * <p>Ex. A property with "fool" <b>should</b> match a query for "foo".
-         */
-        public static final int INDEXING_TYPE_PREFIXES = 2;
-
-        /**
-         * Configures how tokens should be extracted from this property.
-         *
-         * @hide
-         */
-        // NOTE: The integer values of these constants must match the proto enum constants in
-        // com.google.android.icing.proto.IndexingConfig.TokenizerType.Code.
-        @IntDef(
-                value = {
-                    TOKENIZER_TYPE_NONE,
-                    TOKENIZER_TYPE_PLAIN,
-                })
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface TokenizerType {}
-
-        /**
-         * It is only valid for tokenizer_type to be 'NONE' if the data type is {@link
-         * PropertyConfig#DATA_TYPE_DOCUMENT}.
-         */
-        public static final int TOKENIZER_TYPE_NONE = 0;
-
-        /** Tokenization for plain text. */
-        public static final int TOKENIZER_TYPE_PLAIN = 1;
-
-        final Bundle mBundle;
-
-        PropertyConfig(@NonNull Bundle bundle) {
-            mBundle = Preconditions.checkNotNull(bundle);
-        }
-
-        @Override
-        public String toString() {
-            return mBundle.toString();
-        }
-
-        /** Returns the name of this property. */
-        @NonNull
-        public String getName() {
-            return mBundle.getString(NAME_FIELD, "");
-        }
-
-        /** Returns the type of data the property contains (e.g. string, int, bytes, etc). */
-        public @DataType int getDataType() {
-            return mBundle.getInt(DATA_TYPE_FIELD, -1);
-        }
-
-        /**
-         * Returns the logical schema-type of the contents of this property.
-         *
-         * <p>Only set when {@link #getDataType} is set to {@link #DATA_TYPE_DOCUMENT}. Otherwise,
-         * it is {@code null}.
-         */
-        @Nullable
-        public String getSchemaType() {
-            return mBundle.getString(SCHEMA_TYPE_FIELD);
-        }
-
-        /**
-         * Returns the cardinality of the property (whether it is optional, required or repeated).
-         */
-        public @Cardinality int getCardinality() {
-            return mBundle.getInt(CARDINALITY_FIELD, -1);
-        }
-
-        /** Returns how the property is indexed. */
-        public @IndexingType int getIndexingType() {
-            return mBundle.getInt(INDEXING_TYPE_FIELD);
-        }
-
-        /** Returns how this property is tokenized (split into words). */
-        public @TokenizerType int getTokenizerType() {
-            return mBundle.getInt(TOKENIZER_TYPE_FIELD);
-        }
-
-        /**
-         * Builder for {@link PropertyConfig}.
-         *
-         * <p>The following properties must be set, or {@link PropertyConfig} construction will
-         * fail:
-         *
-         * <ul>
-         *   <li>dataType
-         *   <li>cardinality
-         * </ul>
-         *
-         * <p>In addition, if {@code schemaType} is {@link #DATA_TYPE_DOCUMENT}, {@code schemaType}
-         * is also required.
-         */
-        public static final class Builder {
-            private final Bundle mBundle = new Bundle();
-            private boolean mBuilt = false;
-
-            /** Creates a new {@link PropertyConfig.Builder}. */
-            public Builder(@NonNull String propertyName) {
-                mBundle.putString(NAME_FIELD, propertyName);
-            }
-
-            /**
-             * Type of data the property contains (e.g. string, int, bytes, etc).
-             *
-             * <p>This property must be set.
-             */
-            @NonNull
-            public PropertyConfig.Builder setDataType(@DataType int dataType) {
-                Preconditions.checkState(!mBuilt, "Builder has already been used");
-                Preconditions.checkArgumentInRange(
-                        dataType, DATA_TYPE_STRING, DATA_TYPE_DOCUMENT, "dataType");
-                mBundle.putInt(DATA_TYPE_FIELD, dataType);
-                return this;
-            }
-
-            /**
-             * The logical schema-type of the contents of this property.
-             *
-             * <p>Only required when {@link #setDataType} is set to {@link #DATA_TYPE_DOCUMENT}.
-             * Otherwise, it is ignored.
-             */
-            @NonNull
-            public PropertyConfig.Builder setSchemaType(@NonNull String schemaType) {
-                Preconditions.checkState(!mBuilt, "Builder has already been used");
-                Preconditions.checkNotNull(schemaType);
-                mBundle.putString(SCHEMA_TYPE_FIELD, schemaType);
-                return this;
-            }
-
-            /**
-             * The cardinality of the property (whether it is optional, required or repeated).
-             *
-             * <p>This property must be set.
-             */
-            @NonNull
-            public PropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
-                Preconditions.checkState(!mBuilt, "Builder has already been used");
-                Preconditions.checkArgumentInRange(
-                        cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
-                mBundle.putInt(CARDINALITY_FIELD, cardinality);
-                return this;
-            }
-
-            /**
-             * Configures how a property should be indexed so that it can be retrieved by queries.
-             */
-            @NonNull
-            public PropertyConfig.Builder setIndexingType(@IndexingType int indexingType) {
-                Preconditions.checkState(!mBuilt, "Builder has already been used");
-                Preconditions.checkArgumentInRange(
-                        indexingType, INDEXING_TYPE_NONE, INDEXING_TYPE_PREFIXES, "indexingType");
-                mBundle.putInt(INDEXING_TYPE_FIELD, indexingType);
-                return this;
-            }
-
-            /** Configures how this property should be tokenized (split into words). */
-            @NonNull
-            public PropertyConfig.Builder setTokenizerType(@TokenizerType int tokenizerType) {
-                Preconditions.checkState(!mBuilt, "Builder has already been used");
-                Preconditions.checkArgumentInRange(
-                        tokenizerType, TOKENIZER_TYPE_NONE, TOKENIZER_TYPE_PLAIN, "tokenizerType");
-                mBundle.putInt(TOKENIZER_TYPE_FIELD, tokenizerType);
-                return this;
-            }
-
-            /**
-             * Constructs a new {@link PropertyConfig} from the contents of this builder.
-             *
-             * <p>After calling this method, the builder must no longer be used.
-             *
-             * @throws IllegalSchemaException If the property is not correctly populated (e.g.
-             *     missing {@code dataType}).
-             */
-            @NonNull
-            public PropertyConfig build() {
-                Preconditions.checkState(!mBuilt, "Builder has already been used");
-                // TODO(b/147692920): Send the schema to Icing Lib for official validation, instead
-                //     of partially reimplementing some of the validation Icing does here.
-                if (!mBundle.containsKey(DATA_TYPE_FIELD)) {
-                    throw new IllegalSchemaException("Missing field: dataType");
-                }
-                if (mBundle.getString(SCHEMA_TYPE_FIELD, "").isEmpty()
-                        && mBundle.getInt(DATA_TYPE_FIELD) == DATA_TYPE_DOCUMENT) {
-                    throw new IllegalSchemaException(
-                            "Missing field: schemaType (required for configs with "
-                                    + "dataType = DOCUMENT)");
-                }
-                if (!mBundle.containsKey(CARDINALITY_FIELD)) {
-                    throw new IllegalSchemaException("Missing field: cardinality");
-                }
-                mBuilt = true;
-                return new PropertyConfig(mBundle);
-            }
-        }
-    }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
index 9c7ccea..b7cd4f5 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
@@ -140,7 +140,11 @@
             schemaBundles.add(schema.getBundle());
         }
         try {
-            mService.setSchema(mDatabaseName, schemaBundles, request.isForceOverride(),
+            mService.setSchema(
+                    mDatabaseName,
+                    schemaBundles,
+                    new ArrayList<>(request.getSchemasNotPlatformSurfaceable()),
+                    request.isForceOverride(),
                     new IAppSearchResultCallback.Stub() {
                         public void onResult(AppSearchResult result) {
                             executor.execute(() -> callback.accept(result));
diff --git a/apex/appsearch/framework/java/android/app/appsearch/GenericDocument.java b/apex/appsearch/framework/java/android/app/appsearch/GenericDocument.java
deleted file mode 100644
index 0056377..0000000
--- a/apex/appsearch/framework/java/android/app/appsearch/GenericDocument.java
+++ /dev/null
@@ -1,963 +0,0 @@
-/*
- * 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.appsearch;
-
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SuppressLint;
-import android.app.appsearch.exceptions.AppSearchException;
-import android.os.Bundle;
-import android.util.Log;
-
-import com.android.internal.util.Preconditions;
-
-import java.lang.reflect.Array;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Set;
-
-/**
- * Represents a document unit.
- *
- * <p>Documents are constructed via {@link GenericDocument.Builder}.
- *
- * @see AppSearchManager#putDocuments
- * @see AppSearchManager#getByUri
- * @see AppSearchManager#query
- */
-public class GenericDocument {
-    private static final String TAG = "GenericDocument";
-
-    /** The default empty namespace. */
-    public static final String DEFAULT_NAMESPACE = "";
-
-    /**
-     * The maximum number of elements in a repeatable field. Will reject the request if exceed this
-     * limit.
-     */
-    private static final int MAX_REPEATED_PROPERTY_LENGTH = 100;
-
-    /**
-     * The maximum {@link String#length} of a {@link String} field. Will reject the request if
-     * {@link String}s longer than this.
-     */
-    private static final int MAX_STRING_LENGTH = 20_000;
-
-    /** The maximum number of indexed properties a document can have. */
-    private static final int MAX_INDEXED_PROPERTIES = 16;
-
-    /** The default score of document. */
-    private static final int DEFAULT_SCORE = 0;
-
-    /** The default time-to-live in millisecond of a document, which is infinity. */
-    private static final long DEFAULT_TTL_MILLIS = 0L;
-
-    private static final String PROPERTIES_FIELD = "properties";
-    private static final String BYTE_ARRAY_FIELD = "byteArray";
-    private static final String SCHEMA_TYPE_FIELD = "schemaType";
-    private static final String URI_FIELD = "uri";
-    private static final String SCORE_FIELD = "score";
-    private static final String TTL_MILLIS_FIELD = "ttlMillis";
-    private static final String CREATION_TIMESTAMP_MILLIS_FIELD = "creationTimestampMillis";
-    private static final String NAMESPACE_FIELD = "namespace";
-
-    /**
-     * The maximum number of indexed properties a document can have.
-     *
-     * <p>Indexed properties are properties where the {@link
-     * AppSearchSchema.PropertyConfig#getIndexingType()} constant is anything other than {@link
-     * AppSearchSchema.PropertyConfig.IndexingType#INDEXING_TYPE_NONE}.
-     */
-    public static int getMaxIndexedProperties() {
-        return MAX_INDEXED_PROPERTIES;
-    }
-
-    /** Contains {@link GenericDocument} basic information (uri, schemaType etc). */
-    @NonNull final Bundle mBundle;
-
-    /**
-     * Contains all properties in {@link GenericDocument} to support getting properties via keys.
-     */
-    @NonNull private final Bundle mProperties;
-
-    @NonNull private final String mUri;
-    @NonNull private final String mSchemaType;
-    private final long mCreationTimestampMillis;
-    @Nullable private Integer mHashCode;
-
-    /**
-     * Rebuilds a {@link GenericDocument} by the a bundle.
-     *
-     * @param bundle Contains {@link GenericDocument} basic information (uri, schemaType etc) and a
-     *     properties bundle contains all properties in {@link GenericDocument} to support getting
-     *     properties via keys.
-     * @hide
-     */
-    public GenericDocument(@NonNull Bundle bundle) {
-        Preconditions.checkNotNull(bundle);
-        mBundle = bundle;
-        mProperties = Preconditions.checkNotNull(bundle.getParcelable(PROPERTIES_FIELD));
-        mUri = Preconditions.checkNotNull(mBundle.getString(URI_FIELD));
-        mSchemaType = Preconditions.checkNotNull(mBundle.getString(SCHEMA_TYPE_FIELD));
-        mCreationTimestampMillis =
-                mBundle.getLong(CREATION_TIMESTAMP_MILLIS_FIELD, System.currentTimeMillis());
-    }
-
-    /**
-     * Creates a new {@link GenericDocument} from an existing instance.
-     *
-     * <p>This method should be only used by constructor of a subclass.
-     */
-    protected GenericDocument(@NonNull GenericDocument document) {
-        this(document.mBundle);
-    }
-
-    /**
-     * Returns the {@link Bundle} populated by this builder.
-     *
-     * @hide
-     */
-    @NonNull
-    public Bundle getBundle() {
-        return mBundle;
-    }
-
-    /** Returns the URI of the {@link GenericDocument}. */
-    @NonNull
-    public String getUri() {
-        return mUri;
-    }
-
-    /** Returns the namespace of the {@link GenericDocument}. */
-    @NonNull
-    public String getNamespace() {
-        return mBundle.getString(NAMESPACE_FIELD, DEFAULT_NAMESPACE);
-    }
-
-    /** Returns the schema type of the {@link GenericDocument}. */
-    @NonNull
-    public String getSchemaType() {
-        return mSchemaType;
-    }
-
-    /**
-     * Returns the creation timestamp of the {@link GenericDocument}, in milliseconds.
-     *
-     * <p>The value is in the {@link System#currentTimeMillis} time base.
-     */
-    public long getCreationTimestampMillis() {
-        return mCreationTimestampMillis;
-    }
-
-    /**
-     * Returns the TTL (Time To Live) of the {@link GenericDocument}, in milliseconds.
-     *
-     * <p>The TTL is measured against {@link #getCreationTimestampMillis}. At the timestamp of
-     * {@code creationTimestampMillis + ttlMillis}, measured in the {@link System#currentTimeMillis}
-     * time base, the document will be auto-deleted.
-     *
-     * <p>The default value is 0, which means the document is permanent and won't be auto-deleted
-     * until the app is uninstalled.
-     */
-    public long getTtlMillis() {
-        return mBundle.getLong(TTL_MILLIS_FIELD, DEFAULT_TTL_MILLIS);
-    }
-
-    /**
-     * Returns the score of the {@link GenericDocument}.
-     *
-     * <p>The score is a query-independent measure of the document's quality, relative to other
-     * {@link GenericDocument}s of the same type.
-     *
-     * <p>Results may be sorted by score using {@link SearchSpec.Builder#setRankingStrategy}.
-     * Documents with higher scores are considered better than documents with lower scores.
-     *
-     * <p>Any nonnegative integer can be used a score.
-     */
-    public int getScore() {
-        return mBundle.getInt(SCORE_FIELD, DEFAULT_SCORE);
-    }
-
-    /** Returns the names of all properties defined in this document. */
-    @NonNull
-    public Set<String> getPropertyNames() {
-        return Collections.unmodifiableSet(mProperties.keySet());
-    }
-
-    /**
-     * Retrieves a {@link String} value by key.
-     *
-     * @param key The key to look for.
-     * @return The first {@link String} associated with the given key or {@code null} if there is no
-     *     such key or the value is of a different type.
-     */
-    @Nullable
-    public String getPropertyString(@NonNull String key) {
-        Preconditions.checkNotNull(key);
-        String[] propertyArray = getPropertyStringArray(key);
-        if (propertyArray == null || propertyArray.length == 0) {
-            return null;
-        }
-        warnIfSinglePropertyTooLong("String", key, propertyArray.length);
-        return propertyArray[0];
-    }
-
-    /**
-     * Retrieves a {@code long} value by key.
-     *
-     * @param key The key to look for.
-     * @return The first {@code long} associated with the given key or default value {@code 0} if
-     *     there is no such key or the value is of a different type.
-     */
-    public long getPropertyLong(@NonNull String key) {
-        Preconditions.checkNotNull(key);
-        long[] propertyArray = getPropertyLongArray(key);
-        if (propertyArray == null || propertyArray.length == 0) {
-            return 0;
-        }
-        warnIfSinglePropertyTooLong("Long", key, propertyArray.length);
-        return propertyArray[0];
-    }
-
-    /**
-     * Retrieves a {@code double} value by key.
-     *
-     * @param key The key to look for.
-     * @return The first {@code double} associated with the given key or default value {@code 0.0}
-     *     if there is no such key or the value is of a different type.
-     */
-    public double getPropertyDouble(@NonNull String key) {
-        Preconditions.checkNotNull(key);
-        double[] propertyArray = getPropertyDoubleArray(key);
-        if (propertyArray == null || propertyArray.length == 0) {
-            return 0.0;
-        }
-        warnIfSinglePropertyTooLong("Double", key, propertyArray.length);
-        return propertyArray[0];
-    }
-
-    /**
-     * Retrieves a {@code boolean} value by key.
-     *
-     * @param key The key to look for.
-     * @return The first {@code boolean} associated with the given key or default value {@code
-     *     false} if there is no such key or the value is of a different type.
-     */
-    public boolean getPropertyBoolean(@NonNull String key) {
-        Preconditions.checkNotNull(key);
-        boolean[] propertyArray = getPropertyBooleanArray(key);
-        if (propertyArray == null || propertyArray.length == 0) {
-            return false;
-        }
-        warnIfSinglePropertyTooLong("Boolean", key, propertyArray.length);
-        return propertyArray[0];
-    }
-
-    /**
-     * Retrieves a {@code byte[]} value by key.
-     *
-     * @param key The key to look for.
-     * @return The first {@code byte[]} associated with the given key or {@code null} if there is no
-     *     such key or the value is of a different type.
-     */
-    @Nullable
-    public byte[] getPropertyBytes(@NonNull String key) {
-        Preconditions.checkNotNull(key);
-        byte[][] propertyArray = getPropertyBytesArray(key);
-        if (propertyArray == null || propertyArray.length == 0) {
-            return null;
-        }
-        warnIfSinglePropertyTooLong("ByteArray", key, propertyArray.length);
-        return propertyArray[0];
-    }
-
-    /**
-     * Retrieves a {@link GenericDocument} value by key.
-     *
-     * @param key The key to look for.
-     * @return The first {@link GenericDocument} associated with the given key or {@code null} if
-     *     there is no such key or the value is of a different type.
-     */
-    @Nullable
-    public GenericDocument getPropertyDocument(@NonNull String key) {
-        Preconditions.checkNotNull(key);
-        GenericDocument[] propertyArray = getPropertyDocumentArray(key);
-        if (propertyArray == null || propertyArray.length == 0) {
-            return null;
-        }
-        warnIfSinglePropertyTooLong("Document", key, propertyArray.length);
-        return propertyArray[0];
-    }
-
-    /** Prints a warning to logcat if the given propertyLength is greater than 1. */
-    private static void warnIfSinglePropertyTooLong(
-            @NonNull String propertyType, @NonNull String key, int propertyLength) {
-        if (propertyLength > 1) {
-            Log.w(
-                    TAG,
-                    "The value for \""
-                            + key
-                            + "\" contains "
-                            + propertyLength
-                            + " elements. Only the first one will be returned from "
-                            + "getProperty"
-                            + propertyType
-                            + "(). Try getProperty"
-                            + propertyType
-                            + "Array().");
-        }
-    }
-
-    /**
-     * Retrieves a repeated {@code String} property by key.
-     *
-     * @param key The key to look for.
-     * @return The {@code String[]} associated with the given key, or {@code null} if no value is
-     *     set or the value is of a different type.
-     */
-    @Nullable
-    public String[] getPropertyStringArray(@NonNull String key) {
-        Preconditions.checkNotNull(key);
-        return getAndCastPropertyArray(key, String[].class);
-    }
-
-    /**
-     * Retrieves a repeated {@link String} property by key.
-     *
-     * @param key The key to look for.
-     * @return The {@code long[]} associated with the given key, or {@code null} if no value is set
-     *     or the value is of a different type.
-     */
-    @Nullable
-    public long[] getPropertyLongArray(@NonNull String key) {
-        Preconditions.checkNotNull(key);
-        return getAndCastPropertyArray(key, long[].class);
-    }
-
-    /**
-     * Retrieves a repeated {@code double} property by key.
-     *
-     * @param key The key to look for.
-     * @return The {@code double[]} associated with the given key, or {@code null} if no value is
-     *     set or the value is of a different type.
-     */
-    @Nullable
-    public double[] getPropertyDoubleArray(@NonNull String key) {
-        Preconditions.checkNotNull(key);
-        return getAndCastPropertyArray(key, double[].class);
-    }
-
-    /**
-     * Retrieves a repeated {@code boolean} property by key.
-     *
-     * @param key The key to look for.
-     * @return The {@code boolean[]} associated with the given key, or {@code null} if no value is
-     *     set or the value is of a different type.
-     */
-    @Nullable
-    public boolean[] getPropertyBooleanArray(@NonNull String key) {
-        Preconditions.checkNotNull(key);
-        return getAndCastPropertyArray(key, boolean[].class);
-    }
-
-    /**
-     * Retrieves a {@code byte[][]} property by key.
-     *
-     * @param key The key to look for.
-     * @return The {@code byte[][]} associated with the given key, or {@code null} if no value is
-     *     set or the value is of a different type.
-     */
-    @SuppressLint("ArrayReturn")
-    @Nullable
-    @SuppressWarnings("unchecked")
-    public byte[][] getPropertyBytesArray(@NonNull String key) {
-        Preconditions.checkNotNull(key);
-        ArrayList<Bundle> bundles = getAndCastPropertyArray(key, ArrayList.class);
-        if (bundles == null || bundles.size() == 0) {
-            return null;
-        }
-        byte[][] bytes = new byte[bundles.size()][];
-        for (int i = 0; i < bundles.size(); i++) {
-            Bundle bundle = bundles.get(i);
-            if (bundle == null) {
-                Log.e(TAG, "The inner bundle is null at " + i + ", for key: " + key);
-                continue;
-            }
-            byte[] innerBytes = bundle.getByteArray(BYTE_ARRAY_FIELD);
-            if (innerBytes == null) {
-                Log.e(TAG, "The bundle at " + i + " contains a null byte[].");
-                continue;
-            }
-            bytes[i] = innerBytes;
-        }
-        return bytes;
-    }
-
-    /**
-     * Retrieves a repeated {@link GenericDocument} property by key.
-     *
-     * @param key The key to look for.
-     * @return The {@link GenericDocument}[] associated with the given key, or {@code null} if no
-     *     value is set or the value is of a different type.
-     */
-    @SuppressLint("ArrayReturn")
-    @Nullable
-    public GenericDocument[] getPropertyDocumentArray(@NonNull String key) {
-        Preconditions.checkNotNull(key);
-        Bundle[] bundles = getAndCastPropertyArray(key, Bundle[].class);
-        if (bundles == null || bundles.length == 0) {
-            return null;
-        }
-        GenericDocument[] documents = new GenericDocument[bundles.length];
-        for (int i = 0; i < bundles.length; i++) {
-            if (bundles[i] == null) {
-                Log.e(TAG, "The inner bundle is null at " + i + ", for key: " + key);
-                continue;
-            }
-            documents[i] = new GenericDocument(bundles[i]);
-        }
-        return documents;
-    }
-
-    /**
-     * Gets a repeated property of the given key, and casts it to the given class type, which must
-     * be an array class type.
-     */
-    @Nullable
-    private <T> T getAndCastPropertyArray(@NonNull String key, @NonNull Class<T> tClass) {
-        Object value = mProperties.get(key);
-        if (value == null) {
-            return null;
-        }
-        try {
-            return tClass.cast(value);
-        } catch (ClassCastException e) {
-            Log.w(TAG, "Error casting to requested type for key \"" + key + "\"", e);
-            return null;
-        }
-    }
-
-    @Override
-    public boolean equals(@Nullable Object other) {
-        if (this == other) {
-            return true;
-        }
-        if (!(other instanceof GenericDocument)) {
-            return false;
-        }
-        GenericDocument otherDocument = (GenericDocument) other;
-        return bundleEquals(this.mBundle, otherDocument.mBundle);
-    }
-
-    /**
-     * Deeply checks whether two bundles are equal.
-     *
-     * <p>Two bundles will be considered equal if they contain the same content.
-     */
-    @SuppressWarnings("unchecked")
-    private static boolean bundleEquals(Bundle one, Bundle two) {
-        if (one.size() != two.size()) {
-            return false;
-        }
-        Set<String> keySetOne = one.keySet();
-        Object valueOne;
-        Object valueTwo;
-        // Bundle inherit its equals() from Object.java, which only compare their memory address.
-        // We should iterate all keys and check their presents and values in both bundle.
-        for (String key : keySetOne) {
-            valueOne = one.get(key);
-            valueTwo = two.get(key);
-            if (valueOne instanceof Bundle
-                    && valueTwo instanceof Bundle
-                    && !bundleEquals((Bundle) valueOne, (Bundle) valueTwo)) {
-                return false;
-            } else if (valueOne == null && (valueTwo != null || !two.containsKey(key))) {
-                // If we call bundle.get(key) when the 'key' doesn't actually exist in the
-                // bundle, we'll get back a null. So make sure that both values are null and
-                // both keys exist in the bundle.
-                return false;
-            } else if (valueOne instanceof boolean[]) {
-                if (!(valueTwo instanceof boolean[])
-                        || !Arrays.equals((boolean[]) valueOne, (boolean[]) valueTwo)) {
-                    return false;
-                }
-            } else if (valueOne instanceof long[]) {
-                if (!(valueTwo instanceof long[])
-                        || !Arrays.equals((long[]) valueOne, (long[]) valueTwo)) {
-                    return false;
-                }
-            } else if (valueOne instanceof double[]) {
-                if (!(valueTwo instanceof double[])
-                        || !Arrays.equals((double[]) valueOne, (double[]) valueTwo)) {
-                    return false;
-                }
-            } else if (valueOne instanceof Bundle[]) {
-                if (!(valueTwo instanceof Bundle[])) {
-                    return false;
-                }
-                Bundle[] bundlesOne = (Bundle[]) valueOne;
-                Bundle[] bundlesTwo = (Bundle[]) valueTwo;
-                if (bundlesOne.length != bundlesTwo.length) {
-                    return false;
-                }
-                for (int i = 0; i < bundlesOne.length; i++) {
-                    if (!bundleEquals(bundlesOne[i], bundlesTwo[i])) {
-                        return false;
-                    }
-                }
-            } else if (valueOne instanceof ArrayList) {
-                if (!(valueTwo instanceof ArrayList)) {
-                    return false;
-                }
-                ArrayList<Bundle> bundlesOne = (ArrayList<Bundle>) valueOne;
-                ArrayList<Bundle> bundlesTwo = (ArrayList<Bundle>) valueTwo;
-                if (bundlesOne.size() != bundlesTwo.size()) {
-                    return false;
-                }
-                for (int i = 0; i < bundlesOne.size(); i++) {
-                    if (!bundleEquals(bundlesOne.get(i), bundlesTwo.get(i))) {
-                        return false;
-                    }
-                }
-            } else if (valueOne instanceof Object[]) {
-                if (!(valueTwo instanceof Object[])
-                        || !Arrays.equals((Object[]) valueOne, (Object[]) valueTwo)) {
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        if (mHashCode == null) {
-            mHashCode = bundleHashCode(mBundle);
-        }
-        return mHashCode;
-    }
-
-    /**
-     * Calculates the hash code for a bundle.
-     *
-     * <p>The hash code is only effected by the contents in the bundle. Bundles will get consistent
-     * hash code if they have same contents.
-     */
-    @SuppressWarnings("unchecked")
-    private static int bundleHashCode(Bundle bundle) {
-        int[] hashCodes = new int[bundle.size()];
-        int i = 0;
-        // Bundle inherit its hashCode() from Object.java, which only relative to their memory
-        // address. Bundle doesn't have an order, so we should iterate all keys and combine
-        // their value's hashcode into an array. And use the hashcode of the array to be
-        // the hashcode of the bundle.
-        for (String key : bundle.keySet()) {
-            Object value = bundle.get(key);
-            if (value instanceof boolean[]) {
-                hashCodes[i++] = Arrays.hashCode((boolean[]) value);
-            } else if (value instanceof long[]) {
-                hashCodes[i++] = Arrays.hashCode((long[]) value);
-            } else if (value instanceof double[]) {
-                hashCodes[i++] = Arrays.hashCode((double[]) value);
-            } else if (value instanceof String[]) {
-                hashCodes[i++] = Arrays.hashCode((Object[]) value);
-            } else if (value instanceof Bundle) {
-                hashCodes[i++] = bundleHashCode((Bundle) value);
-            } else if (value instanceof Bundle[]) {
-                Bundle[] bundles = (Bundle[]) value;
-                int[] innerHashCodes = new int[bundles.length];
-                for (int j = 0; j < innerHashCodes.length; j++) {
-                    innerHashCodes[j] = bundleHashCode(bundles[j]);
-                }
-                hashCodes[i++] = Arrays.hashCode(innerHashCodes);
-            } else if (value instanceof ArrayList) {
-                ArrayList<Bundle> bundles = (ArrayList<Bundle>) value;
-                int[] innerHashCodes = new int[bundles.size()];
-                for (int j = 0; j < innerHashCodes.length; j++) {
-                    innerHashCodes[j] = bundleHashCode(bundles.get(j));
-                }
-                hashCodes[i++] = Arrays.hashCode(innerHashCodes);
-            } else {
-                hashCodes[i++] = value.hashCode();
-            }
-        }
-        return Arrays.hashCode(hashCodes);
-    }
-
-    @Override
-    @NonNull
-    public String toString() {
-        return bundleToString(mBundle).toString();
-    }
-
-    @SuppressWarnings("unchecked")
-    private static StringBuilder bundleToString(Bundle bundle) {
-        StringBuilder stringBuilder = new StringBuilder();
-        try {
-            final Set<String> keySet = bundle.keySet();
-            String[] keys = keySet.toArray(new String[0]);
-            // Sort keys to make output deterministic. We need a custom comparator to handle
-            // nulls (arbitrarily putting them first, similar to Comparator.nullsFirst, which is
-            // only available since N).
-            Arrays.sort(
-                    keys,
-                    (@Nullable String s1, @Nullable String s2) -> {
-                        if (s1 == null) {
-                            return s2 == null ? 0 : -1;
-                        } else if (s2 == null) {
-                            return 1;
-                        } else {
-                            return s1.compareTo(s2);
-                        }
-                    });
-            for (String key : keys) {
-                stringBuilder.append("{ key: '").append(key).append("' value: ");
-                Object valueObject = bundle.get(key);
-                if (valueObject == null) {
-                    stringBuilder.append("<null>");
-                } else if (valueObject instanceof Bundle) {
-                    stringBuilder.append(bundleToString((Bundle) valueObject));
-                } else if (valueObject.getClass().isArray()) {
-                    stringBuilder.append("[ ");
-                    for (int i = 0; i < Array.getLength(valueObject); i++) {
-                        Object element = Array.get(valueObject, i);
-                        stringBuilder.append("'");
-                        if (element instanceof Bundle) {
-                            stringBuilder.append(bundleToString((Bundle) element));
-                        } else {
-                            stringBuilder.append(Array.get(valueObject, i));
-                        }
-                        stringBuilder.append("' ");
-                    }
-                    stringBuilder.append("]");
-                } else if (valueObject instanceof ArrayList) {
-                    for (Bundle innerBundle : (ArrayList<Bundle>) valueObject) {
-                        stringBuilder.append(bundleToString(innerBundle));
-                    }
-                } else {
-                    stringBuilder.append(valueObject.toString());
-                }
-                stringBuilder.append(" } ");
-            }
-        } catch (RuntimeException e) {
-            // Catch any exceptions here since corrupt Bundles can throw different types of
-            // exceptions (e.g. b/38445840 & b/68937025).
-            stringBuilder.append("<error>");
-        }
-        return stringBuilder;
-    }
-
-    /**
-     * The builder class for {@link GenericDocument}.
-     *
-     * @param <BuilderType> Type of subclass who extends this.
-     */
-    // This builder is specifically designed to be extended by classes deriving from
-    // GenericDocument.
-    @SuppressLint("StaticFinalBuilder")
-    public static class Builder<BuilderType extends Builder> {
-
-        private final Bundle mProperties = new Bundle();
-        private final Bundle mBundle = new Bundle();
-        private final BuilderType mBuilderTypeInstance;
-        private boolean mBuilt = false;
-
-        /**
-         * Create a new {@link GenericDocument.Builder}.
-         *
-         * @param uri The uri of {@link GenericDocument}.
-         * @param schemaType The schema type of the {@link GenericDocument}. The passed-in {@code
-         *     schemaType} must be defined using {@link AppSearchManager#setSchema} prior to
-         *     inserting a document of this {@code schemaType} into the AppSearch index using {@link
-         *     AppSearchManager#putDocuments}. Otherwise, the document will be rejected by {@link
-         *     AppSearchManager#putDocuments}.
-         */
-        @SuppressWarnings("unchecked")
-        public Builder(@NonNull String uri, @NonNull String schemaType) {
-            Preconditions.checkNotNull(uri);
-            Preconditions.checkNotNull(schemaType);
-            mBuilderTypeInstance = (BuilderType) this;
-            mBundle.putString(GenericDocument.URI_FIELD, uri);
-            mBundle.putString(GenericDocument.SCHEMA_TYPE_FIELD, schemaType);
-            mBundle.putString(GenericDocument.NAMESPACE_FIELD, DEFAULT_NAMESPACE);
-            // Set current timestamp for creation timestamp by default.
-            mBundle.putLong(
-                    GenericDocument.CREATION_TIMESTAMP_MILLIS_FIELD, System.currentTimeMillis());
-            mBundle.putLong(GenericDocument.TTL_MILLIS_FIELD, DEFAULT_TTL_MILLIS);
-            mBundle.putInt(GenericDocument.SCORE_FIELD, DEFAULT_SCORE);
-            mBundle.putBundle(PROPERTIES_FIELD, mProperties);
-        }
-
-        /**
-         * Sets the app-defined namespace this Document resides in. No special values are reserved
-         * or understood by the infrastructure.
-         *
-         * <p>URIs are unique within a namespace.
-         *
-         * <p>The number of namespaces per app should be kept small for efficiency reasons.
-         */
-        @NonNull
-        public BuilderType setNamespace(@NonNull String namespace) {
-            mBundle.putString(GenericDocument.NAMESPACE_FIELD, namespace);
-            return mBuilderTypeInstance;
-        }
-
-        /**
-         * Sets the score of the {@link GenericDocument}.
-         *
-         * <p>The score is a query-independent measure of the document's quality, relative to other
-         * {@link GenericDocument}s of the same type.
-         *
-         * <p>Results may be sorted by score using {@link SearchSpec.Builder#setRankingStrategy}.
-         * Documents with higher scores are considered better than documents with lower scores.
-         *
-         * <p>Any nonnegative integer can be used a score.
-         *
-         * @throws IllegalArgumentException If the provided value is negative.
-         */
-        @NonNull
-        public BuilderType setScore(@IntRange(from = 0, to = Integer.MAX_VALUE) int score) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            if (score < 0) {
-                throw new IllegalArgumentException("Document score cannot be negative.");
-            }
-            mBundle.putInt(GenericDocument.SCORE_FIELD, score);
-            return mBuilderTypeInstance;
-        }
-
-        /**
-         * Sets the creation timestamp of the {@link GenericDocument}, in milliseconds.
-         *
-         * <p>Should be set using a value obtained from the {@link System#currentTimeMillis} time
-         * base.
-         */
-        @NonNull
-        public BuilderType setCreationTimestampMillis(long creationTimestampMillis) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mBundle.putLong(
-                    GenericDocument.CREATION_TIMESTAMP_MILLIS_FIELD, creationTimestampMillis);
-            return mBuilderTypeInstance;
-        }
-
-        /**
-         * Sets the TTL (Time To Live) of the {@link GenericDocument}, in milliseconds.
-         *
-         * <p>The TTL is measured against {@link #getCreationTimestampMillis}. At the timestamp of
-         * {@code creationTimestampMillis + ttlMillis}, measured in the {@link
-         * System#currentTimeMillis} time base, the document will be auto-deleted.
-         *
-         * <p>The default value is 0, which means the document is permanent and won't be
-         * auto-deleted until the app is uninstalled.
-         *
-         * @param ttlMillis A non-negative duration in milliseconds.
-         * @throws IllegalArgumentException If the provided value is negative.
-         */
-        @NonNull
-        public BuilderType setTtlMillis(long ttlMillis) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            if (ttlMillis < 0) {
-                throw new IllegalArgumentException("Document ttlMillis cannot be negative.");
-            }
-            mBundle.putLong(GenericDocument.TTL_MILLIS_FIELD, ttlMillis);
-            return mBuilderTypeInstance;
-        }
-
-        /**
-         * Sets one or multiple {@code String} values for a property, replacing its previous values.
-         *
-         * @param key The key associated with the {@code values}.
-         * @param values The {@code String} values of the property.
-         */
-        @NonNull
-        public BuilderType setPropertyString(@NonNull String key, @NonNull String... values) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            Preconditions.checkNotNull(key);
-            Preconditions.checkNotNull(values);
-            putInPropertyBundle(key, values);
-            return mBuilderTypeInstance;
-        }
-
-        /**
-         * Sets one or multiple {@code boolean} values for a property, replacing its previous
-         * values.
-         *
-         * @param key The key associated with the {@code values}.
-         * @param values The {@code boolean} values of the property.
-         */
-        @NonNull
-        public BuilderType setPropertyBoolean(@NonNull String key, @NonNull boolean... values) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            Preconditions.checkNotNull(key);
-            Preconditions.checkNotNull(values);
-            putInPropertyBundle(key, values);
-            return mBuilderTypeInstance;
-        }
-
-        /**
-         * Sets one or multiple {@code long} values for a property, replacing its previous values.
-         *
-         * @param key The key associated with the {@code values}.
-         * @param values The {@code long} values of the property.
-         */
-        @NonNull
-        public BuilderType setPropertyLong(@NonNull String key, @NonNull long... values) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            Preconditions.checkNotNull(key);
-            Preconditions.checkNotNull(values);
-            putInPropertyBundle(key, values);
-            return mBuilderTypeInstance;
-        }
-
-        /**
-         * Sets one or multiple {@code double} values for a property, replacing its previous values.
-         *
-         * @param key The key associated with the {@code values}.
-         * @param values The {@code double} values of the property.
-         */
-        @NonNull
-        public BuilderType setPropertyDouble(@NonNull String key, @NonNull double... values) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            Preconditions.checkNotNull(key);
-            Preconditions.checkNotNull(values);
-            putInPropertyBundle(key, values);
-            return mBuilderTypeInstance;
-        }
-
-        /**
-         * Sets one or multiple {@code byte[]} for a property, replacing its previous values.
-         *
-         * @param key The key associated with the {@code values}.
-         * @param values The {@code byte[]} of the property.
-         */
-        @NonNull
-        public BuilderType setPropertyBytes(@NonNull String key, @NonNull byte[]... values) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            Preconditions.checkNotNull(key);
-            Preconditions.checkNotNull(values);
-            putInPropertyBundle(key, values);
-            return mBuilderTypeInstance;
-        }
-
-        /**
-         * Sets one or multiple {@link GenericDocument} values for a property, replacing its
-         * previous values.
-         *
-         * @param key The key associated with the {@code values}.
-         * @param values The {@link GenericDocument} values of the property.
-         */
-        @NonNull
-        public BuilderType setPropertyDocument(
-                @NonNull String key, @NonNull GenericDocument... values) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            Preconditions.checkNotNull(key);
-            Preconditions.checkNotNull(values);
-            putInPropertyBundle(key, values);
-            return mBuilderTypeInstance;
-        }
-
-        private void putInPropertyBundle(@NonNull String key, @NonNull String[] values)
-                throws IllegalArgumentException {
-            validateRepeatedPropertyLength(key, values.length);
-            for (int i = 0; i < values.length; i++) {
-                if (values[i] == null) {
-                    throw new IllegalArgumentException("The String at " + i + " is null.");
-                } else if (values[i].length() > MAX_STRING_LENGTH) {
-                    throw new IllegalArgumentException(
-                            "The String at "
-                                    + i
-                                    + " length is: "
-                                    + values[i].length()
-                                    + ", which exceeds length limit: "
-                                    + MAX_STRING_LENGTH
-                                    + ".");
-                }
-            }
-            mProperties.putStringArray(key, values);
-        }
-
-        private void putInPropertyBundle(@NonNull String key, @NonNull boolean[] values) {
-            validateRepeatedPropertyLength(key, values.length);
-            mProperties.putBooleanArray(key, values);
-        }
-
-        private void putInPropertyBundle(@NonNull String key, @NonNull double[] values) {
-            validateRepeatedPropertyLength(key, values.length);
-            mProperties.putDoubleArray(key, values);
-        }
-
-        private void putInPropertyBundle(@NonNull String key, @NonNull long[] values) {
-            validateRepeatedPropertyLength(key, values.length);
-            mProperties.putLongArray(key, values);
-        }
-
-        /**
-         * Converts and saves a byte[][] into {@link #mProperties}.
-         *
-         * <p>Bundle doesn't support for two dimension array byte[][], we are converting byte[][]
-         * into ArrayList<Bundle>, and each elements will contain a one dimension byte[].
-         */
-        private void putInPropertyBundle(@NonNull String key, @NonNull byte[][] values) {
-            validateRepeatedPropertyLength(key, values.length);
-            ArrayList<Bundle> bundles = new ArrayList<>(values.length);
-            for (int i = 0; i < values.length; i++) {
-                if (values[i] == null) {
-                    throw new IllegalArgumentException("The byte[] at " + i + " is null.");
-                }
-                Bundle bundle = new Bundle();
-                bundle.putByteArray(BYTE_ARRAY_FIELD, values[i]);
-                bundles.add(bundle);
-            }
-            mProperties.putParcelableArrayList(key, bundles);
-        }
-
-        private void putInPropertyBundle(@NonNull String key, @NonNull GenericDocument[] values) {
-            validateRepeatedPropertyLength(key, values.length);
-            Bundle[] documentBundles = new Bundle[values.length];
-            for (int i = 0; i < values.length; i++) {
-                if (values[i] == null) {
-                    throw new IllegalArgumentException("The document at " + i + " is null.");
-                }
-                documentBundles[i] = values[i].mBundle;
-            }
-            mProperties.putParcelableArray(key, documentBundles);
-        }
-
-        private static void validateRepeatedPropertyLength(@NonNull String key, int length) {
-            if (length == 0) {
-                throw new IllegalArgumentException("The input array is empty.");
-            } else if (length > MAX_REPEATED_PROPERTY_LENGTH) {
-                throw new IllegalArgumentException(
-                        "Repeated property \""
-                                + key
-                                + "\" has length "
-                                + length
-                                + ", which exceeds the limit of "
-                                + MAX_REPEATED_PROPERTY_LENGTH);
-            }
-        }
-
-        /** Builds the {@link GenericDocument} object. */
-        @NonNull
-        public GenericDocument build() {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mBuilt = true;
-            return new GenericDocument(mBundle);
-        }
-    }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/GetByUriRequest.java b/apex/appsearch/framework/java/android/app/appsearch/GetByUriRequest.java
deleted file mode 100644
index 053d401..0000000
--- a/apex/appsearch/framework/java/android/app/appsearch/GetByUriRequest.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * 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.appsearch;
-
-import android.annotation.NonNull;
-import android.util.ArraySet;
-
-import com.android.internal.util.Preconditions;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Set;
-
-/**
- * Encapsulates a request to retrieve documents by namespace and URI.
- *
- * @see AppSearchSession#getByUri
- * @hide
- */
-public final class GetByUriRequest {
-    private final String mNamespace;
-    private final Set<String> mUris;
-
-    GetByUriRequest(@NonNull String namespace, @NonNull Set<String> uris) {
-        mNamespace = namespace;
-        mUris = uris;
-    }
-
-    /** Returns the namespace to get documents from. */
-    @NonNull
-    public String getNamespace() {
-        return mNamespace;
-    }
-
-    /** Returns the URIs to get from the namespace. */
-    @NonNull
-    public Set<String> getUris() {
-        return Collections.unmodifiableSet(mUris);
-    }
-
-    /** Builder for {@link GetByUriRequest} objects. */
-    public static final class Builder {
-        private String mNamespace = GenericDocument.DEFAULT_NAMESPACE;
-        private final Set<String> mUris = new ArraySet<>();
-        private boolean mBuilt = false;
-
-        /**
-         * Sets which namespace these documents will be retrieved from.
-         *
-         * <p>If this is not set, it defaults to {@link GenericDocument#DEFAULT_NAMESPACE}.
-         */
-        @NonNull
-        public Builder setNamespace(@NonNull String namespace) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            Preconditions.checkNotNull(namespace);
-            mNamespace = namespace;
-            return this;
-        }
-
-        /** Adds one or more URIs to the request. */
-        @NonNull
-        public Builder addUri(@NonNull String... uris) {
-            Preconditions.checkNotNull(uris);
-            return addUri(Arrays.asList(uris));
-        }
-
-        /** Adds one or more URIs to the request. */
-        @NonNull
-        public Builder addUri(@NonNull Collection<String> uris) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            Preconditions.checkNotNull(uris);
-            mUris.addAll(uris);
-            return this;
-        }
-
-        /** Builds a new {@link GetByUriRequest}. */
-        @NonNull
-        public GetByUriRequest build() {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mBuilt = true;
-            return new GetByUriRequest(mNamespace, mUris);
-        }
-    }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
index 22e00f2..1d7cb87 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
+++ b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
@@ -32,6 +32,8 @@
      *
      * @param databaseName  The databaseName this document resides in.
      * @param schemaBundles List of AppSearchSchema bundles.
+     * @param schemasNotPlatformSurfaceable Schema types that should not be surfaced on platform
+     *     surfaces.
      * @param forceOverride Whether to apply the new schema even if it is incompatible. All
      *     incompatible documents will be deleted.
      * @param callback {@link IAppSearchResultCallback#onResult} will be called with an
@@ -40,6 +42,7 @@
     void setSchema(
         in String databaseName,
         in List<Bundle> schemaBundles,
+        in List<String> schemasNotPlatformSurfaceable,
         boolean forceOverride,
         in IAppSearchResultCallback callback);
 
diff --git a/apex/appsearch/framework/java/android/app/appsearch/PutDocumentsRequest.java b/apex/appsearch/framework/java/android/app/appsearch/PutDocumentsRequest.java
deleted file mode 100644
index 42f1ff2..0000000
--- a/apex/appsearch/framework/java/android/app/appsearch/PutDocumentsRequest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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.appsearch;
-
-import android.annotation.NonNull;
-import android.annotation.SuppressLint;
-import android.app.appsearch.exceptions.AppSearchException;
-
-import com.android.internal.util.Preconditions;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Encapsulates a request to index a document into an {@link AppSearchSession} database.
- *
- * @see AppSearchSession#putDocuments
- * @hide
- */
-public final class PutDocumentsRequest {
-    private final List<GenericDocument> mDocuments;
-
-    PutDocumentsRequest(List<GenericDocument> documents) {
-        mDocuments = documents;
-    }
-
-    /** Returns the documents that are part of this request. */
-    @NonNull
-    public List<GenericDocument> getDocuments() {
-        return Collections.unmodifiableList(mDocuments);
-    }
-
-    /** Builder for {@link PutDocumentsRequest} objects. */
-    public static final class Builder {
-        private final List<GenericDocument> mDocuments = new ArrayList<>();
-        private boolean mBuilt = false;
-
-        /** Adds one or more documents to the request. */
-        @SuppressLint("MissingGetterMatchingBuilder") // Merged list available from getDocuments()
-        @NonNull
-        public Builder addGenericDocument(@NonNull GenericDocument... documents) {
-            Preconditions.checkNotNull(documents);
-            return addGenericDocument(Arrays.asList(documents));
-        }
-
-        /** Adds one or more documents to the request. */
-        @SuppressLint("MissingGetterMatchingBuilder") // Merged list available from getDocuments()
-        @NonNull
-        public Builder addGenericDocument(@NonNull Collection<GenericDocument> documents) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            Preconditions.checkNotNull(documents);
-            mDocuments.addAll(documents);
-            return this;
-        }
-
-        /** Builds a new {@link PutDocumentsRequest}. */
-        @NonNull
-        public PutDocumentsRequest build() {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mBuilt = true;
-            return new PutDocumentsRequest(mDocuments);
-        }
-    }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/RemoveByUriRequest.java b/apex/appsearch/framework/java/android/app/appsearch/RemoveByUriRequest.java
deleted file mode 100644
index 3d83c39..0000000
--- a/apex/appsearch/framework/java/android/app/appsearch/RemoveByUriRequest.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * 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.appsearch;
-
-import android.annotation.NonNull;
-import android.util.ArraySet;
-
-import com.android.internal.util.Preconditions;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Set;
-
-/**
- * Encapsulates a request to remove documents by namespace and URI.
- *
- * @see AppSearchSession#removeByUri
- * @hide
- */
-public final class RemoveByUriRequest {
-    private final String mNamespace;
-    private final Set<String> mUris;
-
-    RemoveByUriRequest(String namespace, Set<String> uris) {
-        mNamespace = namespace;
-        mUris = uris;
-    }
-
-    /** Returns the namespace to remove documents from. */
-    @NonNull
-    public String getNamespace() {
-        return mNamespace;
-    }
-
-    /** Returns the URIs to remove from the namespace. */
-    @NonNull
-    public Set<String> getUris() {
-        return Collections.unmodifiableSet(mUris);
-    }
-
-    /** Builder for {@link RemoveByUriRequest} objects. */
-    public static final class Builder {
-        private String mNamespace = GenericDocument.DEFAULT_NAMESPACE;
-        private final Set<String> mUris = new ArraySet<>();
-        private boolean mBuilt = false;
-
-        /**
-         * Sets which namespace these documents will be removed from.
-         *
-         * <p>If this is not set, it defaults to {@link GenericDocument#DEFAULT_NAMESPACE}.
-         */
-        @NonNull
-        public Builder setNamespace(@NonNull String namespace) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            Preconditions.checkNotNull(namespace);
-            mNamespace = namespace;
-            return this;
-        }
-
-        /** Adds one or more URIs to the request. */
-        @NonNull
-        public Builder addUri(@NonNull String... uris) {
-            Preconditions.checkNotNull(uris);
-            return addUri(Arrays.asList(uris));
-        }
-
-        /** Adds one or more URIs to the request. */
-        @NonNull
-        public Builder addUri(@NonNull Collection<String> uris) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            Preconditions.checkNotNull(uris);
-            mUris.addAll(uris);
-            return this;
-        }
-
-        /** Builds a new {@link RemoveByUriRequest}. */
-        @NonNull
-        public RemoveByUriRequest build() {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mBuilt = true;
-            return new RemoveByUriRequest(mNamespace, mUris);
-        }
-    }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/SetSchemaRequest.java b/apex/appsearch/framework/java/android/app/appsearch/SetSchemaRequest.java
deleted file mode 100644
index 3e472fd..0000000
--- a/apex/appsearch/framework/java/android/app/appsearch/SetSchemaRequest.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * 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.appsearch;
-
-import android.annotation.NonNull;
-import android.annotation.SuppressLint;
-import android.app.appsearch.exceptions.AppSearchException;
-import android.util.ArraySet;
-
-import com.android.internal.util.Preconditions;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Encapsulates a request to update the schema of an {@link AppSearchSession} database.
- *
- * @see AppSearchSession#setSchema
- * @hide
- */
-public final class SetSchemaRequest {
-    private final Set<AppSearchSchema> mSchemas;
-    private final boolean mForceOverride;
-
-    SetSchemaRequest(Set<AppSearchSchema> schemas, boolean forceOverride) {
-        mSchemas = schemas;
-        mForceOverride = forceOverride;
-    }
-
-    /** Returns the schemas that are part of this request. */
-    @NonNull
-    public Set<AppSearchSchema> getSchemas() {
-        return mSchemas;
-    }
-
-    /** Returns whether this request will force the schema to be overridden. */
-    public boolean isForceOverride() {
-        return mForceOverride;
-    }
-
-    /** Builder for {@link SetSchemaRequest} objects. */
-    public static final class Builder {
-        private final Set<AppSearchSchema> mSchemas = new ArraySet<>();
-        private boolean mForceOverride = false;
-        private boolean mBuilt = false;
-
-        /** Adds one or more types to the schema. */
-        @NonNull
-        public Builder addSchema(@NonNull AppSearchSchema... schemas) {
-            Preconditions.checkNotNull(schemas);
-            return addSchema(Arrays.asList(schemas));
-        }
-
-        /** Adds one or more types to the schema. */
-        @NonNull
-        public Builder addSchema(@NonNull Collection<AppSearchSchema> schemas) {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            Preconditions.checkNotNull(schemas);
-            mSchemas.addAll(schemas);
-            return this;
-        }
-
-        /**
-         * Configures the {@link SetSchemaRequest} to delete any existing documents that don't
-         * follow the new schema.
-         *
-         * <p>By default, this is {@code false} and schema incompatibility causes the {@link
-         * AppSearchSession#setSchema} call to fail.
-         *
-         * @see AppSearchSession#setSchema
-         */
-        @NonNull
-        public Builder setForceOverride(boolean forceOverride) {
-            mForceOverride = forceOverride;
-            return this;
-        }
-
-        /** Builds a new {@link SetSchemaRequest}. */
-        @NonNull
-        public SetSchemaRequest build() {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mBuilt = true;
-            return new SetSchemaRequest(mSchemas, mForceOverride);
-        }
-    }
-}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchEmail.java b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchEmail.java
similarity index 100%
rename from apex/appsearch/framework/java/android/app/appsearch/AppSearchEmail.java
rename to apex/appsearch/framework/java/external/android/app/appsearch/AppSearchEmail.java
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
new file mode 100644
index 0000000..62cf38b
--- /dev/null
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
@@ -0,0 +1,491 @@
+/*
+ * 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.appsearch;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.app.appsearch.exceptions.IllegalSchemaException;
+import android.app.appsearch.util.BundleUtil;
+import android.os.Bundle;
+import android.util.ArraySet;
+
+import com.android.internal.util.Preconditions;
+
+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.Objects;
+import java.util.Set;
+
+/**
+ * The AppSearch Schema for a particular type of document.
+ *
+ * <p>For example, an e-mail message or a music recording could be a schema type.
+ *
+ * <p>The schema consists of type information, properties, and config (like tokenization type).
+ *
+ * @see AppSearchSession#setSchema
+ */
+public final class AppSearchSchema {
+    private static final String SCHEMA_TYPE_FIELD = "schemaType";
+    private static final String PROPERTIES_FIELD = "properties";
+
+    private final Bundle mBundle;
+
+    /** @hide */
+    public AppSearchSchema(@NonNull Bundle bundle) {
+        Preconditions.checkNotNull(bundle);
+        mBundle = bundle;
+    }
+
+    /**
+     * Returns the {@link Bundle} populated by this builder.
+     *
+     * @hide
+     */
+    @NonNull
+    public Bundle getBundle() {
+        return mBundle;
+    }
+
+    @Override
+    public String toString() {
+        return mBundle.toString();
+    }
+
+    /** Returns the name of this schema type, e.g. Email. */
+    @NonNull
+    public String getSchemaType() {
+        return mBundle.getString(SCHEMA_TYPE_FIELD, "");
+    }
+
+    /**
+     * Returns the list of {@link PropertyConfig}s that are part of this schema.
+     *
+     * <p>This method creates a new list when called.
+     */
+    @NonNull
+    public List<PropertyConfig> getProperties() {
+        ArrayList<Bundle> propertyBundles =
+                mBundle.getParcelableArrayList(AppSearchSchema.PROPERTIES_FIELD);
+        if (propertyBundles.isEmpty()) {
+            return Collections.emptyList();
+        }
+        List<PropertyConfig> ret = new ArrayList<>(propertyBundles.size());
+        for (int i = 0; i < propertyBundles.size(); i++) {
+            ret.add(new PropertyConfig(propertyBundles.get(i)));
+        }
+        return ret;
+    }
+
+    @Override
+    public boolean equals(@Nullable Object other) {
+        if (this == other) {
+            return true;
+        }
+        if (!(other instanceof AppSearchSchema)) {
+            return false;
+        }
+        AppSearchSchema otherSchema = (AppSearchSchema) other;
+        if (!getSchemaType().equals(otherSchema.getSchemaType())) {
+            return false;
+        }
+        return getProperties().equals(otherSchema.getProperties());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(getSchemaType(), getProperties());
+    }
+
+    /** Builder for {@link AppSearchSchema objects}. */
+    public static final class Builder {
+        private final String mSchemaType;
+        private final ArrayList<Bundle> mPropertyBundles = new ArrayList<>();
+        private final Set<String> mPropertyNames = new ArraySet<>();
+        private boolean mBuilt = false;
+
+        /** Creates a new {@link AppSearchSchema.Builder}. */
+        public Builder(@NonNull String schemaType) {
+            Preconditions.checkNotNull(schemaType);
+            mSchemaType = schemaType;
+        }
+
+        /** Adds a property to the given type. */
+        // TODO(b/171360120): MissingGetterMatchingBuilder expects a method called getPropertys, but
+        //  we provide the (correct) method getProperties. Once the bug referenced in this TODO is
+        //  fixed, remove this SuppressLint.
+        @SuppressLint("MissingGetterMatchingBuilder")
+        @NonNull
+        public AppSearchSchema.Builder addProperty(@NonNull PropertyConfig propertyConfig) {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            Preconditions.checkNotNull(propertyConfig);
+            String name = propertyConfig.getName();
+            if (!mPropertyNames.add(name)) {
+                throw new IllegalSchemaException("Property defined more than once: " + name);
+            }
+            mPropertyBundles.add(propertyConfig.mBundle);
+            return this;
+        }
+
+        /**
+         * Constructs a new {@link AppSearchSchema} from the contents of this builder.
+         *
+         * <p>After calling this method, the builder must no longer be used.
+         */
+        @NonNull
+        public AppSearchSchema build() {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            Bundle bundle = new Bundle();
+            bundle.putString(AppSearchSchema.SCHEMA_TYPE_FIELD, mSchemaType);
+            bundle.putParcelableArrayList(AppSearchSchema.PROPERTIES_FIELD, mPropertyBundles);
+            mBuilt = true;
+            return new AppSearchSchema(bundle);
+        }
+    }
+
+    /**
+     * Configuration for a single property (field) of a document type.
+     *
+     * <p>For example, an {@code EmailMessage} would be a type and the {@code subject} would be a
+     * property.
+     */
+    public static final class PropertyConfig {
+        private static final String NAME_FIELD = "name";
+        private static final String DATA_TYPE_FIELD = "dataType";
+        private static final String SCHEMA_TYPE_FIELD = "schemaType";
+        private static final String CARDINALITY_FIELD = "cardinality";
+        private static final String INDEXING_TYPE_FIELD = "indexingType";
+        private static final String TOKENIZER_TYPE_FIELD = "tokenizerType";
+
+        /**
+         * Physical data-types of the contents of the property.
+         *
+         * @hide
+         */
+        // NOTE: The integer values of these constants must match the proto enum constants in
+        // com.google.android.icing.proto.PropertyConfigProto.DataType.Code.
+        @IntDef(
+                value = {
+                    DATA_TYPE_STRING,
+                    DATA_TYPE_INT64,
+                    DATA_TYPE_DOUBLE,
+                    DATA_TYPE_BOOLEAN,
+                    DATA_TYPE_BYTES,
+                    DATA_TYPE_DOCUMENT,
+                })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface DataType {}
+
+        public static final int DATA_TYPE_STRING = 1;
+        public static final int DATA_TYPE_INT64 = 2;
+        public static final int DATA_TYPE_DOUBLE = 3;
+        public static final int DATA_TYPE_BOOLEAN = 4;
+
+        /** Unstructured BLOB. */
+        public static final int DATA_TYPE_BYTES = 5;
+
+        /**
+         * Indicates that the property is itself a {@link GenericDocument}, making it part of a
+         * hierarchical schema. Any property using this DataType MUST have a valid {@link
+         * PropertyConfig#getSchemaType}.
+         */
+        public static final int DATA_TYPE_DOCUMENT = 6;
+
+        /**
+         * The cardinality of the property (whether it is required, optional or repeated).
+         *
+         * @hide
+         */
+        // NOTE: The integer values of these constants must match the proto enum constants in
+        // com.google.android.icing.proto.PropertyConfigProto.Cardinality.Code.
+        @IntDef(
+                value = {
+                    CARDINALITY_REPEATED,
+                    CARDINALITY_OPTIONAL,
+                    CARDINALITY_REQUIRED,
+                })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface Cardinality {}
+
+        /** Any number of items (including zero) [0...*]. */
+        public static final int CARDINALITY_REPEATED = 1;
+
+        /** Zero or one value [0,1]. */
+        public static final int CARDINALITY_OPTIONAL = 2;
+
+        /** Exactly one value [1]. */
+        public static final int CARDINALITY_REQUIRED = 3;
+
+        /**
+         * Encapsulates the configurations on how AppSearch should query/index these terms.
+         *
+         * @hide
+         */
+        @IntDef(
+                value = {
+                    INDEXING_TYPE_NONE,
+                    INDEXING_TYPE_EXACT_TERMS,
+                    INDEXING_TYPE_PREFIXES,
+                })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface IndexingType {}
+
+        /**
+         * Content in this property will not be tokenized or indexed.
+         *
+         * <p>Useful if the data type is not made up of terms (e.g. {@link
+         * PropertyConfig#DATA_TYPE_DOCUMENT} or {@link PropertyConfig#DATA_TYPE_BYTES} type). None
+         * of the properties inside the nested property will be indexed regardless of the value of
+         * {@code indexingType} for the nested properties.
+         */
+        public static final int INDEXING_TYPE_NONE = 0;
+
+        /**
+         * Content in this property should only be returned for queries matching the exact tokens
+         * appearing in this property.
+         *
+         * <p>Ex. A property with "fool" should NOT match a query for "foo".
+         */
+        public static final int INDEXING_TYPE_EXACT_TERMS = 1;
+
+        /**
+         * Content in this property should be returned for queries that are either exact matches or
+         * query matches of the tokens appearing in this property.
+         *
+         * <p>Ex. A property with "fool" <b>should</b> match a query for "foo".
+         */
+        public static final int INDEXING_TYPE_PREFIXES = 2;
+
+        /**
+         * Configures how tokens should be extracted from this property.
+         *
+         * @hide
+         */
+        // NOTE: The integer values of these constants must match the proto enum constants in
+        // com.google.android.icing.proto.IndexingConfig.TokenizerType.Code.
+        @IntDef(
+                value = {
+                    TOKENIZER_TYPE_NONE,
+                    TOKENIZER_TYPE_PLAIN,
+                })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface TokenizerType {}
+
+        /**
+         * It is only valid for tokenizer_type to be 'NONE' if the data type is {@link
+         * PropertyConfig#DATA_TYPE_DOCUMENT}.
+         */
+        public static final int TOKENIZER_TYPE_NONE = 0;
+
+        /** Tokenization for plain text. */
+        public static final int TOKENIZER_TYPE_PLAIN = 1;
+
+        final Bundle mBundle;
+
+        @Nullable private Integer mHashCode;
+
+        PropertyConfig(@NonNull Bundle bundle) {
+            mBundle = Preconditions.checkNotNull(bundle);
+        }
+
+        @Override
+        public String toString() {
+            return mBundle.toString();
+        }
+
+        /** Returns the name of this property. */
+        @NonNull
+        public String getName() {
+            return mBundle.getString(NAME_FIELD, "");
+        }
+
+        /** Returns the type of data the property contains (e.g. string, int, bytes, etc). */
+        public @DataType int getDataType() {
+            return mBundle.getInt(DATA_TYPE_FIELD, -1);
+        }
+
+        /**
+         * Returns the logical schema-type of the contents of this property.
+         *
+         * <p>Only set when {@link #getDataType} is set to {@link #DATA_TYPE_DOCUMENT}. Otherwise,
+         * it is {@code null}.
+         */
+        @Nullable
+        public String getSchemaType() {
+            return mBundle.getString(SCHEMA_TYPE_FIELD);
+        }
+
+        /**
+         * Returns the cardinality of the property (whether it is optional, required or repeated).
+         */
+        public @Cardinality int getCardinality() {
+            return mBundle.getInt(CARDINALITY_FIELD, -1);
+        }
+
+        /** Returns how the property is indexed. */
+        public @IndexingType int getIndexingType() {
+            return mBundle.getInt(INDEXING_TYPE_FIELD);
+        }
+
+        /** Returns how this property is tokenized (split into words). */
+        public @TokenizerType int getTokenizerType() {
+            return mBundle.getInt(TOKENIZER_TYPE_FIELD);
+        }
+
+        @Override
+        public boolean equals(@Nullable Object other) {
+            if (this == other) {
+                return true;
+            }
+            if (!(other instanceof PropertyConfig)) {
+                return false;
+            }
+            PropertyConfig otherProperty = (PropertyConfig) other;
+            return BundleUtil.deepEquals(this.mBundle, otherProperty.mBundle);
+        }
+
+        @Override
+        public int hashCode() {
+            if (mHashCode == null) {
+                mHashCode = BundleUtil.deepHashCode(mBundle);
+            }
+            return mHashCode;
+        }
+
+        /**
+         * Builder for {@link PropertyConfig}.
+         *
+         * <p>The following properties must be set, or {@link PropertyConfig} construction will
+         * fail:
+         *
+         * <ul>
+         *   <li>dataType
+         *   <li>cardinality
+         * </ul>
+         *
+         * <p>In addition, if {@code schemaType} is {@link #DATA_TYPE_DOCUMENT}, {@code schemaType}
+         * is also required.
+         */
+        public static final class Builder {
+            private final Bundle mBundle = new Bundle();
+            private boolean mBuilt = false;
+
+            /** Creates a new {@link PropertyConfig.Builder}. */
+            public Builder(@NonNull String propertyName) {
+                mBundle.putString(NAME_FIELD, propertyName);
+            }
+
+            /**
+             * Type of data the property contains (e.g. string, int, bytes, etc).
+             *
+             * <p>This property must be set.
+             */
+            @NonNull
+            public PropertyConfig.Builder setDataType(@DataType int dataType) {
+                Preconditions.checkState(!mBuilt, "Builder has already been used");
+                Preconditions.checkArgumentInRange(
+                        dataType, DATA_TYPE_STRING, DATA_TYPE_DOCUMENT, "dataType");
+                mBundle.putInt(DATA_TYPE_FIELD, dataType);
+                return this;
+            }
+
+            /**
+             * The logical schema-type of the contents of this property.
+             *
+             * <p>Only required when {@link #setDataType} is set to {@link #DATA_TYPE_DOCUMENT}.
+             * Otherwise, it is ignored.
+             */
+            @NonNull
+            public PropertyConfig.Builder setSchemaType(@NonNull String schemaType) {
+                Preconditions.checkState(!mBuilt, "Builder has already been used");
+                Preconditions.checkNotNull(schemaType);
+                mBundle.putString(SCHEMA_TYPE_FIELD, schemaType);
+                return this;
+            }
+
+            /**
+             * The cardinality of the property (whether it is optional, required or repeated).
+             *
+             * <p>This property must be set.
+             */
+            @NonNull
+            public PropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
+                Preconditions.checkState(!mBuilt, "Builder has already been used");
+                Preconditions.checkArgumentInRange(
+                        cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
+                mBundle.putInt(CARDINALITY_FIELD, cardinality);
+                return this;
+            }
+
+            /**
+             * Configures how a property should be indexed so that it can be retrieved by queries.
+             */
+            @NonNull
+            public PropertyConfig.Builder setIndexingType(@IndexingType int indexingType) {
+                Preconditions.checkState(!mBuilt, "Builder has already been used");
+                Preconditions.checkArgumentInRange(
+                        indexingType, INDEXING_TYPE_NONE, INDEXING_TYPE_PREFIXES, "indexingType");
+                mBundle.putInt(INDEXING_TYPE_FIELD, indexingType);
+                return this;
+            }
+
+            /** Configures how this property should be tokenized (split into words). */
+            @NonNull
+            public PropertyConfig.Builder setTokenizerType(@TokenizerType int tokenizerType) {
+                Preconditions.checkState(!mBuilt, "Builder has already been used");
+                Preconditions.checkArgumentInRange(
+                        tokenizerType, TOKENIZER_TYPE_NONE, TOKENIZER_TYPE_PLAIN, "tokenizerType");
+                mBundle.putInt(TOKENIZER_TYPE_FIELD, tokenizerType);
+                return this;
+            }
+
+            /**
+             * Constructs a new {@link PropertyConfig} from the contents of this builder.
+             *
+             * <p>After calling this method, the builder must no longer be used.
+             *
+             * @throws IllegalSchemaException If the property is not correctly populated (e.g.
+             *     missing {@code dataType}).
+             */
+            @NonNull
+            public PropertyConfig build() {
+                Preconditions.checkState(!mBuilt, "Builder has already been used");
+                // TODO(b/147692920): Send the schema to Icing Lib for official validation, instead
+                //     of partially reimplementing some of the validation Icing does here.
+                if (!mBundle.containsKey(DATA_TYPE_FIELD)) {
+                    throw new IllegalSchemaException("Missing field: dataType");
+                }
+                if (mBundle.getString(SCHEMA_TYPE_FIELD, "").isEmpty()
+                        && mBundle.getInt(DATA_TYPE_FIELD) == DATA_TYPE_DOCUMENT) {
+                    throw new IllegalSchemaException(
+                            "Missing field: schemaType (required for configs with "
+                                    + "dataType = DOCUMENT)");
+                }
+                if (!mBundle.containsKey(CARDINALITY_FIELD)) {
+                    throw new IllegalSchemaException("Missing field: cardinality");
+                }
+                mBuilt = true;
+                return new PropertyConfig(mBundle);
+            }
+        }
+    }
+}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
new file mode 100644
index 0000000..85207f7
--- /dev/null
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
@@ -0,0 +1,837 @@
+/*
+ * 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.appsearch;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.app.appsearch.exceptions.AppSearchException;
+import android.app.appsearch.util.BundleUtil;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * Represents a document unit.
+ *
+ * <p>Documents are constructed via {@link GenericDocument.Builder}.
+ *
+ * @see AppSearchSession#putDocuments
+ * @see AppSearchSession#getByUri
+ * @see AppSearchSession#query
+ */
+public class GenericDocument {
+    private static final String TAG = "AppSearchGenericDocumen";
+
+    /** The default empty namespace. */
+    public static final String DEFAULT_NAMESPACE = "";
+
+    /**
+     * The maximum number of elements in a repeatable field. Will reject the request if exceed this
+     * limit.
+     */
+    private static final int MAX_REPEATED_PROPERTY_LENGTH = 100;
+
+    /**
+     * The maximum {@link String#length} of a {@link String} field. Will reject the request if
+     * {@link String}s longer than this.
+     */
+    private static final int MAX_STRING_LENGTH = 20_000;
+
+    /** The maximum number of indexed properties a document can have. */
+    private static final int MAX_INDEXED_PROPERTIES = 16;
+
+    /** The default score of document. */
+    private static final int DEFAULT_SCORE = 0;
+
+    /** The default time-to-live in millisecond of a document, which is infinity. */
+    private static final long DEFAULT_TTL_MILLIS = 0L;
+
+    private static final String PROPERTIES_FIELD = "properties";
+    private static final String BYTE_ARRAY_FIELD = "byteArray";
+    private static final String SCHEMA_TYPE_FIELD = "schemaType";
+    private static final String URI_FIELD = "uri";
+    private static final String SCORE_FIELD = "score";
+    private static final String TTL_MILLIS_FIELD = "ttlMillis";
+    private static final String CREATION_TIMESTAMP_MILLIS_FIELD = "creationTimestampMillis";
+    private static final String NAMESPACE_FIELD = "namespace";
+
+    /**
+     * The maximum number of indexed properties a document can have.
+     *
+     * <p>Indexed properties are properties where the {@link
+     * AppSearchSchema.PropertyConfig#getIndexingType()} constant is anything other than {@link
+     * AppSearchSchema.PropertyConfig.IndexingType#INDEXING_TYPE_NONE}.
+     */
+    public static int getMaxIndexedProperties() {
+        return MAX_INDEXED_PROPERTIES;
+    }
+
+    /** Contains {@link GenericDocument} basic information (uri, schemaType etc). */
+    @NonNull final Bundle mBundle;
+
+    /**
+     * Contains all properties in {@link GenericDocument} to support getting properties via keys.
+     */
+    @NonNull private final Bundle mProperties;
+
+    @NonNull private final String mUri;
+    @NonNull private final String mSchemaType;
+    private final long mCreationTimestampMillis;
+    @Nullable private Integer mHashCode;
+
+    /**
+     * Rebuilds a {@link GenericDocument} by the a bundle.
+     *
+     * @param bundle Contains {@link GenericDocument} basic information (uri, schemaType etc) and a
+     *     properties bundle contains all properties in {@link GenericDocument} to support getting
+     *     properties via keys.
+     * @hide
+     */
+    public GenericDocument(@NonNull Bundle bundle) {
+        Preconditions.checkNotNull(bundle);
+        mBundle = bundle;
+        mProperties = Preconditions.checkNotNull(bundle.getParcelable(PROPERTIES_FIELD));
+        mUri = Preconditions.checkNotNull(mBundle.getString(URI_FIELD));
+        mSchemaType = Preconditions.checkNotNull(mBundle.getString(SCHEMA_TYPE_FIELD));
+        mCreationTimestampMillis =
+                mBundle.getLong(CREATION_TIMESTAMP_MILLIS_FIELD, System.currentTimeMillis());
+    }
+
+    /**
+     * Creates a new {@link GenericDocument} from an existing instance.
+     *
+     * <p>This method should be only used by constructor of a subclass.
+     */
+    protected GenericDocument(@NonNull GenericDocument document) {
+        this(document.mBundle);
+    }
+
+    /**
+     * Returns the {@link Bundle} populated by this builder.
+     *
+     * @hide
+     */
+    @NonNull
+    public Bundle getBundle() {
+        return mBundle;
+    }
+
+    /** Returns the URI of the {@link GenericDocument}. */
+    @NonNull
+    public String getUri() {
+        return mUri;
+    }
+
+    /** Returns the namespace of the {@link GenericDocument}. */
+    @NonNull
+    public String getNamespace() {
+        return mBundle.getString(NAMESPACE_FIELD, DEFAULT_NAMESPACE);
+    }
+
+    /** Returns the schema type of the {@link GenericDocument}. */
+    @NonNull
+    public String getSchemaType() {
+        return mSchemaType;
+    }
+
+    /**
+     * Returns the creation timestamp of the {@link GenericDocument}, in milliseconds.
+     *
+     * <p>The value is in the {@link System#currentTimeMillis} time base.
+     */
+    public long getCreationTimestampMillis() {
+        return mCreationTimestampMillis;
+    }
+
+    /**
+     * Returns the TTL (Time To Live) of the {@link GenericDocument}, in milliseconds.
+     *
+     * <p>The TTL is measured against {@link #getCreationTimestampMillis}. At the timestamp of
+     * {@code creationTimestampMillis + ttlMillis}, measured in the {@link System#currentTimeMillis}
+     * time base, the document will be auto-deleted.
+     *
+     * <p>The default value is 0, which means the document is permanent and won't be auto-deleted
+     * until the app is uninstalled.
+     */
+    public long getTtlMillis() {
+        return mBundle.getLong(TTL_MILLIS_FIELD, DEFAULT_TTL_MILLIS);
+    }
+
+    /**
+     * Returns the score of the {@link GenericDocument}.
+     *
+     * <p>The score is a query-independent measure of the document's quality, relative to other
+     * {@link GenericDocument}s of the same type.
+     *
+     * <p>Results may be sorted by score using {@link SearchSpec.Builder#setRankingStrategy}.
+     * Documents with higher scores are considered better than documents with lower scores.
+     *
+     * <p>Any nonnegative integer can be used a score.
+     */
+    public int getScore() {
+        return mBundle.getInt(SCORE_FIELD, DEFAULT_SCORE);
+    }
+
+    /** Returns the names of all properties defined in this document. */
+    @NonNull
+    public Set<String> getPropertyNames() {
+        return Collections.unmodifiableSet(mProperties.keySet());
+    }
+
+    /**
+     * Retrieves a {@link String} value by key.
+     *
+     * @param key The key to look for.
+     * @return The first {@link String} associated with the given key or {@code null} if there is no
+     *     such key or the value is of a different type.
+     */
+    @Nullable
+    public String getPropertyString(@NonNull String key) {
+        Preconditions.checkNotNull(key);
+        String[] propertyArray = getPropertyStringArray(key);
+        if (propertyArray == null || propertyArray.length == 0) {
+            return null;
+        }
+        warnIfSinglePropertyTooLong("String", key, propertyArray.length);
+        return propertyArray[0];
+    }
+
+    /**
+     * Retrieves a {@code long} value by key.
+     *
+     * @param key The key to look for.
+     * @return The first {@code long} associated with the given key or default value {@code 0} if
+     *     there is no such key or the value is of a different type.
+     */
+    public long getPropertyLong(@NonNull String key) {
+        Preconditions.checkNotNull(key);
+        long[] propertyArray = getPropertyLongArray(key);
+        if (propertyArray == null || propertyArray.length == 0) {
+            return 0;
+        }
+        warnIfSinglePropertyTooLong("Long", key, propertyArray.length);
+        return propertyArray[0];
+    }
+
+    /**
+     * Retrieves a {@code double} value by key.
+     *
+     * @param key The key to look for.
+     * @return The first {@code double} associated with the given key or default value {@code 0.0}
+     *     if there is no such key or the value is of a different type.
+     */
+    public double getPropertyDouble(@NonNull String key) {
+        Preconditions.checkNotNull(key);
+        double[] propertyArray = getPropertyDoubleArray(key);
+        if (propertyArray == null || propertyArray.length == 0) {
+            return 0.0;
+        }
+        warnIfSinglePropertyTooLong("Double", key, propertyArray.length);
+        return propertyArray[0];
+    }
+
+    /**
+     * Retrieves a {@code boolean} value by key.
+     *
+     * @param key The key to look for.
+     * @return The first {@code boolean} associated with the given key or default value {@code
+     *     false} if there is no such key or the value is of a different type.
+     */
+    public boolean getPropertyBoolean(@NonNull String key) {
+        Preconditions.checkNotNull(key);
+        boolean[] propertyArray = getPropertyBooleanArray(key);
+        if (propertyArray == null || propertyArray.length == 0) {
+            return false;
+        }
+        warnIfSinglePropertyTooLong("Boolean", key, propertyArray.length);
+        return propertyArray[0];
+    }
+
+    /**
+     * Retrieves a {@code byte[]} value by key.
+     *
+     * @param key The key to look for.
+     * @return The first {@code byte[]} associated with the given key or {@code null} if there is no
+     *     such key or the value is of a different type.
+     */
+    @Nullable
+    public byte[] getPropertyBytes(@NonNull String key) {
+        Preconditions.checkNotNull(key);
+        byte[][] propertyArray = getPropertyBytesArray(key);
+        if (propertyArray == null || propertyArray.length == 0) {
+            return null;
+        }
+        warnIfSinglePropertyTooLong("ByteArray", key, propertyArray.length);
+        return propertyArray[0];
+    }
+
+    /**
+     * Retrieves a {@link GenericDocument} value by key.
+     *
+     * @param key The key to look for.
+     * @return The first {@link GenericDocument} associated with the given key or {@code null} if
+     *     there is no such key or the value is of a different type.
+     */
+    @Nullable
+    public GenericDocument getPropertyDocument(@NonNull String key) {
+        Preconditions.checkNotNull(key);
+        GenericDocument[] propertyArray = getPropertyDocumentArray(key);
+        if (propertyArray == null || propertyArray.length == 0) {
+            return null;
+        }
+        warnIfSinglePropertyTooLong("Document", key, propertyArray.length);
+        return propertyArray[0];
+    }
+
+    /** Prints a warning to logcat if the given propertyLength is greater than 1. */
+    private static void warnIfSinglePropertyTooLong(
+            @NonNull String propertyType, @NonNull String key, int propertyLength) {
+        if (propertyLength > 1) {
+            Log.w(
+                    TAG,
+                    "The value for \""
+                            + key
+                            + "\" contains "
+                            + propertyLength
+                            + " elements. Only the first one will be returned from "
+                            + "getProperty"
+                            + propertyType
+                            + "(). Try getProperty"
+                            + propertyType
+                            + "Array().");
+        }
+    }
+
+    /**
+     * Retrieves a repeated {@code String} property by key.
+     *
+     * @param key The key to look for.
+     * @return The {@code String[]} associated with the given key, or {@code null} if no value is
+     *     set or the value is of a different type.
+     */
+    @Nullable
+    public String[] getPropertyStringArray(@NonNull String key) {
+        Preconditions.checkNotNull(key);
+        return getAndCastPropertyArray(key, String[].class);
+    }
+
+    /**
+     * Retrieves a repeated {@link String} property by key.
+     *
+     * @param key The key to look for.
+     * @return The {@code long[]} associated with the given key, or {@code null} if no value is set
+     *     or the value is of a different type.
+     */
+    @Nullable
+    public long[] getPropertyLongArray(@NonNull String key) {
+        Preconditions.checkNotNull(key);
+        return getAndCastPropertyArray(key, long[].class);
+    }
+
+    /**
+     * Retrieves a repeated {@code double} property by key.
+     *
+     * @param key The key to look for.
+     * @return The {@code double[]} associated with the given key, or {@code null} if no value is
+     *     set or the value is of a different type.
+     */
+    @Nullable
+    public double[] getPropertyDoubleArray(@NonNull String key) {
+        Preconditions.checkNotNull(key);
+        return getAndCastPropertyArray(key, double[].class);
+    }
+
+    /**
+     * Retrieves a repeated {@code boolean} property by key.
+     *
+     * @param key The key to look for.
+     * @return The {@code boolean[]} associated with the given key, or {@code null} if no value is
+     *     set or the value is of a different type.
+     */
+    @Nullable
+    public boolean[] getPropertyBooleanArray(@NonNull String key) {
+        Preconditions.checkNotNull(key);
+        return getAndCastPropertyArray(key, boolean[].class);
+    }
+
+    /**
+     * Retrieves a {@code byte[][]} property by key.
+     *
+     * @param key The key to look for.
+     * @return The {@code byte[][]} associated with the given key, or {@code null} if no value is
+     *     set or the value is of a different type.
+     */
+    @SuppressLint("ArrayReturn")
+    @Nullable
+    @SuppressWarnings("unchecked")
+    public byte[][] getPropertyBytesArray(@NonNull String key) {
+        Preconditions.checkNotNull(key);
+        ArrayList<Bundle> bundles = getAndCastPropertyArray(key, ArrayList.class);
+        if (bundles == null || bundles.size() == 0) {
+            return null;
+        }
+        byte[][] bytes = new byte[bundles.size()][];
+        for (int i = 0; i < bundles.size(); i++) {
+            Bundle bundle = bundles.get(i);
+            if (bundle == null) {
+                Log.e(TAG, "The inner bundle is null at " + i + ", for key: " + key);
+                continue;
+            }
+            byte[] innerBytes = bundle.getByteArray(BYTE_ARRAY_FIELD);
+            if (innerBytes == null) {
+                Log.e(TAG, "The bundle at " + i + " contains a null byte[].");
+                continue;
+            }
+            bytes[i] = innerBytes;
+        }
+        return bytes;
+    }
+
+    /**
+     * Retrieves a repeated {@link GenericDocument} property by key.
+     *
+     * @param key The key to look for.
+     * @return The {@link GenericDocument}[] associated with the given key, or {@code null} if no
+     *     value is set or the value is of a different type.
+     */
+    @SuppressLint("ArrayReturn")
+    @Nullable
+    public GenericDocument[] getPropertyDocumentArray(@NonNull String key) {
+        Preconditions.checkNotNull(key);
+        Bundle[] bundles = getAndCastPropertyArray(key, Bundle[].class);
+        if (bundles == null || bundles.length == 0) {
+            return null;
+        }
+        GenericDocument[] documents = new GenericDocument[bundles.length];
+        for (int i = 0; i < bundles.length; i++) {
+            if (bundles[i] == null) {
+                Log.e(TAG, "The inner bundle is null at " + i + ", for key: " + key);
+                continue;
+            }
+            documents[i] = new GenericDocument(bundles[i]);
+        }
+        return documents;
+    }
+
+    /**
+     * Gets a repeated property of the given key, and casts it to the given class type, which must
+     * be an array class type.
+     */
+    @Nullable
+    private <T> T getAndCastPropertyArray(@NonNull String key, @NonNull Class<T> tClass) {
+        Object value = mProperties.get(key);
+        if (value == null) {
+            return null;
+        }
+        try {
+            return tClass.cast(value);
+        } catch (ClassCastException e) {
+            Log.w(TAG, "Error casting to requested type for key \"" + key + "\"", e);
+            return null;
+        }
+    }
+
+    @Override
+    public boolean equals(@Nullable Object other) {
+        if (this == other) {
+            return true;
+        }
+        if (!(other instanceof GenericDocument)) {
+            return false;
+        }
+        GenericDocument otherDocument = (GenericDocument) other;
+        return BundleUtil.deepEquals(this.mBundle, otherDocument.mBundle);
+    }
+
+    @Override
+    public int hashCode() {
+        if (mHashCode == null) {
+            mHashCode = BundleUtil.deepHashCode(mBundle);
+        }
+        return mHashCode;
+    }
+
+    @Override
+    @NonNull
+    public String toString() {
+        return bundleToString(mBundle).toString();
+    }
+
+    @SuppressWarnings("unchecked")
+    private static StringBuilder bundleToString(Bundle bundle) {
+        StringBuilder stringBuilder = new StringBuilder();
+        try {
+            final Set<String> keySet = bundle.keySet();
+            String[] keys = keySet.toArray(new String[0]);
+            // Sort keys to make output deterministic. We need a custom comparator to handle
+            // nulls (arbitrarily putting them first, similar to Comparator.nullsFirst, which is
+            // only available since N).
+            Arrays.sort(
+                    keys,
+                    (@Nullable String s1, @Nullable String s2) -> {
+                        if (s1 == null) {
+                            return s2 == null ? 0 : -1;
+                        } else if (s2 == null) {
+                            return 1;
+                        } else {
+                            return s1.compareTo(s2);
+                        }
+                    });
+            for (String key : keys) {
+                stringBuilder.append("{ key: '").append(key).append("' value: ");
+                Object valueObject = bundle.get(key);
+                if (valueObject == null) {
+                    stringBuilder.append("<null>");
+                } else if (valueObject instanceof Bundle) {
+                    stringBuilder.append(bundleToString((Bundle) valueObject));
+                } else if (valueObject.getClass().isArray()) {
+                    stringBuilder.append("[ ");
+                    for (int i = 0; i < Array.getLength(valueObject); i++) {
+                        Object element = Array.get(valueObject, i);
+                        stringBuilder.append("'");
+                        if (element instanceof Bundle) {
+                            stringBuilder.append(bundleToString((Bundle) element));
+                        } else {
+                            stringBuilder.append(Array.get(valueObject, i));
+                        }
+                        stringBuilder.append("' ");
+                    }
+                    stringBuilder.append("]");
+                } else if (valueObject instanceof ArrayList) {
+                    for (Bundle innerBundle : (ArrayList<Bundle>) valueObject) {
+                        stringBuilder.append(bundleToString(innerBundle));
+                    }
+                } else {
+                    stringBuilder.append(valueObject.toString());
+                }
+                stringBuilder.append(" } ");
+            }
+        } catch (RuntimeException e) {
+            // Catch any exceptions here since corrupt Bundles can throw different types of
+            // exceptions (e.g. b/38445840 & b/68937025).
+            stringBuilder.append("<error>");
+        }
+        return stringBuilder;
+    }
+
+    /**
+     * The builder class for {@link GenericDocument}.
+     *
+     * @param <BuilderType> Type of subclass who extends this.
+     */
+    // This builder is specifically designed to be extended by classes deriving from
+    // GenericDocument.
+    @SuppressLint("StaticFinalBuilder")
+    public static class Builder<BuilderType extends Builder> {
+
+        private final Bundle mProperties = new Bundle();
+        private final Bundle mBundle = new Bundle();
+        private final BuilderType mBuilderTypeInstance;
+        private boolean mBuilt = false;
+
+        /**
+         * Create a new {@link GenericDocument.Builder}.
+         *
+         * @param uri The uri of {@link GenericDocument}.
+         * @param schemaType The schema type of the {@link GenericDocument}. The passed-in {@code
+         *     schemaType} must be defined using {@link AppSearchSession#setSchema} prior to
+         *     inserting a document of this {@code schemaType} into the AppSearch index using {@link
+         *     AppSearchSession#putDocuments}. Otherwise, the document will be rejected by {@link
+         *     AppSearchSession#putDocuments}.
+         */
+        @SuppressWarnings("unchecked")
+        public Builder(@NonNull String uri, @NonNull String schemaType) {
+            Preconditions.checkNotNull(uri);
+            Preconditions.checkNotNull(schemaType);
+            mBuilderTypeInstance = (BuilderType) this;
+            mBundle.putString(GenericDocument.URI_FIELD, uri);
+            mBundle.putString(GenericDocument.SCHEMA_TYPE_FIELD, schemaType);
+            mBundle.putString(GenericDocument.NAMESPACE_FIELD, DEFAULT_NAMESPACE);
+            // Set current timestamp for creation timestamp by default.
+            mBundle.putLong(
+                    GenericDocument.CREATION_TIMESTAMP_MILLIS_FIELD, System.currentTimeMillis());
+            mBundle.putLong(GenericDocument.TTL_MILLIS_FIELD, DEFAULT_TTL_MILLIS);
+            mBundle.putInt(GenericDocument.SCORE_FIELD, DEFAULT_SCORE);
+            mBundle.putBundle(PROPERTIES_FIELD, mProperties);
+        }
+
+        /**
+         * Sets the app-defined namespace this Document resides in. No special values are reserved
+         * or understood by the infrastructure.
+         *
+         * <p>URIs are unique within a namespace.
+         *
+         * <p>The number of namespaces per app should be kept small for efficiency reasons.
+         */
+        @NonNull
+        public BuilderType setNamespace(@NonNull String namespace) {
+            mBundle.putString(GenericDocument.NAMESPACE_FIELD, namespace);
+            return mBuilderTypeInstance;
+        }
+
+        /**
+         * Sets the score of the {@link GenericDocument}.
+         *
+         * <p>The score is a query-independent measure of the document's quality, relative to other
+         * {@link GenericDocument}s of the same type.
+         *
+         * <p>Results may be sorted by score using {@link SearchSpec.Builder#setRankingStrategy}.
+         * Documents with higher scores are considered better than documents with lower scores.
+         *
+         * <p>Any nonnegative integer can be used a score.
+         *
+         * @throws IllegalArgumentException If the provided value is negative.
+         */
+        @NonNull
+        public BuilderType setScore(@IntRange(from = 0, to = Integer.MAX_VALUE) int score) {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            if (score < 0) {
+                throw new IllegalArgumentException("Document score cannot be negative.");
+            }
+            mBundle.putInt(GenericDocument.SCORE_FIELD, score);
+            return mBuilderTypeInstance;
+        }
+
+        /**
+         * Sets the creation timestamp of the {@link GenericDocument}, in milliseconds.
+         *
+         * <p>Should be set using a value obtained from the {@link System#currentTimeMillis} time
+         * base.
+         */
+        @NonNull
+        public BuilderType setCreationTimestampMillis(long creationTimestampMillis) {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            mBundle.putLong(
+                    GenericDocument.CREATION_TIMESTAMP_MILLIS_FIELD, creationTimestampMillis);
+            return mBuilderTypeInstance;
+        }
+
+        /**
+         * Sets the TTL (Time To Live) of the {@link GenericDocument}, in milliseconds.
+         *
+         * <p>The TTL is measured against {@link #getCreationTimestampMillis}. At the timestamp of
+         * {@code creationTimestampMillis + ttlMillis}, measured in the {@link
+         * System#currentTimeMillis} time base, the document will be auto-deleted.
+         *
+         * <p>The default value is 0, which means the document is permanent and won't be
+         * auto-deleted until the app is uninstalled.
+         *
+         * @param ttlMillis A non-negative duration in milliseconds.
+         * @throws IllegalArgumentException If the provided value is negative.
+         */
+        @NonNull
+        public BuilderType setTtlMillis(long ttlMillis) {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            if (ttlMillis < 0) {
+                throw new IllegalArgumentException("Document ttlMillis cannot be negative.");
+            }
+            mBundle.putLong(GenericDocument.TTL_MILLIS_FIELD, ttlMillis);
+            return mBuilderTypeInstance;
+        }
+
+        /**
+         * Sets one or multiple {@code String} values for a property, replacing its previous values.
+         *
+         * @param key The key associated with the {@code values}.
+         * @param values The {@code String} values of the property.
+         */
+        @NonNull
+        public BuilderType setPropertyString(@NonNull String key, @NonNull String... values) {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            Preconditions.checkNotNull(key);
+            Preconditions.checkNotNull(values);
+            putInPropertyBundle(key, values);
+            return mBuilderTypeInstance;
+        }
+
+        /**
+         * Sets one or multiple {@code boolean} values for a property, replacing its previous
+         * values.
+         *
+         * @param key The key associated with the {@code values}.
+         * @param values The {@code boolean} values of the property.
+         */
+        @NonNull
+        public BuilderType setPropertyBoolean(@NonNull String key, @NonNull boolean... values) {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            Preconditions.checkNotNull(key);
+            Preconditions.checkNotNull(values);
+            putInPropertyBundle(key, values);
+            return mBuilderTypeInstance;
+        }
+
+        /**
+         * Sets one or multiple {@code long} values for a property, replacing its previous values.
+         *
+         * @param key The key associated with the {@code values}.
+         * @param values The {@code long} values of the property.
+         */
+        @NonNull
+        public BuilderType setPropertyLong(@NonNull String key, @NonNull long... values) {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            Preconditions.checkNotNull(key);
+            Preconditions.checkNotNull(values);
+            putInPropertyBundle(key, values);
+            return mBuilderTypeInstance;
+        }
+
+        /**
+         * Sets one or multiple {@code double} values for a property, replacing its previous values.
+         *
+         * @param key The key associated with the {@code values}.
+         * @param values The {@code double} values of the property.
+         */
+        @NonNull
+        public BuilderType setPropertyDouble(@NonNull String key, @NonNull double... values) {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            Preconditions.checkNotNull(key);
+            Preconditions.checkNotNull(values);
+            putInPropertyBundle(key, values);
+            return mBuilderTypeInstance;
+        }
+
+        /**
+         * Sets one or multiple {@code byte[]} for a property, replacing its previous values.
+         *
+         * @param key The key associated with the {@code values}.
+         * @param values The {@code byte[]} of the property.
+         */
+        @NonNull
+        public BuilderType setPropertyBytes(@NonNull String key, @NonNull byte[]... values) {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            Preconditions.checkNotNull(key);
+            Preconditions.checkNotNull(values);
+            putInPropertyBundle(key, values);
+            return mBuilderTypeInstance;
+        }
+
+        /**
+         * Sets one or multiple {@link GenericDocument} values for a property, replacing its
+         * previous values.
+         *
+         * @param key The key associated with the {@code values}.
+         * @param values The {@link GenericDocument} values of the property.
+         */
+        @NonNull
+        public BuilderType setPropertyDocument(
+                @NonNull String key, @NonNull GenericDocument... values) {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            Preconditions.checkNotNull(key);
+            Preconditions.checkNotNull(values);
+            putInPropertyBundle(key, values);
+            return mBuilderTypeInstance;
+        }
+
+        private void putInPropertyBundle(@NonNull String key, @NonNull String[] values)
+                throws IllegalArgumentException {
+            validateRepeatedPropertyLength(key, values.length);
+            for (int i = 0; i < values.length; i++) {
+                if (values[i] == null) {
+                    throw new IllegalArgumentException("The String at " + i + " is null.");
+                } else if (values[i].length() > MAX_STRING_LENGTH) {
+                    throw new IllegalArgumentException(
+                            "The String at "
+                                    + i
+                                    + " length is: "
+                                    + values[i].length()
+                                    + ", which exceeds length limit: "
+                                    + MAX_STRING_LENGTH
+                                    + ".");
+                }
+            }
+            mProperties.putStringArray(key, values);
+        }
+
+        private void putInPropertyBundle(@NonNull String key, @NonNull boolean[] values) {
+            validateRepeatedPropertyLength(key, values.length);
+            mProperties.putBooleanArray(key, values);
+        }
+
+        private void putInPropertyBundle(@NonNull String key, @NonNull double[] values) {
+            validateRepeatedPropertyLength(key, values.length);
+            mProperties.putDoubleArray(key, values);
+        }
+
+        private void putInPropertyBundle(@NonNull String key, @NonNull long[] values) {
+            validateRepeatedPropertyLength(key, values.length);
+            mProperties.putLongArray(key, values);
+        }
+
+        /**
+         * Converts and saves a byte[][] into {@link #mProperties}.
+         *
+         * <p>Bundle doesn't support for two dimension array byte[][], we are converting byte[][]
+         * into ArrayList<Bundle>, and each elements will contain a one dimension byte[].
+         */
+        private void putInPropertyBundle(@NonNull String key, @NonNull byte[][] values) {
+            validateRepeatedPropertyLength(key, values.length);
+            ArrayList<Bundle> bundles = new ArrayList<>(values.length);
+            for (int i = 0; i < values.length; i++) {
+                if (values[i] == null) {
+                    throw new IllegalArgumentException("The byte[] at " + i + " is null.");
+                }
+                Bundle bundle = new Bundle();
+                bundle.putByteArray(BYTE_ARRAY_FIELD, values[i]);
+                bundles.add(bundle);
+            }
+            mProperties.putParcelableArrayList(key, bundles);
+        }
+
+        private void putInPropertyBundle(@NonNull String key, @NonNull GenericDocument[] values) {
+            validateRepeatedPropertyLength(key, values.length);
+            Bundle[] documentBundles = new Bundle[values.length];
+            for (int i = 0; i < values.length; i++) {
+                if (values[i] == null) {
+                    throw new IllegalArgumentException("The document at " + i + " is null.");
+                }
+                documentBundles[i] = values[i].mBundle;
+            }
+            mProperties.putParcelableArray(key, documentBundles);
+        }
+
+        private static void validateRepeatedPropertyLength(@NonNull String key, int length) {
+            if (length == 0) {
+                throw new IllegalArgumentException("The input array is empty.");
+            } else if (length > MAX_REPEATED_PROPERTY_LENGTH) {
+                throw new IllegalArgumentException(
+                        "Repeated property \""
+                                + key
+                                + "\" has length "
+                                + length
+                                + ", which exceeds the limit of "
+                                + MAX_REPEATED_PROPERTY_LENGTH);
+            }
+        }
+
+        /** Builds the {@link GenericDocument} object. */
+        @NonNull
+        public GenericDocument build() {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            mBuilt = true;
+            return new GenericDocument(mBundle);
+        }
+    }
+}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java
new file mode 100644
index 0000000..74afdd2
--- /dev/null
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/GetByUriRequest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.appsearch;
+
+import android.annotation.NonNull;
+import android.util.ArraySet;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * Encapsulates a request to retrieve documents by namespace and URI.
+ *
+ * @see AppSearchSession#getByUri
+ */
+public final class GetByUriRequest {
+    private final String mNamespace;
+    private final Set<String> mUris;
+
+    GetByUriRequest(@NonNull String namespace, @NonNull Set<String> uris) {
+        mNamespace = namespace;
+        mUris = uris;
+    }
+
+    /** Returns the namespace to get documents from. */
+    @NonNull
+    public String getNamespace() {
+        return mNamespace;
+    }
+
+    /** Returns the URIs to get from the namespace. */
+    @NonNull
+    public Set<String> getUris() {
+        return Collections.unmodifiableSet(mUris);
+    }
+
+    /** Builder for {@link GetByUriRequest} objects. */
+    public static final class Builder {
+        private String mNamespace = GenericDocument.DEFAULT_NAMESPACE;
+        private final Set<String> mUris = new ArraySet<>();
+        private boolean mBuilt = false;
+
+        /**
+         * Sets which namespace these documents will be retrieved from.
+         *
+         * <p>If this is not set, it defaults to {@link GenericDocument#DEFAULT_NAMESPACE}.
+         */
+        @NonNull
+        public Builder setNamespace(@NonNull String namespace) {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            Preconditions.checkNotNull(namespace);
+            mNamespace = namespace;
+            return this;
+        }
+
+        /** Adds one or more URIs to the request. */
+        @NonNull
+        public Builder addUri(@NonNull String... uris) {
+            Preconditions.checkNotNull(uris);
+            return addUri(Arrays.asList(uris));
+        }
+
+        /** Adds one or more URIs to the request. */
+        @NonNull
+        public Builder addUri(@NonNull Collection<String> uris) {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            Preconditions.checkNotNull(uris);
+            mUris.addAll(uris);
+            return this;
+        }
+
+        /** Builds a new {@link GetByUriRequest}. */
+        @NonNull
+        public GetByUriRequest build() {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            mBuilt = true;
+            return new GetByUriRequest(mNamespace, mUris);
+        }
+    }
+}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java
new file mode 100644
index 0000000..1c360a6
--- /dev/null
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/PutDocumentsRequest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.appsearch;
+
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.app.appsearch.exceptions.AppSearchException;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Encapsulates a request to index a document into an {@link AppSearchSession} database.
+ *
+ * @see AppSearchSession#putDocuments
+ */
+public final class PutDocumentsRequest {
+    private final List<GenericDocument> mDocuments;
+
+    PutDocumentsRequest(List<GenericDocument> documents) {
+        mDocuments = documents;
+    }
+
+    /** Returns the documents that are part of this request. */
+    @NonNull
+    public List<GenericDocument> getDocuments() {
+        return Collections.unmodifiableList(mDocuments);
+    }
+
+    /** Builder for {@link PutDocumentsRequest} objects. */
+    public static final class Builder {
+        private final List<GenericDocument> mDocuments = new ArrayList<>();
+        private boolean mBuilt = false;
+
+        /** Adds one or more documents to the request. */
+        @SuppressLint("MissingGetterMatchingBuilder") // Merged list available from getDocuments()
+        @NonNull
+        public Builder addGenericDocument(@NonNull GenericDocument... documents) {
+            Preconditions.checkNotNull(documents);
+            return addGenericDocument(Arrays.asList(documents));
+        }
+
+        /** Adds one or more documents to the request. */
+        @SuppressLint("MissingGetterMatchingBuilder") // Merged list available from getDocuments()
+        @NonNull
+        public Builder addGenericDocument(@NonNull Collection<GenericDocument> documents) {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            Preconditions.checkNotNull(documents);
+            mDocuments.addAll(documents);
+            return this;
+        }
+
+        /** Builds a new {@link PutDocumentsRequest}. */
+        @NonNull
+        public PutDocumentsRequest build() {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            mBuilt = true;
+            return new PutDocumentsRequest(mDocuments);
+        }
+    }
+}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/RemoveByUriRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/RemoveByUriRequest.java
new file mode 100644
index 0000000..be6d157
--- /dev/null
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/RemoveByUriRequest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.appsearch;
+
+import android.annotation.NonNull;
+import android.util.ArraySet;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * Encapsulates a request to remove documents by namespace and URI.
+ *
+ * @see AppSearchSession#removeByUri
+ */
+public final class RemoveByUriRequest {
+    private final String mNamespace;
+    private final Set<String> mUris;
+
+    RemoveByUriRequest(String namespace, Set<String> uris) {
+        mNamespace = namespace;
+        mUris = uris;
+    }
+
+    /** Returns the namespace to remove documents from. */
+    @NonNull
+    public String getNamespace() {
+        return mNamespace;
+    }
+
+    /** Returns the URIs to remove from the namespace. */
+    @NonNull
+    public Set<String> getUris() {
+        return Collections.unmodifiableSet(mUris);
+    }
+
+    /** Builder for {@link RemoveByUriRequest} objects. */
+    public static final class Builder {
+        private String mNamespace = GenericDocument.DEFAULT_NAMESPACE;
+        private final Set<String> mUris = new ArraySet<>();
+        private boolean mBuilt = false;
+
+        /**
+         * Sets which namespace these documents will be removed from.
+         *
+         * <p>If this is not set, it defaults to {@link GenericDocument#DEFAULT_NAMESPACE}.
+         */
+        @NonNull
+        public Builder setNamespace(@NonNull String namespace) {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            Preconditions.checkNotNull(namespace);
+            mNamespace = namespace;
+            return this;
+        }
+
+        /** Adds one or more URIs to the request. */
+        @NonNull
+        public Builder addUri(@NonNull String... uris) {
+            Preconditions.checkNotNull(uris);
+            return addUri(Arrays.asList(uris));
+        }
+
+        /** Adds one or more URIs to the request. */
+        @NonNull
+        public Builder addUri(@NonNull Collection<String> uris) {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            Preconditions.checkNotNull(uris);
+            mUris.addAll(uris);
+            return this;
+        }
+
+        /** Builds a new {@link RemoveByUriRequest}. */
+        @NonNull
+        public RemoveByUriRequest build() {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            mBuilt = true;
+            return new RemoveByUriRequest(mNamespace, mUris);
+        }
+    }
+}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchResult.java b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
similarity index 100%
rename from apex/appsearch/framework/java/android/app/appsearch/SearchResult.java
rename to apex/appsearch/framework/java/external/android/app/appsearch/SearchResult.java
diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchResultPage.java b/apex/appsearch/framework/java/external/android/app/appsearch/SearchResultPage.java
similarity index 100%
rename from apex/appsearch/framework/java/android/app/appsearch/SearchResultPage.java
rename to apex/appsearch/framework/java/external/android/app/appsearch/SearchResultPage.java
diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java b/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
similarity index 100%
rename from apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java
rename to apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
new file mode 100644
index 0000000..0e03131
--- /dev/null
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
@@ -0,0 +1,179 @@
+/*
+ * 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.appsearch;
+
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.app.appsearch.exceptions.AppSearchException;
+import android.util.ArraySet;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Encapsulates a request to update the schema of an {@link AppSearchSession} database.
+ *
+ * @see AppSearchSession#setSchema
+ */
+public final class SetSchemaRequest {
+    private final Set<AppSearchSchema> mSchemas;
+    private final Set<String> mSchemasNotPlatformSurfaceable;
+    private final boolean mForceOverride;
+
+    SetSchemaRequest(
+            @NonNull Set<AppSearchSchema> schemas,
+            @NonNull Set<String> schemasNotPlatformSurfaceable,
+            boolean forceOverride) {
+        mSchemas = Preconditions.checkNotNull(schemas);
+        mSchemasNotPlatformSurfaceable = Preconditions.checkNotNull(schemasNotPlatformSurfaceable);
+        mForceOverride = forceOverride;
+    }
+
+    /** Returns the schemas that are part of this request. */
+    @NonNull
+    public Set<AppSearchSchema> getSchemas() {
+        return Collections.unmodifiableSet(mSchemas);
+    }
+
+    /**
+     * Returns the set of schema types that have opted out of being visible on system UI surfaces.
+     *
+     * @hide
+     */
+    @NonNull
+    public Set<String> getSchemasNotPlatformSurfaceable() {
+        return Collections.unmodifiableSet(mSchemasNotPlatformSurfaceable);
+    }
+
+    /** Returns whether this request will force the schema to be overridden. */
+    public boolean isForceOverride() {
+        return mForceOverride;
+    }
+
+    /** Builder for {@link SetSchemaRequest} objects. */
+    public static final class Builder {
+        private final Set<AppSearchSchema> mSchemas = new ArraySet<>();
+        private final Set<String> mSchemasNotPlatformSurfaceable = new ArraySet<>();
+        private boolean mForceOverride = false;
+        private boolean mBuilt = false;
+
+        /**
+         * Adds one or more types to the schema.
+         *
+         * <p>Any documents of these types will be visible on system UI surfaces by default.
+         */
+        @NonNull
+        public Builder addSchema(@NonNull AppSearchSchema... schemas) {
+            Preconditions.checkNotNull(schemas);
+            return addSchema(Arrays.asList(schemas));
+        }
+
+        /**
+         * Adds one or more types to the schema.
+         *
+         * <p>Any documents of these types will be visible on system UI surfaces by default.
+         */
+        @NonNull
+        public Builder addSchema(@NonNull Collection<AppSearchSchema> schemas) {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            Preconditions.checkNotNull(schemas);
+            mSchemas.addAll(schemas);
+            return this;
+        }
+
+        /**
+         * Sets visibility on system UI surfaces for schema types.
+         *
+         * @hide
+         */
+        @NonNull
+        public Builder setSchemaTypeVisibilityForSystemUi(
+                boolean visible, @NonNull String... schemaTypes) {
+            Preconditions.checkNotNull(schemaTypes);
+            return this.setSchemaTypeVisibilityForSystemUi(visible, Arrays.asList(schemaTypes));
+        }
+
+        /**
+         * Sets visibility on system UI surfaces for schema types.
+         *
+         * @hide
+         */
+        @NonNull
+        public Builder setSchemaTypeVisibilityForSystemUi(
+                boolean visible, @NonNull Collection<String> schemaTypes) {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            Preconditions.checkNotNull(schemaTypes);
+            if (visible) {
+                mSchemasNotPlatformSurfaceable.removeAll(schemaTypes);
+            } else {
+                mSchemasNotPlatformSurfaceable.addAll(schemaTypes);
+            }
+            return this;
+        }
+
+        /**
+         * Configures the {@link SetSchemaRequest} to delete any existing documents that don't
+         * follow the new schema.
+         *
+         * <p>By default, this is {@code false} and schema incompatibility causes the {@link
+         * AppSearchSession#setSchema} call to fail.
+         *
+         * @see AppSearchSession#setSchema
+         */
+        @NonNull
+        public Builder setForceOverride(boolean forceOverride) {
+            mForceOverride = forceOverride;
+            return this;
+        }
+
+        /**
+         * Builds a new {@link SetSchemaRequest}.
+         *
+         * @throws IllegalArgumentException If schema types were referenced, but the corresponding
+         *     {@link AppSearchSchema} was never added.
+         */
+        @NonNull
+        public SetSchemaRequest build() {
+            Preconditions.checkState(!mBuilt, "Builder has already been used");
+            mBuilt = true;
+
+            // Verify that any schema types with visibility settings refer to a real schema.
+            // Create a copy because we're going to remove from the set for verification purposes.
+            Set<String> schemasNotPlatformSurfaceableCopy =
+                    new ArraySet<>(mSchemasNotPlatformSurfaceable);
+            for (AppSearchSchema schema : mSchemas) {
+                schemasNotPlatformSurfaceableCopy.remove(schema.getSchemaType());
+            }
+            if (!schemasNotPlatformSurfaceableCopy.isEmpty()) {
+                // We still have schema types that weren't seen in our mSchemas set. This means
+                // there wasn't a corresponding AppSearchSchema.
+                throw new IllegalArgumentException(
+                        "Schema types "
+                                + schemasNotPlatformSurfaceableCopy
+                                + " referenced, but were not added.");
+            }
+
+            return new SetSchemaRequest(mSchemas, mSchemasNotPlatformSurfaceable, mForceOverride);
+        }
+    }
+}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/exceptions/AppSearchException.java b/apex/appsearch/framework/java/external/android/app/appsearch/exceptions/AppSearchException.java
similarity index 100%
rename from apex/appsearch/framework/java/android/app/appsearch/exceptions/AppSearchException.java
rename to apex/appsearch/framework/java/external/android/app/appsearch/exceptions/AppSearchException.java
diff --git a/apex/appsearch/framework/java/android/app/appsearch/exceptions/IllegalSchemaException.java b/apex/appsearch/framework/java/external/android/app/appsearch/exceptions/IllegalSchemaException.java
similarity index 100%
rename from apex/appsearch/framework/java/android/app/appsearch/exceptions/IllegalSchemaException.java
rename to apex/appsearch/framework/java/external/android/app/appsearch/exceptions/IllegalSchemaException.java
diff --git a/apex/appsearch/framework/java/android/app/appsearch/exceptions/IllegalSearchSpecException.java b/apex/appsearch/framework/java/external/android/app/appsearch/exceptions/IllegalSearchSpecException.java
similarity index 100%
rename from apex/appsearch/framework/java/android/app/appsearch/exceptions/IllegalSearchSpecException.java
rename to apex/appsearch/framework/java/external/android/app/appsearch/exceptions/IllegalSearchSpecException.java
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/util/BundleUtil.java b/apex/appsearch/framework/java/external/android/app/appsearch/util/BundleUtil.java
new file mode 100644
index 0000000..1b4d284
--- /dev/null
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/util/BundleUtil.java
@@ -0,0 +1,221 @@
+/*
+ * 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.appsearch.util;
+
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.util.SparseArray;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Utilities for working with {@link android.os.Bundle}.
+ *
+ * @hide
+ */
+public final class BundleUtil {
+    private BundleUtil() {}
+
+    /**
+     * Deeply checks two bundles are equal or not.
+     *
+     * <p>Two bundles will be considered equal if they contain the same keys, and each value is also
+     * equal. Bundle values are compared using deepEquals.
+     */
+    public static boolean deepEquals(@Nullable Bundle one, @Nullable Bundle two) {
+        if (one == null && two == null) {
+            return true;
+        }
+        if (one == null || two == null) {
+            return false;
+        }
+        if (one.size() != two.size()) {
+            return false;
+        }
+        if (!one.keySet().equals(two.keySet())) {
+            return false;
+        }
+        // Bundle inherit its equals() from Object.java, which only compare their memory address.
+        // We should iterate all keys and check their presents and values in both bundle.
+        for (String key : one.keySet()) {
+            if (!bundleValueEquals(one.get(key), two.get(key))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Deeply checks whether two values in a Bundle are equal or not.
+     *
+     * <p>Values of type Bundle are compared using {@link #deepEquals}.
+     */
+    private static boolean bundleValueEquals(@Nullable Object one, @Nullable Object two) {
+        if (one == null && two == null) {
+            return true;
+        }
+        if (one == null || two == null) {
+            return false;
+        }
+        if (one.equals(two)) {
+            return true;
+        }
+        if (one instanceof Bundle && two instanceof Bundle) {
+            return deepEquals((Bundle) one, (Bundle) two);
+        } else if (one instanceof int[] && two instanceof int[]) {
+            return Arrays.equals((int[]) one, (int[]) two);
+        } else if (one instanceof byte[] && two instanceof byte[]) {
+            return Arrays.equals((byte[]) one, (byte[]) two);
+        } else if (one instanceof char[] && two instanceof char[]) {
+            return Arrays.equals((char[]) one, (char[]) two);
+        } else if (one instanceof long[] && two instanceof long[]) {
+            return Arrays.equals((long[]) one, (long[]) two);
+        } else if (one instanceof float[] && two instanceof float[]) {
+            return Arrays.equals((float[]) one, (float[]) two);
+        } else if (one instanceof short[] && two instanceof short[]) {
+            return Arrays.equals((short[]) one, (short[]) two);
+        } else if (one instanceof double[] && two instanceof double[]) {
+            return Arrays.equals((double[]) one, (double[]) two);
+        } else if (one instanceof boolean[] && two instanceof boolean[]) {
+            return Arrays.equals((boolean[]) one, (boolean[]) two);
+        } else if (one instanceof Object[] && two instanceof Object[]) {
+            Object[] arrayOne = (Object[]) one;
+            Object[] arrayTwo = (Object[]) two;
+            if (arrayOne.length != arrayTwo.length) {
+                return false;
+            }
+            if (Arrays.equals(arrayOne, arrayTwo)) {
+                return true;
+            }
+            for (int i = 0; i < arrayOne.length; i++) {
+                if (!bundleValueEquals(arrayOne[i], arrayTwo[i])) {
+                    return false;
+                }
+            }
+            return true;
+        } else if (one instanceof ArrayList && two instanceof ArrayList) {
+            ArrayList<?> listOne = (ArrayList<?>) one;
+            ArrayList<?> listTwo = (ArrayList<?>) two;
+            if (listOne.size() != listTwo.size()) {
+                return false;
+            }
+            for (int i = 0; i < listOne.size(); i++) {
+                if (!bundleValueEquals(listOne.get(i), listTwo.get(i))) {
+                    return false;
+                }
+            }
+            return true;
+        } else if (one instanceof SparseArray && two instanceof SparseArray) {
+            SparseArray<?> arrayOne = (SparseArray<?>) one;
+            SparseArray<?> arrayTwo = (SparseArray<?>) two;
+            if (arrayOne.size() != arrayTwo.size()) {
+                return false;
+            }
+            for (int i = 0; i < arrayOne.size(); i++) {
+                if (arrayOne.keyAt(i) != arrayTwo.keyAt(i)
+                        || !bundleValueEquals(arrayOne.valueAt(i), arrayTwo.valueAt(i))) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Calculates the hash code for a bundle.
+     *
+     * <p>The hash code is only effected by the contents in the bundle. Bundles will get consistent
+     * hash code if they have same contents.
+     */
+    public static int deepHashCode(@Nullable Bundle bundle) {
+        if (bundle == null) {
+            return 0;
+        }
+        int[] hashCodes = new int[bundle.size()];
+        int i = 0;
+        // Bundle inherit its hashCode() from Object.java, which only relative to their memory
+        // address. Bundle doesn't have an order, so we should iterate all keys and combine
+        // their value's hashcode into an array. And use the hashcode of the array to be
+        // the hashcode of the bundle.
+        for (String key : bundle.keySet()) {
+            Object value = bundle.get(key);
+            if (value instanceof Bundle) {
+                hashCodes[i++] = deepHashCode((Bundle) value);
+            } else if (value instanceof int[]) {
+                hashCodes[i++] = Arrays.hashCode((int[]) value);
+            } else if (value instanceof byte[]) {
+                hashCodes[i++] = Arrays.hashCode((byte[]) value);
+            } else if (value instanceof char[]) {
+                hashCodes[i++] = Arrays.hashCode((char[]) value);
+            } else if (value instanceof long[]) {
+                hashCodes[i++] = Arrays.hashCode((long[]) value);
+            } else if (value instanceof float[]) {
+                hashCodes[i++] = Arrays.hashCode((float[]) value);
+            } else if (value instanceof short[]) {
+                hashCodes[i++] = Arrays.hashCode((short[]) value);
+            } else if (value instanceof double[]) {
+                hashCodes[i++] = Arrays.hashCode((double[]) value);
+            } else if (value instanceof boolean[]) {
+                hashCodes[i++] = Arrays.hashCode((boolean[]) value);
+            } else if (value instanceof String[]) {
+                // Optimization to avoid Object[] handler creating an inner array for common cases
+                hashCodes[i++] = Arrays.hashCode((String[]) value);
+            } else if (value instanceof Object[]) {
+                Object[] array = (Object[]) value;
+                int[] innerHashCodes = new int[array.length];
+                for (int j = 0; j < array.length; j++) {
+                    if (array[j] instanceof Bundle) {
+                        innerHashCodes[j] = deepHashCode((Bundle) array[j]);
+                    } else if (array[j] != null) {
+                        innerHashCodes[j] = array[j].hashCode();
+                    }
+                }
+                hashCodes[i++] = Arrays.hashCode(innerHashCodes);
+            } else if (value instanceof ArrayList) {
+                ArrayList<?> list = (ArrayList<?>) value;
+                int[] innerHashCodes = new int[list.size()];
+                for (int j = 0; j < innerHashCodes.length; j++) {
+                    Object item = list.get(j);
+                    if (item instanceof Bundle) {
+                        innerHashCodes[j] = deepHashCode((Bundle) item);
+                    } else if (item != null) {
+                        innerHashCodes[j] = item.hashCode();
+                    }
+                }
+                hashCodes[i++] = Arrays.hashCode(innerHashCodes);
+            } else if (value instanceof SparseArray) {
+                SparseArray<?> array = (SparseArray<?>) value;
+                int[] innerHashCodes = new int[array.size() * 2];
+                for (int j = 0; j < array.size(); j++) {
+                    innerHashCodes[j * 2] = array.keyAt(j);
+                    Object item = array.valueAt(j);
+                    if (item instanceof Bundle) {
+                        innerHashCodes[j * 2 + 1] = deepHashCode((Bundle) item);
+                    } else if (item != null) {
+                        innerHashCodes[j * 2 + 1] = item.hashCode();
+                    }
+                }
+                hashCodes[i++] = Arrays.hashCode(innerHashCodes);
+            } else {
+                hashCodes[i++] = value.hashCode();
+            }
+        }
+        return Arrays.hashCode(hashCodes);
+    }
+}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index d5146dd..551347c 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -33,15 +33,14 @@
 import android.os.ParcelableException;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.util.ArraySet;
 import android.util.Log;
 
 import com.android.internal.util.Preconditions;
 import com.android.server.SystemService;
 import com.android.server.appsearch.external.localstorage.AppSearchImpl;
 
+import java.util.ArrayList;
 import java.util.List;
-import java.util.Set;
 
 /**
  * TODO(b/142567528): add comments when implement this class
@@ -64,6 +63,7 @@
         public void setSchema(
                 @NonNull String databaseName,
                 @NonNull List<Bundle> schemaBundles,
+                @NonNull List<String> schemasNotPlatformSurfaceable,
                 boolean forceOverride,
                 @NonNull IAppSearchResultCallback callback) {
             Preconditions.checkNotNull(databaseName);
@@ -73,13 +73,13 @@
             int callingUserId = UserHandle.getUserId(callingUid);
             final long callingIdentity = Binder.clearCallingIdentity();
             try {
-                Set<AppSearchSchema> schemas = new ArraySet<>(schemaBundles.size());
+                List<AppSearchSchema> schemas = new ArrayList<>(schemaBundles.size());
                 for (int i = 0; i < schemaBundles.size(); i++) {
                     schemas.add(new AppSearchSchema(schemaBundles.get(i)));
                 }
                 AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
                 databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
-                impl.setSchema(databaseName, schemas, forceOverride);
+                impl.setSchema(databaseName, schemas, schemasNotPlatformSurfaceable, forceOverride);
                 invokeCallbackOnResult(callback,
                         AppSearchResult.newSuccessfulResult(/*result=*/ null));
             } catch (Throwable t) {
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
index 247089b..62b81d0 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
@@ -60,6 +60,7 @@
 import com.google.android.icing.proto.StatusProto;
 
 import java.io.File;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -226,13 +227,16 @@
      *
      * @param databaseName The name of the database where this schema lives.
      * @param schemas Schemas to set for this app.
+     * @param schemasNotPlatformSurfaceable Schema types that should not be surfaced on platform
+     *     surfaces.
      * @param forceOverride Whether to force-apply the schema even if it is incompatible. Documents
      *     which do not comply with the new schema will be deleted.
      * @throws AppSearchException on IcingSearchEngine error.
      */
     public void setSchema(
             @NonNull String databaseName,
-            @NonNull Set<AppSearchSchema> schemas,
+            @NonNull List<AppSearchSchema> schemas,
+            @NonNull List<String> schemasNotPlatformSurfaceable,
             boolean forceOverride)
             throws AppSearchException {
         mReadWriteLock.writeLock().lock();
@@ -240,8 +244,9 @@
             SchemaProto.Builder existingSchemaBuilder = getSchemaProtoLocked().toBuilder();
 
             SchemaProto.Builder newSchemaBuilder = SchemaProto.newBuilder();
-            for (AppSearchSchema schema : schemas) {
-                SchemaTypeConfigProto schemaTypeProto = SchemaToProtoConverter.convert(schema);
+            for (int i = 0; i < schemas.size(); i++) {
+                SchemaTypeConfigProto schemaTypeProto =
+                        SchemaToProtoConverter.toSchemaTypeConfigProto(schemas.get(i));
                 newSchemaBuilder.addTypes(schemaTypeProto);
             }
 
@@ -276,8 +281,16 @@
 
             // Update derived data structures.
             mSchemaMapLocked.put(databaseName, rewrittenSchemaResults.mRewrittenQualifiedTypes);
-            mVisibilityStoreLocked.updateSchemas(
-                    databaseName, rewrittenSchemaResults.mDeletedQualifiedTypes);
+
+            String databasePrefix = getDatabasePrefix(databaseName);
+            Set<String> qualifiedSchemasNotPlatformSurfaceable =
+                    new ArraySet<>(schemasNotPlatformSurfaceable.size());
+            for (int i = 0; i < schemasNotPlatformSurfaceable.size(); i++) {
+                qualifiedSchemasNotPlatformSurfaceable.add(
+                        databasePrefix + schemasNotPlatformSurfaceable.get(i));
+            }
+            mVisibilityStoreLocked.setVisibility(
+                    databaseName, qualifiedSchemasNotPlatformSurfaceable);
 
             // Determine whether to schedule an immediate optimize.
             if (setSchemaResultProto.getDeletedSchemaTypesCount() > 0
@@ -294,38 +307,55 @@
     }
 
     /**
-     * Update the visibility settings for this app.
+     * Retrieves the AppSearch schema for this database.
      *
-     * <p>This method belongs to the mutate group
+     * <p>This method belongs to query group.
      *
-     * @param databaseName The name of the database where the visibility settings will apply.
-     * @param schemasHiddenFromPlatformSurfaces Schemas that should be hidden from platform surfaces
-     * @throws AppSearchException on IcingSearchEngine error
+     * @param databaseName The name of the database where this schema lives.
+     * @throws AppSearchException on IcingSearchEngine error.
      */
-    public void setVisibility(
-            @NonNull String databaseName, @NonNull Set<String> schemasHiddenFromPlatformSurfaces)
-            throws AppSearchException {
-        mReadWriteLock.writeLock().lock();
+    @NonNull
+    public List<AppSearchSchema> getSchema(@NonNull String databaseName) throws AppSearchException {
+        SchemaProto fullSchema;
+        mReadWriteLock.readLock().lock();
         try {
-            String databasePrefix = getDatabasePrefix(databaseName);
-            Set<String> qualifiedSchemasHiddenFromPlatformSurface =
-                    new ArraySet<>(schemasHiddenFromPlatformSurfaces.size());
-            for (String schema : schemasHiddenFromPlatformSurfaces) {
-                Set<String> existingSchemas = mSchemaMapLocked.get(databaseName);
-                if (existingSchemas == null || !existingSchemas.contains(databasePrefix + schema)) {
-                    throw new AppSearchException(
-                            AppSearchResult.RESULT_NOT_FOUND,
-                            "Unknown schema(s): "
-                                    + schemasHiddenFromPlatformSurfaces
-                                    + " provided during setVisibility.");
-                }
-                qualifiedSchemasHiddenFromPlatformSurface.add(databasePrefix + schema);
-            }
-            mVisibilityStoreLocked.setVisibility(
-                    databaseName, qualifiedSchemasHiddenFromPlatformSurface);
+            fullSchema = getSchemaProtoLocked();
         } finally {
-            mReadWriteLock.writeLock().lock();
+            mReadWriteLock.readLock().unlock();
         }
+
+        List<AppSearchSchema> result = new ArrayList<>();
+        for (int i = 0; i < fullSchema.getTypesCount(); i++) {
+            String typeDatabase = getDatabaseName(fullSchema.getTypes(i).getSchemaType());
+            if (!databaseName.equals(typeDatabase)) {
+                continue;
+            }
+            // Rewrite SchemaProto.types.schema_type
+            SchemaTypeConfigProto.Builder typeConfigBuilder = fullSchema.getTypes(i).toBuilder();
+            String newSchemaType =
+                    typeConfigBuilder.getSchemaType().substring(databaseName.length() + 1);
+            typeConfigBuilder.setSchemaType(newSchemaType);
+
+            // Rewrite SchemaProto.types.properties.schema_type
+            for (int propertyIdx = 0;
+                    propertyIdx < typeConfigBuilder.getPropertiesCount();
+                    propertyIdx++) {
+                PropertyConfigProto.Builder propertyConfigBuilder =
+                        typeConfigBuilder.getProperties(propertyIdx).toBuilder();
+                if (!propertyConfigBuilder.getSchemaType().isEmpty()) {
+                    String newPropertySchemaType =
+                            propertyConfigBuilder
+                                    .getSchemaType()
+                                    .substring(databaseName.length() + 1);
+                    propertyConfigBuilder.setSchemaType(newPropertySchemaType);
+                    typeConfigBuilder.setProperties(propertyIdx, propertyConfigBuilder);
+                }
+            }
+
+            AppSearchSchema schema = SchemaToProtoConverter.toAppSearchSchema(typeConfigBuilder);
+            result.add(schema);
+        }
+        return result;
     }
 
     /**
@@ -340,7 +370,7 @@
     public void putDocument(@NonNull String databaseName, @NonNull GenericDocument document)
             throws AppSearchException {
         DocumentProto.Builder documentBuilder =
-                GenericDocumentToProtoConverter.convert(document).toBuilder();
+                GenericDocumentToProtoConverter.toDocumentProto(document).toBuilder();
         addPrefixToDocument(documentBuilder, getDatabasePrefix(databaseName));
 
         PutResultProto putResultProto;
@@ -384,7 +414,7 @@
 
         DocumentProto.Builder documentBuilder = getResultProto.getDocument().toBuilder();
         removeDatabasesFromDocument(documentBuilder);
-        return GenericDocumentToProtoConverter.convert(documentBuilder.build());
+        return GenericDocumentToProtoConverter.toGenericDocument(documentBuilder.build());
     }
 
     /**
@@ -969,7 +999,7 @@
                 resultsBuilder.setResults(i, resultBuilder);
             }
         }
-        return SearchResultToProtoConverter.convertToSearchResultPage(resultsBuilder);
+        return SearchResultToProtoConverter.toSearchResultPage(resultsBuilder);
     }
 
     @GuardedBy("mReadWriteLock")
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/VisibilityStore.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/VisibilityStore.java
index 4722822..0b68ebc 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/VisibilityStore.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/VisibilityStore.java
@@ -53,19 +53,23 @@
 class VisibilityStore {
     // Schema type for documents that hold AppSearch's metadata, e.g. visibility settings
     @VisibleForTesting static final String SCHEMA_TYPE = "Visibility";
+
     // Property that holds the list of platform-hidden schemas, as part of the visibility
     // settings.
-    @VisibleForTesting static final String PLATFORM_HIDDEN_PROPERTY = "platformHidden";
+    @VisibleForTesting
+    static final String NOT_PLATFORM_SURFACEABLE_PROPERTY = "notPlatformSurfaceable";
     // Database name to prefix all visibility schemas and documents with. Special-cased to
     // minimize the chance of collision with a client-supplied database.
+
     @VisibleForTesting static final String DATABASE_NAME = "$$__AppSearch__Database";
+
     // Namespace of documents that contain visibility settings
     private static final String NAMESPACE = "namespace";
     private final AppSearchImpl mAppSearchImpl;
 
     // The map contains schemas that are platform-hidden for each database. All schemas in the map
     // have a database name prefix.
-    private final Map<String, Set<String>> mPlatformHiddenMap = new ArrayMap<>();
+    private final Map<String, Set<String>> mNotPlatformSurfaceableMap = new ArrayMap<>();
 
     /**
      * Creates an uninitialized VisibilityStore object. Callers must also call {@link #initialize()}
@@ -82,8 +86,8 @@
      *
      * <p>This is kept separate from the constructor because this will call methods on
      * AppSearchImpl. Some may even then recursively call back into VisibilityStore (for example,
-     * {@link AppSearchImpl#setSchema} will call {@link #updateSchemas}. We need to have both
-     * AppSearchImpl and VisibilityStore fully initialized for this call flow to work.
+     * {@link AppSearchImpl#setSchema} will call {@link #setVisibility(String, Set)}. We need to
+     * have both AppSearchImpl and VisibilityStore fully initialized for this call flow to work.
      *
      * @throws AppSearchException AppSearchException on AppSearchImpl error.
      */
@@ -92,11 +96,11 @@
             // Schema type doesn't exist yet. Add it.
             mAppSearchImpl.setSchema(
                     DATABASE_NAME,
-                    Collections.singleton(
+                    Collections.singletonList(
                             new AppSearchSchema.Builder(SCHEMA_TYPE)
                                     .addProperty(
                                             new AppSearchSchema.PropertyConfig.Builder(
-                                                            PLATFORM_HIDDEN_PROPERTY)
+                                                            NOT_PLATFORM_SURFACEABLE_PROPERTY)
                                                     .setDataType(
                                                             AppSearchSchema.PropertyConfig
                                                                     .DATA_TYPE_STRING)
@@ -105,6 +109,7 @@
                                                                     .CARDINALITY_REPEATED)
                                                     .build())
                                     .build()),
+                    /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
                     /*forceOverride=*/ false);
         }
 
@@ -120,8 +125,9 @@
                 GenericDocument document =
                         mAppSearchImpl.getDocument(DATABASE_NAME, NAMESPACE, /*uri=*/ database);
 
-                String[] schemas = document.getPropertyStringArray(PLATFORM_HIDDEN_PROPERTY);
-                mPlatformHiddenMap.put(database, new ArraySet<>(Arrays.asList(schemas)));
+                String[] schemas =
+                        document.getPropertyStringArray(NOT_PLATFORM_SURFACEABLE_PROPERTY);
+                mNotPlatformSurfaceableMap.put(database, new ArraySet<>(Arrays.asList(schemas)));
             } catch (AppSearchException e) {
                 if (e.getResultCode() == AppSearchResult.RESULT_NOT_FOUND) {
                     // TODO(b/172068212): This indicates some desync error. We were expecting a
@@ -136,94 +142,33 @@
     }
 
     /**
-     * Update visibility settings for the {@code databaseName}.
-     *
-     * @param schemasToRemove Database-prefixed schemas that should be removed
-     */
-    public void updateSchemas(@NonNull String databaseName, @NonNull Set<String> schemasToRemove)
-            throws AppSearchException {
-        Preconditions.checkNotNull(databaseName);
-        Preconditions.checkNotNull(schemasToRemove);
-
-        GenericDocument visibilityDocument;
-        try {
-            visibilityDocument =
-                    mAppSearchImpl.getDocument(DATABASE_NAME, NAMESPACE, /*uri=*/ databaseName);
-        } catch (AppSearchException e) {
-            if (e.getResultCode() == AppSearchResult.RESULT_NOT_FOUND) {
-                // This might be the first time we're seeing visibility changes for a database.
-                // Create a new visibility document.
-                mAppSearchImpl.putDocument(
-                        DATABASE_NAME,
-                        new GenericDocument.Builder(/*uri=*/ databaseName, SCHEMA_TYPE)
-                                .setNamespace(NAMESPACE)
-                                .build());
-
-                // Since we know there was nothing that existed before, we don't need to remove
-                // anything either. Return early.
-                return;
-            }
-            // Otherwise, this is some real error we should pass up.
-            throw e;
-        }
-
-        String[] hiddenSchemas =
-                visibilityDocument.getPropertyStringArray(PLATFORM_HIDDEN_PROPERTY);
-        if (hiddenSchemas == null) {
-            // Nothing to remove.
-            return;
-        }
-
-        // Create a new set so we can remove from it.
-        Set<String> remainingSchemas = new ArraySet<>(Arrays.asList(hiddenSchemas));
-        boolean changed = remainingSchemas.removeAll(schemasToRemove);
-        if (!changed) {
-            // Nothing was actually removed. Can return early.
-            return;
-        }
-
-        // Update our persisted document
-        // TODO(b/171882200): Switch to a .toBuilder API when it's available.
-        GenericDocument.Builder newVisibilityDocument =
-                new GenericDocument.Builder(/*uri=*/ databaseName, SCHEMA_TYPE)
-                        .setNamespace(NAMESPACE);
-        if (!remainingSchemas.isEmpty()) {
-            newVisibilityDocument.setPropertyString(
-                    PLATFORM_HIDDEN_PROPERTY, remainingSchemas.toArray(new String[0]));
-        }
-        mAppSearchImpl.putDocument(DATABASE_NAME, newVisibilityDocument.build());
-
-        // Update derived data structures
-        mPlatformHiddenMap.put(databaseName, remainingSchemas);
-    }
-
-    /**
      * Sets visibility settings for {@code databaseName}. Any previous visibility settings will be
      * overwritten.
      *
-     * @param databaseName Database name that owns the {@code platformHiddenSchemas}.
-     * @param platformHiddenSchemas Set of database-qualified schemas that should be hidden from the
-     *     platform.
+     * @param databaseName Database name that owns the {@code schemasNotPlatformSurfaceable}.
+     * @param schemasNotPlatformSurfaceable Set of database-qualified schemas that should be hidden
+     *     from the platform.
      * @throws AppSearchException on AppSearchImpl error.
      */
     public void setVisibility(
-            @NonNull String databaseName, @NonNull Set<String> platformHiddenSchemas)
+            @NonNull String databaseName, @NonNull Set<String> schemasNotPlatformSurfaceable)
             throws AppSearchException {
         Preconditions.checkNotNull(databaseName);
-        Preconditions.checkNotNull(platformHiddenSchemas);
+        Preconditions.checkNotNull(schemasNotPlatformSurfaceable);
 
         // Persist the document
         GenericDocument.Builder visibilityDocument =
                 new GenericDocument.Builder(/*uri=*/ databaseName, SCHEMA_TYPE)
                         .setNamespace(NAMESPACE);
-        if (!platformHiddenSchemas.isEmpty()) {
+        if (!schemasNotPlatformSurfaceable.isEmpty()) {
             visibilityDocument.setPropertyString(
-                    PLATFORM_HIDDEN_PROPERTY, platformHiddenSchemas.toArray(new String[0]));
+                    NOT_PLATFORM_SURFACEABLE_PROPERTY,
+                    schemasNotPlatformSurfaceable.toArray(new String[0]));
         }
         mAppSearchImpl.putDocument(DATABASE_NAME, visibilityDocument.build());
 
         // Update derived data structures.
-        mPlatformHiddenMap.put(databaseName, platformHiddenSchemas);
+        mNotPlatformSurfaceableMap.put(databaseName, schemasNotPlatformSurfaceable);
     }
 
     /**
@@ -235,13 +180,13 @@
      *     none exist.
      */
     @NonNull
-    public Set<String> getPlatformHiddenSchemas(@NonNull String databaseName) {
+    public Set<String> getSchemasNotPlatformSurfaceable(@NonNull String databaseName) {
         Preconditions.checkNotNull(databaseName);
-        Set<String> platformHiddenSchemas = mPlatformHiddenMap.get(databaseName);
-        if (platformHiddenSchemas == null) {
+        Set<String> schemasNotPlatformSurfaceable = mNotPlatformSurfaceableMap.get(databaseName);
+        if (schemasNotPlatformSurfaceable == null) {
             return Collections.emptySet();
         }
-        return platformHiddenSchemas;
+        return schemasNotPlatformSurfaceable;
     }
 
     /**
@@ -251,7 +196,7 @@
      * @throws AppSearchException on AppSearchImpl error.
      */
     public void handleReset() throws AppSearchException {
-        mPlatformHiddenMap.clear();
+        mNotPlatformSurfaceableMap.clear();
         initialize();
     }
 }
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java
index 8f4e7ff6..5474cd0 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverter.java
@@ -39,7 +39,7 @@
     /** Converts a {@link GenericDocument} into a {@link DocumentProto}. */
     @NonNull
     @SuppressWarnings("unchecked")
-    public static DocumentProto convert(@NonNull GenericDocument document) {
+    public static DocumentProto toDocumentProto(@NonNull GenericDocument document) {
         Preconditions.checkNotNull(document);
         DocumentProto.Builder mProtoBuilder = DocumentProto.newBuilder();
         mProtoBuilder
@@ -82,7 +82,7 @@
                 }
             } else if (documentValues != null) {
                 for (int j = 0; j < documentValues.length; j++) {
-                    DocumentProto proto = convert(documentValues[j]);
+                    DocumentProto proto = toDocumentProto(documentValues[j]);
                     propertyProto.addDocumentValues(proto);
                 }
             } else {
@@ -96,7 +96,7 @@
 
     /** Converts a {@link DocumentProto} into a {@link GenericDocument}. */
     @NonNull
-    public static GenericDocument convert(@NonNull DocumentProto proto) {
+    public static GenericDocument toGenericDocument(@NonNull DocumentProto proto) {
         Preconditions.checkNotNull(proto);
         GenericDocument.Builder<?> documentBuilder =
                 new GenericDocument.Builder<>(proto.getUri(), proto.getSchema())
@@ -141,7 +141,7 @@
             } else if (property.getDocumentValuesCount() > 0) {
                 GenericDocument[] values = new GenericDocument[property.getDocumentValuesCount()];
                 for (int j = 0; j < values.length; j++) {
-                    values[j] = convert(property.getDocumentValues(j));
+                    values[j] = toGenericDocument(property.getDocumentValues(j));
                 }
                 documentBuilder.setPropertyDocument(name, values);
             } else {
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverter.java
index 642c2a7..4165af3 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverter.java
@@ -18,11 +18,13 @@
 
 import android.annotation.NonNull;
 import android.app.appsearch.AppSearchSchema;
+import android.util.Log;
 
 import com.android.internal.util.Preconditions;
 
 import com.google.android.icing.proto.PropertyConfigProto;
 import com.google.android.icing.proto.SchemaTypeConfigProto;
+import com.google.android.icing.proto.SchemaTypeConfigProtoOrBuilder;
 import com.google.android.icing.proto.StringIndexingConfig;
 import com.google.android.icing.proto.TermMatchType;
 
@@ -34,6 +36,8 @@
  * @hide
  */
 public final class SchemaToProtoConverter {
+    private static final String TAG = "AppSearchSchemaToProtoC";
+
     private SchemaToProtoConverter() {}
 
     /**
@@ -41,23 +45,23 @@
      * SchemaTypeConfigProto}.
      */
     @NonNull
-    public static SchemaTypeConfigProto convert(@NonNull AppSearchSchema schema) {
+    public static SchemaTypeConfigProto toSchemaTypeConfigProto(@NonNull AppSearchSchema schema) {
         Preconditions.checkNotNull(schema);
         SchemaTypeConfigProto.Builder protoBuilder =
                 SchemaTypeConfigProto.newBuilder().setSchemaType(schema.getSchemaType());
         List<AppSearchSchema.PropertyConfig> properties = schema.getProperties();
         for (int i = 0; i < properties.size(); i++) {
-            PropertyConfigProto propertyProto = convertProperty(properties.get(i));
+            PropertyConfigProto propertyProto = toPropertyConfigProto(properties.get(i));
             protoBuilder.addProperties(propertyProto);
         }
         return protoBuilder.build();
     }
 
     @NonNull
-    private static PropertyConfigProto convertProperty(
+    private static PropertyConfigProto toPropertyConfigProto(
             @NonNull AppSearchSchema.PropertyConfig property) {
         Preconditions.checkNotNull(property);
-        PropertyConfigProto.Builder propertyConfigProto =
+        PropertyConfigProto.Builder builder =
                 PropertyConfigProto.newBuilder().setPropertyName(property.getName());
         StringIndexingConfig.Builder indexingConfig = StringIndexingConfig.newBuilder();
 
@@ -68,12 +72,12 @@
         if (dataTypeProto == null) {
             throw new IllegalArgumentException("Invalid dataType: " + dataType);
         }
-        propertyConfigProto.setDataType(dataTypeProto);
+        builder.setDataType(dataTypeProto);
 
         // Set schemaType
         String schemaType = property.getSchemaType();
         if (schemaType != null) {
-            propertyConfigProto.setSchemaType(schemaType);
+            builder.setSchemaType(schemaType);
         }
 
         // Set cardinality
@@ -83,7 +87,7 @@
         if (cardinalityProto == null) {
             throw new IllegalArgumentException("Invalid cardinality: " + dataType);
         }
-        propertyConfigProto.setCardinality(cardinalityProto);
+        builder.setCardinality(cardinalityProto);
 
         // Set indexingType
         @AppSearchSchema.PropertyConfig.IndexingType int indexingType = property.getIndexingType();
@@ -114,7 +118,63 @@
         indexingConfig.setTokenizerType(tokenizerTypeProto);
 
         // Build!
-        propertyConfigProto.setStringIndexingConfig(indexingConfig);
-        return propertyConfigProto.build();
+        builder.setStringIndexingConfig(indexingConfig);
+        return builder.build();
+    }
+
+    /**
+     * Converts a {@link SchemaTypeConfigProto} into an {@link
+     * android.app.appsearch.AppSearchSchema}.
+     */
+    @NonNull
+    public static AppSearchSchema toAppSearchSchema(@NonNull SchemaTypeConfigProtoOrBuilder proto) {
+        Preconditions.checkNotNull(proto);
+        AppSearchSchema.Builder builder = new AppSearchSchema.Builder(proto.getSchemaType());
+        List<PropertyConfigProto> properties = proto.getPropertiesList();
+        for (int i = 0; i < properties.size(); i++) {
+            AppSearchSchema.PropertyConfig propertyConfig = toPropertyConfig(properties.get(i));
+            builder.addProperty(propertyConfig);
+        }
+        return builder.build();
+    }
+
+    @NonNull
+    private static AppSearchSchema.PropertyConfig toPropertyConfig(
+            @NonNull PropertyConfigProto proto) {
+        Preconditions.checkNotNull(proto);
+        AppSearchSchema.PropertyConfig.Builder builder =
+                new AppSearchSchema.PropertyConfig.Builder(proto.getPropertyName())
+                        .setDataType(proto.getDataType().getNumber())
+                        .setCardinality(proto.getCardinality().getNumber())
+                        .setTokenizerType(
+                                proto.getStringIndexingConfig().getTokenizerType().getNumber());
+
+        // Set schema
+        if (!proto.getSchemaType().isEmpty()) {
+            builder.setSchemaType(proto.getSchemaType());
+        }
+
+        // Set indexingType
+        @AppSearchSchema.PropertyConfig.IndexingType int indexingType;
+        TermMatchType.Code termMatchTypeProto = proto.getStringIndexingConfig().getTermMatchType();
+        switch (termMatchTypeProto) {
+            case UNKNOWN:
+                indexingType = AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE;
+                break;
+            case EXACT_ONLY:
+                indexingType = AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS;
+                break;
+            case PREFIX:
+                indexingType = AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES;
+                break;
+            default:
+                // Avoid crashing in the 'read' path; we should try to interpret the document to the
+                // extent possible.
+                Log.w(TAG, "Invalid indexingType: " + termMatchTypeProto.getNumber());
+                indexingType = AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE;
+        }
+        builder.setIndexingType(indexingType);
+
+        return builder.build();
     }
 }
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
index b91a393..4d107a9 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
@@ -39,13 +39,12 @@
 
     /** Translate a {@link SearchResultProto} into {@link SearchResultPage}. */
     @NonNull
-    public static SearchResultPage convertToSearchResultPage(
-            @NonNull SearchResultProtoOrBuilder proto) {
+    public static SearchResultPage toSearchResultPage(@NonNull SearchResultProtoOrBuilder proto) {
         Bundle bundle = new Bundle();
         bundle.putLong(SearchResultPage.NEXT_PAGE_TOKEN_FIELD, proto.getNextPageToken());
         ArrayList<Bundle> resultBundles = new ArrayList<>(proto.getResultsCount());
         for (int i = 0; i < proto.getResultsCount(); i++) {
-            resultBundles.add(convertToSearchResultBundle(proto.getResults(i)));
+            resultBundles.add(toSearchResultBundle(proto.getResults(i)));
         }
         bundle.putParcelableArrayList(SearchResultPage.RESULTS_FIELD, resultBundles);
         return new SearchResultPage(bundle);
@@ -53,10 +52,11 @@
 
     /** Translate a {@link SearchResultProto.ResultProto} into {@link SearchResult}. */
     @NonNull
-    private static Bundle convertToSearchResultBundle(
+    private static Bundle toSearchResultBundle(
             @NonNull SearchResultProto.ResultProtoOrBuilder proto) {
         Bundle bundle = new Bundle();
-        GenericDocument document = GenericDocumentToProtoConverter.convert(proto.getDocument());
+        GenericDocument document =
+                GenericDocumentToProtoConverter.toGenericDocument(proto.getDocument());
         bundle.putBundle(SearchResult.DOCUMENT_FIELD, document.getBundle());
 
         ArrayList<Bundle> matchList = new ArrayList<>();
diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt
index a2bf0d5..57c48d8 100644
--- a/apex/appsearch/synced_jetpack_changeid.txt
+++ b/apex/appsearch/synced_jetpack_changeid.txt
@@ -1 +1 @@
-I2decd83fab4c4d58fe38c9970f804046479c942c
+If5fd2bd705d5507d044706701a94b2e1496ef1df
diff --git a/apex/jobscheduler/OWNERS b/apex/jobscheduler/OWNERS
index d004eed..0fe6cdf 100644
--- a/apex/jobscheduler/OWNERS
+++ b/apex/jobscheduler/OWNERS
@@ -1,6 +1,6 @@
 yamasani@google.com
 omakoto@google.com
-ctate@android.com
+ctate@google.com
 ctate@google.com
 kwekua@google.com
 suprabh@google.com
\ No newline at end of file
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index 3597c27..d16217d 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -274,13 +274,20 @@
 
     /**
      * This job needs to be exempted from the app standby throttling. Only the system (UID 1000)
-     * can set it. Jobs with a time constrant must not have it.
+     * can set it. Jobs with a time constraint must not have it.
      *
      * @hide
      */
     public static final int FLAG_EXEMPT_FROM_APP_STANDBY = 1 << 3;
 
     /**
+     * Whether it's a so-called "HPJ" or not.
+     *
+     * @hide
+     */
+    public static final int FLAG_FOREGROUND_JOB = 1 << 4;
+
+    /**
      * @hide
      */
     public static final int CONSTRAINT_FLAG_CHARGING = 1 << 0;
@@ -571,6 +578,7 @@
 
     /**
      * Return the backoff policy of this job.
+     *
      * @see JobInfo.Builder#setBackoffCriteria(long, int)
      */
     public @BackoffPolicy int getBackoffPolicy() {
@@ -578,6 +586,13 @@
     }
 
     /**
+     * @see JobInfo.Builder#setForeground(boolean)
+     */
+    public boolean isForegroundJob() {
+        return (flags & FLAG_FOREGROUND_JOB) != 0;
+    }
+
+    /**
      * @see JobInfo.Builder#setImportantWhileForeground(boolean)
      */
     public boolean isImportantWhileForeground() {
@@ -1442,6 +1457,41 @@
         }
 
         /**
+         * Setting this to true indicates that this job is important and needs to run as soon as
+         * possible with stronger guarantees than regular jobs. These "foreground" jobs will:
+         * <ol>
+         *     <li>Run as soon as possible</li>
+         *     <li>Be exempted from Doze and battery saver restrictions</li>
+         *     <li>Have network access</li>
+         * </ol>
+         *
+         * Since these jobs have stronger guarantees than regular jobs, they will be subject to
+         * stricter quotas. As long as an app has available foreground quota, jobs scheduled with
+         * this set to true will run with these guarantees. If an app has run out of available
+         * foreground quota, any pending foreground jobs will run as regular jobs.
+         * {@link JobParameters#isForegroundJob()} can be used to know whether the executing job
+         * has foreground guarantees or not. In addition, {@link JobScheduler#schedule(JobInfo)}
+         * will immediately return {@link JobScheduler#RESULT_FAILURE} if the app does not have
+         * available quota (and the job will not be successfully scheduled).
+         *
+         * Foreground jobs may only set network constraints. No other constraints are allowed.
+         *
+         * Note: Even though foreground jobs are meant to run as soon as possible, they may be
+         * deferred if the system is under heavy load or the network constraint is satisfied
+         *
+         * @see JobInfo#isForegroundJob()
+         */
+        @NonNull
+        public Builder setForeground(boolean foreground) {
+            if (foreground) {
+                mFlags |= FLAG_FOREGROUND_JOB;
+            } else {
+                mFlags &= (~FLAG_FOREGROUND_JOB);
+            }
+            return this;
+        }
+
+        /**
          * Setting this to true indicates that this job is important while the scheduling app
          * is in the foreground or on the temporary whitelist for background restrictions.
          * This means that the system will relax doze restrictions on this job during this time.
@@ -1456,7 +1506,9 @@
          * @param importantWhileForeground whether to relax doze restrictions for this job when the
          *                                 app is in the foreground. False by default.
          * @see JobInfo#isImportantWhileForeground()
+         * @deprecated Use {@link #setForeground(boolean)} instead.
          */
+        @Deprecated
         public Builder setImportantWhileForeground(boolean importantWhileForeground) {
             if (importantWhileForeground) {
                 mFlags |= FLAG_IMPORTANT_WHILE_FOREGROUND;
@@ -1580,6 +1632,29 @@
             throw new IllegalArgumentException(
                     "An important while foreground job cannot have a time delay");
         }
+
+        if ((flags & FLAG_FOREGROUND_JOB) != 0) {
+            if (hasEarlyConstraint) {
+                throw new IllegalArgumentException("A foreground job cannot have a time delay");
+            }
+            if (hasLateConstraint) {
+                throw new IllegalArgumentException("A foreground job cannot have a deadline");
+            }
+            if (isPeriodic) {
+                throw new IllegalArgumentException("A foreground job cannot be periodic");
+            }
+            if (isPersisted) {
+                throw new IllegalArgumentException("A foreground job cannot be persisted");
+            }
+            if (constraintFlags != 0 || (flags & ~FLAG_FOREGROUND_JOB) != 0) {
+                throw new IllegalArgumentException(
+                        "A foreground job can only have network constraints");
+            }
+            if (triggerContentUris != null && triggerContentUris.length > 0) {
+                throw new IllegalArgumentException(
+                        "Can't call addTriggerContentUri() on a foreground job");
+            }
+        }
     }
 
     /**
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
index e251ff0..a71b856 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
@@ -111,6 +111,9 @@
     @UnsupportedAppUsage
     private final IBinder callback;
     private final boolean overrideDeadlineExpired;
+    // HPJs = foreground jobs.
+    // TODO(171305774): clean up naming
+    private final boolean mIsHpj;
     private final Uri[] mTriggeredContentUris;
     private final String[] mTriggeredContentAuthorities;
     private final Network network;
@@ -121,7 +124,7 @@
     /** @hide */
     public JobParameters(IBinder callback, int jobId, PersistableBundle extras,
             Bundle transientExtras, ClipData clipData, int clipGrantFlags,
-            boolean overrideDeadlineExpired, Uri[] triggeredContentUris,
+            boolean overrideDeadlineExpired, boolean isHpj, Uri[] triggeredContentUris,
             String[] triggeredContentAuthorities, Network network) {
         this.jobId = jobId;
         this.extras = extras;
@@ -130,6 +133,7 @@
         this.clipGrantFlags = clipGrantFlags;
         this.callback = callback;
         this.overrideDeadlineExpired = overrideDeadlineExpired;
+        this.mIsHpj = isHpj;
         this.mTriggeredContentUris = triggeredContentUris;
         this.mTriggeredContentAuthorities = triggeredContentAuthorities;
         this.network = network;
@@ -195,6 +199,17 @@
     }
 
     /**
+     * @return Whether this job is running as a foreground job or not. A job is guaranteed to have
+     * all foreground job guarantees for the duration of the job execution if this returns
+     * {@code true}. This will return {@code false} if the job that wasn't requested to run as a
+     * foreground job, or if it was requested to run as a foreground job but the app didn't have
+     * any remaining foreground job quota at the time of execution.
+     */
+    public boolean isForegroundJob() {
+        return mIsHpj;
+    }
+
+    /**
      * For jobs with {@link android.app.job.JobInfo.Builder#setOverrideDeadline(long)} set, this
      * provides an easy way to tell whether the job is being executed due to the deadline
      * expiring. Note: If the job is running because its deadline expired, it implies that its
@@ -337,6 +352,7 @@
         }
         callback = in.readStrongBinder();
         overrideDeadlineExpired = in.readInt() == 1;
+        mIsHpj = in.readBoolean();
         mTriggeredContentUris = in.createTypedArray(Uri.CREATOR);
         mTriggeredContentAuthorities = in.createStringArray();
         if (in.readInt() != 0) {
@@ -373,6 +389,7 @@
         }
         dest.writeStrongBinder(callback);
         dest.writeInt(overrideDeadlineExpired ? 1 : 0);
+        dest.writeBoolean(mIsHpj);
         dest.writeTypedArray(mTriggeredContentUris, flags);
         dest.writeStringArray(mTriggeredContentAuthorities);
         if (network != null) {
diff --git a/apex/jobscheduler/framework/java/android/app/job/OWNERS b/apex/jobscheduler/framework/java/android/app/job/OWNERS
new file mode 100644
index 0000000..b4a45f5
--- /dev/null
+++ b/apex/jobscheduler/framework/java/android/app/job/OWNERS
@@ -0,0 +1,7 @@
+# Bug component: 330738
+
+yamasani@google.com
+omakoto@google.com
+ctate@android.com
+ctate@google.com
+kwekua@google.com
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index b35a7be..0feaade 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -205,7 +205,9 @@
     }
 
     private boolean isFgJob(JobStatus job) {
-        return job.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP;
+        // (It's super confusing PRIORITY_BOUND_FOREGROUND_SERVICE isn't FG here)
+        return job.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP
+                || job.shouldTreatAsForegroundJob();
     }
 
     @GuardedBy("mLock")
@@ -336,6 +338,8 @@
                 continue;
             }
 
+            // TODO(171305774): make sure HPJs aren't pre-empted and add dedicated contexts for them
+
             final boolean isPendingFg = isFgJob(nextPending);
 
             // Find an available slot for nextPending. The context should be available OR
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 255e2f6..99a9b979 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -834,6 +834,13 @@
             // Higher override state (OVERRIDE_FULL) should be before lower state (OVERRIDE_SOFT)
             return o2.overrideState - o1.overrideState;
         }
+        if (o1.getSourceUid() == o2.getSourceUid()) {
+            final boolean o1FGJ = o1.isRequestedForegroundJob();
+            if (o1FGJ != o2.isRequestedForegroundJob()) {
+                // Attempt to run requested HPJs ahead of regular jobs, regardless of HPJ quota.
+                return o1FGJ ? -1 : 1;
+            }
+        }
         if (o1.enqueueTime < o2.enqueueTime) {
             return -1;
         }
@@ -1136,6 +1143,12 @@
 
             JobStatus jobStatus = JobStatus.createFromJobInfo(job, uId, packageName, userId, tag);
 
+            // Return failure early if HPJ quota used up.
+            if (jobStatus.isRequestedForegroundJob()
+                    && !mQuotaController.isWithinHpjQuotaLocked(jobStatus)) {
+                return JobScheduler.RESULT_FAILURE;
+            }
+
             // Give exemption if the source is in the foreground just now.
             // Note if it's a sync job, this method is called on the handler so it's not exactly
             // the state when requestSync() was called, but that should be fine because of the
@@ -1791,9 +1804,9 @@
      * time of the job to be the time of completion (i.e. the time at which this function is
      * called).
      * <p>This could be inaccurate b/c the job can run for as long as
-     * {@link com.android.server.job.JobServiceContext#EXECUTING_TIMESLICE_MILLIS}, but will lead
-     * to underscheduling at least, rather than if we had taken the last execution time to be the
-     * start of the execution.
+     * {@link com.android.server.job.JobServiceContext#DEFAULT_EXECUTING_TIMESLICE_MILLIS}, but
+     * will lead to underscheduling at least, rather than if we had taken the last execution time
+     * to be the start of the execution.
      *
      * @return A new job representing the execution criteria for this instantiation of the
      * recurring job.
@@ -1884,6 +1897,10 @@
             Slog.d(TAG, "Completed " + jobStatus + ", reschedule=" + needsReschedule);
         }
 
+        // Intentionally not checking HPJ quota here. An app can't find out if it's run out of quota
+        // when it asks JS to reschedule an HPJ. Instead, the rescheduled HPJ will just be demoted
+        // to a regular job if the app has no HPJ quota left.
+
         // If the job wants to be rescheduled, we first need to make the next upcoming
         // job so we can transfer any appropriate state over from the previous job when
         // we stop it.
@@ -2027,7 +2044,6 @@
 
                 }
                 maybeRunPendingJobsLocked();
-                // Don't remove JOB_EXPIRED in case one came along while processing the queue.
             }
         }
     }
@@ -2093,6 +2109,15 @@
      * as many as we can.
      */
     private void queueReadyJobsForExecutionLocked() {
+        // This method will check and capture all ready jobs, so we don't need to keep any messages
+        // in the queue.
+        mHandler.removeMessages(MSG_CHECK_JOB_GREEDY);
+        // MSG_CHECK_JOB is a weaker form of _GREEDY. Since we're checking and queueing all ready
+        // jobs, we don't need to keep any MSG_CHECK_JOB messages in the queue.
+        mHandler.removeMessages(MSG_CHECK_JOB);
+        // This method will capture all expired jobs that are ready, so there's no need to keep
+        // the _EXPIRED messages in the queue.
+        mHandler.removeMessages(MSG_JOB_EXPIRED);
         if (DEBUG) {
             Slog.d(TAG, "queuing all ready jobs for execution:");
         }
@@ -2382,7 +2407,7 @@
     public long getMaxJobExecutionTimeMs(JobStatus job) {
         synchronized (mLock) {
             return Math.min(mQuotaController.getMaxJobExecutionTimeMsLocked(job),
-                    JobServiceContext.EXECUTING_TIMESLICE_MILLIS);
+                    JobServiceContext.DEFAULT_EXECUTING_TIMESLICE_MILLIS);
         }
     }
 
@@ -2600,7 +2625,6 @@
         // job that runs one of the app's services, as well as verifying that the
         // named service properly requires the BIND_JOB_SERVICE permission
         private void enforceValidJobRequest(int uid, JobInfo job) {
-            job.enforceValidity();
             final PackageManager pm = getContext()
                     .createContextAsUser(UserHandle.getUserHandleForUid(uid), 0)
                     .getPackageManager();
@@ -2649,6 +2673,7 @@
         }
 
         private void validateJobFlags(JobInfo job, int callingUid) {
+            job.enforceValidity();
             if ((job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0) {
                 getContext().enforceCallingOrSelfPermission(
                         android.Manifest.permission.CONNECTIVITY_INTERNAL, TAG);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index 565ed95..5fed199 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -16,6 +16,7 @@
 
 package com.android.server.job;
 
+import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
 import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
 
 import android.app.job.IJobCallback;
@@ -73,7 +74,13 @@
 
     private static final String TAG = "JobServiceContext";
     /** Amount of time a job is allowed to execute for before being considered timed-out. */
-    public static final long EXECUTING_TIMESLICE_MILLIS = 10 * 60 * 1000;  // 10mins.
+    public static final long DEFAULT_EXECUTING_TIMESLICE_MILLIS = 10 * 60 * 1000;  // 10mins.
+    /**
+     * Amount of time a RESTRICTED HPJ is allowed to execute for before being considered
+     * timed-out.
+     */
+    public static final long DEFAULT_RESTRICTED_HPJ_EXECUTING_TIMESLICE_MILLIS =
+            DEFAULT_EXECUTING_TIMESLICE_MILLIS / 2;
     /** Amount of time the JobScheduler waits for the initial service launch+bind. */
     private static final long OP_BIND_TIMEOUT_MILLIS = 18 * 1000;
     /** Amount of time the JobScheduler will wait for a response from an app for a message. */
@@ -224,7 +231,8 @@
             final JobInfo ji = job.getJob();
             mParams = new JobParameters(mRunningCallback, job.getJobId(), ji.getExtras(),
                     ji.getTransientExtras(), ji.getClipData(), ji.getClipGrantFlags(),
-                    isDeadlineExpired, triggeredUris, triggeredAuthorities, job.network);
+                    isDeadlineExpired, job.shouldTreatAsForegroundJob(),
+                    triggeredUris, triggeredAuthorities, job.network);
             mExecutionStartTimeElapsed = sElapsedRealtimeClock.millis();
 
             final long whenDeferred = job.getWhenStandbyDeferred();
@@ -250,9 +258,18 @@
             final Intent intent = new Intent().setComponent(job.getServiceComponent());
             boolean binding = false;
             try {
-                binding = mContext.bindServiceAsUser(intent, this,
-                        Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
-                        | Context.BIND_NOT_PERCEPTIBLE,
+                final int bindFlags;
+                if (job.shouldTreatAsForegroundJob()) {
+                    // Add BIND_FOREGROUND_SERVICE to make it BFGS. Without it, it'll be
+                    // PROCESS_STATE_IMPORTANT_FOREGROUND. Unclear which is better here.
+                    // TODO(171305774): The job should run on the little cores. We'll probably need
+                    // another binding flag for that.
+                    bindFlags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
+                } else {
+                    bindFlags = Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
+                            | Context.BIND_NOT_PERCEPTIBLE;
+                }
+                binding = mContext.bindServiceAsUser(intent, this, bindFlags,
                         UserHandle.of(job.getUserId()));
             } catch (SecurityException e) {
                 // Some permission policy, for example INTERACT_ACROSS_USERS and
@@ -848,7 +865,10 @@
         final long timeoutMillis;
         switch (mVerb) {
             case VERB_EXECUTING:
-                timeoutMillis = EXECUTING_TIMESLICE_MILLIS;
+                timeoutMillis = mRunningJob.shouldTreatAsForegroundJob()
+                        && mRunningJob.getStandbyBucket() == RESTRICTED_INDEX
+                        ? DEFAULT_RESTRICTED_HPJ_EXECUTING_TIMESLICE_MILLIS
+                        : DEFAULT_EXECUTING_TIMESLICE_MILLIS;
                 break;
 
             case VERB_BINDING:
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 8f6c68d..5ec1b89 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
@@ -85,6 +85,7 @@
     static final int CONSTRAINT_CONTENT_TRIGGER = 1<<26;
     static final int CONSTRAINT_DEVICE_NOT_DOZING = 1 << 25; // Implicit constraint
     static final int CONSTRAINT_WITHIN_QUOTA = 1 << 24;      // Implicit constraint
+    static final int CONSTRAINT_WITHIN_HPJ_QUOTA = 1 << 23;  // Implicit constraint
     static final int CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 1 << 22; // Implicit constraint
 
     /**
@@ -376,6 +377,9 @@
     /** The job is within its quota based on its standby bucket. */
     private boolean mReadyWithinQuota;
 
+    /** The job is a foreground job with sufficient quota to run as a foreground job. */
+    private boolean mReadyWithinHpjQuota;
+
     /** The job's dynamic requirements have been satisfied. */
     private boolean mReadyDynamicSatisfied;
 
@@ -1036,20 +1040,34 @@
         mPersistedUtcTimes = null;
     }
 
+    /** @return true if the app has requested that this run as a foreground job. */
+    public boolean isRequestedForegroundJob() {
+        return (getFlags() & JobInfo.FLAG_FOREGROUND_JOB) != 0;
+    }
+
+    /**
+     * @return true if all foreground job requirements are satisfied and therefore this should be
+     * treated as a foreground job.
+     */
+    public boolean shouldTreatAsForegroundJob() {
+        return mReadyWithinHpjQuota && isRequestedForegroundJob();
+    }
+
     /**
      * @return true if the job is exempted from Doze restrictions and therefore allowed to run
      * in Doze.
      */
     public boolean canRunInDoze() {
-        return (getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
+        return (getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0 || shouldTreatAsForegroundJob();
     }
 
     boolean canRunInBatterySaver() {
-        return (getInternalFlags() & INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION) != 0;
+        return (getInternalFlags() & INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION) != 0
+                || shouldTreatAsForegroundJob();
     }
 
     boolean shouldIgnoreNetworkBlocking() {
-        return (getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
+        return (getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0 || shouldTreatAsForegroundJob();
     }
 
     /** @return true if the constraint was changed, false otherwise. */
@@ -1128,6 +1146,16 @@
         return false;
     }
 
+    /** @return true if the constraint was changed, false otherwise. */
+    boolean setForegroundJobQuotaConstraintSatisfied(boolean state) {
+        if (setConstraintSatisfied(CONSTRAINT_WITHIN_HPJ_QUOTA, state)) {
+            // The constraint was changed. Update the ready flag.
+            mReadyWithinHpjQuota = state;
+            return true;
+        }
+        return false;
+    }
+
     /** @return true if the state was changed, false otherwise. */
     boolean setUidActive(final boolean newActiveState) {
         if (newActiveState != uidActive) {
@@ -1257,6 +1285,10 @@
                 oldValue = mReadyWithinQuota;
                 mReadyWithinQuota = true;
                 break;
+            case CONSTRAINT_WITHIN_HPJ_QUOTA:
+                oldValue = mReadyWithinHpjQuota;
+                mReadyWithinHpjQuota = true;
+                break;
             default:
                 satisfied |= constraint;
                 mReadyDynamicSatisfied = mDynamicConstraints != 0
@@ -1279,6 +1311,9 @@
             case CONSTRAINT_WITHIN_QUOTA:
                 mReadyWithinQuota = oldValue;
                 break;
+            case CONSTRAINT_WITHIN_HPJ_QUOTA:
+                mReadyWithinHpjQuota = oldValue;
+                break;
             default:
                 mReadyDynamicSatisfied = mDynamicConstraints != 0
                         && mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints);
@@ -1293,7 +1328,7 @@
         // sessions (exempt from dynamic restrictions), we need the additional check to ensure
         // that NEVER jobs don't run.
         // TODO: cleanup quota and standby bucket management so we don't need the additional checks
-        if ((!mReadyWithinQuota && !mReadyDynamicSatisfied)
+        if ((!mReadyWithinQuota && !mReadyDynamicSatisfied && !shouldTreatAsForegroundJob())
                 || getEffectiveStandbyBucket() == NEVER_INDEX) {
             return false;
         }
@@ -1506,6 +1541,9 @@
         if ((constraints & CONSTRAINT_WITHIN_QUOTA) != 0) {
             pw.print(" WITHIN_QUOTA");
         }
+        if ((constraints & CONSTRAINT_WITHIN_HPJ_QUOTA) != 0) {
+            pw.print(" WITHIN_HPJ_QUOTA");
+        }
         if (constraints != 0) {
             pw.print(" [0x");
             pw.print(Integer.toHexString(constraints));
@@ -1578,6 +1616,9 @@
         if ((constraints & CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0) {
             proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_BACKGROUND_NOT_RESTRICTED);
         }
+        if ((constraints & CONSTRAINT_WITHIN_HPJ_QUOTA) != 0) {
+            proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_WITHIN_HPJ_QUOTA);
+        }
     }
 
     private void dumpJobWorkItem(PrintWriter pw, String prefix, JobWorkItem work, int index) {
@@ -1795,6 +1836,11 @@
         pw.print(prefix);
         pw.print("  readyComponentEnabled: ");
         pw.println(serviceInfo != null);
+        if ((getFlags() & JobInfo.FLAG_FOREGROUND_JOB) != 0) {
+            pw.print(prefix);
+            pw.print("  mReadyWithinHpjQuota: ");
+            pw.println(mReadyWithinHpjQuota);
+        }
 
         if (changedAuthorities != null) {
             pw.print(prefix); pw.println("Changed authorities:");
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index 1d72b42..a3a20c6 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -36,6 +36,9 @@
 import android.app.AlarmManager;
 import android.app.AppGlobals;
 import android.app.IUidObserver;
+import android.app.usage.UsageEvents;
+import android.app.usage.UsageStatsManagerInternal;
+import android.app.usage.UsageStatsManagerInternal.UsageEventListener;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -53,6 +56,7 @@
 import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.SparseArrayMap;
 import android.util.SparseBooleanArray;
 import android.util.SparseSetArray;
@@ -297,10 +301,17 @@
     /** Timer for each package-userId combo. */
     private final SparseArrayMap<String, Timer> mPkgTimers = new SparseArrayMap<>();
 
-    /** List of all timing sessions for a package-userId combo, in chronological order. */
+    /** Timer for HPJs for each package-userId combo. */
+    private final SparseArrayMap<String, Timer> mHpjPkgTimers = new SparseArrayMap<>();
+
+    /** List of all regular timing sessions for a package-userId combo, in chronological order. */
     private final SparseArrayMap<String, List<TimingSession>> mTimingSessions =
             new SparseArrayMap<>();
 
+    /** List of all hpj timing sessions for a package-userId combo, in chronological order. */
+    private final SparseArrayMap<String, List<TimingSession>> mHpjTimingSessions =
+            new SparseArrayMap<>();
+
     /**
      * Listener to track and manage when each package comes back within quota.
      */
@@ -311,6 +322,10 @@
     private final SparseArrayMap<String, ExecutionStats[]> mExecutionStatsCache =
             new SparseArrayMap<>();
 
+    private final SparseArrayMap<String, ShrinkableDebits> mHpjStats = new SparseArrayMap<>();
+
+    private final SparseArrayMap<String, TopAppTimer> mTopAppTrackers = new SparseArrayMap<>();
+
     /** List of UIDs currently in the foreground. */
     private final SparseBooleanArray mForegroundUids = new SparseBooleanArray();
 
@@ -327,7 +342,7 @@
     private final ActivityManagerInternal mActivityManagerInternal;
     private final AlarmManager mAlarmManager;
     private final ChargingTracker mChargeTracker;
-    private final Handler mHandler;
+    private final QcHandler mHandler;
     private final QcConstants mQcConstants;
 
     /** How much time each app will have to run jobs within their standby bucket window. */
@@ -474,14 +489,63 @@
     private long mTimingSessionCoalescingDurationMs =
             QcConstants.DEFAULT_TIMING_SESSION_COALESCING_DURATION_MS;
 
+    /**
+     * The rolling window size for each standby bucket. Within each window, an app will have 10
+     * minutes to run its jobs.
+     */
+    private final long[] mHpjLimitsMs = new long[]{
+            QcConstants.DEFAULT_HPJ_LIMIT_ACTIVE_MS,
+            QcConstants.DEFAULT_HPJ_LIMIT_WORKING_MS,
+            QcConstants.DEFAULT_HPJ_LIMIT_FREQUENT_MS,
+            QcConstants.DEFAULT_HPJ_LIMIT_RARE_MS,
+            0, // NEVER
+            QcConstants.DEFAULT_HPJ_LIMIT_RESTRICTED_MS
+    };
+
+    /**
+     * The period of time used to calculate HPJ sessions. Apps can only have HPJ sessions
+     * totalling {@link #mHpjLimitsMs}[bucket within this period of time (without factoring in any
+     * rewards or free HPJs).
+     */
+    private long mHpjLimitWindowSizeMs = QcConstants.DEFAULT_HPJ_WINDOW_SIZE_MS;
+
+    /**
+     * Length of time used to split an app's top time into chunks.
+     */
+    public long mHpjTopAppTimeChunkSizeMs = QcConstants.DEFAULT_HPJ_TOP_APP_TIME_CHUNK_SIZE_MS;
+
+    /**
+     * How much HPJ quota to give back to an app based on the number of top app time chunks it had.
+     */
+    public long mHpjRewardTopAppMs = QcConstants.DEFAULT_HPJ_REWARD_TOP_APP_MS;
+
+    /**
+     * How much HPJ quota to give back to an app based on each non-top user interaction.
+     */
+    public long mHpjRewardInteractionMs = QcConstants.DEFAULT_HPJ_REWARD_INTERACTION_MS;
+
+    /**
+     * How much HPJ quota to give back to an app based on each notification seen event.
+     */
+    public long mHpjRewardNotificationSeenMs = QcConstants.DEFAULT_HPJ_REWARD_NOTIFICATION_SEEN_MS;
+
     /** An app has reached its quota. The message should contain a {@link Package} object. */
-    private static final int MSG_REACHED_QUOTA = 0;
+    @VisibleForTesting
+    static final int MSG_REACHED_QUOTA = 0;
     /** Drop any old timing sessions. */
     private static final int MSG_CLEAN_UP_SESSIONS = 1;
     /** Check if a package is now within its quota. */
     private static final int MSG_CHECK_PACKAGE = 2;
     /** Process state for a UID has changed. */
     private static final int MSG_UID_PROCESS_STATE_CHANGED = 3;
+    /** An app has reached its HPJ quota. The message should contain a {@link Package} object. */
+    @VisibleForTesting
+    static final int MSG_REACHED_HPJ_QUOTA = 4;
+    /**
+     * Process a new {@link UsageEvents.Event}. The event will be the message's object and the
+     * userId will the first arg.
+     */
+    private static final int MSG_PROCESS_USAGE_EVENT = 5;
 
     public QuotaController(JobSchedulerService service) {
         super(service);
@@ -499,6 +563,9 @@
         AppStandbyInternal appStandby = LocalServices.getService(AppStandbyInternal.class);
         appStandby.addListener(new StandbyTracker());
 
+        UsageStatsManagerInternal usmi = LocalServices.getService(UsageStatsManagerInternal.class);
+        usmi.registerListener(new UsageEventTracker());
+
         try {
             ActivityManager.getService().registerUidObserver(mUidObserver,
                     ActivityManager.UID_OBSERVER_PROCSTATE,
@@ -521,7 +588,15 @@
         jobStatus.setTrackingController(JobStatus.TRACKING_QUOTA);
         final boolean isWithinQuota = isWithinQuotaLocked(jobStatus);
         setConstraintSatisfied(jobStatus, isWithinQuota);
-        if (!isWithinQuota) {
+        final boolean outOfHpjQuota;
+        if (jobStatus.isRequestedForegroundJob()) {
+            final boolean isWithinHpjQuota = isWithinHpjQuotaLocked(jobStatus);
+            jobStatus.setForegroundJobQuotaConstraintSatisfied(isWithinHpjQuota);
+            outOfHpjQuota = !isWithinHpjQuota;
+        } else {
+            outOfHpjQuota = false;
+        }
+        if (!isWithinQuota || outOfHpjQuota) {
             maybeScheduleStartAlarmLocked(userId, pkgName, jobStatus.getEffectiveStandbyBucket());
         }
     }
@@ -544,10 +619,12 @@
 
         final int userId = jobStatus.getSourceUserId();
         final String packageName = jobStatus.getSourcePackageName();
-        Timer timer = mPkgTimers.get(userId, packageName);
+        final SparseArrayMap<String, Timer> timerMap =
+                jobStatus.shouldTreatAsForegroundJob() ? mHpjPkgTimers : mPkgTimers;
+        Timer timer = timerMap.get(userId, packageName);
         if (timer == null) {
-            timer = new Timer(uid, userId, packageName);
-            mPkgTimers.add(userId, packageName, timer);
+            timer = new Timer(uid, userId, packageName, !jobStatus.shouldTreatAsForegroundJob());
+            timerMap.add(userId, packageName, timer);
         }
         timer.startTrackingJobLocked(jobStatus);
     }
@@ -561,6 +638,13 @@
             if (timer != null) {
                 timer.stopTrackingJob(jobStatus);
             }
+            if (jobStatus.isRequestedForegroundJob()) {
+                timer = mHpjPkgTimers.get(jobStatus.getSourceUserId(),
+                        jobStatus.getSourcePackageName());
+                if (timer != null) {
+                    timer.stopTrackingJob(jobStatus);
+                }
+            }
             ArraySet<JobStatus> jobs = mTrackedJobs.get(jobStatus.getSourceUserId(),
                     jobStatus.getSourcePackageName());
             if (jobs != null) {
@@ -585,26 +669,37 @@
     public void onUserRemovedLocked(int userId) {
         mTrackedJobs.delete(userId);
         mPkgTimers.delete(userId);
+        mHpjPkgTimers.delete(userId);
         mTimingSessions.delete(userId);
+        mHpjTimingSessions.delete(userId);
         mInQuotaAlarmListener.removeAlarmsLocked(userId);
         mExecutionStatsCache.delete(userId);
+        mHpjStats.delete(userId);
         mUidToPackageCache.clear();
     }
 
     /** Drop all historical stats and stop tracking any active sessions for the specified app. */
     public void clearAppStatsLocked(int userId, @NonNull String packageName) {
         mTrackedJobs.delete(userId, packageName);
-        Timer timer = mPkgTimers.get(userId, packageName);
+        Timer timer = mPkgTimers.delete(userId, packageName);
         if (timer != null) {
             if (timer.isActive()) {
                 Slog.e(TAG, "clearAppStats called before Timer turned off.");
                 timer.dropEverythingLocked();
             }
-            mPkgTimers.delete(userId, packageName);
+        }
+        timer = mHpjPkgTimers.delete(userId, packageName);
+        if (timer != null) {
+            if (timer.isActive()) {
+                Slog.e(TAG, "clearAppStats called before HPJ Timer turned off.");
+                timer.dropEverythingLocked();
+            }
         }
         mTimingSessions.delete(userId, packageName);
+        mHpjTimingSessions.delete(userId, packageName);
         mInQuotaAlarmListener.removeAlarmLocked(userId, packageName);
         mExecutionStatsCache.delete(userId, packageName);
+        mHpjStats.delete(userId, packageName);
     }
 
     private boolean isUidInForeground(int uid) {
@@ -627,11 +722,53 @@
         if (mChargeTracker.isCharging()
                 || isTopStartedJobLocked(jobStatus)
                 || isUidInForeground(jobStatus.getSourceUid())) {
-            return JobServiceContext.EXECUTING_TIMESLICE_MILLIS;
+            return JobServiceContext.DEFAULT_EXECUTING_TIMESLICE_MILLIS;
+        }
+        if (jobStatus.shouldTreatAsForegroundJob()) {
+            return jobStatus.getStandbyBucket() == RESTRICTED_INDEX
+                    ? JobServiceContext.DEFAULT_RESTRICTED_HPJ_EXECUTING_TIMESLICE_MILLIS
+                    : JobServiceContext.DEFAULT_EXECUTING_TIMESLICE_MILLIS;
         }
         return getRemainingExecutionTimeLocked(jobStatus);
     }
 
+    /** @return true if the job is within hpj quota. */
+    public boolean isWithinHpjQuotaLocked(@NonNull final JobStatus jobStatus) {
+        if (isQuotaFree(jobStatus.getEffectiveStandbyBucket())) {
+            return true;
+        }
+        // A job is within quota if one of the following is true:
+        //   1. it's already running (already executing HPJS should be allowed to finish)
+        //   2. the app is currently in the foreground
+        //   3. the app overall is within its quota
+        if (isTopStartedJobLocked(jobStatus) || isUidInForeground(jobStatus.getSourceUid())) {
+            return true;
+        }
+        Timer hpjTimer = mHpjPkgTimers.get(jobStatus.getSourceUserId(),
+                jobStatus.getSourcePackageName());
+        // Any already executing HPJs should be allowed to finish.
+        if (hpjTimer != null && hpjTimer.isRunning(jobStatus)) {
+            return true;
+        }
+
+        return 0 < getRemainingHpjExecutionTimeLocked(
+                jobStatus.getSourceUserId(), jobStatus.getSourcePackageName());
+    }
+
+    @NonNull
+    private ShrinkableDebits getHpjQuotaLocked(final int userId,
+            @NonNull final String packageName) {
+        ShrinkableDebits debits = mHpjStats.get(userId, packageName);
+        if (debits == null) {
+            debits = new ShrinkableDebits(
+                    JobSchedulerService.standbyBucketForPackage(
+                            packageName, userId, sElapsedRealtimeClock.millis())
+            );
+            mHpjStats.add(userId, packageName, debits);
+        }
+        return debits;
+    }
+
     @VisibleForTesting
     boolean isWithinQuotaLocked(@NonNull final JobStatus jobStatus) {
         final int standbyBucket = jobStatus.getEffectiveStandbyBucket();
@@ -645,19 +782,22 @@
                 jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), standbyBucket);
     }
 
+    private boolean isQuotaFree(final int standbyBucket) {
+        // Quota constraint is not enforced while charging.
+        if (mChargeTracker.isCharging()) {
+            // Restricted jobs require additional constraints when charging, so don't immediately
+            // mark quota as free when charging.
+            return standbyBucket != RESTRICTED_INDEX;
+        }
+        return false;
+    }
+
     @VisibleForTesting
     boolean isWithinQuotaLocked(final int userId, @NonNull final String packageName,
             final int standbyBucket) {
         if (standbyBucket == NEVER_INDEX) return false;
 
-        // Quota constraint is not enforced while charging.
-        if (mChargeTracker.isCharging()) {
-            // Restricted jobs require additional constraints when charging, so don't immediately
-            // mark quota as free when charging.
-            if (standbyBucket != RESTRICTED_INDEX) {
-                return true;
-            }
-        }
+        if (isQuotaFree(standbyBucket)) return true;
 
         ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket);
         return getRemainingExecutionTimeLocked(stats) > 0
@@ -717,6 +857,49 @@
                 mMaxExecutionTimeMs - stats.executionTimeInMaxPeriodMs);
     }
 
+    @VisibleForTesting
+    long getRemainingHpjExecutionTimeLocked(final int userId, @NonNull final String packageName) {
+        ShrinkableDebits quota = getHpjQuotaLocked(userId, packageName);
+        if (quota.getStandbyBucketLocked() == NEVER_INDEX) {
+            return 0;
+        }
+        final long limitMs = mHpjLimitsMs[quota.getStandbyBucketLocked()];
+        long remainingMs = limitMs - quota.getTallyLocked();
+
+        // Stale sessions may still be factored into tally. Make sure they're removed.
+        List<TimingSession> timingSessions = mHpjTimingSessions.get(userId, packageName);
+        final long nowElapsed = sElapsedRealtimeClock.millis();
+        final long windowStartTimeElapsed = nowElapsed - mHpjLimitWindowSizeMs;
+        if (timingSessions != null) {
+            while (timingSessions.size() > 0) {
+                TimingSession ts = timingSessions.get(0);
+                if (ts.endTimeElapsed < windowStartTimeElapsed) {
+                    final long duration = ts.endTimeElapsed - ts.startTimeElapsed;
+                    remainingMs += duration;
+                    quota.transactOnDebitsLocked(-duration);
+                    timingSessions.remove(0);
+                } else if (ts.startTimeElapsed < windowStartTimeElapsed) {
+                    remainingMs += windowStartTimeElapsed - ts.startTimeElapsed;
+                    break;
+                } else {
+                    // Fully within the window.
+                    break;
+                }
+            }
+        }
+
+        Timer timer = mHpjPkgTimers.get(userId, packageName);
+        if (timer == null) {
+            return remainingMs;
+        }
+        // There's a case where the debits tally is 0 but a currently running HPJ still counts
+        // towards quota. If the app gets a reward in this case, the reward is lost and the HPJ
+        // run is still fully counted.
+        // TODO(171305774)/STOPSHIP: make sure getting rewards while HPJ currently executing isn't
+        // treated negatively
+        return remainingMs - timer.getCurrentDuration(sElapsedRealtimeClock.millis());
+    }
+
     /**
      * Returns the amount of time, in milliseconds, until the package would have reached its
      * duration quota, assuming it has a job counting towards its quota the entire time. This takes
@@ -802,6 +985,61 @@
         return timeUntilQuotaConsumedMs;
     }
 
+    /**
+     * Returns the amount of time, in milliseconds, until the package would have reached its HPJ
+     * quota, assuming it has a job counting towards the quota the entire time and the quota isn't
+     * replenished at all in that time.
+     */
+    @VisibleForTesting
+    long getTimeUntilHpjQuotaConsumedLocked(final int userId, @NonNull final String packageName) {
+        final long remainingExecutionTimeMs =
+                getRemainingHpjExecutionTimeLocked(userId, packageName);
+
+        List<TimingSession> sessions = mHpjTimingSessions.get(userId, packageName);
+        if (sessions == null || sessions.size() == 0) {
+            return remainingExecutionTimeMs;
+        }
+
+        final long nowElapsed = sElapsedRealtimeClock.millis();
+        ShrinkableDebits quota = getHpjQuotaLocked(userId, packageName);
+        final long limitMs = mHpjLimitsMs[quota.getStandbyBucketLocked()];
+        final long startWindowElapsed = Math.max(0, nowElapsed - mHpjLimitWindowSizeMs);
+        long remainingDeadSpaceMs = remainingExecutionTimeMs;
+        // Total time looked at where a session wouldn't be phasing out.
+        long deadSpaceMs = 0;
+        // Time regained from sessions phasing out
+        long phasedOutSessionTimeMs = 0;
+
+        for (int i = 0; i < sessions.size(); ++i) {
+            TimingSession session = sessions.get(i);
+            if (session.endTimeElapsed < startWindowElapsed) {
+                // Edge case where a session became stale in the time between the call to
+                // getRemainingHpjExecutionTimeLocked and this line.
+                remainingDeadSpaceMs += session.endTimeElapsed - session.startTimeElapsed;
+                sessions.remove(i);
+                i--;
+            } else if (session.startTimeElapsed < startWindowElapsed) {
+                // Session straddles start of window
+                phasedOutSessionTimeMs = session.endTimeElapsed - startWindowElapsed;
+            } else {
+                // Session fully inside window
+                final long timeBetweenSessions = session.startTimeElapsed
+                        - (i == 0 ? startWindowElapsed : sessions.get(i - 1).endTimeElapsed);
+                final long usedDeadSpaceMs = Math.min(remainingDeadSpaceMs, timeBetweenSessions);
+                deadSpaceMs += usedDeadSpaceMs;
+                if (usedDeadSpaceMs == timeBetweenSessions) {
+                    phasedOutSessionTimeMs += session.endTimeElapsed - session.startTimeElapsed;
+                }
+                remainingDeadSpaceMs -= usedDeadSpaceMs;
+                if (remainingDeadSpaceMs <= 0) {
+                    break;
+                }
+            }
+        }
+
+        return Math.min(limitMs, deadSpaceMs + phasedOutSessionTimeMs + remainingDeadSpaceMs);
+    }
+
     /** Returns the execution stats of the app in the most recent window. */
     @VisibleForTesting
     @NonNull
@@ -1053,18 +1291,36 @@
 
     @VisibleForTesting
     void saveTimingSession(final int userId, @NonNull final String packageName,
-            @NonNull final TimingSession session) {
+            @NonNull final TimingSession session, boolean isHpj) {
         synchronized (mLock) {
-            List<TimingSession> sessions = mTimingSessions.get(userId, packageName);
+            final SparseArrayMap<String, List<TimingSession>> sessionMap =
+                    isHpj ? mHpjTimingSessions : mTimingSessions;
+            List<TimingSession> sessions = sessionMap.get(userId, packageName);
             if (sessions == null) {
                 sessions = new ArrayList<>();
-                mTimingSessions.add(userId, packageName, sessions);
+                sessionMap.add(userId, packageName, sessions);
             }
             sessions.add(session);
-            // Adding a new session means that the current stats are now incorrect.
-            invalidateAllExecutionStatsLocked(userId, packageName);
+            if (isHpj) {
+                final ShrinkableDebits quota = getHpjQuotaLocked(userId, packageName);
+                quota.transactOnDebitsLocked(session.endTimeElapsed - session.startTimeElapsed);
+            } else {
+                // Adding a new session means that the current stats are now incorrect.
+                invalidateAllExecutionStatsLocked(userId, packageName);
 
-            maybeScheduleCleanupAlarmLocked();
+                maybeScheduleCleanupAlarmLocked();
+            }
+        }
+    }
+
+    private void grantRewardForInstantEvent(
+            final int userId, @NonNull final String packageName, final long credit) {
+        synchronized (mLock) {
+            final ShrinkableDebits quota = getHpjQuotaLocked(userId, packageName);
+            quota.transactOnDebitsLocked(-credit);
+            if (maybeUpdateConstraintForPkgLocked(userId, packageName)) {
+                mStateChangedListener.onControllerStateChanged();
+            }
         }
     }
 
@@ -1100,6 +1356,7 @@
         }
         mEarliestEndTimeFunctor.reset();
         mTimingSessions.forEach(mEarliestEndTimeFunctor);
+        mHpjTimingSessions.forEach(mEarliestEndTimeFunctor);
         final long earliestEndElapsed = mEarliestEndTimeFunctor.earliestEndElapsed;
         if (earliestEndElapsed == Long.MAX_VALUE) {
             // Couldn't find a good time to clean up. Maybe this was called after we deleted all
@@ -1155,6 +1412,7 @@
             Slog.d(TAG, "handleNewChargingStateLocked: " + mChargeTracker.isCharging());
         }
         // Deal with Timers first.
+        mHpjPkgTimers.forEach(mTimerChargingUpdateFunctor);
         mPkgTimers.forEach(mTimerChargingUpdateFunctor);
         // Now update jobs.
         maybeUpdateAllConstraintsLocked();
@@ -1189,6 +1447,7 @@
         // Quota is the same for all jobs within a package.
         final int realStandbyBucket = jobs.valueAt(0).getStandbyBucket();
         final boolean realInQuota = isWithinQuotaLocked(userId, packageName, realStandbyBucket);
+        boolean outOfHpjQuota = false;
         boolean changed = false;
         for (int i = jobs.size() - 1; i >= 0; --i) {
             final JobStatus js = jobs.valueAt(i);
@@ -1206,8 +1465,14 @@
                 // This job is somehow exempted. Need to determine its own quota status.
                 changed |= setConstraintSatisfied(js, isWithinQuotaLocked(js));
             }
+
+            if (js.isRequestedForegroundJob()) {
+                boolean isWithinHpjQuota = isWithinHpjQuotaLocked(js);
+                changed |= js.setForegroundJobQuotaConstraintSatisfied(isWithinHpjQuota);
+                outOfHpjQuota |= !isWithinHpjQuota;
+            }
         }
-        if (!realInQuota) {
+        if (!realInQuota || outOfHpjQuota) {
             // Don't want to use the effective standby bucket here since that bump the bucket to
             // ACTIVE for one of the jobs, which doesn't help with other jobs that aren't
             // exempted.
@@ -1226,10 +1491,22 @@
         @Override
         public void accept(JobStatus jobStatus) {
             wasJobChanged |= setConstraintSatisfied(jobStatus, isWithinQuotaLocked(jobStatus));
+            final boolean outOfHpjQuota;
+            if (jobStatus.isRequestedForegroundJob()) {
+                final boolean isWithinHpjQuota = isWithinHpjQuotaLocked(jobStatus);
+                wasJobChanged |= jobStatus.setForegroundJobQuotaConstraintSatisfied(
+                        isWithinHpjQuota);
+                outOfHpjQuota = !isWithinHpjQuota;
+            } else {
+                outOfHpjQuota = false;
+            }
+
             final int userId = jobStatus.getSourceUserId();
             final String packageName = jobStatus.getSourcePackageName();
             final int realStandbyBucket = jobStatus.getStandbyBucket();
-            if (isWithinQuotaLocked(userId, packageName, realStandbyBucket)) {
+            if (isWithinQuotaLocked(userId, packageName, realStandbyBucket) && !outOfHpjQuota) {
+                // TODO(141645789): we probably shouldn't cancel the alarm until we've verified
+                // that all jobs for the userId-package are within quota.
                 mInQuotaAlarmListener.removeAlarmLocked(userId, packageName);
             } else {
                 mToScheduleStartAlarms.add(userId, packageName, realStandbyBucket);
@@ -1280,11 +1557,13 @@
         final boolean isUnderJobCountQuota = isUnderJobCountQuotaLocked(stats, standbyBucket);
         final boolean isUnderTimingSessionCountQuota = isUnderSessionCountQuotaLocked(stats,
                 standbyBucket);
+        final long remainingHpjQuota = getRemainingHpjExecutionTimeLocked(userId, packageName);
 
         if (stats.executionTimeInWindowMs < mAllowedTimePerPeriodMs
                 && stats.executionTimeInMaxPeriodMs < mMaxExecutionTimeMs
                 && isUnderJobCountQuota
-                && isUnderTimingSessionCountQuota) {
+                && isUnderTimingSessionCountQuota
+                && remainingHpjQuota > 0) {
             // Already in quota. Why was this method called?
             if (DEBUG) {
                 Slog.e(TAG, "maybeScheduleStartAlarmLocked called for " + pkgString
@@ -1297,19 +1576,44 @@
             return;
         }
 
-        // The time this app will have quota again.
-        long inQuotaTimeElapsed = stats.inQuotaTimeElapsed;
-        if (!isUnderJobCountQuota && stats.bgJobCountInWindow < stats.jobCountLimit) {
-            // App hit the rate limit.
-            inQuotaTimeElapsed = Math.max(inQuotaTimeElapsed,
-                    stats.jobRateLimitExpirationTimeElapsed);
+        long inRegularQuotaTimeElapsed = Long.MAX_VALUE;
+        long inHpjQuotaTimeElapsed = Long.MAX_VALUE;
+        if (!(stats.executionTimeInWindowMs < mAllowedTimePerPeriodMs
+                && stats.executionTimeInMaxPeriodMs < mMaxExecutionTimeMs
+                && isUnderJobCountQuota
+                && isUnderTimingSessionCountQuota)) {
+            // The time this app will have quota again.
+            long inQuotaTimeElapsed = stats.inQuotaTimeElapsed;
+            if (!isUnderJobCountQuota && stats.bgJobCountInWindow < stats.jobCountLimit) {
+                // App hit the rate limit.
+                inQuotaTimeElapsed =
+                        Math.max(inQuotaTimeElapsed, stats.jobRateLimitExpirationTimeElapsed);
+            }
+            if (!isUnderTimingSessionCountQuota
+                    && stats.sessionCountInWindow < stats.sessionCountLimit) {
+                // App hit the rate limit.
+                inQuotaTimeElapsed =
+                        Math.max(inQuotaTimeElapsed, stats.sessionRateLimitExpirationTimeElapsed);
+            }
+            inRegularQuotaTimeElapsed = inQuotaTimeElapsed;
         }
-        if (!isUnderTimingSessionCountQuota
-                && stats.sessionCountInWindow < stats.sessionCountLimit) {
-            // App hit the rate limit.
-            inQuotaTimeElapsed = Math.max(inQuotaTimeElapsed,
-                    stats.sessionRateLimitExpirationTimeElapsed);
+        if (remainingHpjQuota <= 0) {
+            final long limitMs = mHpjLimitsMs[standbyBucket] - mQuotaBufferMs;
+            List<TimingSession> timingSessions = mHpjTimingSessions.get(userId, packageName);
+            long sumMs = 0;
+            for (int i = timingSessions.size() - 1; i >= 0; --i) {
+                TimingSession ts = timingSessions.get(i);
+                final long durationMs = ts.endTimeElapsed - ts.startTimeElapsed;
+                sumMs += durationMs;
+                if (sumMs >= limitMs) {
+                    inHpjQuotaTimeElapsed =
+                            ts.startTimeElapsed + (sumMs - limitMs) + mHpjLimitWindowSizeMs;
+                    break;
+                }
+            }
         }
+        long inQuotaTimeElapsed = Math.min(inRegularQuotaTimeElapsed, inHpjQuotaTimeElapsed);
+
         if (inQuotaTimeElapsed <= sElapsedRealtimeClock.millis()) {
             final long nowElapsed = sElapsedRealtimeClock.millis();
             Slog.wtf(TAG,
@@ -1450,9 +1754,52 @@
         }
     }
 
+    private static final class ShrinkableDebits {
+        /** The amount of quota remaining. Can be negative if limit changes. */
+        private long mDebitTally;
+        private int mStandbyBucket;
+
+        ShrinkableDebits(int standbyBucket) {
+            mDebitTally = 0;
+            mStandbyBucket = standbyBucket;
+        }
+
+        long getTallyLocked() {
+            return mDebitTally;
+        }
+
+        /**
+         * Negative if the tally should decrease (therefore increasing available quota);
+         * or positive if the tally should increase (therefore decreasing available quota).
+         */
+        void transactOnDebitsLocked(final long amount) {
+            mDebitTally = Math.max(0, mDebitTally + amount);
+        }
+
+        void setStandbyBucketLocked(int standbyBucket) {
+            mStandbyBucket = standbyBucket;
+        }
+
+        int getStandbyBucketLocked() {
+            return mStandbyBucket;
+        }
+
+        @Override
+        public String toString() {
+            return "ShrinkableDebits { debit tally: "
+                    + mDebitTally + ", bucket: " + mStandbyBucket
+                    + " }";
+        }
+
+        void dumpLocked(IndentingPrintWriter pw) {
+            pw.println(toString());
+        }
+    }
+
     private final class Timer {
         private final Package mPkg;
         private final int mUid;
+        private final boolean mRegularJobTimer;
 
         // List of jobs currently running for this app that started when the app wasn't in the
         // foreground.
@@ -1460,9 +1807,10 @@
         private long mStartTimeElapsed;
         private int mBgJobCount;
 
-        Timer(int uid, int userId, String packageName) {
+        Timer(int uid, int userId, String packageName, boolean regularJobTimer) {
             mPkg = new Package(userId, packageName);
             mUid = uid;
+            mRegularJobTimer = regularJobTimer;
         }
 
         void startTrackingJobLocked(@NonNull JobStatus jobStatus) {
@@ -1482,12 +1830,17 @@
             mRunningBgJobs.add(jobStatus);
             if (shouldTrackLocked()) {
                 mBgJobCount++;
-                incrementJobCountLocked(mPkg.userId, mPkg.packageName, 1);
+                if (mRegularJobTimer) {
+                    incrementJobCountLocked(mPkg.userId, mPkg.packageName, 1);
+                }
                 if (mRunningBgJobs.size() == 1) {
                     // Started tracking the first job.
                     mStartTimeElapsed = sElapsedRealtimeClock.millis();
-                    // Starting the timer means that all cached execution stats are now incorrect.
-                    invalidateAllExecutionStatsLocked(mPkg.userId, mPkg.packageName);
+                    if (mRegularJobTimer) {
+                        // Starting the timer means that all cached execution stats are now
+                        // incorrect.
+                        invalidateAllExecutionStatsLocked(mPkg.userId, mPkg.packageName);
+                    }
                     scheduleCutoff();
                 }
             }
@@ -1529,13 +1882,15 @@
                 return;
             }
             TimingSession ts = new TimingSession(mStartTimeElapsed, nowElapsed, mBgJobCount);
-            saveTimingSession(mPkg.userId, mPkg.packageName, ts);
+            saveTimingSession(mPkg.userId, mPkg.packageName, ts, !mRegularJobTimer);
             mBgJobCount = 0;
             // Don't reset the tracked jobs list as we need to keep tracking the current number
             // of jobs.
             // However, cancel the currently scheduled cutoff since it's not currently useful.
             cancelCutoff();
-            incrementTimingSessionCountLocked(mPkg.userId, mPkg.packageName);
+            if (mRegularJobTimer) {
+                incrementTimingSessionCountLocked(mPkg.userId, mPkg.packageName);
+            }
         }
 
         /**
@@ -1582,10 +1937,13 @@
                     // repeatedly plugged in and unplugged, or an app changes foreground state
                     // very frequently, the job count for a package may be artificially high.
                     mBgJobCount = mRunningBgJobs.size();
-                    incrementJobCountLocked(mPkg.userId, mPkg.packageName, mBgJobCount);
-                    // Starting the timer means that all cached execution stats are now
-                    // incorrect.
-                    invalidateAllExecutionStatsLocked(mPkg.userId, mPkg.packageName);
+
+                    if (mRegularJobTimer) {
+                        incrementJobCountLocked(mPkg.userId, mPkg.packageName, mBgJobCount);
+                        // Starting the timer means that all cached execution stats are now
+                        // incorrect.
+                        invalidateAllExecutionStatsLocked(mPkg.userId, mPkg.packageName);
+                    }
                     // Schedule cutoff since we're now actively tracking for quotas again.
                     scheduleCutoff();
                 }
@@ -1605,11 +1963,15 @@
                 if (!isActive()) {
                     return;
                 }
-                Message msg = mHandler.obtainMessage(MSG_REACHED_QUOTA, mPkg);
-                final long timeRemainingMs = getTimeUntilQuotaConsumedLocked(mPkg.userId,
-                        mPkg.packageName);
+                Message msg = mHandler.obtainMessage(
+                        mRegularJobTimer ? MSG_REACHED_QUOTA : MSG_REACHED_HPJ_QUOTA, mPkg);
+                final long timeRemainingMs = mRegularJobTimer
+                        ? getTimeUntilQuotaConsumedLocked(mPkg.userId, mPkg.packageName)
+                        : getTimeUntilHpjQuotaConsumedLocked(mPkg.userId, mPkg.packageName);
                 if (DEBUG) {
-                    Slog.i(TAG, "Job for " + mPkg + " has " + timeRemainingMs + "ms left.");
+                    Slog.i(TAG,
+                            (mRegularJobTimer ? "Regular job" : "HPJ") + " for " + mPkg + " has "
+                                    + timeRemainingMs + "ms left.");
                 }
                 // If the job was running the entire time, then the system would be up, so it's
                 // fine to use uptime millis for these messages.
@@ -1618,11 +1980,14 @@
         }
 
         private void cancelCutoff() {
-            mHandler.removeMessages(MSG_REACHED_QUOTA, mPkg);
+            mHandler.removeMessages(
+                    mRegularJobTimer ? MSG_REACHED_QUOTA : MSG_REACHED_HPJ_QUOTA, mPkg);
         }
 
         public void dump(IndentingPrintWriter pw, Predicate<JobStatus> predicate) {
-            pw.print("Timer{");
+            pw.print("Timer<");
+            pw.print(mRegularJobTimer ? "REG" : " HPJ");
+            pw.print(">{");
             pw.print(mPkg);
             pw.print("} ");
             if (isActive()) {
@@ -1668,6 +2033,98 @@
         }
     }
 
+    private final class TopAppTimer {
+        private final Package mPkg;
+
+        // List of jobs currently running for this app that started when the app wasn't in the
+        // foreground.
+        private final SparseArray<UsageEvents.Event> mActivities = new SparseArray<>();
+        private long mStartTimeElapsed;
+
+        TopAppTimer(int userId, String packageName) {
+            mPkg = new Package(userId, packageName);
+        }
+
+        void processEventLocked(@NonNull UsageEvents.Event event) {
+            final long nowElapsed = sElapsedRealtimeClock.millis();
+            switch (event.getEventType()) {
+                case UsageEvents.Event.ACTIVITY_RESUMED:
+                    if (mActivities.size() == 0) {
+                        mStartTimeElapsed = nowElapsed;
+                    }
+                    mActivities.put(event.mInstanceId, event);
+                    break;
+                case UsageEvents.Event.ACTIVITY_PAUSED:
+                case UsageEvents.Event.ACTIVITY_STOPPED:
+                case UsageEvents.Event.ACTIVITY_DESTROYED:
+                    final UsageEvents.Event existingEvent =
+                            mActivities.removeReturnOld(event.mInstanceId);
+                    if (existingEvent != null && mActivities.size() == 0) {
+                        final long totalTopTimeMs = nowElapsed - mStartTimeElapsed;
+                        int numTimeChunks = (int) (totalTopTimeMs / mHpjTopAppTimeChunkSizeMs);
+                        final long remainderMs = totalTopTimeMs % mHpjTopAppTimeChunkSizeMs;
+                        if (remainderMs >= SECOND_IN_MILLIS) {
+                            // "Round up"
+                            numTimeChunks++;
+                        }
+                        if (DEBUG) {
+                            Slog.d(TAG,
+                                    "Crediting " + mPkg + " for " + numTimeChunks + " time chunks");
+                        }
+                        final ShrinkableDebits quota =
+                                getHpjQuotaLocked(mPkg.userId, mPkg.packageName);
+                        quota.transactOnDebitsLocked(-mHpjRewardTopAppMs * numTimeChunks);
+                        if (maybeUpdateConstraintForPkgLocked(mPkg.userId, mPkg.packageName)) {
+                            mStateChangedListener.onControllerStateChanged();
+                        }
+                    }
+                    break;
+            }
+        }
+
+        boolean isActive() {
+            synchronized (mLock) {
+                return mActivities.size() > 0;
+            }
+        }
+
+        public void dump(IndentingPrintWriter pw) {
+            pw.print("TopAppTimer{");
+            pw.print(mPkg);
+            pw.print("} ");
+            if (isActive()) {
+                pw.print("started at ");
+                pw.print(mStartTimeElapsed);
+                pw.print(" (");
+                pw.print(sElapsedRealtimeClock.millis() - mStartTimeElapsed);
+                pw.print("ms ago)");
+            } else {
+                pw.print("NOT active");
+            }
+            pw.println();
+            pw.increaseIndent();
+            for (int i = 0; i < mActivities.size(); i++) {
+                UsageEvents.Event event = mActivities.valueAt(i);
+                pw.println(event.getClassName());
+            }
+            pw.decreaseIndent();
+        }
+
+        public void dump(ProtoOutputStream proto, long fieldId) {
+            final long token = proto.start(fieldId);
+
+            mPkg.dumpDebug(proto, StateControllerProto.QuotaController.TopAppTimer.PKG);
+            proto.write(StateControllerProto.QuotaController.TopAppTimer.IS_ACTIVE, isActive());
+            proto.write(StateControllerProto.QuotaController.TopAppTimer.START_TIME_ELAPSED,
+                    mStartTimeElapsed);
+            proto.write(StateControllerProto.QuotaController.TopAppTimer.ACTIVITY_COUNT,
+                    mActivities.size());
+            // TODO: maybe dump activities/events
+
+            proto.end(token);
+        }
+    }
+
     /**
      * Tracking of app assignments to standby buckets
      */
@@ -1693,8 +2150,14 @@
         }
         List<JobStatus> restrictedChanges = new ArrayList<>();
         synchronized (mLock) {
+            ShrinkableDebits debits = mHpjStats.get(userId, packageName);
+            if (debits != null) {
+                debits.setStandbyBucketLocked(bucketIndex);
+            }
+
             ArraySet<JobStatus> jobs = mTrackedJobs.get(userId, packageName);
             if (jobs == null || jobs.size() == 0) {
+                // Nothing further to do.
                 return;
             }
             for (int i = jobs.size() - 1; i >= 0; i--) {
@@ -1711,6 +2174,10 @@
             if (timer != null && timer.isActive()) {
                 timer.rescheduleCutoff();
             }
+            timer = mHpjPkgTimers.get(userId, packageName);
+            if (timer != null && timer.isActive()) {
+                timer.rescheduleCutoff();
+            }
             if (maybeUpdateConstraintForPkgLocked(userId, packageName)) {
                 mStateChangedListener.onControllerStateChanged();
             }
@@ -1720,6 +2187,16 @@
         }
     }
 
+    final class UsageEventTracker implements UsageEventListener {
+        /**
+         * Callback to inform listeners of a new event.
+         */
+        @Override
+        public void onUsageEvent(int userId, @NonNull UsageEvents.Event event) {
+            mHandler.obtainMessage(MSG_PROCESS_USAGE_EVENT, userId, 0, event);
+        }
+    }
+
     private final class DeleteTimingSessionsFunctor implements Consumer<List<TimingSession>> {
         private final Predicate<TimingSession> mTooOld = new Predicate<TimingSession>() {
             public boolean test(TimingSession ts) {
@@ -1742,9 +2219,13 @@
     @VisibleForTesting
     void deleteObsoleteSessionsLocked() {
         mTimingSessions.forEach(mDeleteOldSessionsFunctor);
+        // Don't delete HPJ timing sessions here. They'll be removed in
+        // getRemainingHpjExecutionTimeLocked().
     }
 
     private class QcHandler extends Handler {
+        private boolean mIsProcessing;
+
         QcHandler(Looper looper) {
             super(looper);
         }
@@ -1752,6 +2233,8 @@
         @Override
         public void handleMessage(Message msg) {
             synchronized (mLock) {
+                mIsProcessing = true;
+
                 switch (msg.what) {
                     case MSG_REACHED_QUOTA: {
                         Package pkg = (Package) msg.obj;
@@ -1781,6 +2264,33 @@
                         }
                         break;
                     }
+                    case MSG_REACHED_HPJ_QUOTA: {
+                        Package pkg = (Package) msg.obj;
+                        if (DEBUG) {
+                            Slog.d(TAG, "Checking if " + pkg + " has reached its HPJ quota.");
+                        }
+
+                        long timeRemainingMs = getRemainingHpjExecutionTimeLocked(
+                                pkg.userId, pkg.packageName);
+                        if (timeRemainingMs <= 0) {
+                            if (DEBUG) Slog.d(TAG, pkg + " has reached its HPJ quota.");
+                            if (maybeUpdateConstraintForPkgLocked(pkg.userId, pkg.packageName)) {
+                                mStateChangedListener.onControllerStateChanged();
+                            }
+                        } else {
+                            // This could potentially happen if an old session phases out while a
+                            // job is currently running.
+                            // Reschedule message
+                            Message rescheduleMsg = obtainMessage(MSG_REACHED_HPJ_QUOTA, pkg);
+                            timeRemainingMs = getTimeUntilHpjQuotaConsumedLocked(
+                                    pkg.userId, pkg.packageName);
+                            if (DEBUG) {
+                                Slog.d(TAG, pkg + " has " + timeRemainingMs + "ms left for HPJ");
+                            }
+                            sendMessageDelayed(rescheduleMsg, timeRemainingMs);
+                        }
+                        break;
+                    }
                     case MSG_CLEAN_UP_SESSIONS:
                         if (DEBUG) {
                             Slog.d(TAG, "Cleaning up timing sessions.");
@@ -1816,7 +2326,8 @@
                                 isQuotaFree = false;
                             }
                             // Update Timers first.
-                            if (mPkgTimers.indexOfKey(userId) >= 0) {
+                            if (mPkgTimers.indexOfKey(userId) >= 0
+                                    || mHpjPkgTimers.indexOfKey(userId) >= 0) {
                                 ArraySet<String> packages = mUidToPackageCache.get(uid);
                                 if (packages == null) {
                                     try {
@@ -1834,7 +2345,11 @@
                                 }
                                 if (packages != null) {
                                     for (int i = packages.size() - 1; i >= 0; --i) {
-                                        Timer t = mPkgTimers.get(userId, packages.valueAt(i));
+                                        Timer t = mHpjPkgTimers.get(userId, packages.valueAt(i));
+                                        if (t != null) {
+                                            t.onStateChangedLocked(nowElapsed, isQuotaFree);
+                                        }
+                                        t = mPkgTimers.get(userId, packages.valueAt(i));
                                         if (t != null) {
                                             t.onStateChangedLocked(nowElapsed, isQuotaFree);
                                         }
@@ -1847,8 +2362,46 @@
                         }
                         break;
                     }
+                    case MSG_PROCESS_USAGE_EVENT: {
+                        final int userId = msg.arg1;
+                        final UsageEvents.Event event = (UsageEvents.Event) msg.obj;
+                        final String pkgName = event.getPackageName();
+                        switch (event.getEventType()) {
+                            case UsageEvents.Event.ACTIVITY_RESUMED:
+                            case UsageEvents.Event.ACTIVITY_PAUSED:
+                            case UsageEvents.Event.ACTIVITY_STOPPED:
+                            case UsageEvents.Event.ACTIVITY_DESTROYED:
+                                synchronized (mLock) {
+                                    TopAppTimer timer = mTopAppTrackers.get(userId, pkgName);
+                                    if (timer == null) {
+                                        timer = new TopAppTimer(userId, pkgName);
+                                        mTopAppTrackers.add(userId, pkgName, timer);
+                                    }
+                                    timer.processEventLocked(event);
+                                }
+                                break;
+                            case UsageEvents.Event.USER_INTERACTION:
+                            case UsageEvents.Event.CHOOSER_ACTION:
+                            case UsageEvents.Event.NOTIFICATION_INTERRUPTION:
+                                // Don't need to include SHORTCUT_INVOCATION. The app will be
+                                // launched through it (if it's not already on top).
+                                grantRewardForInstantEvent(
+                                        userId, pkgName, mHpjRewardInteractionMs);
+                                break;
+                            case UsageEvents.Event.NOTIFICATION_SEEN:
+                                // Intentionally don't give too much for notification seen.
+                                // Interactions will award more.
+                                grantRewardForInstantEvent(
+                                        userId, pkgName, mHpjRewardNotificationSeenMs);
+                                break;
+                        }
+
+                        break;
+                    }
                 }
             }
+
+            mIsProcessing = false;
         }
     }
 
@@ -2030,6 +2583,7 @@
         mQcConstants.mShouldReevaluateConstraints = false;
         mQcConstants.mRateLimitingConstantsUpdated = false;
         mQcConstants.mExecutionPeriodConstantsUpdated = false;
+        mQcConstants.mHpjLimitConstantsUpdated = false;
     }
 
     @Override
@@ -2055,6 +2609,7 @@
         private boolean mShouldReevaluateConstraints = false;
         private boolean mRateLimitingConstantsUpdated = false;
         private boolean mExecutionPeriodConstantsUpdated = false;
+        private boolean mHpjLimitConstantsUpdated = false;
 
         /** Prefix to use with all constant keys in order to "sub-namespace" the keys. */
         private static final String QC_CONSTANT_PREFIX = "qc_";
@@ -2128,6 +2683,36 @@
         @VisibleForTesting
         static final String KEY_MIN_QUOTA_CHECK_DELAY_MS =
                 QC_CONSTANT_PREFIX + "min_quota_check_delay_ms";
+        @VisibleForTesting
+        static final String KEY_HPJ_LIMIT_ACTIVE_MS =
+                QC_CONSTANT_PREFIX + "hpj_limit_active_ms";
+        @VisibleForTesting
+        static final String KEY_HPJ_LIMIT_WORKING_MS =
+                QC_CONSTANT_PREFIX + "hpj_limit_working_ms";
+        @VisibleForTesting
+        static final String KEY_HPJ_LIMIT_FREQUENT_MS =
+                QC_CONSTANT_PREFIX + "hpj_limit_frequent_ms";
+        @VisibleForTesting
+        static final String KEY_HPJ_LIMIT_RARE_MS =
+                QC_CONSTANT_PREFIX + "hpj_limit_rare_ms";
+        @VisibleForTesting
+        static final String KEY_HPJ_LIMIT_RESTRICTED_MS =
+                QC_CONSTANT_PREFIX + "hpj_limit_restricted_ms";
+        @VisibleForTesting
+        static final String KEY_HPJ_WINDOW_SIZE_MS =
+                QC_CONSTANT_PREFIX + "hpj_window_size_ms";
+        @VisibleForTesting
+        static final String KEY_HPJ_TOP_APP_TIME_CHUNK_SIZE_MS =
+                QC_CONSTANT_PREFIX + "hpj_top_app_time_chunk_size_ms";
+        @VisibleForTesting
+        static final String KEY_HPJ_REWARD_TOP_APP_MS =
+                QC_CONSTANT_PREFIX + "hpj_reward_top_app_ms";
+        @VisibleForTesting
+        static final String KEY_HPJ_REWARD_INTERACTION_MS =
+                QC_CONSTANT_PREFIX + "hpj_reward_interaction_ms";
+        @VisibleForTesting
+        static final String KEY_HPJ_REWARD_NOTIFICATION_SEEN_MS =
+                QC_CONSTANT_PREFIX + "hpj_reward_notification_seen_ms";
 
         private static final long DEFAULT_ALLOWED_TIME_PER_PERIOD_MS =
                 10 * 60 * 1000L; // 10 minutes
@@ -2169,6 +2754,16 @@
         private static final int DEFAULT_MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW = 20;
         private static final long DEFAULT_TIMING_SESSION_COALESCING_DURATION_MS = 5000; // 5 seconds
         private static final long DEFAULT_MIN_QUOTA_CHECK_DELAY_MS = MINUTE_IN_MILLIS;
+        private static final long DEFAULT_HPJ_LIMIT_ACTIVE_MS = 30 * MINUTE_IN_MILLIS;
+        private static final long DEFAULT_HPJ_LIMIT_WORKING_MS = DEFAULT_HPJ_LIMIT_ACTIVE_MS;
+        private static final long DEFAULT_HPJ_LIMIT_FREQUENT_MS = 10 * MINUTE_IN_MILLIS;
+        private static final long DEFAULT_HPJ_LIMIT_RARE_MS = DEFAULT_HPJ_LIMIT_FREQUENT_MS;
+        private static final long DEFAULT_HPJ_LIMIT_RESTRICTED_MS = 5 * MINUTE_IN_MILLIS;
+        private static final long DEFAULT_HPJ_WINDOW_SIZE_MS = 24 * HOUR_IN_MILLIS;
+        private static final long DEFAULT_HPJ_TOP_APP_TIME_CHUNK_SIZE_MS = 30 * SECOND_IN_MILLIS;
+        private static final long DEFAULT_HPJ_REWARD_TOP_APP_MS = 10 * SECOND_IN_MILLIS;
+        private static final long DEFAULT_HPJ_REWARD_INTERACTION_MS = 15 * SECOND_IN_MILLIS;
+        private static final long DEFAULT_HPJ_REWARD_NOTIFICATION_SEEN_MS = 0;
 
         /** How much time each app will have to run jobs within their standby bucket window. */
         public long ALLOWED_TIME_PER_PERIOD_MS = DEFAULT_ALLOWED_TIME_PER_PERIOD_MS;
@@ -2328,6 +2923,74 @@
         /** The minimum value that {@link #RATE_LIMITING_WINDOW_MS} can have. */
         private static final long MIN_RATE_LIMITING_WINDOW_MS = 30 * SECOND_IN_MILLIS;
 
+        /**
+         * The total session limit of the particular standby bucket. Apps in this standby bucket
+         * can
+         * only have HPJ sessions totalling HPJ_LIMIT (without factoring in any rewards or free
+         * HPJs).
+         */
+        public long HPJ_LIMIT_ACTIVE_MS = DEFAULT_HPJ_LIMIT_ACTIVE_MS;
+
+        /**
+         * The total session limit of the particular standby bucket. Apps in this standby bucket
+         * can
+         * only have HPJ sessions totalling HPJ_LIMIT (without factoring in any rewards or free
+         * HPJs).
+         */
+        public long HPJ_LIMIT_WORKING_MS = DEFAULT_HPJ_LIMIT_WORKING_MS;
+
+        /**
+         * The total session limit of the particular standby bucket. Apps in this standby bucket
+         * can
+         * only have HPJ sessions totalling HPJ_LIMIT (without factoring in any rewards or free
+         * HPJs).
+         */
+        public long HPJ_LIMIT_FREQUENT_MS = DEFAULT_HPJ_LIMIT_FREQUENT_MS;
+
+        /**
+         * The total session limit of the particular standby bucket. Apps in this standby bucket
+         * can
+         * only have HPJ sessions totalling HPJ_LIMIT (without factoring in any rewards or free
+         * HPJs).
+         */
+        public long HPJ_LIMIT_RARE_MS = DEFAULT_HPJ_LIMIT_RARE_MS;
+
+        /**
+         * The total session limit of the particular standby bucket. Apps in this standby bucket
+         * can
+         * only have HPJ sessions totalling HPJ_LIMIT (without factoring in any rewards or free
+         * HPJs).
+         */
+        public long HPJ_LIMIT_RESTRICTED_MS = DEFAULT_HPJ_LIMIT_RESTRICTED_MS;
+
+        /**
+         * The period of time used to calculate HPJ sessions. Apps can only have HPJ sessions
+         * totalling HPJ_LIMIT_<bucket>_MS within this period of time (without factoring in any
+         * rewards or free HPJs).
+         */
+        public long HPJ_WINDOW_SIZE_MS = DEFAULT_HPJ_WINDOW_SIZE_MS;
+
+        /**
+         * Length of time used to split an app's top time into chunks.
+         */
+        public long HPJ_TOP_APP_TIME_CHUNK_SIZE_MS = DEFAULT_HPJ_TOP_APP_TIME_CHUNK_SIZE_MS;
+
+        /**
+         * How much HPJ quota to give back to an app based on the number of top app time chunks it
+         * had.
+         */
+        public long HPJ_REWARD_TOP_APP_MS = DEFAULT_HPJ_REWARD_TOP_APP_MS;
+
+        /**
+         * How much HPJ quota to give back to an app based on each non-top user interaction.
+         */
+        public long HPJ_REWARD_INTERACTION_MS = DEFAULT_HPJ_REWARD_INTERACTION_MS;
+
+        /**
+         * How much HPJ quota to give back to an app based on each notification seen event.
+         */
+        public long HPJ_REWARD_NOTIFICATION_SEEN_MS = DEFAULT_HPJ_REWARD_NOTIFICATION_SEEN_MS;
+
         public void processConstantLocked(@NonNull DeviceConfig.Properties properties,
                 @NonNull String key) {
             switch (key) {
@@ -2348,6 +3011,15 @@
                     updateRateLimitingConstantsLocked();
                     break;
 
+                case KEY_HPJ_LIMIT_ACTIVE_MS:
+                case KEY_HPJ_LIMIT_WORKING_MS:
+                case KEY_HPJ_LIMIT_FREQUENT_MS:
+                case KEY_HPJ_LIMIT_RARE_MS:
+                case KEY_HPJ_LIMIT_RESTRICTED_MS:
+                case KEY_HPJ_WINDOW_SIZE_MS:
+                    updateHpjLimitConstantsLocked();
+                    break;
+
                 case KEY_MAX_JOB_COUNT_ACTIVE:
                     MAX_JOB_COUNT_ACTIVE = properties.getInt(key, DEFAULT_MAX_JOB_COUNT_ACTIVE);
                     int newActiveMaxJobCount = Math.max(MIN_BUCKET_JOB_COUNT, MAX_JOB_COUNT_ACTIVE);
@@ -2458,6 +3130,64 @@
                     mInQuotaAlarmListener.setMinQuotaCheckDelayMs(
                             Math.min(15 * MINUTE_IN_MILLIS, Math.max(0, MIN_QUOTA_CHECK_DELAY_MS)));
                     break;
+                case KEY_HPJ_TOP_APP_TIME_CHUNK_SIZE_MS:
+                    // We don't need to re-evaluate execution stats or constraint status for this.
+                    HPJ_TOP_APP_TIME_CHUNK_SIZE_MS =
+                            properties.getLong(key, DEFAULT_HPJ_TOP_APP_TIME_CHUNK_SIZE_MS);
+                    // Limit chunking to be in the range [1 millisecond, 15 minutes] per event.
+                    long newChunkSizeMs = Math.min(15 * MINUTE_IN_MILLIS,
+                            Math.max(1, HPJ_TOP_APP_TIME_CHUNK_SIZE_MS));
+                    if (mHpjTopAppTimeChunkSizeMs != newChunkSizeMs) {
+                        mHpjTopAppTimeChunkSizeMs = newChunkSizeMs;
+                        if (mHpjTopAppTimeChunkSizeMs < mHpjRewardTopAppMs) {
+                            // Not making chunk sizes and top rewards to be the upper/lower
+                            // limits of the other to allow trying different policies. Just log
+                            // the discrepancy.
+                            Slog.w(TAG, "HPJ top app time chunk less than reward: "
+                                    + mHpjTopAppTimeChunkSizeMs + " vs " + mHpjRewardTopAppMs);
+                        }
+                    }
+                    break;
+                case KEY_HPJ_REWARD_TOP_APP_MS:
+                    // We don't need to re-evaluate execution stats or constraint status for this.
+                    HPJ_REWARD_TOP_APP_MS =
+                            properties.getLong(key, DEFAULT_HPJ_REWARD_TOP_APP_MS);
+                    // Limit top reward to be in the range [10 seconds, 15 minutes] per event.
+                    long newTopReward = Math.min(15 * MINUTE_IN_MILLIS,
+                            Math.max(10 * SECOND_IN_MILLIS, HPJ_REWARD_TOP_APP_MS));
+                    if (mHpjRewardTopAppMs != newTopReward) {
+                        mHpjRewardTopAppMs = newTopReward;
+                        if (mHpjTopAppTimeChunkSizeMs < mHpjRewardTopAppMs) {
+                            // Not making chunk sizes and top rewards to be the upper/lower
+                            // limits of the other to allow trying different policies. Just log
+                            // the discrepancy.
+                            Slog.w(TAG, "HPJ top app time chunk less than reward: "
+                                    + mHpjTopAppTimeChunkSizeMs + " vs " + mHpjRewardTopAppMs);
+                        }
+                    }
+                    break;
+                case KEY_HPJ_REWARD_INTERACTION_MS:
+                    // We don't need to re-evaluate execution stats or constraint status for this.
+                    HPJ_REWARD_INTERACTION_MS =
+                            properties.getLong(key, DEFAULT_HPJ_REWARD_INTERACTION_MS);
+                    // Limit interaction reward to be in the range [5 seconds, 15 minutes] per
+                    // event.
+                    long newInteractionReward = Math.min(15 * MINUTE_IN_MILLIS,
+                            Math.max(5 * SECOND_IN_MILLIS, HPJ_REWARD_INTERACTION_MS));
+                    if (mHpjRewardInteractionMs != newInteractionReward) {
+                        mHpjRewardInteractionMs = newInteractionReward;
+                    }
+                    break;
+                case KEY_HPJ_REWARD_NOTIFICATION_SEEN_MS:
+                    // We don't need to re-evaluate execution stats or constraint status for this.
+                    HPJ_REWARD_NOTIFICATION_SEEN_MS =
+                            properties.getLong(key, DEFAULT_HPJ_REWARD_NOTIFICATION_SEEN_MS);
+                    // Limit notification seen reward to be in the range [0, 5] minutes per event.
+                    long newNotiSeenReward = Math.min(5 * MINUTE_IN_MILLIS,
+                            Math.max(0, HPJ_REWARD_NOTIFICATION_SEEN_MS));
+                    if (mHpjRewardNotificationSeenMs != newNotiSeenReward) {
+                        mHpjRewardNotificationSeenMs = newNotiSeenReward;
+                    }
             }
         }
 
@@ -2598,6 +3328,75 @@
             }
         }
 
+        private void updateHpjLimitConstantsLocked() {
+            if (mHpjLimitConstantsUpdated) {
+                return;
+            }
+            mHpjLimitConstantsUpdated = true;
+
+            // Query the values as an atomic set.
+            final DeviceConfig.Properties properties = DeviceConfig.getProperties(
+                    DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+                    KEY_HPJ_LIMIT_ACTIVE_MS, KEY_HPJ_LIMIT_WORKING_MS,
+                    KEY_HPJ_LIMIT_FREQUENT_MS, KEY_HPJ_LIMIT_RARE_MS,
+                    KEY_HPJ_LIMIT_RESTRICTED_MS, KEY_HPJ_WINDOW_SIZE_MS);
+            HPJ_LIMIT_ACTIVE_MS = properties.getLong(
+                    KEY_HPJ_LIMIT_ACTIVE_MS, DEFAULT_HPJ_LIMIT_ACTIVE_MS);
+            HPJ_LIMIT_WORKING_MS = properties.getLong(
+                    KEY_HPJ_LIMIT_WORKING_MS, DEFAULT_HPJ_LIMIT_WORKING_MS);
+            HPJ_LIMIT_FREQUENT_MS = properties.getLong(
+                    KEY_HPJ_LIMIT_FREQUENT_MS, DEFAULT_HPJ_LIMIT_FREQUENT_MS);
+            HPJ_LIMIT_RARE_MS = properties.getLong(
+                    KEY_HPJ_LIMIT_RARE_MS, DEFAULT_HPJ_LIMIT_RARE_MS);
+            HPJ_LIMIT_RESTRICTED_MS = properties.getLong(
+                    KEY_HPJ_LIMIT_RESTRICTED_MS, DEFAULT_HPJ_LIMIT_RESTRICTED_MS);
+            HPJ_WINDOW_SIZE_MS = properties.getLong(
+                    KEY_HPJ_WINDOW_SIZE_MS, DEFAULT_HPJ_WINDOW_SIZE_MS);
+
+            // The window must be in the range [1 hour, 24 hours].
+            long newWindowSizeMs = Math.max(HOUR_IN_MILLIS,
+                    Math.min(MAX_PERIOD_MS, HPJ_WINDOW_SIZE_MS));
+            if (mHpjLimitWindowSizeMs != newWindowSizeMs) {
+                mHpjLimitWindowSizeMs = newWindowSizeMs;
+                mShouldReevaluateConstraints = true;
+            }
+            // The limit must be in the range [15 minutes, window size].
+            long newActiveLimitMs = Math.max(15 * MINUTE_IN_MILLIS,
+                    Math.min(newWindowSizeMs, HPJ_LIMIT_ACTIVE_MS));
+            if (mHpjLimitsMs[ACTIVE_INDEX] != newActiveLimitMs) {
+                mHpjLimitsMs[ACTIVE_INDEX] = newActiveLimitMs;
+                mShouldReevaluateConstraints = true;
+            }
+            // The limit must be in the range [15 minutes, active limit].
+            long newWorkingLimitMs = Math.max(15 * MINUTE_IN_MILLIS,
+                    Math.min(newActiveLimitMs, HPJ_LIMIT_WORKING_MS));
+            if (mHpjLimitsMs[WORKING_INDEX] != newWorkingLimitMs) {
+                mHpjLimitsMs[WORKING_INDEX] = newWorkingLimitMs;
+                mShouldReevaluateConstraints = true;
+            }
+            // The limit must be in the range [10 minutes, working limit].
+            long newFrequentLimitMs = Math.max(10 * MINUTE_IN_MILLIS,
+                    Math.min(newWorkingLimitMs, HPJ_LIMIT_FREQUENT_MS));
+            if (mHpjLimitsMs[FREQUENT_INDEX] != newFrequentLimitMs) {
+                mHpjLimitsMs[FREQUENT_INDEX] = newFrequentLimitMs;
+                mShouldReevaluateConstraints = true;
+            }
+            // The limit must be in the range [10 minutes, frequent limit].
+            long newRareLimitMs = Math.max(10 * MINUTE_IN_MILLIS,
+                    Math.min(newFrequentLimitMs, HPJ_LIMIT_RARE_MS));
+            if (mHpjLimitsMs[RARE_INDEX] != newRareLimitMs) {
+                mHpjLimitsMs[RARE_INDEX] = newRareLimitMs;
+                mShouldReevaluateConstraints = true;
+            }
+            // The limit must be in the range [0 minutes, rare limit].
+            long newRestrictedLimitMs = Math.max(0,
+                    Math.min(newRareLimitMs, HPJ_LIMIT_RESTRICTED_MS));
+            if (mHpjLimitsMs[RESTRICTED_INDEX] != newRestrictedLimitMs) {
+                mHpjLimitsMs[RESTRICTED_INDEX] = newRestrictedLimitMs;
+                mShouldReevaluateConstraints = true;
+            }
+        }
+
         private void dump(IndentingPrintWriter pw) {
             pw.println();
             pw.println("QuotaController:");
@@ -2628,6 +3427,19 @@
             pw.print(KEY_TIMING_SESSION_COALESCING_DURATION_MS,
                     TIMING_SESSION_COALESCING_DURATION_MS).println();
             pw.print(KEY_MIN_QUOTA_CHECK_DELAY_MS, MIN_QUOTA_CHECK_DELAY_MS).println();
+
+            pw.print(KEY_HPJ_LIMIT_ACTIVE_MS, HPJ_LIMIT_ACTIVE_MS).println();
+            pw.print(KEY_HPJ_LIMIT_WORKING_MS, HPJ_LIMIT_WORKING_MS).println();
+            pw.print(KEY_HPJ_LIMIT_FREQUENT_MS, HPJ_LIMIT_FREQUENT_MS).println();
+            pw.print(KEY_HPJ_LIMIT_RARE_MS, HPJ_LIMIT_RARE_MS).println();
+            pw.print(KEY_HPJ_LIMIT_RESTRICTED_MS, HPJ_LIMIT_RESTRICTED_MS).println();
+            pw.print(KEY_HPJ_WINDOW_SIZE_MS, HPJ_WINDOW_SIZE_MS).println();
+            pw.print(KEY_HPJ_TOP_APP_TIME_CHUNK_SIZE_MS, HPJ_TOP_APP_TIME_CHUNK_SIZE_MS).println();
+            pw.print(KEY_HPJ_REWARD_TOP_APP_MS, HPJ_REWARD_TOP_APP_MS).println();
+            pw.print(KEY_HPJ_REWARD_INTERACTION_MS, HPJ_REWARD_INTERACTION_MS).println();
+            pw.print(KEY_HPJ_REWARD_NOTIFICATION_SEEN_MS,
+                    HPJ_REWARD_NOTIFICATION_SEEN_MS).println();
+
             pw.decreaseIndent();
         }
 
@@ -2675,6 +3487,24 @@
                     TIMING_SESSION_COALESCING_DURATION_MS);
             proto.write(ConstantsProto.QuotaController.MIN_QUOTA_CHECK_DELAY_MS,
                     MIN_QUOTA_CHECK_DELAY_MS);
+
+            proto.write(ConstantsProto.QuotaController.HPJ_LIMIT_ACTIVE_MS, HPJ_LIMIT_ACTIVE_MS);
+            proto.write(ConstantsProto.QuotaController.HPJ_LIMIT_WORKING_MS, HPJ_LIMIT_WORKING_MS);
+            proto.write(ConstantsProto.QuotaController.HPJ_LIMIT_FREQUENT_MS,
+                    HPJ_LIMIT_FREQUENT_MS);
+            proto.write(ConstantsProto.QuotaController.HPJ_LIMIT_RARE_MS, HPJ_LIMIT_RARE_MS);
+            proto.write(ConstantsProto.QuotaController.HPJ_LIMIT_RESTRICTED_MS,
+                    HPJ_LIMIT_RESTRICTED_MS);
+            proto.write(ConstantsProto.QuotaController.HPJ_WINDOW_SIZE_MS, HPJ_WINDOW_SIZE_MS);
+            proto.write(ConstantsProto.QuotaController.HPJ_TOP_APP_TIME_CHUNK_SIZE_MS,
+                    HPJ_TOP_APP_TIME_CHUNK_SIZE_MS);
+            proto.write(ConstantsProto.QuotaController.HPJ_REWARD_TOP_APP_MS,
+                    HPJ_REWARD_TOP_APP_MS);
+            proto.write(ConstantsProto.QuotaController.HPJ_REWARD_INTERACTION_MS,
+                    HPJ_REWARD_INTERACTION_MS);
+            proto.write(ConstantsProto.QuotaController.HPJ_REWARD_NOTIFICATION_SEEN_MS,
+                    HPJ_REWARD_NOTIFICATION_SEEN_MS);
+
             proto.end(qcToken);
         }
     }
@@ -2717,6 +3547,49 @@
     }
 
     @VisibleForTesting
+    @NonNull
+    long[] getHpjLimitsMs() {
+        return mHpjLimitsMs;
+    }
+
+    @VisibleForTesting
+    @NonNull
+    long getHpjLimitWindowSizeMs() {
+        return mHpjLimitWindowSizeMs;
+    }
+
+    @VisibleForTesting
+    @NonNull
+    long getHpjRewardInteractionMs() {
+        return mHpjRewardInteractionMs;
+    }
+
+    @VisibleForTesting
+    @NonNull
+    long getHpjRewardNotificationSeenMs() {
+        return mHpjRewardNotificationSeenMs;
+    }
+
+    @VisibleForTesting
+    @NonNull
+    long getHpjRewardTopAppMs() {
+        return mHpjRewardTopAppMs;
+    }
+
+
+    @VisibleForTesting
+    @Nullable
+    List<TimingSession> getHpjTimingSessions(int userId, String packageName) {
+        return mHpjTimingSessions.get(userId, packageName);
+    }
+
+    @VisibleForTesting
+    @NonNull
+    long getHpjTopAppTimeChunkSizeMs() {
+        return mHpjTopAppTimeChunkSizeMs;
+    }
+
+    @VisibleForTesting
     long getInQuotaBufferMs() {
         return mQuotaBufferMs;
     }
@@ -2763,6 +3636,11 @@
         return mQcConstants;
     }
 
+    @VisibleForTesting
+    boolean isActiveBackgroundProcessing() {
+        return mHandler.mIsProcessing;
+    }
+
     //////////////////////////// DATA DUMP //////////////////////////////
 
     @Override
@@ -2805,16 +3683,24 @@
                 pw.increaseIndent();
                 pw.print(JobStatus.bucketName(js.getEffectiveStandbyBucket()));
                 pw.print(", ");
-                if (js.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)) {
-                    pw.print("within quota");
+                if (js.shouldTreatAsForegroundJob()) {
+                    pw.print("within HPJ quota");
+                } else if (js.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)) {
+                    pw.print("within regular quota");
                 } else {
                     pw.print("not within quota");
                 }
                 pw.print(", ");
-                pw.print(getRemainingExecutionTimeLocked(js));
-                pw.print("ms remaining in quota");
-                pw.decreaseIndent();
+                if (js.shouldTreatAsForegroundJob()) {
+                    pw.print(getRemainingHpjExecutionTimeLocked(
+                            js.getSourceUserId(), js.getSourcePackageName()));
+                    pw.print("ms remaining in HPJ quota");
+                } else {
+                    pw.print(getRemainingExecutionTimeLocked(js));
+                    pw.print("ms remaining in quota");
+                }
                 pw.println();
+                pw.decreaseIndent();
             }
         });
 
@@ -2841,6 +3727,33 @@
             }
         }
 
+        pw.println();
+        for (int u = 0; u < mHpjPkgTimers.numMaps(); ++u) {
+            final int userId = mHpjPkgTimers.keyAt(u);
+            for (int p = 0; p < mHpjPkgTimers.numElementsForKey(userId); ++p) {
+                final String pkgName = mHpjPkgTimers.keyAt(u, p);
+                mHpjPkgTimers.valueAt(u, p).dump(pw, predicate);
+                pw.println();
+                List<TimingSession> sessions = mHpjTimingSessions.get(userId, pkgName);
+                if (sessions != null) {
+                    pw.increaseIndent();
+                    pw.println("Saved sessions:");
+                    pw.increaseIndent();
+                    for (int j = sessions.size() - 1; j >= 0; j--) {
+                        TimingSession session = sessions.get(j);
+                        session.dump(pw);
+                    }
+                    pw.decreaseIndent();
+                    pw.decreaseIndent();
+                    pw.println();
+                }
+            }
+        }
+
+        pw.println();
+        mTopAppTrackers.forEach((timer) -> timer.dump(pw));
+
+        pw.println();
         pw.println("Cached execution stats:");
         pw.increaseIndent();
         for (int u = 0; u < mExecutionStatsCache.numMaps(); ++u) {
@@ -2865,6 +3778,22 @@
         pw.decreaseIndent();
 
         pw.println();
+        pw.println("HPJ debits:");
+        pw.increaseIndent();
+        for (int u = 0; u < mHpjStats.numMaps(); ++u) {
+            final int userId = mHpjStats.keyAt(u);
+            for (int p = 0; p < mHpjStats.numElementsForKey(userId); ++p) {
+                final String pkgName = mHpjStats.keyAt(u, p);
+                ShrinkableDebits debits = mHpjStats.valueAt(u, p);
+
+                pw.print(string(userId, pkgName));
+                pw.print(": ");
+                debits.dumpLocked(pw);
+            }
+        }
+        pw.decreaseIndent();
+
+        pw.println();
         mInQuotaAlarmListener.dumpLocked(pw);
         pw.decreaseIndent();
     }
@@ -2919,6 +3848,12 @@
                         js.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
                 proto.write(StateControllerProto.QuotaController.TrackedJob.REMAINING_QUOTA_MS,
                         getRemainingExecutionTimeLocked(js));
+                proto.write(
+                        StateControllerProto.QuotaController.TrackedJob.IS_REQUESTED_FOREGROUND_JOB,
+                        js.isRequestedForegroundJob());
+                proto.write(
+                        StateControllerProto.QuotaController.TrackedJob.IS_WITHIN_FG_JOB_QUOTA,
+                        js.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_HPJ_QUOTA));
                 proto.end(jsToken);
             }
         });
@@ -2929,8 +3864,15 @@
                 final String pkgName = mPkgTimers.keyAt(u, p);
                 final long psToken = proto.start(
                         StateControllerProto.QuotaController.PACKAGE_STATS);
+
                 mPkgTimers.valueAt(u, p).dump(proto,
                         StateControllerProto.QuotaController.PackageStats.TIMER, predicate);
+                final Timer hpjTimer = mHpjPkgTimers.get(userId, pkgName);
+                if (hpjTimer != null) {
+                    hpjTimer.dump(proto,
+                            StateControllerProto.QuotaController.PackageStats.FG_JOB_TIMER,
+                            predicate);
+                }
 
                 List<TimingSession> sessions = mTimingSessions.get(userId, pkgName);
                 if (sessions != null) {
diff --git a/apex/statsd/.clang-format b/apex/statsd/.clang-format
deleted file mode 100644
index cead3a0..0000000
--- a/apex/statsd/.clang-format
+++ /dev/null
@@ -1,17 +0,0 @@
-BasedOnStyle: Google
-AllowShortIfStatementsOnASingleLine: true
-AllowShortFunctionsOnASingleLine: false
-AllowShortLoopsOnASingleLine: true
-BinPackArguments: true
-BinPackParameters: true
-ColumnLimit: 100
-CommentPragmas: NOLINT:.*
-ContinuationIndentWidth: 8
-DerivePointerAlignment: false
-IndentWidth: 4
-PointerAlignment: Left
-TabWidth: 4
-AccessModifierOffset: -4
-IncludeCategories:
-  - Regex:    '^"Log\.h"'
-    Priority:    -1
diff --git a/apex/statsd/Android.bp b/apex/statsd/Android.bp
deleted file mode 100644
index f13861e..0000000
--- a/apex/statsd/Android.bp
+++ /dev/null
@@ -1,83 +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.
-
-apex {
-    name: "com.android.os.statsd",
-    defaults: ["com.android.os.statsd-defaults"],
-    manifest: "apex_manifest.json",
-}
-
-apex_defaults {
-    jni_libs: [
-        "libstats_jni",
-    ],
-    native_shared_libs: [
-        "libstatspull",
-        "libstatssocket",
-    ],
-    binaries: ["statsd"],
-    java_libs: [
-        "framework-statsd",
-        "service-statsd",
-    ],
-    compile_multilib: "both",
-    prebuilts: ["com.android.os.statsd.init.rc"],
-    name: "com.android.os.statsd-defaults",
-    updatable: true,
-    min_sdk_version: "30",
-    key: "com.android.os.statsd.key",
-    certificate: ":com.android.os.statsd.certificate",
-}
-
-apex_key {
-    name: "com.android.os.statsd.key",
-    public_key: "com.android.os.statsd.avbpubkey",
-    private_key: "com.android.os.statsd.pem",
-}
-
-android_app_certificate {
-    name: "com.android.os.statsd.certificate",
-    // This will use com.android.os.statsd.x509.pem (the cert) and
-    // com.android.os.statsd.pk8 (the private key)
-    certificate: "com.android.os.statsd",
-}
-
-prebuilt_etc {
-    name: "com.android.os.statsd.init.rc",
-    src: "statsd.rc",
-    filename: "init.rc",
-    installable: false,
-}
-
-// JNI library for StatsLog.write
-cc_library_shared {
-    name: "libstats_jni",
-    srcs: ["jni/**/*.cpp"],
-    header_libs: ["libnativehelper_header_only"],
-    shared_libs: [
-        "liblog",  // Has a stable abi - should not be copied into apex.
-        "libstatssocket",
-    ],
-    stl: "libc++_static",
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wextra",
-        "-Wno-unused-parameter",
-    ],
-    apex_available: [
-        "com.android.os.statsd",
-        "test_com.android.os.statsd",
-    ],
-}
diff --git a/apex/statsd/OWNERS b/apex/statsd/OWNERS
deleted file mode 100644
index bed9600..0000000
--- a/apex/statsd/OWNERS
+++ /dev/null
@@ -1,9 +0,0 @@
-jeffreyhuang@google.com
-joeo@google.com
-jtnguyen@google.com
-muhammadq@google.com
-ruchirr@google.com
-singhtejinder@google.com
-tsaichristine@google.com
-yaochen@google.com
-yro@google.com
\ No newline at end of file
diff --git a/apex/statsd/TEST_MAPPING b/apex/statsd/TEST_MAPPING
deleted file mode 100644
index 331fe77..0000000
--- a/apex/statsd/TEST_MAPPING
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-  "presubmit" : [
-    {
-      "name" : "FrameworkStatsdTest"
-    },
-    {
-      "name" : "LibStatsPullTests"
-    }
-  ],
-
-  "postsubmit" : [
-    {
-      "name" : "CtsStatsdHostTestCases"
-    },
-    {
-      "name" : "GtsStatsdHostTestCases"
-    }
-  ]
-}
diff --git a/apex/statsd/aidl/Android.bp b/apex/statsd/aidl/Android.bp
deleted file mode 100644
index f66cf7c..0000000
--- a/apex/statsd/aidl/Android.bp
+++ /dev/null
@@ -1,52 +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.
-//
-filegroup {
-    name: "framework-statsd-aidl-sources",
-    srcs: ["**/*.aidl"],
-}
-
-aidl_interface {
-    name: "statsd-aidl",
-    unstable: true,
-    srcs: [
-        "android/os/IPendingIntentRef.aidl",
-        "android/os/IPullAtomCallback.aidl",
-        "android/os/IPullAtomResultReceiver.aidl",
-        "android/os/IStatsCompanionService.aidl",
-        "android/os/IStatsd.aidl",
-        "android/os/StatsDimensionsValueParcel.aidl",
-        "android/util/StatsEventParcel.aidl",
-    ],
-    host_supported: true,
-    backend: {
-        java: {
-            enabled: false, // framework-statsd and service-statsd use framework-statsd-aidl-sources
-        },
-        cpp: {
-            enabled: false,
-        },
-        ndk: {
-            enabled: true,
-            apex_available: [
-                // TODO(b/145923087): Remove this once statsd binary is in apex
-                "//apex_available:platform",
-
-                "com.android.os.statsd",
-                "test_com.android.os.statsd",
-            ],
-        },
-    }
-}
diff --git a/apex/statsd/aidl/android/os/IPendingIntentRef.aidl b/apex/statsd/aidl/android/os/IPendingIntentRef.aidl
deleted file mode 100644
index 000a699..0000000
--- a/apex/statsd/aidl/android/os/IPendingIntentRef.aidl
+++ /dev/null
@@ -1,46 +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.
- */
-
-package android.os;
-
-import android.os.StatsDimensionsValueParcel;
-
-/**
-  * Binder interface to hold a PendingIntent for StatsCompanionService.
-  * {@hide}
-  */
-interface IPendingIntentRef {
-
-    /**
-     * Sends a broadcast to the specified PendingIntent that it should getData now.
-     * This should be only called from StatsCompanionService.
-     */
-     oneway void sendDataBroadcast(long lastReportTimeNs);
-
-    /**
-     * Send a broadcast to the specified PendingIntent notifying it that the list of active configs
-     * has changed. This should be only called from StatsCompanionService.
-     */
-     oneway void sendActiveConfigsChangedBroadcast(in long[] configIds);
-
-     /**
-      * Send a broadcast to the specified PendingIntent, along with the other information
-      * specified. This should only be called from StatsCompanionService.
-      */
-     oneway void sendSubscriberBroadcast(long configUid, long configId, long subscriptionId,
-                                         long subscriptionRuleId, in String[] cookies,
-                                         in StatsDimensionsValueParcel dimensionsValueParcel);
-}
diff --git a/apex/statsd/aidl/android/os/IPullAtomCallback.aidl b/apex/statsd/aidl/android/os/IPullAtomCallback.aidl
deleted file mode 100644
index ff0b97b..0000000
--- a/apex/statsd/aidl/android/os/IPullAtomCallback.aidl
+++ /dev/null
@@ -1,31 +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.
- */
-
-package android.os;
-
-import android.os.IPullAtomResultReceiver;
-
-/**
-  * Binder interface to pull atoms for the stats service.
-  * {@hide}
-  */
-interface IPullAtomCallback {
-    /**
-     * Initiate a request for a pull for an atom.
-     */
-     oneway void onPullAtom(int atomTag, IPullAtomResultReceiver resultReceiver);
-
-}
diff --git a/apex/statsd/aidl/android/os/IPullAtomResultReceiver.aidl b/apex/statsd/aidl/android/os/IPullAtomResultReceiver.aidl
deleted file mode 100644
index 00d026e..0000000
--- a/apex/statsd/aidl/android/os/IPullAtomResultReceiver.aidl
+++ /dev/null
@@ -1,32 +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.
- */
-
-package android.os;
-
-import android.util.StatsEventParcel;
-
-/**
-  * Binder interface to pull atoms for the stats service.
-  * {@hide}
-  */
-interface IPullAtomResultReceiver {
-
-    /**
-     * Indicate that a pull request for an atom is complete.
-     */
-     oneway void pullFinished(int atomTag, boolean success, in StatsEventParcel[] output);
-
-}
diff --git a/apex/statsd/aidl/android/os/IStatsCompanionService.aidl b/apex/statsd/aidl/android/os/IStatsCompanionService.aidl
deleted file mode 100644
index d56a4bd..0000000
--- a/apex/statsd/aidl/android/os/IStatsCompanionService.aidl
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os;
-
-/**
-  * Binder interface to communicate with the Java-based statistics service helper.
-  * {@hide}
-  */
-interface IStatsCompanionService {
-    /**
-     * Tell statscompanion that stastd is up and running.
-     */
-    oneway void statsdReady();
-
-    /**
-      * Register a repeating alarm for pulling to fire at the given timestamp and every
-      * intervalMs thereafter (in ms since epoch).
-      * If polling alarm had already been registered, it will be replaced by new one.
-      * Uses AlarmManager.setRepeating API, so if the timestamp is in past, alarm fires immediately,
-      * and alarm is inexact.
-      */
-    oneway void setPullingAlarm(long nextPullTimeMs);
-
-    /** Cancel any repeating pulling alarm. */
-    oneway void cancelPullingAlarm();
-
-    /**
-      * Register an alarm when we want to trigger subscribers at the given
-      * timestamp (in ms since epoch).
-      * If an alarm had already been registered, it will be replaced by new one.
-      */
-    oneway void setAlarmForSubscriberTriggering(long timestampMs);
-
-    /** Cancel any alarm for the purpose of subscriber triggering. */
-    oneway void cancelAlarmForSubscriberTriggering();
-
-    /**
-     * Ask StatsCompanionService if the given permission is allowed for a particular process
-     * and user ID. statsd is incapable of doing this check itself because checkCallingPermission
-     * is not currently supported by libbinder_ndk.
-     */
-    boolean checkPermission(String permission, int pid, int uid);
-}
diff --git a/apex/statsd/aidl/android/os/IStatsManagerService.aidl b/apex/statsd/aidl/android/os/IStatsManagerService.aidl
deleted file mode 100644
index b59a97e..0000000
--- a/apex/statsd/aidl/android/os/IStatsManagerService.aidl
+++ /dev/null
@@ -1,136 +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.
- */
-
-package android.os;
-
-import android.app.PendingIntent;
-import android.os.IPullAtomCallback;
-
-/**
-  * Binder interface to communicate with the Java-based statistics service helper.
-  * Contains parcelable objects available only in Java.
-  * {@hide}
-  */
-interface IStatsManagerService {
-
-    /**
-     * Registers the given pending intent for this config key. This intent is invoked when the
-     * memory consumed by the metrics for this configuration approach the pre-defined limits. There
-     * can be at most one listener per config key.
-     *
-     * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
-     */
-    void setDataFetchOperation(long configId, in PendingIntent pendingIntent,
-        in String packageName);
-
-    /**
-     * Removes the data fetch operation for the specified configuration.
-     *
-     * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
-     */
-    void removeDataFetchOperation(long configId, in String packageName);
-
-    /**
-     * Registers the given pending intent for this packagename. This intent is invoked when the
-     * active status of any of the configs sent by this package changes and will contain a list of
-     * config ids that are currently active. It also returns the list of configs that are currently
-     * active. There can be at most one active configs changed listener per package.
-     *
-     * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
-     */
-    long[] setActiveConfigsChangedOperation(in PendingIntent pendingIntent, in String packageName);
-
-    /**
-     * Removes the active configs changed operation for the specified package name.
-     *
-     * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
-     */
-    void removeActiveConfigsChangedOperation(in String packageName);
-
-    /**
-     * Set the PendingIntent to be used when broadcasting subscriber
-     * information to the given subscriberId within the given config.
-     *
-     * Suppose that the calling uid has added a config with key configKey, and that in this config
-     * it is specified that when a particular anomaly is detected, a broadcast should be sent to
-     * a BroadcastSubscriber with id subscriberId. This function links the given pendingIntent with
-     * that subscriberId (for that config), so that this pendingIntent is used to send the broadcast
-     * when the anomaly is detected.
-     *
-     * This function can only be called by the owner (uid) of the config. It must be called each
-     * time statsd starts. Later calls overwrite previous calls; only one PendingIntent is stored.
-     *
-     * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
-     */
-    void setBroadcastSubscriber(long configKey, long subscriberId, in PendingIntent pendingIntent,
-                                in String packageName);
-
-    /**
-     * Undoes setBroadcastSubscriber() for the (configKey, subscriberId) pair.
-     * Any broadcasts associated with subscriberId will henceforth not be sent.
-     * No-op if this (configKey, subscriberId) pair was not associated with an PendingIntent.
-     *
-     * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
-     */
-    void unsetBroadcastSubscriber(long configKey, long subscriberId, in String packageName);
-
-    /**
-     * Returns the most recently registered experiment IDs.
-     *
-     * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
-     */
-    long[] getRegisteredExperimentIds();
-
-    /**
-     * Fetches metadata across statsd. Returns byte array representing wire-encoded proto.
-     *
-     * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
-     */
-    byte[] getMetadata(in String packageName);
-
-    /**
-     * Fetches data for the specified configuration key. Returns a byte array representing proto
-     * wire-encoded of ConfigMetricsReportList.
-     *
-     * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
-     */
-    byte[] getData(in long key, in String packageName);
-
-    /**
-     * Sets a configuration with the specified config id and subscribes to updates for this
-     * configuration id. Broadcasts will be sent if this configuration needs to be collected.
-     * The configuration must be a wire-encoded StatsdConfig. The receiver for this data is
-     * registered in a separate function.
-     *
-     * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
-     */
-    void addConfiguration(in long configId, in byte[] config, in String packageName);
-
-    /**
-     * Removes the configuration with the matching config id. No-op if this config id does not
-     * exist.
-     *
-     * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
-     */
-    void removeConfiguration(in long configId, in String packageName);
-
-    /** Tell StatsManagerService to register a puller for the given atom tag with statsd. */
-    oneway void registerPullAtomCallback(int atomTag, long coolDownMillis, long timeoutMillis,
-            in int[] additiveFields, IPullAtomCallback pullerCallback);
-
-    /** Tell StatsManagerService to unregister the pulller for the given atom tag from statsd. */
-    oneway void unregisterPullAtomCallback(int atomTag);
-}
diff --git a/apex/statsd/aidl/android/os/IStatsd.aidl b/apex/statsd/aidl/android/os/IStatsd.aidl
deleted file mode 100644
index 066412a..0000000
--- a/apex/statsd/aidl/android/os/IStatsd.aidl
+++ /dev/null
@@ -1,230 +0,0 @@
-/**
- * Copyright (c) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os;
-
-import android.os.IPendingIntentRef;
-import android.os.IPullAtomCallback;
-import android.os.ParcelFileDescriptor;
-
-/**
-  * Binder interface to communicate with the statistics management service.
-  * {@hide}
-  */
-interface IStatsd {
-    /**
-     * Tell the stats daemon that the android system server is up and running.
-     */
-    oneway void systemRunning();
-
-    /**
-     * Tell the stats daemon that the android system has finished booting.
-     */
-    oneway void bootCompleted();
-
-    /**
-     * Tell the stats daemon that the StatsCompanionService is up and running.
-     * Two-way binder call so that caller knows message received.
-     */
-    void statsCompanionReady();
-
-    /**
-     * Tells statsd that it is time to poll some stats. Statsd will be responsible for determing
-     * what stats to poll and initiating the polling.
-     * Two-way binder call so that caller's method (and corresponding wakelocks) will linger.
-     */
-    void informPollAlarmFired();
-
-    /**
-     * Tells statsd that it is time to handle periodic alarms. Statsd will be responsible for
-     * determing what alarm subscriber to trigger.
-     * Two-way binder call so that caller's method (and corresponding wakelocks) will linger.
-     */
-    void informAlarmForSubscriberTriggeringFired();
-
-    /**
-     * Tells statsd that the device is about to shutdown.
-     */
-    void informDeviceShutdown();
-
-    /**
-     * Inform statsd about a file descriptor for a pipe through which we will pipe version
-     * and package information for each uid.
-     * Versions and package information are supplied via UidData proto where info for each app
-     * is captured in its own element of a repeated ApplicationInfo message.
-     */
-    oneway void informAllUidData(in ParcelFileDescriptor fd);
-
-    /**
-     * Inform statsd what the uid, version, version_string, and installer are for one app that was
-     * updated.
-     */
-    oneway void informOnePackage(in String app, in int uid, in long version,
-        in String version_string, in String installer);
-
-    /**
-     * Inform stats that an app was removed.
-     */
-    oneway void informOnePackageRemoved(in String app, in int uid);
-
-    /**
-     * Fetches data for the specified configuration key. Returns a byte array representing proto
-     * wire-encoded of ConfigMetricsReportList.
-     *
-     * Requires Manifest.permission.DUMP.
-     */
-    byte[] getData(in long key, int callingUid);
-
-    /**
-     * Fetches metadata across statsd. Returns byte array representing wire-encoded proto.
-     *
-     * Requires Manifest.permission.DUMP.
-     */
-    byte[] getMetadata();
-
-    /**
-     * Sets a configuration with the specified config id and subscribes to updates for this
-     * configuration key. Broadcasts will be sent if this configuration needs to be collected.
-     * The configuration must be a wire-encoded StatsdConfig. The receiver for this data is
-     * registered in a separate function.
-     *
-     * Requires Manifest.permission.DUMP.
-     */
-    void addConfiguration(in long configId, in byte[] config, in int callingUid);
-
-    /**
-     * Registers the given pending intent for this config key. This intent is invoked when the
-     * memory consumed by the metrics for this configuration approach the pre-defined limits. There
-     * can be at most one listener per config key.
-     *
-     * Requires Manifest.permission.DUMP.
-     */
-    void setDataFetchOperation(long configId, in IPendingIntentRef pendingIntentRef,
-                               int callingUid);
-
-    /**
-     * Removes the data fetch operation for the specified configuration.
-     *
-     * Requires Manifest.permission.DUMP.
-     */
-    void removeDataFetchOperation(long configId, int callingUid);
-
-    /**
-     * Registers the given pending intent for this packagename. This intent is invoked when the
-     * active status of any of the configs sent by this package changes and will contain a list of
-     * config ids that are currently active. It also returns the list of configs that are currently
-     * active. There can be at most one active configs changed listener per package.
-     *
-     * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
-     */
-    long[] setActiveConfigsChangedOperation(in IPendingIntentRef pendingIntentRef, int callingUid);
-
-    /**
-     * Removes the active configs changed operation for the specified package name.
-     *
-     * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
-     */
-    void removeActiveConfigsChangedOperation(int callingUid);
-
-    /**
-     * Removes the configuration with the matching config id. No-op if this config id does not
-     * exist.
-     *
-     * Requires Manifest.permission.DUMP.
-     */
-    void removeConfiguration(in long configId, in int callingUid);
-
-    /**
-     * Set the PendingIntentRef to be used when broadcasting subscriber
-     * information to the given subscriberId within the given config.
-     *
-     * Suppose that the calling uid has added a config with key configId, and that in this config
-     * it is specified that when a particular anomaly is detected, a broadcast should be sent to
-     * a BroadcastSubscriber with id subscriberId. This function links the given pendingIntent with
-     * that subscriberId (for that config), so that this pendingIntent is used to send the broadcast
-     * when the anomaly is detected.
-     *
-     * This function can only be called by the owner (uid) of the config. It must be called each
-     * time statsd starts. Later calls overwrite previous calls; only one pendingIntent is stored.
-     *
-     * Requires Manifest.permission.DUMP.
-     */
-    void setBroadcastSubscriber(long configId, long subscriberId, in IPendingIntentRef pir,
-                                int callingUid);
-
-    /**
-     * Undoes setBroadcastSubscriber() for the (configId, subscriberId) pair.
-     * Any broadcasts associated with subscriberId will henceforth not be sent.
-     * No-op if this (configKey, subscriberId) pair was not associated with an PendingIntentRef.
-     *
-     * Requires Manifest.permission.DUMP.
-     */
-    void unsetBroadcastSubscriber(long configId, long subscriberId, int callingUid);
-
-    /**
-     * Tell the stats daemon that all the pullers registered during boot have been sent.
-     */
-    oneway void allPullersFromBootRegistered();
-
-    /**
-     * Registers a puller callback function that, when invoked, pulls the data
-     * for the specified atom tag.
-     */
-    oneway void registerPullAtomCallback(int uid, int atomTag, long coolDownMillis,
-                                         long timeoutMillis,in int[] additiveFields,
-                                         IPullAtomCallback pullerCallback);
-
-    /**
-     * Registers a puller callback function that, when invoked, pulls the data
-     * for the specified atom tag.
-     *
-     * Enforces the REGISTER_STATS_PULL_ATOM permission.
-     */
-    oneway void registerNativePullAtomCallback(int atomTag, long coolDownMillis, long timeoutMillis,
-                           in int[] additiveFields, IPullAtomCallback pullerCallback);
-
-    /**
-     * Unregisters any pullAtomCallback for the given uid/atom.
-     */
-    oneway void unregisterPullAtomCallback(int uid, int atomTag);
-
-    /**
-     * Unregisters any pullAtomCallback for the given atom + caller.
-     *
-     * Enforces the REGISTER_STATS_PULL_ATOM permission.
-     */
-    oneway void unregisterNativePullAtomCallback(int atomTag);
-
-    /**
-     * The install requires staging.
-     */
-    const int FLAG_REQUIRE_STAGING = 0x01;
-
-    /**
-     * Rollback is enabled with this install.
-     */
-    const int FLAG_ROLLBACK_ENABLED = 0x02;
-
-    /**
-     * Requires low latency monitoring.
-     */
-    const int FLAG_REQUIRE_LOW_LATENCY_MONITOR = 0x04;
-
-    /**
-     * Returns the most recently registered experiment IDs.
-     */
-    long[] getRegisteredExperimentIds();
-}
diff --git a/apex/statsd/aidl/android/os/StatsDimensionsValueParcel.aidl b/apex/statsd/aidl/android/os/StatsDimensionsValueParcel.aidl
deleted file mode 100644
index 05f78d0..0000000
--- a/apex/statsd/aidl/android/os/StatsDimensionsValueParcel.aidl
+++ /dev/null
@@ -1,21 +0,0 @@
-package android.os;
-
-/**
- * @hide
- */
-parcelable StatsDimensionsValueParcel {
-    // Field equals atomTag for top level StatsDimensionsValueParcels or
-    // positions in depth (1-indexed) for lower level parcels.
-    int field;
-
-    // Indicator for which type of value is stored. Should be set to one
-    // of the constants in StatsDimensionsValue.java.
-    int valueType;
-
-    String stringValue;
-    int intValue;
-    long longValue;
-    boolean boolValue;
-    float floatValue;
-    StatsDimensionsValueParcel[] tupleValue;
-}
diff --git a/apex/statsd/aidl/android/util/StatsEventParcel.aidl b/apex/statsd/aidl/android/util/StatsEventParcel.aidl
deleted file mode 100644
index add8bfb..0000000
--- a/apex/statsd/aidl/android/util/StatsEventParcel.aidl
+++ /dev/null
@@ -1,8 +0,0 @@
-package android.util;
-
-/**
- * @hide
- */
-parcelable StatsEventParcel {
-    byte[] buffer;
-}
diff --git a/apex/statsd/apex_manifest.json b/apex/statsd/apex_manifest.json
deleted file mode 100644
index 1d029c6..0000000
--- a/apex/statsd/apex_manifest.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "name": "com.android.os.statsd",
-  "version": 309999900
-}
-
diff --git a/apex/statsd/com.android.os.statsd.avbpubkey b/apex/statsd/com.android.os.statsd.avbpubkey
deleted file mode 100644
index d78af8b..0000000
--- a/apex/statsd/com.android.os.statsd.avbpubkey
+++ /dev/null
Binary files differ
diff --git a/apex/statsd/com.android.os.statsd.pem b/apex/statsd/com.android.os.statsd.pem
deleted file mode 100644
index 558e17f..0000000
--- a/apex/statsd/com.android.os.statsd.pem
+++ /dev/null
@@ -1,51 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIJKgIBAAKCAgEA893bbpkivKEiNgfknYBSlzC0csaKU/ddBm5Pb4ZFuab+LQSR
-9DDc5JrsmxyrsrvuwL/zAtMbkyYWzEiUxJtx/w0bw8rC90GoPRSCmxyI0ZK8FuPy
-IAQ7UeNfTWZ485mAUaTSasGIfQ3DY4F0P+aUSijeG3NUY02nALHDMqJX7lXR+mL1
-DUYDg05KB0jxQwlYqBeujTPPiAzEqm3PlBoHuan8/qgK2wdQMTVg/fieUD3lupmV
-Wj2dRZgqfBPA16ZbV4Uo0j0bZSf+fQLiXlU2VJGb5i/FQfjLqMKGABDI0MgK7Sc2
-m4ySpV4g4XKDv/vw6Dw4kwWC7mATEVAkH+q6V7uiZeN6a7w30UMtPI8fPaUvAP3L
-VBjCBIv/3m+CKkWcNxOZ3sQBQl5bS05dxcfiVsBvBLYbvQgC+Wy0Sc3b+1pXFT/E
-uAsbZ4CyVsi1+PAdx3h5e2QAyNCXgZDOcvTUyxY6JLTE0LOVHmI4fJEujBex//Oz
-PCRHvC8K+KiljyQWf/NYrLSD3QGYAjVMtQh7yu2yhzWzgBUxyhuv3rY4ATXsN3bJ
-wW4w7/L/RSLSW5+lp/NoJOD9utbsKTyGMHOY6K8JLOmhv3ORoAEmLYlFTI+FqBi9
-AH1HQEKCyh8Z/bYHLUzGWl6FqAMtcnuintv40BbKyt0/D1ItdbSNKmOZ5rkCAwEA
-AQKCAgAY7ll8mRNADYkd1Pi+UVwgMM6B3WJO6z8LZUOhtyxxqmzZ1VnGiShMBrqh
-sPCsuSHTeswxQbvT81TpVZI/91RUKtbn0VbVSFUWyX4AtY4XPtUT0gHy2/vkh0Y6
-93ruDIdd0Wfhmh+GCV4sUhO8ZKpMWpk6XTQHYuzr2UCHcKlkqElrO6qpzLqXNe3D
-iOWBYPc7WBB0RxO0aPnCIq/SCEc55/MBZdSWR80e+sILtNsagPl3djQaoanub3wI
-a0yPv2YfMHHX7H9cfBY8WYsi8bs4MhqqEcAs2m6XtitU3mJpVcooLJYcmOZ1GYZr
-BfYKLouWcnGmNi4IiLHqVzMaQDkEhAZsRaAXCkoVVrFBedLlmLPpiUIQlINF4vxe
-3IcekTKWyMzkU6h+K8T15MU5mLSqeL2Gji1JIwKJno51FZ9uc++pUJVtfYQmNny8
-8RKvQ1hv/S5yLQKgN+VkNbaWlUoMP73dtUe3m/At71/2Dj7xB0KtcgT1lEMrM1GR
-oynJAJLz/d0n5RUUREwkZZMcA4fQVC7Db6vpK69jPiQMShpZ3JKCEjfYLUuN0slt
-FPhjiR175E0vTRuLoIj4kXNwLLswH0c9zqrKM2S92SCxAV3E4JJGKhUZalvT9s1g
-LrPhMCl6CsOES98T87d3RyAIK0iVRCnRUG3bc+8rzyRd4fzkAQKCAQEA/UjmCSm3
-H46t/1w7YBZPew7SFQOAJe81iDzbonc3fNPD2R8lxtD3MwdvrQ5f9fhT4+uveWNr
-dyBX7ppnissyM3LZRN+7BdeIVVeIPVen6Ou9W2i7q18ZoQx9IpRcZEw5tGJFZaGx
-EmyPN4i1K0ccUkGbBvbXXQ/tcG3wElRpBAc5/TQ8vrpUgHll2/MbYhowx6P9uHv5
-thoyG98X+7Fbg8ikzw5GtyuedXfyX1CpJ7yUQVS2PEaOMXOkZdx2bbWRAYYCpsqB
-dMmjs2PsFhZHu6CpLhlocHbfUiRztCUCaMZJPQXFSVmy8QDMvZEdVLvad9Poi8ny
-lmHVRgxaNbAtIQKCAQEA9nscqRaaO7hIX9bOUxcDbI0486Ws4H0hAFApIN+6/LP4
-hkxey3xWArTYWrvSG1d5GkJAdn99ayWzo2PevmJlrhIJiO1QqYBAk+87cnhwSCmB
-kb0sGkNWcc/xNRy7eqdhyCmVhaUnIbORee+cD6qiu/l2BAclTf2ZARFOGXjhQkvt
-cDbc/9ZR467ceXbiTIU34Be4xnNAY1mo59jvwl9eqxgpefYTqPhcZ7OmlDli77Hd
-XuRfuxLZCscv7A9M5Enc2zwOEP5VwRNwYzYtMm2Yh9CQZxNWC7JVh1Gw5MPFzsGl
-sgEdb4WGneN6PPLQHK7NF0f7wYSNnF0i3XSME9MumQKCAQEA0qMbWydr+TyJC0LC
-xigHtUkgAQXGPsXuePxTk4sdhBwAVcKHgg4qZi+a+gpoV4BLE9LfPU4nAwzM08to
-rI5Lk2nBsnt1Z2hVItQGoy0QoK3b7fbti5ktETf3oRhMtcSGgLLxD5ImVjId8Isq
-T3F15hpVOLdzZxtl1Qg4jKXSJ91yplYY5mzC9Yz/3qkQbsdlJcIFsLS5eG3UmkUw
-Bsr6VmA4X1F6Eb6eqwYzdHz6D+fOS36NhxcODaYkY+myO46xptixv8/NVTiTgQ5q
-OfwRb8Iur/3FUzIoioFyD7Bvjn7ITY1NArEsFS0bF9Nk1yDakKiUThyGN/Xojbac
-FuYKwQKCAQEAxOWJ+qU8phJLdowBHC0ZJiEWasRhep9auoZOpJ01IWOfV6EwZLs5
-dkYDQ1Agwoi5DDn6hu7HQM3IV/CS4mF2OnzcMw7ozc7PR53nTkVZ5LuLbuHAlmZO
-avKjDDucpJmLqjtV34IT5X8t6kt3zqgQAbuBBCy1Jz07ebfaPMzsnWpMDcU1/AW4
-OvrX0wweMOSGwzQP/i/ZMsRQAo2w0gQfeuv9Thk+kU99ebXwjx3co//hCEnFE4s1
-6L8/0AJU+VTr4hJyZi7WUDt4HzkLF+qm22/Hux+eMA/Q9R1UAxtFLCpTdAQiAJGY
-/Q3X+1I434DgAwYU3f1Gpq9cB65vq/KamQKCAQEAjIub5wde/ttHlLALvnOXrbqe
-nUIfWHExMzhul/rkr8fFEJwij2nZUuN2EWUGzBWQQoNXw5QKHLZyPsyFUOa/P2BS
-osnffAa+sumL4k36E71xFdTVV5ExyTXZVB49sPmUpivP9gEucFFqDHKjGsF45dBF
-+DZdykLUIv+/jQUzXGkZ5Wv/r52YUNho4EZdwnlJ2so7cxnsYnjW+c1nlp17tkq5
-DfwktkeD9iFzlaZ66vLoO44luaBm+lC3xM2sHinOTwbk0gvhJAIoLfkOYhpmGc8A
-4W/E1OHfVz6xqVDsMBFhRbQpHNkf8XZNqkIoqHVMTaMOJJlM+lb0+A9B8Bm/XA==
------END RSA PRIVATE KEY-----
diff --git a/apex/statsd/com.android.os.statsd.pk8 b/apex/statsd/com.android.os.statsd.pk8
deleted file mode 100644
index 49910f8..0000000
--- a/apex/statsd/com.android.os.statsd.pk8
+++ /dev/null
Binary files differ
diff --git a/apex/statsd/com.android.os.statsd.x509.pem b/apex/statsd/com.android.os.statsd.x509.pem
deleted file mode 100644
index e7b16b2..0000000
--- a/apex/statsd/com.android.os.statsd.x509.pem
+++ /dev/null
@@ -1,30 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIFDTCCAvWgAwIBAgIUCnta1LAl5fMMLLQx//4zWz9A2A8wDQYJKoZIhvcNAQEL
-BQAwFTETMBEGA1UECgwKR29vZ2xlIExMQzAgFw0xOTA4MTIyMjM5MzBaGA80NzU3
-MDcwODIyMzkzMFowFTETMBEGA1UECgwKR29vZ2xlIExMQzCCAiIwDQYJKoZIhvcN
-AQEBBQADggIPADCCAgoCggIBAOranWZ19jkXCF9WIlXv01tUUvLKMHWKV7X9Earw
-cL7/aax0pFbNJutgyBUiOszbR+0T7quZxz6jACu+6y7iaMJnvMluZsfTi+p2UvQt
-y6Ql7ZUOQ7bVluCFIW5hZ+8d9RrLmZdvX1r4YfF6HufDBkAbj+os+y6407OezJAV
-8EATpemc9gsCC4RJZpwzTs1RUXMD4UoNrLZAE8+7iaJZeBxmz0MAPj92pYc9M7/d
-xInzYvOR08/uEpHt8jlMdVgSQS/FaRlIOIqcGBk3cjkjDlpVATQ4Hyjy+IPQPjTD
-bJUmDJiYeBCyY/pYZQvTQjl8s+fvykTsF9Lfb+E+PhZ0+N8pRi7sUSpisZHSiqaN
-W3oxYWc0YQSuzygHHog8HH/azHX5L805g/+Rwfb/cUF9eJgjq0vrkFnsz4UKgKNV
-hHL90mfqpbc2UvJ8VY8BvIjbsHQ77LrBKlqI9VMPorttpTOuwHHJPKsyN972F0Ul
-lRB6CwFE8csVGWXoNaDZWBv7xTDdbdirmlKDNueg9pw6ksYV2Is9Dv8PxmsZvb+4
-oftC/hb4X1Pudn01PPs9Tx44CwHuVLENUwlDEVzG5zNetsv9kAuCYt3VRVF+NYqj
-NAfLbxCKLe25wGzJrZUEJ1YrYIjpUbfwnttEad/9Pu13DAS7HZwn5vwqEKB/1LlT
-NSUXAgMBAAGjUzBRMB0GA1UdDgQWBBSKElkhJSbzgh8+iysye8SrkmJ62DAfBgNV
-HSMEGDAWgBSKElkhJSbzgh8+iysye8SrkmJ62DAPBgNVHRMBAf8EBTADAQH/MA0G
-CSqGSIb3DQEBCwUAA4ICAQANFGnc2wJBrFbh2nzhl06g4TjPKGRCw365vZ1A3T9O
-jXP0lToHDxB33TpKk6d7zszR1uPphQQxgzhSVZB/jx8q4kWSSoKoF9Dlx7h8rAt+
-2TM5DaBvxrwu5mqOALwQuF81wap1Pl2L2fFHvygCm8b+Ci4iS5vcr0axNnp1rK1b
-vUtRWY4mfxTjJYcgeCVUGskqTb+cCxQZ6Icno6VTKajT1FybRmD3KZJaUuLbNEN+
-IE4nGTMG2WZ5Hl2vR8JJp1sYYn8T3ElMAb0MSNFkqsfI+tToEwGsuJDgYEdtEnzf
-lTycQvn5NhrIZRRN3pqSyWpAU7p9mmyTK0PHMz2D/Rtfb7lE692vXzxCmZND51mc
-YXCCoanV6eZZ7Sbqzh60+5QV38hgFBst5l8CcFaWWSFK9nBWdzS5lhs9lmQ4aiYd
-IE0qsNZgMob+TTP1VW39hu4EDjNmOrKfimM9J2tcPZ5QP01DgETPvAsB7vn2Xz9J
-HGt5ntiSV4W2izDP8viQ1M5NvfdBaUhcnNsE6/sxfU0USRs2hrEp1oiqrv4p6V0P
-qOt7C2/YtJzkrxfsHZAxBUSRHa7LwtzgeiJDUivHn94VnAzSAH8MLx6CzDPQ8HWN
-NiZFxTKfMVyjEmbQ2PalHWB8pWtpdEh7X4rzaqhnLBTis3pGssASgo3ArLIYleAU
-+g==
------END CERTIFICATE-----
diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp
deleted file mode 100644
index bf4323d..0000000
--- a/apex/statsd/framework/Android.bp
+++ /dev/null
@@ -1,81 +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.
-
-package {
-    default_visibility: [ ":__pkg__" ]
-}
-
-genrule {
-    name: "statslog-statsd-java-gen",
-    tools: ["stats-log-api-gen"],
-    cmd: "$(location stats-log-api-gen) --java $(out) --module statsd" +
-         " --javaPackage com.android.internal.statsd --javaClass StatsdStatsLog",
-    out: ["com/android/internal/statsd/StatsdStatsLog.java"],
-}
-
-java_library_static {
-    name: "statslog-statsd",
-    srcs: [
-        ":statslog-statsd-java-gen",
-    ],
-    visibility: [
-        "//cts/hostsidetests/statsd/apps:__subpackages__",
-        "//vendor:__subpackages__",
-    ],
-}
-
-filegroup {
-    name: "framework-statsd-sources",
-    srcs: [
-        "java/**/*.java",
-        ":framework-statsd-aidl-sources",
-        ":statslog-statsd-java-gen",
-    ],
-    visibility: [
-        "//frameworks/base", // For the "global" stubs.
-        "//frameworks/base/apex/statsd:__subpackages__",
-    ],
-}
-java_sdk_library {
-    name: "framework-statsd",
-    defaults: ["framework-module-defaults"],
-    installable: true,
-
-    srcs: [
-        ":framework-statsd-sources",
-    ],
-
-    permitted_packages: [
-        "android.app",
-        "android.os",
-        "android.util",
-        // From :statslog-statsd-java-gen
-        "com.android.internal.statsd",
-    ],
-
-    api_packages: [
-        "android.app",
-        "android.os",
-        "android.util",
-    ],
-
-    hostdex: true, // for hiddenapi check
-
-    impl_library_visibility: ["//frameworks/base/apex/statsd/framework/test:__subpackages__"],
-
-    apex_available: [
-        "com.android.os.statsd",
-        "test_com.android.os.statsd",
-    ],
-}
diff --git a/apex/statsd/framework/api/current.txt b/apex/statsd/framework/api/current.txt
deleted file mode 100644
index a655693..0000000
--- a/apex/statsd/framework/api/current.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-// Signature format: 2.0
-package android.util {
-
-  public final class StatsLog {
-    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public static boolean logBinaryPushStateChanged(@NonNull String, long, int, int, @NonNull long[]);
-    method public static boolean logEvent(int);
-    method public static boolean logStart(int);
-    method public static boolean logStop(int);
-  }
-
-}
-
diff --git a/apex/statsd/framework/api/module-lib-current.txt b/apex/statsd/framework/api/module-lib-current.txt
deleted file mode 100644
index 8b6e217..0000000
--- a/apex/statsd/framework/api/module-lib-current.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-// Signature format: 2.0
-package android.os {
-
-  public class StatsFrameworkInitializer {
-    method public static void registerServiceWrappers();
-    method public static void setStatsServiceManager(@NonNull android.os.StatsServiceManager);
-  }
-
-}
-
diff --git a/apex/statsd/framework/api/module-lib-removed.txt b/apex/statsd/framework/api/module-lib-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/apex/statsd/framework/api/module-lib-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/statsd/framework/api/removed.txt b/apex/statsd/framework/api/removed.txt
deleted file mode 100644
index d802177..0000000
--- a/apex/statsd/framework/api/removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/statsd/framework/api/system-current.txt b/apex/statsd/framework/api/system-current.txt
deleted file mode 100644
index 3ea5724..0000000
--- a/apex/statsd/framework/api/system-current.txt
+++ /dev/null
@@ -1,111 +0,0 @@
-// Signature format: 2.0
-package android.app {
-
-  public final class StatsManager {
-    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void addConfig(long, byte[]) throws android.app.StatsManager.StatsUnavailableException;
-    method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean addConfiguration(long, byte[]);
-    method @RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM) public void clearPullAtomCallback(int);
-    method @Deprecated @Nullable @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getData(long);
-    method @Deprecated @Nullable @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getMetadata();
-    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public long[] getRegisteredExperimentIds() throws android.app.StatsManager.StatsUnavailableException;
-    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getReports(long) throws android.app.StatsManager.StatsUnavailableException;
-    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getStatsMetadata() throws android.app.StatsManager.StatsUnavailableException;
-    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void removeConfig(long) throws android.app.StatsManager.StatsUnavailableException;
-    method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean removeConfiguration(long);
-    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public long[] setActiveConfigsChangedOperation(@Nullable android.app.PendingIntent) throws android.app.StatsManager.StatsUnavailableException;
-    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void setBroadcastSubscriber(android.app.PendingIntent, long, long) throws android.app.StatsManager.StatsUnavailableException;
-    method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean setBroadcastSubscriber(long, long, android.app.PendingIntent);
-    method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean setDataFetchOperation(long, android.app.PendingIntent);
-    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void setFetchReportsOperation(android.app.PendingIntent, long) throws android.app.StatsManager.StatsUnavailableException;
-    method @RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM) public void setPullAtomCallback(int, @Nullable android.app.StatsManager.PullAtomMetadata, @NonNull java.util.concurrent.Executor, @NonNull android.app.StatsManager.StatsPullAtomCallback);
-    field public static final String ACTION_STATSD_STARTED = "android.app.action.STATSD_STARTED";
-    field public static final String EXTRA_STATS_ACTIVE_CONFIG_KEYS = "android.app.extra.STATS_ACTIVE_CONFIG_KEYS";
-    field public static final String EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES = "android.app.extra.STATS_BROADCAST_SUBSCRIBER_COOKIES";
-    field public static final String EXTRA_STATS_CONFIG_KEY = "android.app.extra.STATS_CONFIG_KEY";
-    field public static final String EXTRA_STATS_CONFIG_UID = "android.app.extra.STATS_CONFIG_UID";
-    field public static final String EXTRA_STATS_DIMENSIONS_VALUE = "android.app.extra.STATS_DIMENSIONS_VALUE";
-    field public static final String EXTRA_STATS_SUBSCRIPTION_ID = "android.app.extra.STATS_SUBSCRIPTION_ID";
-    field public static final String EXTRA_STATS_SUBSCRIPTION_RULE_ID = "android.app.extra.STATS_SUBSCRIPTION_RULE_ID";
-    field public static final int PULL_SKIP = 1; // 0x1
-    field public static final int PULL_SUCCESS = 0; // 0x0
-  }
-
-  public static class StatsManager.PullAtomMetadata {
-    method @Nullable public int[] getAdditiveFields();
-    method public long getCoolDownMillis();
-    method public long getTimeoutMillis();
-  }
-
-  public static class StatsManager.PullAtomMetadata.Builder {
-    ctor public StatsManager.PullAtomMetadata.Builder();
-    method @NonNull public android.app.StatsManager.PullAtomMetadata build();
-    method @NonNull public android.app.StatsManager.PullAtomMetadata.Builder setAdditiveFields(@NonNull int[]);
-    method @NonNull public android.app.StatsManager.PullAtomMetadata.Builder setCoolDownMillis(long);
-    method @NonNull public android.app.StatsManager.PullAtomMetadata.Builder setTimeoutMillis(long);
-  }
-
-  public static interface StatsManager.StatsPullAtomCallback {
-    method public int onPullAtom(int, @NonNull java.util.List<android.util.StatsEvent>);
-  }
-
-  public static class StatsManager.StatsUnavailableException extends android.util.AndroidException {
-    ctor public StatsManager.StatsUnavailableException(String);
-    ctor public StatsManager.StatsUnavailableException(String, Throwable);
-  }
-
-}
-
-package android.os {
-
-  public final class StatsDimensionsValue implements android.os.Parcelable {
-    method public int describeContents();
-    method public boolean getBooleanValue();
-    method public int getField();
-    method public float getFloatValue();
-    method public int getIntValue();
-    method public long getLongValue();
-    method public String getStringValue();
-    method public java.util.List<android.os.StatsDimensionsValue> getTupleValueList();
-    method public int getValueType();
-    method public boolean isValueType(int);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final int BOOLEAN_VALUE_TYPE = 5; // 0x5
-    field @NonNull public static final android.os.Parcelable.Creator<android.os.StatsDimensionsValue> CREATOR;
-    field public static final int FLOAT_VALUE_TYPE = 6; // 0x6
-    field public static final int INT_VALUE_TYPE = 3; // 0x3
-    field public static final int LONG_VALUE_TYPE = 4; // 0x4
-    field public static final int STRING_VALUE_TYPE = 2; // 0x2
-    field public static final int TUPLE_VALUE_TYPE = 7; // 0x7
-  }
-
-}
-
-package android.util {
-
-  public final class StatsEvent {
-    method @NonNull public static android.util.StatsEvent.Builder newBuilder();
-  }
-
-  public static final class StatsEvent.Builder {
-    method @NonNull public android.util.StatsEvent.Builder addBooleanAnnotation(byte, boolean);
-    method @NonNull public android.util.StatsEvent.Builder addIntAnnotation(byte, int);
-    method @NonNull public android.util.StatsEvent build();
-    method @NonNull public android.util.StatsEvent.Builder setAtomId(int);
-    method @NonNull public android.util.StatsEvent.Builder usePooledBuffer();
-    method @NonNull public android.util.StatsEvent.Builder writeAttributionChain(@NonNull int[], @NonNull String[]);
-    method @NonNull public android.util.StatsEvent.Builder writeBoolean(boolean);
-    method @NonNull public android.util.StatsEvent.Builder writeByteArray(@NonNull byte[]);
-    method @NonNull public android.util.StatsEvent.Builder writeFloat(float);
-    method @NonNull public android.util.StatsEvent.Builder writeInt(int);
-    method @NonNull public android.util.StatsEvent.Builder writeKeyValuePairs(@Nullable android.util.SparseIntArray, @Nullable android.util.SparseLongArray, @Nullable android.util.SparseArray<java.lang.String>, @Nullable android.util.SparseArray<java.lang.Float>);
-    method @NonNull public android.util.StatsEvent.Builder writeLong(long);
-    method @NonNull public android.util.StatsEvent.Builder writeString(@NonNull String);
-  }
-
-  public final class StatsLog {
-    method public static void write(@NonNull android.util.StatsEvent);
-    method public static void writeRaw(@NonNull byte[], int);
-  }
-
-}
-
diff --git a/apex/statsd/framework/api/system-removed.txt b/apex/statsd/framework/api/system-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/apex/statsd/framework/api/system-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/apex/statsd/framework/java/android/app/StatsManager.java b/apex/statsd/framework/java/android/app/StatsManager.java
deleted file mode 100644
index 41803cf..0000000
--- a/apex/statsd/framework/java/android/app/StatsManager.java
+++ /dev/null
@@ -1,725 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.app;
-
-import static android.Manifest.permission.DUMP;
-import static android.Manifest.permission.PACKAGE_USAGE_STATS;
-
-import android.annotation.CallbackExecutor;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
-import android.content.Context;
-import android.os.Binder;
-import android.os.IPullAtomCallback;
-import android.os.IPullAtomResultReceiver;
-import android.os.IStatsManagerService;
-import android.os.RemoteException;
-import android.os.StatsFrameworkInitializer;
-import android.util.AndroidException;
-import android.util.Log;
-import android.util.StatsEvent;
-import android.util.StatsEventParcel;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Executor;
-
-/**
- * API for statsd clients to send configurations and retrieve data.
- *
- * @hide
- */
-@SystemApi
-public final class StatsManager {
-    private static final String TAG = "StatsManager";
-    private static final boolean DEBUG = false;
-
-    private static final Object sLock = new Object();
-    private final Context mContext;
-
-    @GuardedBy("sLock")
-    private IStatsManagerService mStatsManagerService;
-
-    /**
-     * Long extra of uid that added the relevant stats config.
-     */
-    public static final String EXTRA_STATS_CONFIG_UID = "android.app.extra.STATS_CONFIG_UID";
-    /**
-     * Long extra of the relevant stats config's configKey.
-     */
-    public static final String EXTRA_STATS_CONFIG_KEY = "android.app.extra.STATS_CONFIG_KEY";
-    /**
-     * Long extra of the relevant statsd_config.proto's Subscription.id.
-     */
-    public static final String EXTRA_STATS_SUBSCRIPTION_ID =
-            "android.app.extra.STATS_SUBSCRIPTION_ID";
-    /**
-     * Long extra of the relevant statsd_config.proto's Subscription.rule_id.
-     */
-    public static final String EXTRA_STATS_SUBSCRIPTION_RULE_ID =
-            "android.app.extra.STATS_SUBSCRIPTION_RULE_ID";
-    /**
-     *   List<String> of the relevant statsd_config.proto's BroadcastSubscriberDetails.cookie.
-     *   Obtain using {@link android.content.Intent#getStringArrayListExtra(String)}.
-     */
-    public static final String EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES =
-            "android.app.extra.STATS_BROADCAST_SUBSCRIBER_COOKIES";
-    /**
-     * Extra of a {@link android.os.StatsDimensionsValue} representing sliced dimension value
-     * information.
-     */
-    public static final String EXTRA_STATS_DIMENSIONS_VALUE =
-            "android.app.extra.STATS_DIMENSIONS_VALUE";
-    /**
-     * Long array extra of the active configs for the uid that added those configs.
-     */
-    public static final String EXTRA_STATS_ACTIVE_CONFIG_KEYS =
-            "android.app.extra.STATS_ACTIVE_CONFIG_KEYS";
-
-    /**
-     * Broadcast Action: Statsd has started.
-     * Configurations and PendingIntents can now be sent to it.
-     */
-    public static final String ACTION_STATSD_STARTED = "android.app.action.STATSD_STARTED";
-
-    // Pull atom callback return codes.
-    /**
-     * Value indicating that this pull was successful and that the result should be used.
-     *
-     **/
-    public static final int PULL_SUCCESS = 0;
-
-    /**
-     * Value indicating that this pull was unsuccessful and that the result should not be used.
-     **/
-    public static final int PULL_SKIP = 1;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting public static final long DEFAULT_COOL_DOWN_MILLIS = 1_000L; // 1 second.
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting public static final long DEFAULT_TIMEOUT_MILLIS = 2_000L; // 2 seconds.
-
-    /**
-     * Constructor for StatsManagerClient.
-     *
-     * @hide
-     */
-    public StatsManager(Context context) {
-        mContext = context;
-    }
-
-    /**
-     * Adds the given configuration and associates it with the given configKey. If a config with the
-     * given configKey already exists for the caller's uid, it is replaced with the new one.
-     *
-     * @param configKey An arbitrary integer that allows clients to track the configuration.
-     * @param config    Wire-encoded StatsdConfig proto that specifies metrics (and all
-     *                  dependencies eg, conditions and matchers).
-     * @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
-     * @throws IllegalArgumentException if config is not a wire-encoded StatsdConfig proto
-     */
-    @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
-    public void addConfig(long configKey, byte[] config) throws StatsUnavailableException {
-        synchronized (sLock) {
-            try {
-                IStatsManagerService service = getIStatsManagerServiceLocked();
-                // can throw IllegalArgumentException
-                service.addConfiguration(configKey, config, mContext.getOpPackageName());
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to connect to statsmanager when adding configuration");
-                throw new StatsUnavailableException("could not connect", e);
-            } catch (SecurityException e) {
-                throw new StatsUnavailableException(e.getMessage(), e);
-            } catch (IllegalStateException e) {
-                Log.e(TAG, "Failed to addConfig in statsmanager");
-                throw new StatsUnavailableException(e.getMessage(), e);
-            }
-        }
-    }
-
-    // TODO: Temporary for backwards compatibility. Remove.
-    /**
-     * @deprecated Use {@link #addConfig(long, byte[])}
-     */
-    @Deprecated
-    @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
-    public boolean addConfiguration(long configKey, byte[] config) {
-        try {
-            addConfig(configKey, config);
-            return true;
-        } catch (StatsUnavailableException | IllegalArgumentException e) {
-            return false;
-        }
-    }
-
-    /**
-     * Remove a configuration from logging.
-     *
-     * @param configKey Configuration key to remove.
-     * @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
-     */
-    @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
-    public void removeConfig(long configKey) throws StatsUnavailableException {
-        synchronized (sLock) {
-            try {
-                IStatsManagerService service = getIStatsManagerServiceLocked();
-                service.removeConfiguration(configKey, mContext.getOpPackageName());
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to connect to statsmanager when removing configuration");
-                throw new StatsUnavailableException("could not connect", e);
-            } catch (SecurityException e) {
-                throw new StatsUnavailableException(e.getMessage(), e);
-            } catch (IllegalStateException e) {
-                Log.e(TAG, "Failed to removeConfig in statsmanager");
-                throw new StatsUnavailableException(e.getMessage(), e);
-            }
-        }
-    }
-
-    // TODO: Temporary for backwards compatibility. Remove.
-    /**
-     * @deprecated Use {@link #removeConfig(long)}
-     */
-    @Deprecated
-    @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
-    public boolean removeConfiguration(long configKey) {
-        try {
-            removeConfig(configKey);
-            return true;
-        } catch (StatsUnavailableException e) {
-            return false;
-        }
-    }
-
-    /**
-     * Set the PendingIntent to be used when broadcasting subscriber information to the given
-     * subscriberId within the given config.
-     * <p>
-     * Suppose that the calling uid has added a config with key configKey, and that in this config
-     * it is specified that when a particular anomaly is detected, a broadcast should be sent to
-     * a BroadcastSubscriber with id subscriberId. This function links the given pendingIntent with
-     * that subscriberId (for that config), so that this pendingIntent is used to send the broadcast
-     * when the anomaly is detected.
-     * <p>
-     * When statsd sends the broadcast, the PendingIntent will used to send an intent with
-     * information of
-     * {@link #EXTRA_STATS_CONFIG_UID},
-     * {@link #EXTRA_STATS_CONFIG_KEY},
-     * {@link #EXTRA_STATS_SUBSCRIPTION_ID},
-     * {@link #EXTRA_STATS_SUBSCRIPTION_RULE_ID},
-     * {@link #EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES}, and
-     * {@link #EXTRA_STATS_DIMENSIONS_VALUE}.
-     * <p>
-     * This function can only be called by the owner (uid) of the config. It must be called each
-     * time statsd starts. The config must have been added first (via {@link #addConfig}).
-     *
-     * @param pendingIntent the PendingIntent to use when broadcasting info to the subscriber
-     *                      associated with the given subscriberId. May be null, in which case
-     *                      it undoes any previous setting of this subscriberId.
-     * @param configKey     The integer naming the config to which this subscriber is attached.
-     * @param subscriberId  ID of the subscriber, as used in the config.
-     * @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
-     */
-    @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
-    public void setBroadcastSubscriber(
-            PendingIntent pendingIntent, long configKey, long subscriberId)
-            throws StatsUnavailableException {
-        synchronized (sLock) {
-            try {
-                IStatsManagerService service = getIStatsManagerServiceLocked();
-                if (pendingIntent != null) {
-                    service.setBroadcastSubscriber(configKey, subscriberId, pendingIntent,
-                            mContext.getOpPackageName());
-                } else {
-                    service.unsetBroadcastSubscriber(configKey, subscriberId,
-                            mContext.getOpPackageName());
-                }
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to connect to statsmanager when adding broadcast subscriber",
-                        e);
-                throw new StatsUnavailableException("could not connect", e);
-            } catch (SecurityException e) {
-                throw new StatsUnavailableException(e.getMessage(), e);
-            }
-        }
-    }
-
-    // TODO: Temporary for backwards compatibility. Remove.
-    /**
-     * @deprecated Use {@link #setBroadcastSubscriber(PendingIntent, long, long)}
-     */
-    @Deprecated
-    @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
-    public boolean setBroadcastSubscriber(
-            long configKey, long subscriberId, PendingIntent pendingIntent) {
-        try {
-            setBroadcastSubscriber(pendingIntent, configKey, subscriberId);
-            return true;
-        } catch (StatsUnavailableException e) {
-            return false;
-        }
-    }
-
-    /**
-     * Registers the operation that is called to retrieve the metrics data. This must be called
-     * each time statsd starts. The config must have been added first (via {@link #addConfig},
-     * although addConfig could have been called on a previous boot). This operation allows
-     * statsd to send metrics data whenever statsd determines that the metrics in memory are
-     * approaching the memory limits. The fetch operation should call {@link #getReports} to fetch
-     * the data, which also deletes the retrieved metrics from statsd's memory.
-     *
-     * @param pendingIntent the PendingIntent to use when broadcasting info to the subscriber
-     *                      associated with the given subscriberId. May be null, in which case
-     *                      it removes any associated pending intent with this configKey.
-     * @param configKey     The integer naming the config to which this operation is attached.
-     * @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
-     */
-    @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
-    public void setFetchReportsOperation(PendingIntent pendingIntent, long configKey)
-            throws StatsUnavailableException {
-        synchronized (sLock) {
-            try {
-                IStatsManagerService service = getIStatsManagerServiceLocked();
-                if (pendingIntent == null) {
-                    service.removeDataFetchOperation(configKey, mContext.getOpPackageName());
-                } else {
-                    service.setDataFetchOperation(configKey, pendingIntent,
-                            mContext.getOpPackageName());
-                }
-
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to connect to statsmanager when registering data listener.");
-                throw new StatsUnavailableException("could not connect", e);
-            } catch (SecurityException e) {
-                throw new StatsUnavailableException(e.getMessage(), e);
-            }
-        }
-    }
-
-    /**
-     * Registers the operation that is called whenever there is a change in which configs are
-     * active. This must be called each time statsd starts. This operation allows
-     * statsd to inform clients that they should pull data of the configs that are currently
-     * active. The activeConfigsChangedOperation should set periodic alarms to pull data of configs
-     * that are active and stop pulling data of configs that are no longer active.
-     *
-     * @param pendingIntent the PendingIntent to use when broadcasting info to the subscriber
-     *                      associated with the given subscriberId. May be null, in which case
-     *                      it removes any associated pending intent for this client.
-     * @return A list of configs that are currently active for this client. If the pendingIntent is
-     *         null, this will be an empty list.
-     * @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
-     */
-    @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
-    public @NonNull long[] setActiveConfigsChangedOperation(@Nullable PendingIntent pendingIntent)
-            throws StatsUnavailableException {
-        synchronized (sLock) {
-            try {
-                IStatsManagerService service = getIStatsManagerServiceLocked();
-                if (pendingIntent == null) {
-                    service.removeActiveConfigsChangedOperation(mContext.getOpPackageName());
-                    return new long[0];
-                } else {
-                    return service.setActiveConfigsChangedOperation(pendingIntent,
-                            mContext.getOpPackageName());
-                }
-
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to connect to statsmanager "
-                        + "when registering active configs listener.");
-                throw new StatsUnavailableException("could not connect", e);
-            } catch (SecurityException e) {
-                throw new StatsUnavailableException(e.getMessage(), e);
-            }
-        }
-    }
-
-    // TODO: Temporary for backwards compatibility. Remove.
-    /**
-     * @deprecated Use {@link #setFetchReportsOperation(PendingIntent, long)}
-     */
-    @Deprecated
-    @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
-    public boolean setDataFetchOperation(long configKey, PendingIntent pendingIntent) {
-        try {
-            setFetchReportsOperation(pendingIntent, configKey);
-            return true;
-        } catch (StatsUnavailableException e) {
-            return false;
-        }
-    }
-
-    /**
-     * Request the data collected for the given configKey.
-     * This getter is destructive - it also clears the retrieved metrics from statsd's memory.
-     *
-     * @param configKey Configuration key to retrieve data from.
-     * @return Serialized ConfigMetricsReportList proto.
-     * @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
-     */
-    @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
-    public byte[] getReports(long configKey) throws StatsUnavailableException {
-        synchronized (sLock) {
-            try {
-                IStatsManagerService service = getIStatsManagerServiceLocked();
-                return service.getData(configKey, mContext.getOpPackageName());
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to connect to statsmanager when getting data");
-                throw new StatsUnavailableException("could not connect", e);
-            } catch (SecurityException e) {
-                throw new StatsUnavailableException(e.getMessage(), e);
-            } catch (IllegalStateException e) {
-                Log.e(TAG, "Failed to getReports in statsmanager");
-                throw new StatsUnavailableException(e.getMessage(), e);
-            }
-        }
-    }
-
-    // TODO: Temporary for backwards compatibility. Remove.
-    /**
-     * @deprecated Use {@link #getReports(long)}
-     */
-    @Deprecated
-    @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
-    public @Nullable byte[] getData(long configKey) {
-        try {
-            return getReports(configKey);
-        } catch (StatsUnavailableException e) {
-            return null;
-        }
-    }
-
-    /**
-     * Clients can request metadata for statsd. Will contain stats across all configurations but not
-     * the actual metrics themselves (metrics must be collected via {@link #getReports(long)}.
-     * This getter is not destructive and will not reset any metrics/counters.
-     *
-     * @return Serialized StatsdStatsReport proto.
-     * @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
-     */
-    @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
-    public byte[] getStatsMetadata() throws StatsUnavailableException {
-        synchronized (sLock) {
-            try {
-                IStatsManagerService service = getIStatsManagerServiceLocked();
-                return service.getMetadata(mContext.getOpPackageName());
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to connect to statsmanager when getting metadata");
-                throw new StatsUnavailableException("could not connect", e);
-            } catch (SecurityException e) {
-                throw new StatsUnavailableException(e.getMessage(), e);
-            } catch (IllegalStateException e) {
-                Log.e(TAG, "Failed to getStatsMetadata in statsmanager");
-                throw new StatsUnavailableException(e.getMessage(), e);
-            }
-        }
-    }
-
-    // TODO: Temporary for backwards compatibility. Remove.
-    /**
-     * @deprecated Use {@link #getStatsMetadata()}
-     */
-    @Deprecated
-    @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
-    public @Nullable byte[] getMetadata() {
-        try {
-            return getStatsMetadata();
-        } catch (StatsUnavailableException e) {
-            return null;
-        }
-    }
-
-    /**
-     * Returns the experiments IDs registered with statsd, or an empty array if there aren't any.
-     *
-     * @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
-     */
-    @RequiresPermission(allOf = {DUMP, PACKAGE_USAGE_STATS})
-    public long[] getRegisteredExperimentIds()
-            throws StatsUnavailableException {
-        synchronized (sLock) {
-            try {
-                IStatsManagerService service = getIStatsManagerServiceLocked();
-                return service.getRegisteredExperimentIds();
-            } catch (RemoteException e) {
-                if (DEBUG) {
-                    Log.d(TAG,
-                            "Failed to connect to StatsManagerService when getting "
-                                    + "registered experiment IDs");
-                }
-                throw new StatsUnavailableException("could not connect", e);
-            } catch (IllegalStateException e) {
-                Log.e(TAG, "Failed to getRegisteredExperimentIds in statsmanager");
-                throw new StatsUnavailableException(e.getMessage(), e);
-            }
-        }
-    }
-
-    /**
-     * Sets a callback for an atom when that atom is to be pulled. The stats service will
-     * invoke pullData in the callback when the stats service determines that this atom needs to be
-     * pulled. This method should not be called by third-party apps.
-     *
-     * @param atomTag           The tag of the atom for this puller callback.
-     * @param metadata          Optional metadata specifying the timeout, cool down time, and
-     *                          additive fields for mapping isolated to host uids.
-     * @param executor          The executor in which to run the callback.
-     * @param callback          The callback to be invoked when the stats service pulls the atom.
-     *
-     */
-    @RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM)
-    public void setPullAtomCallback(int atomTag, @Nullable PullAtomMetadata metadata,
-            @NonNull @CallbackExecutor Executor executor,
-            @NonNull StatsPullAtomCallback callback) {
-        long coolDownMillis =
-                metadata == null ? DEFAULT_COOL_DOWN_MILLIS : metadata.mCoolDownMillis;
-        long timeoutMillis = metadata == null ? DEFAULT_TIMEOUT_MILLIS : metadata.mTimeoutMillis;
-        int[] additiveFields = metadata == null ? new int[0] : metadata.mAdditiveFields;
-        if (additiveFields == null) {
-            additiveFields = new int[0];
-        }
-
-        synchronized (sLock) {
-            try {
-                IStatsManagerService service = getIStatsManagerServiceLocked();
-                PullAtomCallbackInternal rec =
-                    new PullAtomCallbackInternal(atomTag, callback, executor);
-                service.registerPullAtomCallback(
-                        atomTag, coolDownMillis, timeoutMillis, additiveFields, rec);
-            } catch (RemoteException e) {
-                throw new RuntimeException("Unable to register pull callback", e);
-            }
-        }
-    }
-
-    /**
-     * Clears a callback for an atom when that atom is to be pulled. Note that any ongoing
-     * pulls will still occur. This method should not be called by third-party apps.
-     *
-     * @param atomTag           The tag of the atom of which to unregister
-     *
-     */
-    @RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM)
-    public void clearPullAtomCallback(int atomTag) {
-        synchronized (sLock) {
-            try {
-                IStatsManagerService service = getIStatsManagerServiceLocked();
-                service.unregisterPullAtomCallback(atomTag);
-            } catch (RemoteException e) {
-                throw new RuntimeException("Unable to unregister pull atom callback");
-            }
-        }
-    }
-
-    private static class PullAtomCallbackInternal extends IPullAtomCallback.Stub {
-        public final int mAtomId;
-        public final StatsPullAtomCallback mCallback;
-        public final Executor mExecutor;
-
-        PullAtomCallbackInternal(int atomId, StatsPullAtomCallback callback, Executor executor) {
-            mAtomId = atomId;
-            mCallback = callback;
-            mExecutor = executor;
-        }
-
-        @Override
-        public void onPullAtom(int atomTag, IPullAtomResultReceiver resultReceiver) {
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mExecutor.execute(() -> {
-                    List<StatsEvent> data = new ArrayList<>();
-                    int successInt = mCallback.onPullAtom(atomTag, data);
-                    boolean success = successInt == PULL_SUCCESS;
-                    StatsEventParcel[] parcels = new StatsEventParcel[data.size()];
-                    for (int i = 0; i < data.size(); i++) {
-                        parcels[i] = new StatsEventParcel();
-                        parcels[i].buffer = data.get(i).getBytes();
-                    }
-                    try {
-                        resultReceiver.pullFinished(atomTag, success, parcels);
-                    } catch (RemoteException e) {
-                        Log.w(TAG, "StatsPullResultReceiver failed for tag " + mAtomId
-                                + " due to TransactionTooLarge. Calling pullFinish with no data");
-                        StatsEventParcel[] emptyData = new StatsEventParcel[0];
-                        try {
-                            resultReceiver.pullFinished(atomTag, /*success=*/false, emptyData);
-                        } catch (RemoteException nestedException) {
-                            Log.w(TAG, "StatsPullResultReceiver failed for tag " + mAtomId
-                                    + " with empty payload");
-                        }
-                    }
-                });
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-    }
-
-    /**
-     * Metadata required for registering a StatsPullAtomCallback.
-     * All fields are optional, and defaults will be used for fields that are unspecified.
-     *
-     */
-    public static class PullAtomMetadata {
-        private final long mCoolDownMillis;
-        private final long mTimeoutMillis;
-        private final int[] mAdditiveFields;
-
-        // Private Constructor for builder
-        private PullAtomMetadata(long coolDownMillis, long timeoutMillis, int[] additiveFields) {
-            mCoolDownMillis = coolDownMillis;
-            mTimeoutMillis = timeoutMillis;
-            mAdditiveFields = additiveFields;
-        }
-
-        /**
-         *  Builder for PullAtomMetadata.
-         */
-        public static class Builder {
-            private long mCoolDownMillis;
-            private long mTimeoutMillis;
-            private int[] mAdditiveFields;
-
-            /**
-             * Returns a new PullAtomMetadata.Builder object for constructing PullAtomMetadata for
-             * StatsManager#registerPullAtomCallback
-             */
-            public Builder() {
-                mCoolDownMillis = DEFAULT_COOL_DOWN_MILLIS;
-                mTimeoutMillis = DEFAULT_TIMEOUT_MILLIS;
-                mAdditiveFields = null;
-            }
-
-            /**
-             * Set the cool down time of the pull in milliseconds. If two successive pulls are
-             * issued within the cool down, a cached version of the first pull will be used for the
-             * second pull. The minimum allowed cool down is 1 second.
-             */
-            @NonNull
-            public Builder setCoolDownMillis(long coolDownMillis) {
-                mCoolDownMillis = coolDownMillis;
-                return this;
-            }
-
-            /**
-             * Set the maximum time the pull can take in milliseconds. The maximum allowed timeout
-             * is 10 seconds.
-             */
-            @NonNull
-            public Builder setTimeoutMillis(long timeoutMillis) {
-                mTimeoutMillis = timeoutMillis;
-                return this;
-            }
-
-            /**
-             * Set the additive fields of this pulled atom.
-             *
-             * This is only applicable for atoms which have a uid field. When tasks are run in
-             * isolated processes, the data will be attributed to the host uid. Additive fields
-             * will be combined when the non-additive fields are the same.
-             */
-            @NonNull
-            public Builder setAdditiveFields(@NonNull int[] additiveFields) {
-                mAdditiveFields = additiveFields;
-                return this;
-            }
-
-            /**
-             * Builds and returns a PullAtomMetadata object with the values set in the builder and
-             * defaults for unset fields.
-             */
-            @NonNull
-            public PullAtomMetadata build() {
-                return new PullAtomMetadata(mCoolDownMillis, mTimeoutMillis, mAdditiveFields);
-            }
-        }
-
-        /**
-         * Return the cool down time of this pull in milliseconds.
-         */
-        public long getCoolDownMillis() {
-            return mCoolDownMillis;
-        }
-
-        /**
-         * Return the maximum amount of time this pull can take in milliseconds.
-         */
-        public long getTimeoutMillis() {
-            return mTimeoutMillis;
-        }
-
-        /**
-         * Return the additive fields of this pulled atom.
-         *
-         * This is only applicable for atoms that have a uid field. When tasks are run in
-         * isolated processes, the data will be attributed to the host uid. Additive fields
-         * will be combined when the non-additive fields are the same.
-         */
-        @Nullable
-        public int[] getAdditiveFields() {
-            return mAdditiveFields;
-        }
-    }
-
-    /**
-     * Callback interface for pulling atoms requested by the stats service.
-     *
-     */
-    public interface StatsPullAtomCallback {
-        /**
-         * Pull data for the specified atom tag, filling in the provided list of StatsEvent data.
-         * @return {@link #PULL_SUCCESS} if the pull was successful, or {@link #PULL_SKIP} if not.
-         */
-        int onPullAtom(int atomTag, @NonNull List<StatsEvent> data);
-    }
-
-    @GuardedBy("sLock")
-    private IStatsManagerService getIStatsManagerServiceLocked() {
-        if (mStatsManagerService != null) {
-            return mStatsManagerService;
-        }
-        mStatsManagerService = IStatsManagerService.Stub.asInterface(
-                StatsFrameworkInitializer
-                .getStatsServiceManager()
-                .getStatsManagerServiceRegisterer()
-                .get());
-        return mStatsManagerService;
-    }
-
-    /**
-     * Exception thrown when communication with the stats service fails (eg if it is not available).
-     * This might be thrown early during boot before the stats service has started or if it crashed.
-     */
-    public static class StatsUnavailableException extends AndroidException {
-        public StatsUnavailableException(String reason) {
-            super("Failed to connect to statsd: " + reason);
-        }
-
-        public StatsUnavailableException(String reason, Throwable e) {
-            super("Failed to connect to statsd: " + reason, e);
-        }
-    }
-}
diff --git a/apex/statsd/framework/java/android/os/StatsDimensionsValue.java b/apex/statsd/framework/java/android/os/StatsDimensionsValue.java
deleted file mode 100644
index 7d9349c..0000000
--- a/apex/statsd/framework/java/android/os/StatsDimensionsValue.java
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.os;
-
-import android.annotation.SystemApi;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Container for statsd dimension value information, corresponding to a
- * stats_log.proto's DimensionValue.
- *
- * This consists of a field (an int representing a statsd atom field)
- * and a value (which may be one of a number of types).
- *
- * <p>
- * Only a single value is held, and it is necessarily one of the following types:
- * {@link String}, int, long, boolean, float,
- * or tuple (i.e. {@link List} of {@code StatsDimensionsValue}).
- *
- * The type of value held can be retrieved using {@link #getValueType()}, which returns one of the
- * following ints, depending on the type of value:
- * <ul>
- *  <li>{@link #STRING_VALUE_TYPE}</li>
- *  <li>{@link #INT_VALUE_TYPE}</li>
- *  <li>{@link #LONG_VALUE_TYPE}</li>
- *  <li>{@link #BOOLEAN_VALUE_TYPE}</li>
- *  <li>{@link #FLOAT_VALUE_TYPE}</li>
- *  <li>{@link #TUPLE_VALUE_TYPE}</li>
- * </ul>
- * Alternatively, this can be determined using {@link #isValueType(int)} with one of these constants
- * as a parameter.
- * The value itself can be retrieved using the correct get...Value() function for its type.
- *
- * <p>
- * The field is always an int, and always exists; it can be obtained using {@link #getField()}.
- *
- *
- * @hide
- */
-@SystemApi
-public final class StatsDimensionsValue implements Parcelable {
-    private static final String TAG = "StatsDimensionsValue";
-
-    // Values of the value type correspond to stats_log.proto's DimensionValue fields.
-    // Keep constants in sync with frameworks/base/cmds/statsd/src/HashableDimensionKey.cpp.
-    /** Indicates that this holds a String. */
-    public static final int STRING_VALUE_TYPE = 2;
-    /** Indicates that this holds an int. */
-    public static final int INT_VALUE_TYPE = 3;
-    /** Indicates that this holds a long. */
-    public static final int LONG_VALUE_TYPE = 4;
-    /** Indicates that this holds a boolean. */
-    public static final int BOOLEAN_VALUE_TYPE = 5;
-    /** Indicates that this holds a float. */
-    public static final int FLOAT_VALUE_TYPE = 6;
-    /** Indicates that this holds a List of StatsDimensionsValues. */
-    public static final int TUPLE_VALUE_TYPE = 7;
-
-    private final StatsDimensionsValueParcel mInner;
-
-    /**
-     * Creates a {@code StatsDimensionValue} from a parcel.
-     *
-     * @hide
-     */
-    public StatsDimensionsValue(Parcel in) {
-        mInner = StatsDimensionsValueParcel.CREATOR.createFromParcel(in);
-    }
-
-    /**
-     * Creates a {@code StatsDimensionsValue} from a StatsDimensionsValueParcel
-     *
-     * @hide
-     */
-    public StatsDimensionsValue(StatsDimensionsValueParcel parcel) {
-        mInner = parcel;
-    }
-
-    /**
-     * Return the field, i.e. the tag of a statsd atom.
-     *
-     * @return the field
-     */
-    public int getField() {
-        return mInner.field;
-    }
-
-    /**
-     * Retrieve the String held, if any.
-     *
-     * @return the {@link String} held if {@link #getValueType()} == {@link #STRING_VALUE_TYPE},
-     *         null otherwise
-     */
-    public String getStringValue() {
-        if (mInner.valueType == STRING_VALUE_TYPE) {
-            return mInner.stringValue;
-        } else {
-            Log.w(TAG, "Value type is " + getValueTypeAsString() + ", not string.");
-            return null;
-        }
-    }
-
-    /**
-     * Retrieve the int held, if any.
-     *
-     * @return the int held if {@link #getValueType()} == {@link #INT_VALUE_TYPE}, 0 otherwise
-     */
-    public int getIntValue() {
-        if (mInner.valueType == INT_VALUE_TYPE) {
-            return mInner.intValue;
-        } else {
-            Log.w(TAG, "Value type is " + getValueTypeAsString() + ", not int.");
-            return 0;
-        }
-    }
-
-    /**
-     * Retrieve the long held, if any.
-     *
-     * @return the long held if {@link #getValueType()} == {@link #LONG_VALUE_TYPE}, 0 otherwise
-     */
-    public long getLongValue() {
-        if (mInner.valueType == LONG_VALUE_TYPE) {
-            return mInner.longValue;
-        } else {
-            Log.w(TAG, "Value type is " + getValueTypeAsString() + ", not long.");
-            return 0;
-        }
-    }
-
-    /**
-     * Retrieve the boolean held, if any.
-     *
-     * @return the boolean held if {@link #getValueType()} == {@link #BOOLEAN_VALUE_TYPE},
-     *         false otherwise
-     */
-    public boolean getBooleanValue() {
-        if (mInner.valueType == BOOLEAN_VALUE_TYPE) {
-            return mInner.boolValue;
-        } else {
-            Log.w(TAG, "Value type is " + getValueTypeAsString() + ", not boolean.");
-            return false;
-        }
-    }
-
-    /**
-     * Retrieve the float held, if any.
-     *
-     * @return the float held if {@link #getValueType()} == {@link #FLOAT_VALUE_TYPE}, 0 otherwise
-     */
-    public float getFloatValue() {
-        if (mInner.valueType == FLOAT_VALUE_TYPE) {
-            return mInner.floatValue;
-        } else {
-            Log.w(TAG, "Value type is " + getValueTypeAsString() + ", not float.");
-            return 0;
-        }
-    }
-
-    /**
-     * Retrieve the tuple, in the form of a {@link List} of {@link StatsDimensionsValue}, held,
-     * if any.
-     *
-     * @return the {@link List} of {@link StatsDimensionsValue} held
-     *         if {@link #getValueType()} == {@link #TUPLE_VALUE_TYPE},
-     *         null otherwise
-     */
-    public List<StatsDimensionsValue> getTupleValueList() {
-        if (mInner.valueType == TUPLE_VALUE_TYPE) {
-            int length = (mInner.tupleValue == null) ? 0 : mInner.tupleValue.length;
-            List<StatsDimensionsValue> tupleValues = new ArrayList<>(length);
-            for (int i = 0; i < length; i++) {
-                tupleValues.add(new StatsDimensionsValue(mInner.tupleValue[i]));
-            }
-            return tupleValues;
-        } else {
-            Log.w(TAG, "Value type is " + getValueTypeAsString() + ", not tuple.");
-            return null;
-        }
-    }
-
-    /**
-     * Returns the constant representing the type of value stored, namely one of
-     * <ul>
-     *   <li>{@link #STRING_VALUE_TYPE}</li>
-     *   <li>{@link #INT_VALUE_TYPE}</li>
-     *   <li>{@link #LONG_VALUE_TYPE}</li>
-     *   <li>{@link #BOOLEAN_VALUE_TYPE}</li>
-     *   <li>{@link #FLOAT_VALUE_TYPE}</li>
-     *   <li>{@link #TUPLE_VALUE_TYPE}</li>
-     * </ul>
-     *
-     * @return the constant representing the type of value stored
-     */
-    public int getValueType() {
-        return mInner.valueType;
-    }
-
-    /**
-     * Returns whether the type of value stored is equal to the given type.
-     *
-     * @param valueType int representing the type of value stored, as used in {@link #getValueType}
-     * @return true if {@link #getValueType()} is equal to {@code valueType}.
-     */
-    public boolean isValueType(int valueType) {
-        return mInner.valueType == valueType;
-    }
-
-    /**
-     * Returns a String representing the information in this StatsDimensionValue.
-     * No guarantees are made about the format of this String.
-     *
-     * @return String representation
-     *
-     * @hide
-     */
-    // Follows the format of statsd's dimension.h toString.
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append(mInner.field);
-        sb.append(":");
-        switch (mInner.valueType) {
-            case STRING_VALUE_TYPE:
-                sb.append(mInner.stringValue);
-                break;
-            case INT_VALUE_TYPE:
-                sb.append(String.valueOf(mInner.intValue));
-                break;
-            case LONG_VALUE_TYPE:
-                sb.append(String.valueOf(mInner.longValue));
-                break;
-            case BOOLEAN_VALUE_TYPE:
-                sb.append(String.valueOf(mInner.boolValue));
-                break;
-            case FLOAT_VALUE_TYPE:
-                sb.append(String.valueOf(mInner.floatValue));
-                break;
-            case TUPLE_VALUE_TYPE:
-                sb.append("{");
-                int length = (mInner.tupleValue == null) ? 0 : mInner.tupleValue.length;
-                for (int i = 0; i < length; i++) {
-                    StatsDimensionsValue child = new StatsDimensionsValue(mInner.tupleValue[i]);
-                    sb.append(child.toString());
-                    sb.append("|");
-                }
-                sb.append("}");
-                break;
-            default:
-                Log.w(TAG, "Incorrect value type");
-                break;
-        }
-        return sb.toString();
-    }
-
-    /**
-     * Parcelable Creator for StatsDimensionsValue.
-     */
-    public static final @android.annotation.NonNull
-            Parcelable.Creator<StatsDimensionsValue> CREATOR = new
-            Parcelable.Creator<StatsDimensionsValue>() {
-                public StatsDimensionsValue createFromParcel(Parcel in) {
-                    return new StatsDimensionsValue(in);
-                }
-
-                public StatsDimensionsValue[] newArray(int size) {
-                    return new StatsDimensionsValue[size];
-                }
-            };
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        mInner.writeToParcel(out, flags);
-    }
-
-    /**
-     * Returns a string representation of the type of value stored.
-     */
-    private String getValueTypeAsString() {
-        switch (mInner.valueType) {
-            case STRING_VALUE_TYPE:
-                return "string";
-            case INT_VALUE_TYPE:
-                return "int";
-            case LONG_VALUE_TYPE:
-                return "long";
-            case BOOLEAN_VALUE_TYPE:
-                return "boolean";
-            case FLOAT_VALUE_TYPE:
-                return "float";
-            case TUPLE_VALUE_TYPE:
-                return "tuple";
-            default:
-                return "unknown";
-        }
-    }
-}
diff --git a/apex/statsd/framework/java/android/os/StatsFrameworkInitializer.java b/apex/statsd/framework/java/android/os/StatsFrameworkInitializer.java
deleted file mode 100644
index 8dc9123..0000000
--- a/apex/statsd/framework/java/android/os/StatsFrameworkInitializer.java
+++ /dev/null
@@ -1,77 +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.os;
-
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.annotation.SystemApi.Client;
-import android.app.StatsManager;
-import android.app.SystemServiceRegistry;
-import android.content.Context;
-
-/**
- * Class for performing registration for all stats services
- *
- * @hide
- */
-@SystemApi(client = Client.MODULE_LIBRARIES)
-public class StatsFrameworkInitializer {
-    private StatsFrameworkInitializer() {
-    }
-
-    private static volatile StatsServiceManager sStatsServiceManager;
-
-    /**
-     * Sets an instance of {@link StatsServiceManager} that allows
-     * the statsd mainline module to register/obtain stats binder services. This is called
-     * by the platform during the system initialization.
-     *
-     * @param statsServiceManager instance of {@link StatsServiceManager} that allows
-     * the statsd mainline module to register/obtain statsd binder services.
-     */
-    public static void setStatsServiceManager(
-            @NonNull StatsServiceManager statsServiceManager) {
-        if (sStatsServiceManager != null) {
-            throw new IllegalStateException("setStatsServiceManager called twice!");
-        }
-
-        if (statsServiceManager == null) {
-            throw new NullPointerException("statsServiceManager is null");
-        }
-
-        sStatsServiceManager = statsServiceManager;
-    }
-
-    /** @hide */
-    public static StatsServiceManager getStatsServiceManager() {
-        return sStatsServiceManager;
-    }
-
-    /**
-     * Called by {@link SystemServiceRegistry}'s static initializer and registers all statsd
-     * services to {@link Context}, so that {@link Context#getSystemService} can return them.
-     *
-     * @throws IllegalStateException if this is called from anywhere besides
-     * {@link SystemServiceRegistry}
-     */
-    public static void registerServiceWrappers() {
-        SystemServiceRegistry.registerContextAwareService(
-                Context.STATS_MANAGER,
-                StatsManager.class,
-                context -> new StatsManager(context)
-        );
-    }
-}
diff --git a/apex/statsd/framework/java/android/util/StatsEvent.java b/apex/statsd/framework/java/android/util/StatsEvent.java
deleted file mode 100644
index 8be5c63..0000000
--- a/apex/statsd/framework/java/android/util/StatsEvent.java
+++ /dev/null
@@ -1,879 +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.
- */
-
-package android.util;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.os.SystemClock;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.Arrays;
-
-/**
- * StatsEvent builds and stores the buffer sent over the statsd socket.
- * This class defines and encapsulates the socket protocol.
- *
- * <p>Usage:</p>
- * <pre>
- *      // Pushed event
- *      StatsEvent statsEvent = StatsEvent.newBuilder()
- *          .setAtomId(atomId)
- *          .writeBoolean(false)
- *          .writeString("annotated String field")
- *          .addBooleanAnnotation(annotationId, true)
- *          .usePooledBuffer()
- *          .build();
- *      StatsLog.write(statsEvent);
- *
- *      // Pulled event
- *      StatsEvent statsEvent = StatsEvent.newBuilder()
- *          .setAtomId(atomId)
- *          .writeBoolean(false)
- *          .writeString("annotated String field")
- *          .addBooleanAnnotation(annotationId, true)
- *          .build();
- * </pre>
- * @hide
- **/
-@SystemApi
-public final class StatsEvent {
-    // Type Ids.
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final byte TYPE_INT = 0x00;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final byte TYPE_LONG = 0x01;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final byte TYPE_STRING = 0x02;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final byte TYPE_LIST = 0x03;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final byte TYPE_FLOAT = 0x04;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final byte TYPE_BOOLEAN = 0x05;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final byte TYPE_BYTE_ARRAY = 0x06;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final byte TYPE_OBJECT = 0x07;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final byte TYPE_KEY_VALUE_PAIRS = 0x08;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final byte TYPE_ATTRIBUTION_CHAIN = 0x09;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final byte TYPE_ERRORS = 0x0F;
-
-    // Error flags.
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final int ERROR_NO_TIMESTAMP = 0x1;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final int ERROR_NO_ATOM_ID = 0x2;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final int ERROR_OVERFLOW = 0x4;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final int ERROR_ATTRIBUTION_CHAIN_TOO_LONG = 0x8;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final int ERROR_TOO_MANY_KEY_VALUE_PAIRS = 0x10;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final int ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD = 0x20;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final int ERROR_INVALID_ANNOTATION_ID = 0x40;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final int ERROR_ANNOTATION_ID_TOO_LARGE = 0x80;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final int ERROR_TOO_MANY_ANNOTATIONS = 0x100;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final int ERROR_TOO_MANY_FIELDS = 0x200;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final int ERROR_ATTRIBUTION_UIDS_TAGS_SIZES_NOT_EQUAL = 0x1000;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final int ERROR_ATOM_ID_INVALID_POSITION = 0x2000;
-
-    // Size limits.
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final int MAX_ANNOTATION_COUNT = 15;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final int MAX_ATTRIBUTION_NODES = 127;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final int MAX_NUM_ELEMENTS = 127;
-
-    /**
-     * @hide
-     **/
-    @VisibleForTesting
-    public static final int MAX_KEY_VALUE_PAIRS = 127;
-
-    private static final int LOGGER_ENTRY_MAX_PAYLOAD = 4068;
-
-    // Max payload size is 4 bytes less as 4 bytes are reserved for statsEventTag.
-    // See android_util_StatsLog.cpp.
-    private static final int MAX_PUSH_PAYLOAD_SIZE = LOGGER_ENTRY_MAX_PAYLOAD - 4;
-
-    private static final int MAX_PULL_PAYLOAD_SIZE = 50 * 1024; // 50 KB
-
-    private final int mAtomId;
-    private final byte[] mPayload;
-    private Buffer mBuffer;
-    private final int mNumBytes;
-
-    private StatsEvent(final int atomId, @Nullable final Buffer buffer,
-            @NonNull final byte[] payload, final int numBytes) {
-        mAtomId = atomId;
-        mBuffer = buffer;
-        mPayload = payload;
-        mNumBytes = numBytes;
-    }
-
-    /**
-     * Returns a new StatsEvent.Builder for building StatsEvent object.
-     **/
-    @NonNull
-    public static StatsEvent.Builder newBuilder() {
-        return new StatsEvent.Builder(Buffer.obtain());
-    }
-
-    /**
-     * Get the atom Id of the atom encoded in this StatsEvent object.
-     *
-     * @hide
-     **/
-    public int getAtomId() {
-        return mAtomId;
-    }
-
-    /**
-     * Get the byte array that contains the encoded payload that can be sent to statsd.
-     *
-     * @hide
-     **/
-    @NonNull
-    public byte[] getBytes() {
-        return mPayload;
-    }
-
-    /**
-     * Get the number of bytes used to encode the StatsEvent payload.
-     *
-     * @hide
-     **/
-    public int getNumBytes() {
-        return mNumBytes;
-    }
-
-    /**
-     * Recycle resources used by this StatsEvent object.
-     * No actions should be taken on this StatsEvent after release() is called.
-     *
-     * @hide
-     **/
-    public void release() {
-        if (mBuffer != null) {
-            mBuffer.release();
-            mBuffer = null;
-        }
-    }
-
-    /**
-     * Builder for constructing a StatsEvent object.
-     *
-     * <p>This class defines and encapsulates the socket encoding for the buffer.
-     * The write methods must be called in the same order as the order of fields in the
-     * atom definition.</p>
-     *
-     * <p>setAtomId() can be called anytime before build().</p>
-     *
-     * <p>Example:</p>
-     * <pre>
-     *     // Atom definition.
-     *     message MyAtom {
-     *         optional int32 field1 = 1;
-     *         optional int64 field2 = 2;
-     *         optional string field3 = 3 [(annotation1) = true];
-     *     }
-     *
-     *     // StatsEvent construction for pushed event.
-     *     StatsEvent.newBuilder()
-     *     StatsEvent statsEvent = StatsEvent.newBuilder()
-     *         .setAtomId(atomId)
-     *         .writeInt(3) // field1
-     *         .writeLong(8L) // field2
-     *         .writeString("foo") // field 3
-     *         .addBooleanAnnotation(annotation1Id, true)
-     *         .usePooledBuffer()
-     *         .build();
-     *
-     *     // StatsEvent construction for pulled event.
-     *     StatsEvent.newBuilder()
-     *     StatsEvent statsEvent = StatsEvent.newBuilder()
-     *         .setAtomId(atomId)
-     *         .writeInt(3) // field1
-     *         .writeLong(8L) // field2
-     *         .writeString("foo") // field 3
-     *         .addBooleanAnnotation(annotation1Id, true)
-     *         .build();
-     * </pre>
-     **/
-    public static final class Builder {
-        // Fixed positions.
-        private static final int POS_NUM_ELEMENTS = 1;
-        private static final int POS_TIMESTAMP_NS = POS_NUM_ELEMENTS + Byte.BYTES;
-        private static final int POS_ATOM_ID = POS_TIMESTAMP_NS + Byte.BYTES + Long.BYTES;
-
-        private final Buffer mBuffer;
-        private long mTimestampNs;
-        private int mAtomId;
-        private byte mCurrentAnnotationCount;
-        private int mPos;
-        private int mPosLastField;
-        private byte mLastType;
-        private int mNumElements;
-        private int mErrorMask;
-        private boolean mUsePooledBuffer = false;
-
-        private Builder(final Buffer buffer) {
-            mBuffer = buffer;
-            mCurrentAnnotationCount = 0;
-            mAtomId = 0;
-            mTimestampNs = SystemClock.elapsedRealtimeNanos();
-            mNumElements = 0;
-
-            // Set mPos to 0 for writing TYPE_OBJECT at 0th position.
-            mPos = 0;
-            writeTypeId(TYPE_OBJECT);
-
-            // Write timestamp.
-            mPos = POS_TIMESTAMP_NS;
-            writeLong(mTimestampNs);
-        }
-
-        /**
-         * Sets the atom id for this StatsEvent.
-         *
-         * This should be called immediately after StatsEvent.newBuilder()
-         * and should only be called once.
-         * Not calling setAtomId will result in ERROR_NO_ATOM_ID.
-         * Calling setAtomId out of order will result in ERROR_ATOM_ID_INVALID_POSITION.
-         **/
-        @NonNull
-        public Builder setAtomId(final int atomId) {
-            if (0 == mAtomId) {
-                mAtomId = atomId;
-
-                if (1 == mNumElements) { // Only timestamp is written so far.
-                    writeInt(atomId);
-                } else {
-                    // setAtomId called out of order.
-                    mErrorMask |= ERROR_ATOM_ID_INVALID_POSITION;
-                }
-            }
-
-            return this;
-        }
-
-        /**
-         * Write a boolean field to this StatsEvent.
-         **/
-        @NonNull
-        public Builder writeBoolean(final boolean value) {
-            // Write boolean typeId byte followed by boolean byte representation.
-            writeTypeId(TYPE_BOOLEAN);
-            mPos += mBuffer.putBoolean(mPos, value);
-            mNumElements++;
-            return this;
-        }
-
-        /**
-         * Write an integer field to this StatsEvent.
-         **/
-        @NonNull
-        public Builder writeInt(final int value) {
-            // Write integer typeId byte followed by 4-byte representation of value.
-            writeTypeId(TYPE_INT);
-            mPos += mBuffer.putInt(mPos, value);
-            mNumElements++;
-            return this;
-        }
-
-        /**
-         * Write a long field to this StatsEvent.
-         **/
-        @NonNull
-        public Builder writeLong(final long value) {
-            // Write long typeId byte followed by 8-byte representation of value.
-            writeTypeId(TYPE_LONG);
-            mPos += mBuffer.putLong(mPos, value);
-            mNumElements++;
-            return this;
-        }
-
-        /**
-         * Write a float field to this StatsEvent.
-         **/
-        @NonNull
-        public Builder writeFloat(final float value) {
-            // Write float typeId byte followed by 4-byte representation of value.
-            writeTypeId(TYPE_FLOAT);
-            mPos += mBuffer.putFloat(mPos, value);
-            mNumElements++;
-            return this;
-        }
-
-        /**
-         * Write a String field to this StatsEvent.
-         **/
-        @NonNull
-        public Builder writeString(@NonNull final String value) {
-            // Write String typeId byte, followed by 4-byte representation of number of bytes
-            // in the UTF-8 encoding, followed by the actual UTF-8 byte encoding of value.
-            final byte[] valueBytes = stringToBytes(value);
-            writeByteArray(valueBytes, TYPE_STRING);
-            return this;
-        }
-
-        /**
-         * Write a byte array field to this StatsEvent.
-         **/
-        @NonNull
-        public Builder writeByteArray(@NonNull final byte[] value) {
-            // Write byte array typeId byte, followed by 4-byte representation of number of bytes
-            // in value, followed by the actual byte array.
-            writeByteArray(value, TYPE_BYTE_ARRAY);
-            return this;
-        }
-
-        private void writeByteArray(@NonNull final byte[] value, final byte typeId) {
-            writeTypeId(typeId);
-            final int numBytes = value.length;
-            mPos += mBuffer.putInt(mPos, numBytes);
-            mPos += mBuffer.putByteArray(mPos, value);
-            mNumElements++;
-        }
-
-        /**
-         * Write an attribution chain field to this StatsEvent.
-         *
-         * The sizes of uids and tags must be equal. The AttributionNode at position i is
-         * made up of uids[i] and tags[i].
-         *
-         * @param uids array of uids in the attribution nodes.
-         * @param tags array of tags in the attribution nodes.
-         **/
-        @NonNull
-        public Builder writeAttributionChain(
-                @NonNull final int[] uids, @NonNull final String[] tags) {
-            final byte numUids = (byte) uids.length;
-            final byte numTags = (byte) tags.length;
-
-            if (numUids != numTags) {
-                mErrorMask |= ERROR_ATTRIBUTION_UIDS_TAGS_SIZES_NOT_EQUAL;
-            } else if (numUids > MAX_ATTRIBUTION_NODES) {
-                mErrorMask |= ERROR_ATTRIBUTION_CHAIN_TOO_LONG;
-            } else {
-                // Write attribution chain typeId byte, followed by 1-byte representation of
-                // number of attribution nodes, followed by encoding of each attribution node.
-                writeTypeId(TYPE_ATTRIBUTION_CHAIN);
-                mPos += mBuffer.putByte(mPos, numUids);
-                for (int i = 0; i < numUids; i++) {
-                    // Each uid is encoded as 4-byte representation of its int value.
-                    mPos += mBuffer.putInt(mPos, uids[i]);
-
-                    // Each tag is encoded as 4-byte representation of number of bytes in its
-                    // UTF-8 encoding, followed by the actual UTF-8 bytes.
-                    final byte[] tagBytes = stringToBytes(tags[i]);
-                    mPos += mBuffer.putInt(mPos, tagBytes.length);
-                    mPos += mBuffer.putByteArray(mPos, tagBytes);
-                }
-                mNumElements++;
-            }
-            return this;
-        }
-
-        /**
-         * Write KeyValuePairsAtom entries to this StatsEvent.
-         *
-         * @param intMap Integer key-value pairs.
-         * @param longMap Long key-value pairs.
-         * @param stringMap String key-value pairs.
-         * @param floatMap Float key-value pairs.
-         **/
-        @NonNull
-        public Builder writeKeyValuePairs(
-                @Nullable final SparseIntArray intMap,
-                @Nullable final SparseLongArray longMap,
-                @Nullable final SparseArray<String> stringMap,
-                @Nullable final SparseArray<Float> floatMap) {
-            final int intMapSize = null == intMap ? 0 : intMap.size();
-            final int longMapSize = null == longMap ? 0 : longMap.size();
-            final int stringMapSize = null == stringMap ? 0 : stringMap.size();
-            final int floatMapSize = null == floatMap ? 0 : floatMap.size();
-            final int totalCount = intMapSize + longMapSize + stringMapSize + floatMapSize;
-
-            if (totalCount > MAX_KEY_VALUE_PAIRS) {
-                mErrorMask |= ERROR_TOO_MANY_KEY_VALUE_PAIRS;
-            } else {
-                writeTypeId(TYPE_KEY_VALUE_PAIRS);
-                mPos += mBuffer.putByte(mPos, (byte) totalCount);
-
-                for (int i = 0; i < intMapSize; i++) {
-                    final int key = intMap.keyAt(i);
-                    final int value = intMap.valueAt(i);
-                    mPos += mBuffer.putInt(mPos, key);
-                    writeTypeId(TYPE_INT);
-                    mPos += mBuffer.putInt(mPos, value);
-                }
-
-                for (int i = 0; i < longMapSize; i++) {
-                    final int key = longMap.keyAt(i);
-                    final long value = longMap.valueAt(i);
-                    mPos += mBuffer.putInt(mPos, key);
-                    writeTypeId(TYPE_LONG);
-                    mPos += mBuffer.putLong(mPos, value);
-                }
-
-                for (int i = 0; i < stringMapSize; i++) {
-                    final int key = stringMap.keyAt(i);
-                    final String value = stringMap.valueAt(i);
-                    mPos += mBuffer.putInt(mPos, key);
-                    writeTypeId(TYPE_STRING);
-                    final byte[] valueBytes = stringToBytes(value);
-                    mPos += mBuffer.putInt(mPos, valueBytes.length);
-                    mPos += mBuffer.putByteArray(mPos, valueBytes);
-                }
-
-                for (int i = 0; i < floatMapSize; i++) {
-                    final int key = floatMap.keyAt(i);
-                    final float value = floatMap.valueAt(i);
-                    mPos += mBuffer.putInt(mPos, key);
-                    writeTypeId(TYPE_FLOAT);
-                    mPos += mBuffer.putFloat(mPos, value);
-                }
-
-                mNumElements++;
-            }
-
-            return this;
-        }
-
-        /**
-         * Write a boolean annotation for the last field written.
-         **/
-        @NonNull
-        public Builder addBooleanAnnotation(
-                final byte annotationId, final boolean value) {
-            // Ensure there's a field written to annotate.
-            if (mNumElements < 2) {
-                mErrorMask |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD;
-            } else if (mCurrentAnnotationCount >= MAX_ANNOTATION_COUNT) {
-                mErrorMask |= ERROR_TOO_MANY_ANNOTATIONS;
-            } else {
-                mPos += mBuffer.putByte(mPos, annotationId);
-                mPos += mBuffer.putByte(mPos, TYPE_BOOLEAN);
-                mPos += mBuffer.putBoolean(mPos, value);
-                mCurrentAnnotationCount++;
-                writeAnnotationCount();
-            }
-
-            return this;
-        }
-
-        /**
-         * Write an integer annotation for the last field written.
-         **/
-        @NonNull
-        public Builder addIntAnnotation(final byte annotationId, final int value) {
-            if (mNumElements < 2) {
-                mErrorMask |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD;
-            } else if (mCurrentAnnotationCount >= MAX_ANNOTATION_COUNT) {
-                mErrorMask |= ERROR_TOO_MANY_ANNOTATIONS;
-            } else {
-                mPos += mBuffer.putByte(mPos, annotationId);
-                mPos += mBuffer.putByte(mPos, TYPE_INT);
-                mPos += mBuffer.putInt(mPos, value);
-                mCurrentAnnotationCount++;
-                writeAnnotationCount();
-            }
-
-            return this;
-        }
-
-        /**
-         * Indicates to reuse Buffer's byte array as the underlying payload in StatsEvent.
-         * This should be called for pushed events to reduce memory allocations and garbage
-         * collections.
-         **/
-        @NonNull
-        public Builder usePooledBuffer() {
-            mUsePooledBuffer = true;
-            mBuffer.setMaxSize(MAX_PUSH_PAYLOAD_SIZE, mPos);
-            return this;
-        }
-
-        /**
-         * Builds a StatsEvent object with values entered in this Builder.
-         **/
-        @NonNull
-        public StatsEvent build() {
-            if (0L == mTimestampNs) {
-                mErrorMask |= ERROR_NO_TIMESTAMP;
-            }
-            if (0 == mAtomId) {
-                mErrorMask |= ERROR_NO_ATOM_ID;
-            }
-            if (mBuffer.hasOverflowed()) {
-                mErrorMask |= ERROR_OVERFLOW;
-            }
-            if (mNumElements > MAX_NUM_ELEMENTS) {
-                mErrorMask |= ERROR_TOO_MANY_FIELDS;
-            }
-
-            if (0 == mErrorMask) {
-                mBuffer.putByte(POS_NUM_ELEMENTS, (byte) mNumElements);
-            } else {
-                // Write atom id and error mask. Overwrite any annotations for atom Id.
-                mPos = POS_ATOM_ID;
-                mPos += mBuffer.putByte(mPos, TYPE_INT);
-                mPos += mBuffer.putInt(mPos, mAtomId);
-                mPos += mBuffer.putByte(mPos, TYPE_ERRORS);
-                mPos += mBuffer.putInt(mPos, mErrorMask);
-                mBuffer.putByte(POS_NUM_ELEMENTS, (byte) 3);
-            }
-
-            final int size = mPos;
-
-            if (mUsePooledBuffer) {
-                return new StatsEvent(mAtomId, mBuffer, mBuffer.getBytes(), size);
-            } else {
-                // Create a copy of the buffer with the required number of bytes.
-                final byte[] payload = new byte[size];
-                System.arraycopy(mBuffer.getBytes(), 0, payload, 0, size);
-
-                // Return Buffer instance to the pool.
-                mBuffer.release();
-
-                return new StatsEvent(mAtomId, null, payload, size);
-            }
-        }
-
-        private void writeTypeId(final byte typeId) {
-            mPosLastField = mPos;
-            mLastType = typeId;
-            mCurrentAnnotationCount = 0;
-            final byte encodedId = (byte) (typeId & 0x0F);
-            mPos += mBuffer.putByte(mPos, encodedId);
-        }
-
-        private void writeAnnotationCount() {
-            // Use first 4 bits for annotation count and last 4 bits for typeId.
-            final byte encodedId = (byte) ((mCurrentAnnotationCount << 4) | (mLastType & 0x0F));
-            mBuffer.putByte(mPosLastField, encodedId);
-        }
-
-        @NonNull
-        private static byte[] stringToBytes(@Nullable final String value) {
-            return (null == value ? "" : value).getBytes(UTF_8);
-        }
-    }
-
-    private static final class Buffer {
-        private static Object sLock = new Object();
-
-        @GuardedBy("sLock")
-        private static Buffer sPool;
-
-        private byte[] mBytes = new byte[MAX_PUSH_PAYLOAD_SIZE];
-        private boolean mOverflow = false;
-        private int mMaxSize = MAX_PULL_PAYLOAD_SIZE;
-
-        @NonNull
-        private static Buffer obtain() {
-            final Buffer buffer;
-            synchronized (sLock) {
-                buffer = null == sPool ? new Buffer() : sPool;
-                sPool = null;
-            }
-            buffer.reset();
-            return buffer;
-        }
-
-        private Buffer() {
-        }
-
-        @NonNull
-        private byte[] getBytes() {
-            return mBytes;
-        }
-
-        private void release() {
-            // Recycle this Buffer if its size is MAX_PUSH_PAYLOAD_SIZE or under.
-            if (mBytes.length <= MAX_PUSH_PAYLOAD_SIZE) {
-                synchronized (sLock) {
-                    if (null == sPool) {
-                        sPool = this;
-                    }
-                }
-            }
-        }
-
-        private void reset() {
-            mOverflow = false;
-            mMaxSize = MAX_PULL_PAYLOAD_SIZE;
-        }
-
-        private void setMaxSize(final int maxSize, final int numBytesWritten) {
-            mMaxSize = maxSize;
-            if (numBytesWritten > maxSize) {
-                mOverflow = true;
-            }
-        }
-
-        private boolean hasOverflowed() {
-            return mOverflow;
-        }
-
-        /**
-         * Checks for available space in the byte array.
-         *
-         * @param index starting position in the buffer to start the check.
-         * @param numBytes number of bytes to check from index.
-         * @return true if space is available, false otherwise.
-         **/
-        private boolean hasEnoughSpace(final int index, final int numBytes) {
-            final int totalBytesNeeded = index + numBytes;
-
-            if (totalBytesNeeded > mMaxSize) {
-                mOverflow = true;
-                return false;
-            }
-
-            // Expand buffer if needed.
-            if (mBytes.length < mMaxSize && totalBytesNeeded > mBytes.length) {
-                int newSize = mBytes.length;
-                do {
-                    newSize *= 2;
-                } while (newSize <= totalBytesNeeded);
-
-                if (newSize > mMaxSize) {
-                    newSize = mMaxSize;
-                }
-
-                mBytes = Arrays.copyOf(mBytes, newSize);
-            }
-
-            return true;
-        }
-
-        /**
-         * Writes a byte into the buffer.
-         *
-         * @param index position in the buffer where the byte is written.
-         * @param value the byte to write.
-         * @return number of bytes written to buffer from this write operation.
-         **/
-        private int putByte(final int index, final byte value) {
-            if (hasEnoughSpace(index, Byte.BYTES)) {
-                mBytes[index] = (byte) (value);
-                return Byte.BYTES;
-            }
-            return 0;
-        }
-
-        /**
-         * Writes a boolean into the buffer.
-         *
-         * @param index position in the buffer where the boolean is written.
-         * @param value the boolean to write.
-         * @return number of bytes written to buffer from this write operation.
-         **/
-        private int putBoolean(final int index, final boolean value) {
-            return putByte(index, (byte) (value ? 1 : 0));
-        }
-
-        /**
-         * Writes an integer into the buffer.
-         *
-         * @param index position in the buffer where the integer is written.
-         * @param value the integer to write.
-         * @return number of bytes written to buffer from this write operation.
-         **/
-        private int putInt(final int index, final int value) {
-            if (hasEnoughSpace(index, Integer.BYTES)) {
-                // Use little endian byte order.
-                mBytes[index] = (byte) (value);
-                mBytes[index + 1] = (byte) (value >> 8);
-                mBytes[index + 2] = (byte) (value >> 16);
-                mBytes[index + 3] = (byte) (value >> 24);
-                return Integer.BYTES;
-            }
-            return 0;
-        }
-
-        /**
-         * Writes a long into the buffer.
-         *
-         * @param index position in the buffer where the long is written.
-         * @param value the long to write.
-         * @return number of bytes written to buffer from this write operation.
-         **/
-        private int putLong(final int index, final long value) {
-            if (hasEnoughSpace(index, Long.BYTES)) {
-                // Use little endian byte order.
-                mBytes[index] = (byte) (value);
-                mBytes[index + 1] = (byte) (value >> 8);
-                mBytes[index + 2] = (byte) (value >> 16);
-                mBytes[index + 3] = (byte) (value >> 24);
-                mBytes[index + 4] = (byte) (value >> 32);
-                mBytes[index + 5] = (byte) (value >> 40);
-                mBytes[index + 6] = (byte) (value >> 48);
-                mBytes[index + 7] = (byte) (value >> 56);
-                return Long.BYTES;
-            }
-            return 0;
-        }
-
-        /**
-         * Writes a float into the buffer.
-         *
-         * @param index position in the buffer where the float is written.
-         * @param value the float to write.
-         * @return number of bytes written to buffer from this write operation.
-         **/
-        private int putFloat(final int index, final float value) {
-            return putInt(index, Float.floatToIntBits(value));
-        }
-
-        /**
-         * Copies a byte array into the buffer.
-         *
-         * @param index position in the buffer where the byte array is copied.
-         * @param value the byte array to copy.
-         * @return number of bytes written to buffer from this write operation.
-         **/
-        private int putByteArray(final int index, @NonNull final byte[] value) {
-            final int numBytes = value.length;
-            if (hasEnoughSpace(index, numBytes)) {
-                System.arraycopy(value, 0, mBytes, index, numBytes);
-                return numBytes;
-            }
-            return 0;
-        }
-    }
-}
diff --git a/apex/statsd/framework/java/android/util/StatsLog.java b/apex/statsd/framework/java/android/util/StatsLog.java
deleted file mode 100644
index 0a9f4eb..0000000
--- a/apex/statsd/framework/java/android/util/StatsLog.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.util;
-
-import static android.Manifest.permission.DUMP;
-import static android.Manifest.permission.PACKAGE_USAGE_STATS;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
-import android.content.Context;
-import android.os.IStatsd;
-import android.os.Process;
-import android.util.proto.ProtoOutputStream;
-
-import com.android.internal.statsd.StatsdStatsLog;
-
-/**
- * StatsLog provides an API for developers to send events to statsd. The events can be used to
- * define custom metrics inside statsd.
- */
-public final class StatsLog {
-
-    // Load JNI library
-    static {
-        System.loadLibrary("stats_jni");
-    }
-    private static final String TAG = "StatsLog";
-    private static final boolean DEBUG = false;
-    private static final int EXPERIMENT_IDS_FIELD_ID = 1;
-
-    private StatsLog() {
-    }
-
-    /**
-     * Logs a start event.
-     *
-     * @param label developer-chosen label.
-     * @return True if the log request was sent to statsd.
-     */
-    public static boolean logStart(int label) {
-        int callingUid = Process.myUid();
-        StatsdStatsLog.write(
-                StatsdStatsLog.APP_BREADCRUMB_REPORTED,
-                callingUid,
-                label,
-                StatsdStatsLog.APP_BREADCRUMB_REPORTED__STATE__START);
-        return true;
-    }
-
-    /**
-     * Logs a stop event.
-     *
-     * @param label developer-chosen label.
-     * @return True if the log request was sent to statsd.
-     */
-    public static boolean logStop(int label) {
-        int callingUid = Process.myUid();
-        StatsdStatsLog.write(
-                StatsdStatsLog.APP_BREADCRUMB_REPORTED,
-                callingUid,
-                label,
-                StatsdStatsLog.APP_BREADCRUMB_REPORTED__STATE__STOP);
-        return true;
-    }
-
-    /**
-     * Logs an event that does not represent a start or stop boundary.
-     *
-     * @param label developer-chosen label.
-     * @return True if the log request was sent to statsd.
-     */
-    public static boolean logEvent(int label) {
-        int callingUid = Process.myUid();
-        StatsdStatsLog.write(
-                StatsdStatsLog.APP_BREADCRUMB_REPORTED,
-                callingUid,
-                label,
-                StatsdStatsLog.APP_BREADCRUMB_REPORTED__STATE__UNSPECIFIED);
-        return true;
-    }
-
-    /**
-     * Logs an event for binary push for module updates.
-     *
-     * @param trainName        name of install train.
-     * @param trainVersionCode version code of the train.
-     * @param options          optional flags about this install.
-     *                         The last 3 bits indicate options:
-     *                             0x01: FLAG_REQUIRE_STAGING
-     *                             0x02: FLAG_ROLLBACK_ENABLED
-     *                             0x04: FLAG_REQUIRE_LOW_LATENCY_MONITOR
-     * @param state            current install state. Defined as State enums in
-     *                         BinaryPushStateChanged atom in
-     *                         frameworks/base/cmds/statsd/src/atoms.proto
-     * @param experimentIds    experiment ids.
-     * @return True if the log request was sent to statsd.
-     */
-    @RequiresPermission(allOf = {DUMP, PACKAGE_USAGE_STATS})
-    public static boolean logBinaryPushStateChanged(@NonNull String trainName,
-            long trainVersionCode, int options, int state,
-            @NonNull long[] experimentIds) {
-        ProtoOutputStream proto = new ProtoOutputStream();
-        for (long id : experimentIds) {
-            proto.write(
-                    ProtoOutputStream.FIELD_TYPE_INT64
-                    | ProtoOutputStream.FIELD_COUNT_REPEATED
-                    | EXPERIMENT_IDS_FIELD_ID,
-                    id);
-        }
-        StatsdStatsLog.write(StatsdStatsLog.BINARY_PUSH_STATE_CHANGED,
-                trainName,
-                trainVersionCode,
-                (options & IStatsd.FLAG_REQUIRE_STAGING) > 0,
-                (options & IStatsd.FLAG_ROLLBACK_ENABLED) > 0,
-                (options & IStatsd.FLAG_REQUIRE_LOW_LATENCY_MONITOR) > 0,
-                state,
-                proto.getBytes(),
-                0,
-                0,
-                false);
-        return true;
-    }
-
-    /**
-     * Write an event to stats log using the raw format.
-     *
-     * @param buffer    The encoded buffer of data to write.
-     * @param size      The number of bytes from the buffer to write.
-     * @hide
-     */
-    // TODO(b/144935988): Mark deprecated.
-    @SystemApi
-    public static void writeRaw(@NonNull byte[] buffer, int size) {
-        // TODO(b/144935988): make this no-op once clients have migrated to StatsEvent.
-        writeImpl(buffer, size, 0);
-    }
-
-    /**
-     * Write an event to stats log using the raw format.
-     *
-     * @param buffer    The encoded buffer of data to write.
-     * @param size      The number of bytes from the buffer to write.
-     * @param atomId    The id of the atom to which the event belongs.
-     */
-    private static native void writeImpl(@NonNull byte[] buffer, int size, int atomId);
-
-    /**
-     * Write an event to stats log using the raw format encapsulated in StatsEvent.
-     * After writing to stats log, release() is called on the StatsEvent object.
-     * No further action should be taken on the StatsEvent object following this call.
-     *
-     * @param statsEvent    The StatsEvent object containing the encoded buffer of data to write.
-     * @hide
-     */
-    @SystemApi
-    public static void write(@NonNull final StatsEvent statsEvent) {
-        writeImpl(statsEvent.getBytes(), statsEvent.getNumBytes(), statsEvent.getAtomId());
-        statsEvent.release();
-    }
-
-    private static void enforceDumpCallingPermission(Context context) {
-        context.enforceCallingPermission(android.Manifest.permission.DUMP, "Need DUMP permission.");
-    }
-
-    private static void enforcesageStatsCallingPermission(Context context) {
-        context.enforceCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS,
-                "Need PACKAGE_USAGE_STATS permission.");
-    }
-}
diff --git a/apex/statsd/framework/test/Android.bp b/apex/statsd/framework/test/Android.bp
deleted file mode 100644
index 5cc5647..0000000
--- a/apex/statsd/framework/test/Android.bp
+++ /dev/null
@@ -1,33 +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.
-
-android_test {
-    name: "FrameworkStatsdTest",
-    sdk_version: "module_current",
-    srcs: [ "**/*.java" ],
-    manifest: "AndroidManifest.xml",
-    static_libs: [
-        "androidx.test.rules",
-        "truth-prebuilt",
-    ],
-    libs: [
-        "android.test.runner.stubs",
-        "android.test.base.stubs",
-        "framework-statsd.impl",
-    ],
-    test_suites: [
-        "device-tests",
-        "mts",
-    ],
-}
diff --git a/apex/statsd/framework/test/AndroidManifest.xml b/apex/statsd/framework/test/AndroidManifest.xml
deleted file mode 100644
index 8f89d23..0000000
--- a/apex/statsd/framework/test/AndroidManifest.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.os.statsd.framework.test"
-        >
-
-    <instrumentation
-            android:name="androidx.test.runner.AndroidJUnitRunner"
-            android:targetPackage="com.android.os.statsd.framework.test"
-            android:label="Framework Statsd Tests" />
-
-</manifest>
diff --git a/apex/statsd/framework/test/AndroidTest.xml b/apex/statsd/framework/test/AndroidTest.xml
deleted file mode 100644
index fb51915..0000000
--- a/apex/statsd/framework/test/AndroidTest.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?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.
--->
-<configuration description="Runs Tests for Statsd.">
-    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
-        <option name="test-file-name" value="FrameworkStatsdTest.apk" />
-        <option name="install-arg" value="-g" />
-    </target_preparer>
-
-    <option name="test-suite-tag" value="apct" />
-    <option name="test-suite-tag" value="mts" />
-    <option name="test-tag" value="FrameworkStatsdTest" />
-    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
-        <option name="package" value="com.android.os.statsd.framework.test" />
-        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
-        <option name="hidden-api-checks" value="false"/>
-    </test>
-
-    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
-        <option name="mainline-module-package-name" value="com.google.android.os.statsd" />
-    </object>
-</configuration>
\ No newline at end of file
diff --git a/apex/statsd/framework/test/src/android/app/PullAtomMetadataTest.java b/apex/statsd/framework/test/src/android/app/PullAtomMetadataTest.java
deleted file mode 100644
index fd386bd..0000000
--- a/apex/statsd/framework/test/src/android/app/PullAtomMetadataTest.java
+++ /dev/null
@@ -1,85 +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.
- */
-
-package android.app;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.StatsManager.PullAtomMetadata;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public final class PullAtomMetadataTest {
-
-    @Test
-    public void testEmpty() {
-        PullAtomMetadata metadata = new PullAtomMetadata.Builder().build();
-        assertThat(metadata.getTimeoutMillis()).isEqualTo(StatsManager.DEFAULT_TIMEOUT_MILLIS);
-        assertThat(metadata.getCoolDownMillis()).isEqualTo(StatsManager.DEFAULT_COOL_DOWN_MILLIS);
-        assertThat(metadata.getAdditiveFields()).isNull();
-    }
-
-    @Test
-    public void testSetTimeoutMillis() {
-        long timeoutMillis = 500L;
-        PullAtomMetadata metadata =
-                new PullAtomMetadata.Builder().setTimeoutMillis(timeoutMillis).build();
-        assertThat(metadata.getTimeoutMillis()).isEqualTo(timeoutMillis);
-        assertThat(metadata.getCoolDownMillis()).isEqualTo(StatsManager.DEFAULT_COOL_DOWN_MILLIS);
-        assertThat(metadata.getAdditiveFields()).isNull();
-    }
-
-    @Test
-    public void testSetCoolDownMillis() {
-        long coolDownMillis = 10_000L;
-        PullAtomMetadata metadata =
-                new PullAtomMetadata.Builder().setCoolDownMillis(coolDownMillis).build();
-        assertThat(metadata.getTimeoutMillis()).isEqualTo(StatsManager.DEFAULT_TIMEOUT_MILLIS);
-        assertThat(metadata.getCoolDownMillis()).isEqualTo(coolDownMillis);
-        assertThat(metadata.getAdditiveFields()).isNull();
-    }
-
-    @Test
-    public void testSetAdditiveFields() {
-        int[] fields = {2, 4, 6};
-        PullAtomMetadata metadata =
-                new PullAtomMetadata.Builder().setAdditiveFields(fields).build();
-        assertThat(metadata.getTimeoutMillis()).isEqualTo(StatsManager.DEFAULT_TIMEOUT_MILLIS);
-        assertThat(metadata.getCoolDownMillis()).isEqualTo(StatsManager.DEFAULT_COOL_DOWN_MILLIS);
-        assertThat(metadata.getAdditiveFields()).isEqualTo(fields);
-    }
-
-    @Test
-    public void testSetAllElements() {
-        long timeoutMillis = 300L;
-        long coolDownMillis = 9572L;
-        int[] fields = {3, 2};
-        PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setTimeoutMillis(timeoutMillis)
-                .setCoolDownMillis(coolDownMillis)
-                .setAdditiveFields(fields)
-                .build();
-        assertThat(metadata.getTimeoutMillis()).isEqualTo(timeoutMillis);
-        assertThat(metadata.getCoolDownMillis()).isEqualTo(coolDownMillis);
-        assertThat(metadata.getAdditiveFields()).isEqualTo(fields);
-    }
-}
diff --git a/apex/statsd/framework/test/src/android/os/StatsDimensionsValueTest.java b/apex/statsd/framework/test/src/android/os/StatsDimensionsValueTest.java
deleted file mode 100644
index db25911..0000000
--- a/apex/statsd/framework/test/src/android/os/StatsDimensionsValueTest.java
+++ /dev/null
@@ -1,115 +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.
- */
-
-package android.os;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.util.List;
-
-@RunWith(JUnit4.class)
-public final class StatsDimensionsValueTest {
-
-    @Test
-    public void testConversionFromStructuredParcel() {
-        int tupleField = 100; // atom id
-        String stringValue = "Hello";
-        int intValue = 123;
-        long longValue = 123456789L;
-        float floatValue = 1.1f;
-        boolean boolValue = true;
-
-        // Construct structured parcel
-        StatsDimensionsValueParcel sdvp = new StatsDimensionsValueParcel();
-        sdvp.field = tupleField;
-        sdvp.valueType = StatsDimensionsValue.TUPLE_VALUE_TYPE;
-        sdvp.tupleValue = new StatsDimensionsValueParcel[5];
-
-        for (int i = 0; i < 5; i++) {
-            sdvp.tupleValue[i] = new StatsDimensionsValueParcel();
-            sdvp.tupleValue[i].field = i + 1;
-        }
-
-        sdvp.tupleValue[0].valueType = StatsDimensionsValue.STRING_VALUE_TYPE;
-        sdvp.tupleValue[1].valueType = StatsDimensionsValue.INT_VALUE_TYPE;
-        sdvp.tupleValue[2].valueType = StatsDimensionsValue.LONG_VALUE_TYPE;
-        sdvp.tupleValue[3].valueType = StatsDimensionsValue.FLOAT_VALUE_TYPE;
-        sdvp.tupleValue[4].valueType = StatsDimensionsValue.BOOLEAN_VALUE_TYPE;
-
-        sdvp.tupleValue[0].stringValue = stringValue;
-        sdvp.tupleValue[1].intValue = intValue;
-        sdvp.tupleValue[2].longValue = longValue;
-        sdvp.tupleValue[3].floatValue = floatValue;
-        sdvp.tupleValue[4].boolValue = boolValue;
-
-        // Convert to StatsDimensionsValue and check result
-        StatsDimensionsValue sdv = new StatsDimensionsValue(sdvp);
-
-        assertThat(sdv.getField()).isEqualTo(tupleField);
-        assertThat(sdv.getValueType()).isEqualTo(StatsDimensionsValue.TUPLE_VALUE_TYPE);
-        List<StatsDimensionsValue> sdvChildren = sdv.getTupleValueList();
-        assertThat(sdvChildren.size()).isEqualTo(5);
-
-        for (int i = 0; i < 5; i++) {
-            assertThat(sdvChildren.get(i).getField()).isEqualTo(i + 1);
-        }
-
-        assertThat(sdvChildren.get(0).getValueType())
-              .isEqualTo(StatsDimensionsValue.STRING_VALUE_TYPE);
-        assertThat(sdvChildren.get(1).getValueType())
-              .isEqualTo(StatsDimensionsValue.INT_VALUE_TYPE);
-        assertThat(sdvChildren.get(2).getValueType())
-              .isEqualTo(StatsDimensionsValue.LONG_VALUE_TYPE);
-        assertThat(sdvChildren.get(3).getValueType())
-              .isEqualTo(StatsDimensionsValue.FLOAT_VALUE_TYPE);
-        assertThat(sdvChildren.get(4).getValueType())
-              .isEqualTo(StatsDimensionsValue.BOOLEAN_VALUE_TYPE);
-
-        assertThat(sdvChildren.get(0).getStringValue()).isEqualTo(stringValue);
-        assertThat(sdvChildren.get(1).getIntValue()).isEqualTo(intValue);
-        assertThat(sdvChildren.get(2).getLongValue()).isEqualTo(longValue);
-        assertThat(sdvChildren.get(3).getFloatValue()).isEqualTo(floatValue);
-        assertThat(sdvChildren.get(4).getBooleanValue()).isEqualTo(boolValue);
-
-        // Ensure that StatsDimensionsValue and StatsDimensionsValueParcel are
-        // parceled equivalently
-        Parcel sdvpParcel = Parcel.obtain();
-        Parcel sdvParcel = Parcel.obtain();
-        sdvp.writeToParcel(sdvpParcel, 0);
-        sdv.writeToParcel(sdvParcel, 0);
-        assertThat(sdvpParcel.dataSize()).isEqualTo(sdvParcel.dataSize());
-    }
-
-    @Test
-    public void testNullTupleArray() {
-        int tupleField = 100; // atom id
-
-        StatsDimensionsValueParcel parcel = new StatsDimensionsValueParcel();
-        parcel.field = tupleField;
-        parcel.valueType = StatsDimensionsValue.TUPLE_VALUE_TYPE;
-        parcel.tupleValue = null;
-
-        StatsDimensionsValue sdv = new StatsDimensionsValue(parcel);
-        assertThat(sdv.getField()).isEqualTo(tupleField);
-        assertThat(sdv.getValueType()).isEqualTo(StatsDimensionsValue.TUPLE_VALUE_TYPE);
-        List<StatsDimensionsValue> sdvChildren = sdv.getTupleValueList();
-        assertThat(sdvChildren.size()).isEqualTo(0);
-    }
-}
diff --git a/apex/statsd/framework/test/src/android/util/StatsEventTest.java b/apex/statsd/framework/test/src/android/util/StatsEventTest.java
deleted file mode 100644
index 8d26369..0000000
--- a/apex/statsd/framework/test/src/android/util/StatsEventTest.java
+++ /dev/null
@@ -1,818 +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.
- */
-
-package android.util;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-import android.os.SystemClock;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.google.common.collect.Range;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Random;
-
-/**
- * Internal tests for {@link StatsEvent}.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class StatsEventTest {
-
-    @Test
-    public void testNoFields() {
-        final long minTimestamp = SystemClock.elapsedRealtimeNanos();
-        final StatsEvent statsEvent = StatsEvent.newBuilder().usePooledBuffer().build();
-        final long maxTimestamp = SystemClock.elapsedRealtimeNanos();
-
-        final int expectedAtomId = 0;
-        assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId);
-
-        final ByteBuffer buffer =
-                ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN);
-
-        assertWithMessage("Root element in buffer is not TYPE_OBJECT")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT);
-
-        assertWithMessage("Incorrect number of elements in root object")
-                .that(buffer.get()).isEqualTo(3);
-
-        assertWithMessage("First element is not timestamp")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG);
-
-        assertWithMessage("Incorrect timestamp")
-                .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp));
-
-        assertWithMessage("Second element is not atom id")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT);
-
-        assertWithMessage("Incorrect atom id")
-                .that(buffer.getInt()).isEqualTo(expectedAtomId);
-
-        assertWithMessage("Third element is not errors type")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_ERRORS);
-
-        final int errorMask = buffer.getInt();
-
-        assertWithMessage("ERROR_NO_ATOM_ID should be the only error in the error mask")
-                .that(errorMask).isEqualTo(StatsEvent.ERROR_NO_ATOM_ID);
-
-        assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position());
-
-        statsEvent.release();
-    }
-
-    @Test
-    public void testOnlyAtomId() {
-        final int expectedAtomId = 109;
-
-        final long minTimestamp = SystemClock.elapsedRealtimeNanos();
-        final StatsEvent statsEvent = StatsEvent.newBuilder()
-                .setAtomId(expectedAtomId)
-                .usePooledBuffer()
-                .build();
-        final long maxTimestamp = SystemClock.elapsedRealtimeNanos();
-
-        assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId);
-
-        final ByteBuffer buffer =
-                ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN);
-
-        assertWithMessage("Root element in buffer is not TYPE_OBJECT")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT);
-
-        assertWithMessage("Incorrect number of elements in root object")
-                .that(buffer.get()).isEqualTo(2);
-
-        assertWithMessage("First element is not timestamp")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG);
-
-        assertWithMessage("Incorrect timestamp")
-                .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp));
-
-        assertWithMessage("Second element is not atom id")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT);
-
-        assertWithMessage("Incorrect atom id")
-                .that(buffer.getInt()).isEqualTo(expectedAtomId);
-
-        assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position());
-
-        statsEvent.release();
-    }
-
-    @Test
-    public void testIntBooleanIntInt() {
-        final int expectedAtomId = 109;
-        final int field1 = 1;
-        final boolean field2 = true;
-        final int field3 = 3;
-        final int field4 = 4;
-
-        final long minTimestamp = SystemClock.elapsedRealtimeNanos();
-        final StatsEvent statsEvent = StatsEvent.newBuilder()
-                .setAtomId(expectedAtomId)
-                .writeInt(field1)
-                .writeBoolean(field2)
-                .writeInt(field3)
-                .writeInt(field4)
-                .usePooledBuffer()
-                .build();
-        final long maxTimestamp = SystemClock.elapsedRealtimeNanos();
-
-        assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId);
-
-        final ByteBuffer buffer =
-                ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN);
-
-        assertWithMessage("Root element in buffer is not TYPE_OBJECT")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT);
-
-        assertWithMessage("Incorrect number of elements in root object")
-                .that(buffer.get()).isEqualTo(6);
-
-        assertWithMessage("First element is not timestamp")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG);
-
-        assertWithMessage("Incorrect timestamp")
-                .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp));
-
-        assertWithMessage("Second element is not atom id")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT);
-
-        assertWithMessage("Incorrect atom id")
-                .that(buffer.getInt()).isEqualTo(expectedAtomId);
-
-        assertWithMessage("First field is not Int")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT);
-
-        assertWithMessage("Incorrect field 1")
-                .that(buffer.getInt()).isEqualTo(field1);
-
-        assertWithMessage("Second field is not Boolean")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_BOOLEAN);
-
-        assertWithMessage("Incorrect field 2")
-                .that(buffer.get()).isEqualTo(1);
-
-        assertWithMessage("Third field is not Int")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT);
-
-        assertWithMessage("Incorrect field 3")
-                .that(buffer.getInt()).isEqualTo(field3);
-
-        assertWithMessage("Fourth field is not Int")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT);
-
-        assertWithMessage("Incorrect field 4")
-                .that(buffer.getInt()).isEqualTo(field4);
-
-        assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position());
-
-        statsEvent.release();
-    }
-
-    @Test
-    public void testStringFloatByteArray() {
-        final int expectedAtomId = 109;
-        final String field1 = "Str 1";
-        final float field2 = 9.334f;
-        final byte[] field3 = new byte[] { 56, 23, 89, -120 };
-
-        final long minTimestamp = SystemClock.elapsedRealtimeNanos();
-        final StatsEvent statsEvent = StatsEvent.newBuilder()
-                .setAtomId(expectedAtomId)
-                .writeString(field1)
-                .writeFloat(field2)
-                .writeByteArray(field3)
-                .usePooledBuffer()
-                .build();
-        final long maxTimestamp = SystemClock.elapsedRealtimeNanos();
-
-        assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId);
-
-        final ByteBuffer buffer =
-                ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN);
-
-        assertWithMessage("Root element in buffer is not TYPE_OBJECT")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT);
-
-        assertWithMessage("Incorrect number of elements in root object")
-                .that(buffer.get()).isEqualTo(5);
-
-        assertWithMessage("First element is not timestamp")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG);
-
-        assertWithMessage("Incorrect timestamp")
-                .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp));
-
-        assertWithMessage("Second element is not atom id")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT);
-
-        assertWithMessage("Incorrect atom id")
-                .that(buffer.getInt()).isEqualTo(expectedAtomId);
-
-        assertWithMessage("First field is not String")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_STRING);
-
-        final String field1Actual = getStringFromByteBuffer(buffer);
-        assertWithMessage("Incorrect field 1")
-                .that(field1Actual).isEqualTo(field1);
-
-        assertWithMessage("Second field is not Float")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_FLOAT);
-
-        assertWithMessage("Incorrect field 2")
-                .that(buffer.getFloat()).isEqualTo(field2);
-
-        assertWithMessage("Third field is not byte array")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_BYTE_ARRAY);
-
-        final byte[] field3Actual = getByteArrayFromByteBuffer(buffer);
-        assertWithMessage("Incorrect field 3")
-                .that(field3Actual).isEqualTo(field3);
-
-        assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position());
-
-        statsEvent.release();
-    }
-
-    @Test
-    public void testAttributionChainLong() {
-        final int expectedAtomId = 109;
-        final int[] uids = new int[] { 1, 2, 3, 4, 5 };
-        final String[] tags = new String[] { "1", "2", "3", "4", "5" };
-        final long field2 = -230909823L;
-
-        final long minTimestamp = SystemClock.elapsedRealtimeNanos();
-        final StatsEvent statsEvent = StatsEvent.newBuilder()
-                .setAtomId(expectedAtomId)
-                .writeAttributionChain(uids, tags)
-                .writeLong(field2)
-                .usePooledBuffer()
-                .build();
-        final long maxTimestamp = SystemClock.elapsedRealtimeNanos();
-
-        assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId);
-
-        final ByteBuffer buffer =
-                ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN);
-
-        assertWithMessage("Root element in buffer is not TYPE_OBJECT")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT);
-
-        assertWithMessage("Incorrect number of elements in root object")
-                .that(buffer.get()).isEqualTo(4);
-
-        assertWithMessage("First element is not timestamp")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG);
-
-        assertWithMessage("Incorrect timestamp")
-                .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp));
-
-        assertWithMessage("Second element is not atom id")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT);
-
-        assertWithMessage("Incorrect atom id")
-                .that(buffer.getInt()).isEqualTo(expectedAtomId);
-
-        assertWithMessage("First field is not Attribution Chain")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_ATTRIBUTION_CHAIN);
-
-        assertWithMessage("Incorrect number of attribution nodes")
-                .that(buffer.get()).isEqualTo((byte) uids.length);
-
-        for (int i = 0; i < tags.length; i++) {
-            assertWithMessage("Incorrect uid in Attribution Chain")
-                    .that(buffer.getInt()).isEqualTo(uids[i]);
-
-            final String tag = getStringFromByteBuffer(buffer);
-            assertWithMessage("Incorrect tag in Attribution Chain")
-                    .that(tag).isEqualTo(tags[i]);
-        }
-
-        assertWithMessage("Second field is not Long")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG);
-
-        assertWithMessage("Incorrect field 2")
-                .that(buffer.getLong()).isEqualTo(field2);
-
-        assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position());
-
-        statsEvent.release();
-    }
-
-    @Test
-    public void testKeyValuePairs() {
-        final int expectedAtomId = 109;
-        final SparseIntArray intMap = new SparseIntArray();
-        final SparseLongArray longMap = new SparseLongArray();
-        final SparseArray<String> stringMap = new SparseArray<>();
-        final SparseArray<Float> floatMap = new SparseArray<>();
-        intMap.put(1, -1);
-        intMap.put(2, -2);
-        stringMap.put(3, "abc");
-        stringMap.put(4, "2h");
-        floatMap.put(9, -234.344f);
-
-        final long minTimestamp = SystemClock.elapsedRealtimeNanos();
-        final StatsEvent statsEvent = StatsEvent.newBuilder()
-                .setAtomId(expectedAtomId)
-                .writeKeyValuePairs(intMap, longMap, stringMap, floatMap)
-                .usePooledBuffer()
-                .build();
-        final long maxTimestamp = SystemClock.elapsedRealtimeNanos();
-
-        assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId);
-
-        final ByteBuffer buffer =
-                ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN);
-
-        assertWithMessage("Root element in buffer is not TYPE_OBJECT")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT);
-
-        assertWithMessage("Incorrect number of elements in root object")
-                .that(buffer.get()).isEqualTo(3);
-
-        assertWithMessage("First element is not timestamp")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG);
-
-        assertWithMessage("Incorrect timestamp")
-                .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp));
-
-        assertWithMessage("Second element is not atom id")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT);
-
-        assertWithMessage("Incorrect atom id")
-                .that(buffer.getInt()).isEqualTo(expectedAtomId);
-
-        assertWithMessage("First field is not KeyValuePairs")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_KEY_VALUE_PAIRS);
-
-        assertWithMessage("Incorrect number of key value pairs")
-                .that(buffer.get()).isEqualTo(
-                        (byte) (intMap.size() + longMap.size() + stringMap.size()
-                                + floatMap.size()));
-
-        for (int i = 0; i < intMap.size(); i++) {
-            assertWithMessage("Incorrect key in intMap")
-                    .that(buffer.getInt()).isEqualTo(intMap.keyAt(i));
-            assertWithMessage("The type id of the value should be TYPE_INT in intMap")
-                    .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT);
-            assertWithMessage("Incorrect value in intMap")
-                    .that(buffer.getInt()).isEqualTo(intMap.valueAt(i));
-        }
-
-        for (int i = 0; i < longMap.size(); i++) {
-            assertWithMessage("Incorrect key in longMap")
-                    .that(buffer.getInt()).isEqualTo(longMap.keyAt(i));
-            assertWithMessage("The type id of the value should be TYPE_LONG in longMap")
-                    .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG);
-            assertWithMessage("Incorrect value in longMap")
-                    .that(buffer.getLong()).isEqualTo(longMap.valueAt(i));
-        }
-
-        for (int i = 0; i < stringMap.size(); i++) {
-            assertWithMessage("Incorrect key in stringMap")
-                    .that(buffer.getInt()).isEqualTo(stringMap.keyAt(i));
-            assertWithMessage("The type id of the value should be TYPE_STRING in stringMap")
-                    .that(buffer.get()).isEqualTo(StatsEvent.TYPE_STRING);
-            final String value = getStringFromByteBuffer(buffer);
-            assertWithMessage("Incorrect value in stringMap")
-                    .that(value).isEqualTo(stringMap.valueAt(i));
-        }
-
-        for (int i = 0; i < floatMap.size(); i++) {
-            assertWithMessage("Incorrect key in floatMap")
-                    .that(buffer.getInt()).isEqualTo(floatMap.keyAt(i));
-            assertWithMessage("The type id of the value should be TYPE_FLOAT in floatMap")
-                    .that(buffer.get()).isEqualTo(StatsEvent.TYPE_FLOAT);
-            assertWithMessage("Incorrect value in floatMap")
-                    .that(buffer.getFloat()).isEqualTo(floatMap.valueAt(i));
-        }
-
-        assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position());
-
-        statsEvent.release();
-    }
-
-    @Test
-    public void testSingleAnnotations() {
-        final int expectedAtomId = 109;
-        final int field1 = 1;
-        final byte field1AnnotationId = 45;
-        final boolean field1AnnotationValue = false;
-        final boolean field2 = true;
-        final byte field2AnnotationId = 1;
-        final int field2AnnotationValue = 23;
-
-        final long minTimestamp = SystemClock.elapsedRealtimeNanos();
-        final StatsEvent statsEvent = StatsEvent.newBuilder()
-                .setAtomId(expectedAtomId)
-                .writeInt(field1)
-                .addBooleanAnnotation(field1AnnotationId, field1AnnotationValue)
-                .writeBoolean(field2)
-                .addIntAnnotation(field2AnnotationId, field2AnnotationValue)
-                .usePooledBuffer()
-                .build();
-        final long maxTimestamp = SystemClock.elapsedRealtimeNanos();
-
-        assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId);
-
-        final ByteBuffer buffer =
-                ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN);
-
-        assertWithMessage("Root element in buffer is not TYPE_OBJECT")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT);
-
-        assertWithMessage("Incorrect number of elements in root object")
-                .that(buffer.get()).isEqualTo(4);
-
-        assertWithMessage("First element is not timestamp")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG);
-
-        assertWithMessage("Incorrect timestamp")
-                .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp));
-
-        assertWithMessage("Second element is not atom id")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT);
-
-        assertWithMessage("Incorrect atom id")
-                .that(buffer.getInt()).isEqualTo(expectedAtomId);
-
-        final byte field1Header = buffer.get();
-        final int field1AnnotationValueCount = field1Header >> 4;
-        final byte field1Type = (byte) (field1Header & 0x0F);
-        assertWithMessage("First field is not Int")
-                .that(field1Type).isEqualTo(StatsEvent.TYPE_INT);
-        assertWithMessage("First field annotation count is wrong")
-                .that(field1AnnotationValueCount).isEqualTo(1);
-        assertWithMessage("Incorrect field 1")
-                .that(buffer.getInt()).isEqualTo(field1);
-        assertWithMessage("First field's annotation id is wrong")
-                .that(buffer.get()).isEqualTo(field1AnnotationId);
-        assertWithMessage("First field's annotation type is wrong")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_BOOLEAN);
-        assertWithMessage("First field's annotation value is wrong")
-                .that(buffer.get()).isEqualTo(field1AnnotationValue ? 1 : 0);
-
-        final byte field2Header = buffer.get();
-        final int field2AnnotationValueCount = field2Header >> 4;
-        final byte field2Type = (byte) (field2Header & 0x0F);
-        assertWithMessage("Second field is not boolean")
-                .that(field2Type).isEqualTo(StatsEvent.TYPE_BOOLEAN);
-        assertWithMessage("Second field annotation count is wrong")
-                .that(field2AnnotationValueCount).isEqualTo(1);
-        assertWithMessage("Incorrect field 2")
-                .that(buffer.get()).isEqualTo(field2 ? 1 : 0);
-        assertWithMessage("Second field's annotation id is wrong")
-                .that(buffer.get()).isEqualTo(field2AnnotationId);
-        assertWithMessage("Second field's annotation type is wrong")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT);
-        assertWithMessage("Second field's annotation value is wrong")
-                .that(buffer.getInt()).isEqualTo(field2AnnotationValue);
-
-        assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position());
-
-        statsEvent.release();
-    }
-
-    @Test
-    public void testAtomIdAnnotations() {
-        final int expectedAtomId = 109;
-        final byte atomAnnotationId = 84;
-        final int atomAnnotationValue = 9;
-        final int field1 = 1;
-        final byte field1AnnotationId = 45;
-        final boolean field1AnnotationValue = false;
-        final boolean field2 = true;
-        final byte field2AnnotationId = 1;
-        final int field2AnnotationValue = 23;
-
-        final long minTimestamp = SystemClock.elapsedRealtimeNanos();
-        final StatsEvent statsEvent = StatsEvent.newBuilder()
-                .setAtomId(expectedAtomId)
-                .addIntAnnotation(atomAnnotationId, atomAnnotationValue)
-                .writeInt(field1)
-                .addBooleanAnnotation(field1AnnotationId, field1AnnotationValue)
-                .writeBoolean(field2)
-                .addIntAnnotation(field2AnnotationId, field2AnnotationValue)
-                .usePooledBuffer()
-                .build();
-        final long maxTimestamp = SystemClock.elapsedRealtimeNanos();
-
-        assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId);
-
-        final ByteBuffer buffer =
-                ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN);
-
-        assertWithMessage("Root element in buffer is not TYPE_OBJECT")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT);
-
-        assertWithMessage("Incorrect number of elements in root object")
-                .that(buffer.get()).isEqualTo(4);
-
-        assertWithMessage("First element is not timestamp")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG);
-
-        assertWithMessage("Incorrect timestamp")
-                .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp));
-
-        final byte atomIdHeader = buffer.get();
-        final int atomIdAnnotationValueCount = atomIdHeader >> 4;
-        final byte atomIdValueType = (byte) (atomIdHeader & 0x0F);
-        assertWithMessage("Second element is not atom id")
-                .that(atomIdValueType).isEqualTo(StatsEvent.TYPE_INT);
-        assertWithMessage("Atom id annotation count is wrong")
-                .that(atomIdAnnotationValueCount).isEqualTo(1);
-        assertWithMessage("Incorrect atom id")
-                .that(buffer.getInt()).isEqualTo(expectedAtomId);
-        assertWithMessage("Atom id's annotation id is wrong")
-                .that(buffer.get()).isEqualTo(atomAnnotationId);
-        assertWithMessage("Atom id's annotation type is wrong")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT);
-        assertWithMessage("Atom id's annotation value is wrong")
-                .that(buffer.getInt()).isEqualTo(atomAnnotationValue);
-
-        final byte field1Header = buffer.get();
-        final int field1AnnotationValueCount = field1Header >> 4;
-        final byte field1Type = (byte) (field1Header & 0x0F);
-        assertWithMessage("First field is not Int")
-                .that(field1Type).isEqualTo(StatsEvent.TYPE_INT);
-        assertWithMessage("First field annotation count is wrong")
-                .that(field1AnnotationValueCount).isEqualTo(1);
-        assertWithMessage("Incorrect field 1")
-                .that(buffer.getInt()).isEqualTo(field1);
-        assertWithMessage("First field's annotation id is wrong")
-                .that(buffer.get()).isEqualTo(field1AnnotationId);
-        assertWithMessage("First field's annotation type is wrong")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_BOOLEAN);
-        assertWithMessage("First field's annotation value is wrong")
-                .that(buffer.get()).isEqualTo(field1AnnotationValue ? 1 : 0);
-
-        final byte field2Header = buffer.get();
-        final int field2AnnotationValueCount = field2Header >> 4;
-        final byte field2Type = (byte) (field2Header & 0x0F);
-        assertWithMessage("Second field is not boolean")
-                .that(field2Type).isEqualTo(StatsEvent.TYPE_BOOLEAN);
-        assertWithMessage("Second field annotation count is wrong")
-                .that(field2AnnotationValueCount).isEqualTo(1);
-        assertWithMessage("Incorrect field 2")
-                .that(buffer.get()).isEqualTo(field2 ? 1 : 0);
-        assertWithMessage("Second field's annotation id is wrong")
-                .that(buffer.get()).isEqualTo(field2AnnotationId);
-        assertWithMessage("Second field's annotation type is wrong")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT);
-        assertWithMessage("Second field's annotation value is wrong")
-                .that(buffer.getInt()).isEqualTo(field2AnnotationValue);
-
-        assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position());
-
-        statsEvent.release();
-    }
-
-    @Test
-    public void testSetAtomIdNotCalledImmediately() {
-        final int expectedAtomId = 109;
-        final int field1 = 25;
-        final boolean field2 = true;
-
-        final long minTimestamp = SystemClock.elapsedRealtimeNanos();
-        final StatsEvent statsEvent = StatsEvent.newBuilder()
-                .writeInt(field1)
-                .setAtomId(expectedAtomId)
-                .writeBoolean(field2)
-                .usePooledBuffer()
-                .build();
-        final long maxTimestamp = SystemClock.elapsedRealtimeNanos();
-
-        assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId);
-
-        final ByteBuffer buffer =
-                ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN);
-
-        assertWithMessage("Root element in buffer is not TYPE_OBJECT")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT);
-
-        assertWithMessage("Incorrect number of elements in root object")
-                .that(buffer.get()).isEqualTo(3);
-
-        assertWithMessage("First element is not timestamp")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG);
-
-        assertWithMessage("Incorrect timestamp")
-                .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp));
-
-        assertWithMessage("Second element is not atom id")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT);
-
-        assertWithMessage("Incorrect atom id")
-                .that(buffer.getInt()).isEqualTo(expectedAtomId);
-
-        assertWithMessage("Third element is not errors type")
-                .that(buffer.get()).isEqualTo(StatsEvent.TYPE_ERRORS);
-
-        final int errorMask = buffer.getInt();
-
-        assertWithMessage("ERROR_ATOM_ID_INVALID_POSITION should be the only error in the mask")
-                .that(errorMask).isEqualTo(StatsEvent.ERROR_ATOM_ID_INVALID_POSITION);
-
-        assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position());
-
-        statsEvent.release();
-    }
-
-    @Test
-    public void testLargePulledEvent() {
-        final int expectedAtomId = 10_020;
-        byte[] field1 = new byte[10 * 1024];
-        new Random().nextBytes(field1);
-
-        final long minTimestamp = SystemClock.elapsedRealtimeNanos();
-        final StatsEvent statsEvent =
-                StatsEvent.newBuilder().setAtomId(expectedAtomId).writeByteArray(field1).build();
-        final long maxTimestamp = SystemClock.elapsedRealtimeNanos();
-
-        assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId);
-
-        final ByteBuffer buffer =
-                ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN);
-
-        assertWithMessage("Root element in buffer is not TYPE_OBJECT")
-                .that(buffer.get())
-                .isEqualTo(StatsEvent.TYPE_OBJECT);
-
-        assertWithMessage("Incorrect number of elements in root object")
-                .that(buffer.get())
-                .isEqualTo(3);
-
-        assertWithMessage("First element is not timestamp")
-                .that(buffer.get())
-                .isEqualTo(StatsEvent.TYPE_LONG);
-
-        assertWithMessage("Incorrect timestamp")
-                .that(buffer.getLong())
-                .isIn(Range.closed(minTimestamp, maxTimestamp));
-
-        assertWithMessage("Second element is not atom id")
-                .that(buffer.get())
-                .isEqualTo(StatsEvent.TYPE_INT);
-
-        assertWithMessage("Incorrect atom id").that(buffer.getInt()).isEqualTo(expectedAtomId);
-
-        assertWithMessage("Third element is not byte array")
-                .that(buffer.get())
-                .isEqualTo(StatsEvent.TYPE_BYTE_ARRAY);
-
-        final byte[] field1Actual = getByteArrayFromByteBuffer(buffer);
-        assertWithMessage("Incorrect field 1").that(field1Actual).isEqualTo(field1);
-
-        assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position());
-
-        statsEvent.release();
-    }
-
-    @Test
-    public void testPulledEventOverflow() {
-        final int expectedAtomId = 10_020;
-        byte[] field1 = new byte[50 * 1024];
-        new Random().nextBytes(field1);
-
-        final long minTimestamp = SystemClock.elapsedRealtimeNanos();
-        final StatsEvent statsEvent =
-                StatsEvent.newBuilder().setAtomId(expectedAtomId).writeByteArray(field1).build();
-        final long maxTimestamp = SystemClock.elapsedRealtimeNanos();
-
-        assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId);
-
-        final ByteBuffer buffer =
-                ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN);
-
-        assertWithMessage("Root element in buffer is not TYPE_OBJECT")
-                .that(buffer.get())
-                .isEqualTo(StatsEvent.TYPE_OBJECT);
-
-        assertWithMessage("Incorrect number of elements in root object")
-                .that(buffer.get())
-                .isEqualTo(3);
-
-        assertWithMessage("First element is not timestamp")
-                .that(buffer.get())
-                .isEqualTo(StatsEvent.TYPE_LONG);
-
-        assertWithMessage("Incorrect timestamp")
-                .that(buffer.getLong())
-                .isIn(Range.closed(minTimestamp, maxTimestamp));
-
-        assertWithMessage("Second element is not atom id")
-                .that(buffer.get())
-                .isEqualTo(StatsEvent.TYPE_INT);
-
-        assertWithMessage("Incorrect atom id").that(buffer.getInt()).isEqualTo(expectedAtomId);
-
-        assertWithMessage("Third element is not errors type")
-                .that(buffer.get())
-                .isEqualTo(StatsEvent.TYPE_ERRORS);
-
-        final int errorMask = buffer.getInt();
-
-        assertWithMessage("ERROR_OVERFLOW should be the only error in the error mask")
-                .that(errorMask)
-                .isEqualTo(StatsEvent.ERROR_OVERFLOW);
-
-        assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position());
-
-        statsEvent.release();
-    }
-
-    @Test
-    public void testPushedEventOverflow() {
-        final int expectedAtomId = 10_020;
-        byte[] field1 = new byte[10 * 1024];
-        new Random().nextBytes(field1);
-
-        final long minTimestamp = SystemClock.elapsedRealtimeNanos();
-        final StatsEvent statsEvent = StatsEvent.newBuilder()
-                                              .setAtomId(expectedAtomId)
-                                              .writeByteArray(field1)
-                                              .usePooledBuffer()
-                                              .build();
-        final long maxTimestamp = SystemClock.elapsedRealtimeNanos();
-
-        assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId);
-
-        final ByteBuffer buffer =
-                ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN);
-
-        assertWithMessage("Root element in buffer is not TYPE_OBJECT")
-                .that(buffer.get())
-                .isEqualTo(StatsEvent.TYPE_OBJECT);
-
-        assertWithMessage("Incorrect number of elements in root object")
-                .that(buffer.get())
-                .isEqualTo(3);
-
-        assertWithMessage("First element is not timestamp")
-                .that(buffer.get())
-                .isEqualTo(StatsEvent.TYPE_LONG);
-
-        assertWithMessage("Incorrect timestamp")
-                .that(buffer.getLong())
-                .isIn(Range.closed(minTimestamp, maxTimestamp));
-
-        assertWithMessage("Second element is not atom id")
-                .that(buffer.get())
-                .isEqualTo(StatsEvent.TYPE_INT);
-
-        assertWithMessage("Incorrect atom id").that(buffer.getInt()).isEqualTo(expectedAtomId);
-
-        assertWithMessage("Third element is not errors type")
-                .that(buffer.get())
-                .isEqualTo(StatsEvent.TYPE_ERRORS);
-
-        final int errorMask = buffer.getInt();
-
-        assertWithMessage("ERROR_OVERFLOW should be the only error in the error mask")
-                .that(errorMask)
-                .isEqualTo(StatsEvent.ERROR_OVERFLOW);
-
-        assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position());
-
-        statsEvent.release();
-    }
-
-    private static byte[] getByteArrayFromByteBuffer(final ByteBuffer buffer) {
-        final int numBytes = buffer.getInt();
-        byte[] bytes = new byte[numBytes];
-        buffer.get(bytes);
-        return bytes;
-    }
-
-    private static String getStringFromByteBuffer(final ByteBuffer buffer) {
-        final byte[] bytes = getByteArrayFromByteBuffer(buffer);
-        return new String(bytes, UTF_8);
-    }
-}
diff --git a/apex/statsd/jni/android_util_StatsLog.cpp b/apex/statsd/jni/android_util_StatsLog.cpp
deleted file mode 100644
index 71ce949..0000000
--- a/apex/statsd/jni/android_util_StatsLog.cpp
+++ /dev/null
@@ -1,90 +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.
- */
-
-#define LOG_NAMESPACE "StatsLog.tag."
-#define LOG_TAG "StatsLog_println"
-
-#include <jni.h>
-#include <log/log.h>
-#include <nativehelper/scoped_local_ref.h>
-#include "stats_buffer_writer.h"
-
-namespace android {
-
-static void android_util_StatsLog_write(JNIEnv* env, jobject clazz, jbyteArray buf, jint size,
-        jint atomId) {
-    if (buf == NULL) {
-        return;
-    }
-    jint actualSize = env->GetArrayLength(buf);
-    if (actualSize < size) {
-        return;
-    }
-
-    jbyte* bufferArray = env->GetByteArrayElements(buf, NULL);
-    if (bufferArray == NULL) {
-        return;
-    }
-
-    write_buffer_to_statsd((void*) bufferArray, size, atomId);
-
-    env->ReleaseByteArrayElements(buf, bufferArray, 0);
-}
-
-/*
- * JNI registration.
- */
-static const JNINativeMethod gMethods[] = {
-    /* name, signature, funcPtr */
-    { "writeImpl", "([BII)V", (void*) android_util_StatsLog_write },
-};
-
-int register_android_util_StatsLog(JNIEnv* env)
-{
-    static const char* kStatsLogClass = "android/util/StatsLog";
-
-    ScopedLocalRef<jclass> cls(env, env->FindClass(kStatsLogClass));
-    if (cls.get() == nullptr) {
-        ALOGE("jni statsd registration failure, class not found '%s'", kStatsLogClass);
-        return JNI_ERR;
-    }
-
-    const jint count = sizeof(gMethods) / sizeof(gMethods[0]);
-    int status = env->RegisterNatives(cls.get(), gMethods, count);
-    if (status < 0) {
-        ALOGE("jni statsd registration failure, status: %d", status);
-        return JNI_ERR;
-    }
-    return JNI_VERSION_1_4;
-}
-
-}; // namespace android
-
-/*
- * JNI Initialization
- */
-jint JNI_OnLoad(JavaVM* jvm, void* reserved) {
-    JNIEnv* e;
-
-    ALOGV("statsd : loading JNI\n");
-    // Check JNI version
-    if (jvm->GetEnv((void**)&e, JNI_VERSION_1_4)) {
-        ALOGE("JNI version mismatch error");
-        return JNI_ERR;
-    }
-
-    return android::register_android_util_StatsLog(e);
-}
diff --git a/apex/statsd/service/Android.bp b/apex/statsd/service/Android.bp
deleted file mode 100644
index df0ccfc..0000000
--- a/apex/statsd/service/Android.bp
+++ /dev/null
@@ -1,35 +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.
-
-filegroup {
-    name: "service-statsd-sources",
-    srcs: [
-        "java/**/*.java",
-    ],
-}
-
-java_library {
-    name: "service-statsd",
-    srcs: [ ":service-statsd-sources" ],
-    sdk_version: "system_server_current",
-    libs: [
-        "framework-annotations-lib",
-        "framework-statsd",
-    ],
-    plugins: ["java_api_finder"],
-    apex_available: [
-        "com.android.os.statsd",
-        "test_com.android.os.statsd",
-    ],
-}
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java
deleted file mode 100644
index dc477a5..0000000
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java
+++ /dev/null
@@ -1,188 +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.
- */
-
-package com.android.server.stats;
-
-import android.app.PendingIntent;
-import android.app.StatsManager;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Binder;
-import android.os.IPendingIntentRef;
-import android.os.Process;
-import android.os.StatsDimensionsValue;
-import android.os.StatsDimensionsValueParcel;
-import android.util.Log;
-
-import com.android.server.SystemService;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-
-/**
- * @hide
- */
-public class StatsCompanion {
-    private static final String TAG = "StatsCompanion";
-    private static final boolean DEBUG = false;
-
-    private static final int AID_STATSD = 1066;
-
-    private static final String STATS_COMPANION_SERVICE = "statscompanion";
-    private static final String STATS_MANAGER_SERVICE = "statsmanager";
-
-    static void enforceStatsdCallingUid() {
-        if (Binder.getCallingPid() == Process.myPid()) {
-            return;
-        }
-        if (Binder.getCallingUid() != AID_STATSD) {
-            throw new SecurityException("Not allowed to access StatsCompanion");
-        }
-    }
-
-    /**
-     * Lifecycle class for both {@link StatsCompanionService} and {@link StatsManagerService}.
-     */
-    public static final class Lifecycle extends SystemService {
-        private StatsCompanionService mStatsCompanionService;
-        private StatsManagerService mStatsManagerService;
-
-        public Lifecycle(Context context) {
-            super(context);
-        }
-
-        @Override
-        public void onStart() {
-            mStatsCompanionService = new StatsCompanionService(getContext());
-            mStatsManagerService = new StatsManagerService(getContext());
-            mStatsCompanionService.setStatsManagerService(mStatsManagerService);
-            mStatsManagerService.setStatsCompanionService(mStatsCompanionService);
-
-            try {
-                publishBinderService(STATS_COMPANION_SERVICE, mStatsCompanionService);
-                if (DEBUG) Log.d(TAG, "Published " + STATS_COMPANION_SERVICE);
-                publishBinderService(STATS_MANAGER_SERVICE, mStatsManagerService);
-                if (DEBUG) Log.d(TAG, "Published " + STATS_MANAGER_SERVICE);
-            } catch (Exception e) {
-                Log.e(TAG, "Failed to publishBinderService", e);
-            }
-        }
-
-        @Override
-        public void onBootPhase(int phase) {
-            super.onBootPhase(phase);
-            if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
-                mStatsCompanionService.systemReady();
-            }
-            if (phase == PHASE_BOOT_COMPLETED) {
-                mStatsCompanionService.bootCompleted();
-            }
-        }
-    }
-
-    /**
-     * Wrapper for {@link PendingIntent}. Allows Statsd to send PendingIntents.
-     */
-    public static class PendingIntentRef extends IPendingIntentRef.Stub {
-
-        private static final String TAG = "PendingIntentRef";
-
-        /**
-         * The last report time is provided with each intent registered to
-         * StatsManager#setFetchReportsOperation. This allows easy de-duping in the receiver if
-         * statsd is requesting the client to retrieve the same statsd data. The last report time
-         * corresponds to the last_report_elapsed_nanos that will provided in the current
-         * ConfigMetricsReport, and this timestamp also corresponds to the
-         * current_report_elapsed_nanos of the most recently obtained ConfigMetricsReport.
-         */
-        private static final String EXTRA_LAST_REPORT_TIME = "android.app.extra.LAST_REPORT_TIME";
-        private static final int CODE_DATA_BROADCAST = 1;
-        private static final int CODE_ACTIVE_CONFIGS_BROADCAST = 1;
-        private static final int CODE_SUBSCRIBER_BROADCAST = 1;
-
-        private final PendingIntent mPendingIntent;
-        private final Context mContext;
-
-        public PendingIntentRef(PendingIntent pendingIntent, Context context) {
-            mPendingIntent = pendingIntent;
-            mContext = context;
-        }
-
-        @Override
-        public void sendDataBroadcast(long lastReportTimeNs) {
-            enforceStatsdCallingUid();
-            Intent intent = new Intent();
-            intent.putExtra(EXTRA_LAST_REPORT_TIME, lastReportTimeNs);
-            try {
-                mPendingIntent.send(mContext, CODE_DATA_BROADCAST, intent, null, null);
-            } catch (PendingIntent.CanceledException e) {
-                Log.w(TAG, "Unable to send PendingIntent");
-            }
-        }
-
-        @Override
-        public void sendActiveConfigsChangedBroadcast(long[] configIds) {
-            enforceStatsdCallingUid();
-            Intent intent = new Intent();
-            intent.putExtra(StatsManager.EXTRA_STATS_ACTIVE_CONFIG_KEYS, configIds);
-            try {
-                mPendingIntent.send(mContext, CODE_ACTIVE_CONFIGS_BROADCAST, intent, null, null);
-                if (DEBUG) {
-                    Log.d(TAG, "Sent broadcast with config ids " + Arrays.toString(configIds));
-                }
-            } catch (PendingIntent.CanceledException e) {
-                Log.w(TAG, "Unable to send active configs changed broadcast using PendingIntent");
-            }
-        }
-
-        @Override
-        public void sendSubscriberBroadcast(long configUid, long configId, long subscriptionId,
-                long subscriptionRuleId, String[] cookies,
-                StatsDimensionsValueParcel dimensionsValueParcel) {
-            enforceStatsdCallingUid();
-            StatsDimensionsValue dimensionsValue = new StatsDimensionsValue(dimensionsValueParcel);
-            Intent intent =
-                    new Intent()
-                            .putExtra(StatsManager.EXTRA_STATS_CONFIG_UID, configUid)
-                            .putExtra(StatsManager.EXTRA_STATS_CONFIG_KEY, configId)
-                            .putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_ID, subscriptionId)
-                            .putExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_RULE_ID,
-                                    subscriptionRuleId)
-                            .putExtra(StatsManager.EXTRA_STATS_DIMENSIONS_VALUE, dimensionsValue);
-
-            ArrayList<String> cookieList = new ArrayList<>(cookies.length);
-            cookieList.addAll(Arrays.asList(cookies));
-            intent.putStringArrayListExtra(
-                    StatsManager.EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES, cookieList);
-
-            if (DEBUG) {
-                Log.d(TAG,
-                        String.format(
-                                "Statsd sendSubscriberBroadcast with params {%d %d %d %d %s %s}",
-                                configUid, configId, subscriptionId, subscriptionRuleId,
-                                Arrays.toString(cookies),
-                                dimensionsValue));
-            }
-            try {
-                mPendingIntent.send(mContext, CODE_SUBSCRIBER_BROADCAST, intent, null, null);
-            } catch (PendingIntent.CanceledException e) {
-                Log.w(TAG,
-                        "Unable to send using PendingIntent from uid " + configUid
-                                + "; presumably it had been cancelled.");
-            }
-        }
-    }
-}
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
deleted file mode 100644
index fbda86f..0000000
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ /dev/null
@@ -1,770 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.stats;
-
-import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
-
-import android.app.AlarmManager;
-import android.app.AlarmManager.OnAlarmListener;
-import android.app.StatsManager;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.FileUtils;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.IStatsCompanionService;
-import android.os.IStatsd;
-import android.os.Looper;
-import android.os.ParcelFileDescriptor;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.StatsFrameworkInitializer;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Log;
-import android.util.proto.ProtoOutputStream;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * Helper service for statsd (the native stats management service in cmds/statsd/).
- * Used for registering and receiving alarms on behalf of statsd.
- *
- * @hide
- */
-public class StatsCompanionService extends IStatsCompanionService.Stub {
-
-    private static final long MILLIS_IN_A_DAY = TimeUnit.DAYS.toMillis(1);
-
-    public static final String RESULT_RECEIVER_CONTROLLER_KEY = "controller_activity";
-    public static final String CONFIG_DIR = "/data/misc/stats-service";
-
-    static final String TAG = "StatsCompanionService";
-    static final boolean DEBUG = false;
-    /**
-     * Hard coded field ids of frameworks/base/cmds/statsd/src/uid_data.proto
-     * to be used in ProtoOutputStream.
-     */
-    private static final int APPLICATION_INFO_FIELD_ID = 1;
-    private static final int UID_FIELD_ID = 1;
-    private static final int VERSION_FIELD_ID = 2;
-    private static final int VERSION_STRING_FIELD_ID = 3;
-    private static final int PACKAGE_NAME_FIELD_ID = 4;
-    private static final int INSTALLER_FIELD_ID = 5;
-
-    public static final int DEATH_THRESHOLD = 10;
-
-    static final class CompanionHandler extends Handler {
-        CompanionHandler(Looper looper) {
-            super(looper);
-        }
-    }
-
-    private final Context mContext;
-    private final AlarmManager mAlarmManager;
-    @GuardedBy("sStatsdLock")
-    private static IStatsd sStatsd;
-    private static final Object sStatsdLock = new Object();
-
-    private final OnAlarmListener mPullingAlarmListener;
-    private final OnAlarmListener mPeriodicAlarmListener;
-
-    private StatsManagerService mStatsManagerService;
-
-    @GuardedBy("sStatsdLock")
-    private final HashSet<Long> mDeathTimeMillis = new HashSet<>();
-    @GuardedBy("sStatsdLock")
-    private final HashMap<Long, String> mDeletedFiles = new HashMap<>();
-    private final CompanionHandler mHandler;
-
-    // Flag that is set when PHASE_BOOT_COMPLETED is triggered in the StatsCompanion lifecycle.
-    private AtomicBoolean mBootCompleted = new AtomicBoolean(false);
-
-    public StatsCompanionService(Context context) {
-        super();
-        mContext = context;
-        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
-        if (DEBUG) Log.d(TAG, "Registered receiver for ACTION_PACKAGE_REPLACED and ADDED.");
-        HandlerThread handlerThread = new HandlerThread(TAG);
-        handlerThread.start();
-        mHandler = new CompanionHandler(handlerThread.getLooper());
-
-        mPullingAlarmListener = new PullingAlarmListener(context);
-        mPeriodicAlarmListener = new PeriodicAlarmListener(context);
-    }
-
-    private final static int[] toIntArray(List<Integer> list) {
-        int[] ret = new int[list.size()];
-        for (int i = 0; i < ret.length; i++) {
-            ret[i] = list.get(i);
-        }
-        return ret;
-    }
-
-    private final static long[] toLongArray(List<Long> list) {
-        long[] ret = new long[list.size()];
-        for (int i = 0; i < ret.length; i++) {
-            ret[i] = list.get(i);
-        }
-        return ret;
-    }
-
-    /**
-     * Non-blocking call to retrieve a reference to statsd
-     *
-     * @return IStatsd object if statsd is ready, null otherwise.
-     */
-    private static IStatsd getStatsdNonblocking() {
-        synchronized (sStatsdLock) {
-            return sStatsd;
-        }
-    }
-
-    private static void informAllUids(Context context) {
-        ParcelFileDescriptor[] fds;
-        try {
-            fds = ParcelFileDescriptor.createPipe();
-        } catch (IOException e) {
-            Log.e(TAG, "Failed to create a pipe to send uid map data.", e);
-            return;
-        }
-        HandlerThread backgroundThread = new HandlerThread(
-                "statsCompanionService.bg", THREAD_PRIORITY_BACKGROUND);
-        backgroundThread.start();
-        Handler handler = new Handler(backgroundThread.getLooper());
-        handler.post(() -> {
-            UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
-            PackageManager pm = context.getPackageManager();
-            final List<UserHandle> users = um.getUserHandles(true);
-            if (DEBUG) {
-                Log.d(TAG, "Iterating over " + users.size() + " userHandles.");
-            }
-            IStatsd statsd = getStatsdNonblocking();
-            if (statsd == null) {
-                return;
-            }
-            try {
-                statsd.informAllUidData(fds[0]);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to send uid map to statsd");
-            }
-            try {
-                fds[0].close();
-            } catch (IOException e) {
-                Log.e(TAG, "Failed to close the read side of the pipe.", e);
-            }
-            final ParcelFileDescriptor writeFd = fds[1];
-            FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(writeFd);
-            try {
-                ProtoOutputStream output = new ProtoOutputStream(fout);
-                int numRecords = 0;
-                // Add in all the apps for every user/profile.
-                for (UserHandle userHandle : users) {
-                    List<PackageInfo> packagesPlusApex = getAllPackagesWithApex(pm, userHandle);
-                    for (int j = 0; j < packagesPlusApex.size(); j++) {
-                        if (packagesPlusApex.get(j).applicationInfo != null) {
-                            String installer;
-                            try {
-                                installer = pm.getInstallerPackageName(
-                                        packagesPlusApex.get(j).packageName);
-                            } catch (IllegalArgumentException e) {
-                                installer = "";
-                            }
-                            long applicationInfoToken =
-                                    output.start(ProtoOutputStream.FIELD_TYPE_MESSAGE
-                                            | ProtoOutputStream.FIELD_COUNT_REPEATED
-                                            | APPLICATION_INFO_FIELD_ID);
-                            output.write(ProtoOutputStream.FIELD_TYPE_INT32
-                                            | ProtoOutputStream.FIELD_COUNT_SINGLE | UID_FIELD_ID,
-                                    packagesPlusApex.get(j).applicationInfo.uid);
-                            output.write(ProtoOutputStream.FIELD_TYPE_INT64
-                                            | ProtoOutputStream.FIELD_COUNT_SINGLE
-                                            | VERSION_FIELD_ID,
-                                    packagesPlusApex.get(j).getLongVersionCode());
-                            output.write(ProtoOutputStream.FIELD_TYPE_STRING
-                                            | ProtoOutputStream.FIELD_COUNT_SINGLE
-                                            | VERSION_STRING_FIELD_ID,
-                                    packagesPlusApex.get(j).versionName);
-                            output.write(ProtoOutputStream.FIELD_TYPE_STRING
-                                    | ProtoOutputStream.FIELD_COUNT_SINGLE
-                                    | PACKAGE_NAME_FIELD_ID, packagesPlusApex.get(j).packageName);
-                            output.write(ProtoOutputStream.FIELD_TYPE_STRING
-                                            | ProtoOutputStream.FIELD_COUNT_SINGLE
-                                            | INSTALLER_FIELD_ID,
-                                    installer == null ? "" : installer);
-                            numRecords++;
-                            output.end(applicationInfoToken);
-                        }
-                    }
-                }
-                output.flush();
-                if (DEBUG) {
-                    Log.d(TAG, "Sent data for " + numRecords + " apps");
-                }
-            } finally {
-                FileUtils.closeQuietly(fout);
-                backgroundThread.quit();
-                backgroundThread.interrupt();
-            }
-        });
-    }
-
-    private static List<PackageInfo> getAllPackagesWithApex(PackageManager pm,
-            UserHandle userHandle) {
-        // We want all the uninstalled packages because uninstalled package uids can still be logged
-        // to statsd.
-        List<PackageInfo> allPackages = new ArrayList<>(
-                pm.getInstalledPackagesAsUser(PackageManager.MATCH_UNINSTALLED_PACKAGES
-                                | PackageManager.MATCH_ANY_USER,
-                        userHandle.getIdentifier()));
-        // We make a second query to package manager for the apex modules because package manager
-        // returns both installed and uninstalled apexes with
-        // PackageManager.MATCH_UNINSTALLED_PACKAGES flag. We only want active apexes because
-        // inactive apexes can conflict with active ones.
-        for (PackageInfo packageInfo : pm.getInstalledPackages(PackageManager.MATCH_APEX)) {
-            if (packageInfo.isApex) {
-                allPackages.add(packageInfo);
-            }
-        }
-        return allPackages;
-    }
-
-    private static class WakelockThread extends Thread {
-        private final PowerManager.WakeLock mWl;
-        private final Runnable mRunnable;
-
-        WakelockThread(Context context, String wakelockName, Runnable runnable) {
-            PowerManager powerManager = (PowerManager)
-                    context.getSystemService(Context.POWER_SERVICE);
-            mWl = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, wakelockName);
-            mRunnable = runnable;
-        }
-        @Override
-        public void run() {
-            try {
-                mRunnable.run();
-            } finally {
-                mWl.release();
-            }
-        }
-        @Override
-        public void start() {
-            mWl.acquire();
-            super.start();
-        }
-    }
-
-    private final static class AppUpdateReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            /**
-             * App updates actually consist of REMOVE, ADD, and then REPLACE broadcasts. To avoid
-             * waste, we ignore the REMOVE and ADD broadcasts that contain the replacing flag.
-             * If we can't find the value for EXTRA_REPLACING, we default to false.
-             */
-            if (!intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED)
-                    && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
-                return; // Keep only replacing or normal add and remove.
-            }
-            if (DEBUG) Log.d(TAG, "StatsCompanionService noticed an app was updated.");
-            synchronized (sStatsdLock) {
-                if (sStatsd == null) {
-                    Log.w(TAG, "Could not access statsd to inform it of an app update");
-                    return;
-                }
-                try {
-                    if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)) {
-                        Bundle b = intent.getExtras();
-                        int uid = b.getInt(Intent.EXTRA_UID);
-                        boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
-                        if (!replacing) {
-                            // Don't bother sending an update if we're right about to get another
-                            // intent for the new version that's added.
-                            String app = intent.getData().getSchemeSpecificPart();
-                            sStatsd.informOnePackageRemoved(app, uid);
-                        }
-                    } else {
-                        PackageManager pm = context.getPackageManager();
-                        Bundle b = intent.getExtras();
-                        int uid = b.getInt(Intent.EXTRA_UID);
-                        String app = intent.getData().getSchemeSpecificPart();
-                        PackageInfo pi = pm.getPackageInfo(app, PackageManager.MATCH_ANY_USER);
-                        String installer;
-                        try {
-                            installer = pm.getInstallerPackageName(app);
-                        } catch (IllegalArgumentException e) {
-                            installer = "";
-                        }
-                        sStatsd.informOnePackage(
-                                app,
-                                uid,
-                                pi.getLongVersionCode(),
-                                pi.versionName == null ? "" : pi.versionName,
-                                installer == null ? "" : installer);
-                    }
-                } catch (Exception e) {
-                    Log.w(TAG, "Failed to inform statsd of an app update", e);
-                }
-            }
-        }
-    }
-
-    private static final class UserUpdateReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            // Pull the latest state of UID->app name, version mapping.
-            // Needed since the new user basically has a version of every app.
-            informAllUids(context);
-        }
-    }
-
-    public final static class PullingAlarmListener implements OnAlarmListener {
-        private final Context mContext;
-
-        PullingAlarmListener(Context context) {
-            mContext = context;
-        }
-
-        @Override
-        public void onAlarm() {
-            if (DEBUG) {
-                Log.d(TAG, "Time to poll something.");
-            }
-            IStatsd statsd = getStatsdNonblocking();
-            if (statsd == null) {
-                Log.w(TAG, "Could not access statsd to inform it of pulling alarm firing.");
-                return;
-            }
-
-            // Wakelock needs to be retained while calling statsd.
-            Thread thread = new WakelockThread(mContext,
-                    PullingAlarmListener.class.getCanonicalName(), new Runnable() {
-                        @Override
-                        public void run() {
-                            try {
-                                statsd.informPollAlarmFired();
-                            } catch (RemoteException e) {
-                                Log.w(TAG, "Failed to inform statsd of pulling alarm firing.", e);
-                            }
-                        }
-                    });
-            thread.start();
-        }
-    }
-
-    public final static class PeriodicAlarmListener implements OnAlarmListener {
-        private final Context mContext;
-
-        PeriodicAlarmListener(Context context) {
-            mContext = context;
-        }
-
-        @Override
-        public void onAlarm() {
-            if (DEBUG) {
-                Log.d(TAG, "Time to trigger periodic alarm.");
-            }
-            IStatsd statsd = getStatsdNonblocking();
-            if (statsd == null) {
-                Log.w(TAG, "Could not access statsd to inform it of periodic alarm firing.");
-                return;
-            }
-
-            // Wakelock needs to be retained while calling statsd.
-            Thread thread = new WakelockThread(mContext,
-                    PeriodicAlarmListener.class.getCanonicalName(), new Runnable() {
-                        @Override
-                        public void run() {
-                            try {
-                                statsd.informAlarmForSubscriberTriggeringFired();
-                            } catch (RemoteException e) {
-                                Log.w(TAG, "Failed to inform statsd of periodic alarm firing.", e);
-                            }
-                        }
-                    });
-            thread.start();
-        }
-    }
-
-    public final static class ShutdownEventReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            /**
-             * Skip immediately if intent is not relevant to device shutdown.
-             */
-            if (!intent.getAction().equals(Intent.ACTION_REBOOT)
-                    && !(intent.getAction().equals(Intent.ACTION_SHUTDOWN)
-                    && (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0)) {
-                return;
-            }
-
-            if (DEBUG) {
-                Log.i(TAG, "StatsCompanionService noticed a shutdown.");
-            }
-            IStatsd statsd = getStatsdNonblocking();
-            if (statsd == null) {
-                Log.w(TAG, "Could not access statsd to inform it of a shutdown event.");
-                return;
-            }
-            try {
-                // two way binder call
-                statsd.informDeviceShutdown();
-            } catch (Exception e) {
-                Log.w(TAG, "Failed to inform statsd of a shutdown event.", e);
-            }
-        }
-    }
-
-    @Override // Binder call
-    public void setAlarmForSubscriberTriggering(long timestampMs) {
-        StatsCompanion.enforceStatsdCallingUid();
-        if (DEBUG) {
-            Log.d(TAG,
-                    "Setting periodic alarm in about " + (timestampMs
-                            - SystemClock.elapsedRealtime()));
-        }
-        final long callingToken = Binder.clearCallingIdentity();
-        try {
-            // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
-            // only fire when it awakens.
-            mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, timestampMs, TAG + ".periodic",
-                    mPeriodicAlarmListener, mHandler);
-        } finally {
-            Binder.restoreCallingIdentity(callingToken);
-        }
-    }
-
-    @Override // Binder call
-    public void cancelAlarmForSubscriberTriggering() {
-        StatsCompanion.enforceStatsdCallingUid();
-        if (DEBUG) {
-            Log.d(TAG, "Cancelling periodic alarm");
-        }
-        final long callingToken = Binder.clearCallingIdentity();
-        try {
-            mAlarmManager.cancel(mPeriodicAlarmListener);
-        } finally {
-            Binder.restoreCallingIdentity(callingToken);
-        }
-    }
-
-    @Override // Binder call
-    public void setPullingAlarm(long nextPullTimeMs) {
-        StatsCompanion.enforceStatsdCallingUid();
-        if (DEBUG) {
-            Log.d(TAG, "Setting pulling alarm in about "
-                    + (nextPullTimeMs - SystemClock.elapsedRealtime()));
-        }
-        final long callingToken = Binder.clearCallingIdentity();
-        try {
-            // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
-            // only fire when it awakens.
-            mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, nextPullTimeMs, TAG + ".pull",
-                    mPullingAlarmListener, mHandler);
-        } finally {
-            Binder.restoreCallingIdentity(callingToken);
-        }
-    }
-
-    @Override // Binder call
-    public void cancelPullingAlarm() {
-        StatsCompanion.enforceStatsdCallingUid();
-        if (DEBUG) {
-            Log.d(TAG, "Cancelling pulling alarm");
-        }
-        final long callingToken = Binder.clearCallingIdentity();
-        try {
-            mAlarmManager.cancel(mPullingAlarmListener);
-        } finally {
-            Binder.restoreCallingIdentity(callingToken);
-        }
-    }
-
-    @Override // Binder call
-    public void statsdReady() {
-        StatsCompanion.enforceStatsdCallingUid();
-        if (DEBUG) {
-            Log.d(TAG, "learned that statsdReady");
-        }
-        sayHiToStatsd(); // tell statsd that we're ready too and link to it
-
-        final Intent intent = new Intent(StatsManager.ACTION_STATSD_STARTED);
-        // Retrieve list of broadcast receivers for this broadcast & send them directed broadcasts
-        // to wake them up (if they're in background).
-        List<ResolveInfo> resolveInfos =
-                mContext.getPackageManager().queryBroadcastReceiversAsUser(
-                        intent, 0, UserHandle.SYSTEM);
-        if (resolveInfos == null || resolveInfos.isEmpty()) {
-            return; // No need to send broadcast.
-        }
-
-        for (ResolveInfo resolveInfo : resolveInfos) {
-            Intent intentToSend = new Intent(intent);
-            intentToSend.setComponent(new ComponentName(
-                    resolveInfo.activityInfo.applicationInfo.packageName,
-                    resolveInfo.activityInfo.name));
-            mContext.sendBroadcastAsUser(intentToSend, UserHandle.SYSTEM,
-                    android.Manifest.permission.DUMP);
-        }
-    }
-
-    @Override // Binder call
-    public boolean checkPermission(String permission, int pid, int uid) {
-        StatsCompanion.enforceStatsdCallingUid();
-        return mContext.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_GRANTED;
-    }
-
-    // Statsd related code
-
-    /**
-     * Fetches the statsd IBinder service. This is a blocking call that always refetches statsd
-     * instead of returning the cached sStatsd.
-     * Note: This should only be called from {@link #sayHiToStatsd()}. All other clients should use
-     * the cached sStatsd via {@link #getStatsdNonblocking()}.
-     */
-    private IStatsd fetchStatsdServiceLocked() {
-        sStatsd = IStatsd.Stub.asInterface(StatsFrameworkInitializer
-                .getStatsServiceManager()
-                .getStatsdServiceRegisterer()
-                .get());
-        return sStatsd;
-    }
-
-    private void registerStatsdDeathRecipient(IStatsd statsd, List<BroadcastReceiver> receivers) {
-        StatsdDeathRecipient deathRecipient = new StatsdDeathRecipient(statsd, receivers);
-
-        try {
-            statsd.asBinder().linkToDeath(deathRecipient, /*flags=*/0);
-        } catch (RemoteException e) {
-            Log.e(TAG, "linkToDeath (StatsdDeathRecipient) failed");
-            // Statsd has already died. Unregister receivers ourselves.
-            for (BroadcastReceiver receiver : receivers) {
-                mContext.unregisterReceiver(receiver);
-            }
-            synchronized (sStatsdLock) {
-                if (statsd == sStatsd) {
-                    statsdNotReadyLocked();
-                }
-            }
-        }
-    }
-
-    /**
-     * Now that the android system is ready, StatsCompanion is ready too, so inform statsd.
-     */
-    void systemReady() {
-        if (DEBUG) Log.d(TAG, "Learned that systemReady");
-        sayHiToStatsd();
-    }
-
-    void setStatsManagerService(StatsManagerService statsManagerService) {
-        mStatsManagerService = statsManagerService;
-    }
-
-    /**
-     * Tells statsd that statscompanion is ready. If the binder call returns, link to
-     * statsd.
-     */
-    private void sayHiToStatsd() {
-        IStatsd statsd;
-        synchronized (sStatsdLock) {
-            if (sStatsd != null && sStatsd.asBinder().isBinderAlive()) {
-                Log.e(TAG, "statsd has already been fetched before",
-                        new IllegalStateException("IStatsd object should be null or dead"));
-                return;
-            }
-            statsd = fetchStatsdServiceLocked();
-        }
-
-        if (statsd == null) {
-            Log.i(TAG, "Could not yet find statsd to tell it that StatsCompanion is alive.");
-            return;
-        }
-
-        // Cleann up from previous statsd - cancel any alarms that had been set. Do this here
-        // instead of in binder death because statsd can come back and set different alarms, or not
-        // want to set an alarm when it had been set. This guarantees that when we get a new statsd,
-        // we cancel any alarms before it is able to set them.
-        cancelPullingAlarm();
-        cancelAlarmForSubscriberTriggering();
-
-        if (DEBUG) Log.d(TAG, "Saying hi to statsd");
-        mStatsManagerService.statsdReady(statsd);
-        try {
-            statsd.statsCompanionReady();
-
-            BroadcastReceiver appUpdateReceiver = new AppUpdateReceiver();
-            BroadcastReceiver userUpdateReceiver = new UserUpdateReceiver();
-            BroadcastReceiver shutdownEventReceiver = new ShutdownEventReceiver();
-
-            // Setup broadcast receiver for updates.
-            IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REPLACED);
-            filter.addAction(Intent.ACTION_PACKAGE_ADDED);
-            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
-            filter.addDataScheme("package");
-            mContext.registerReceiverForAllUsers(appUpdateReceiver, filter, null, null);
-
-            // Setup receiver for user initialize (which happens once for a new user)
-            // and if a user is removed.
-            filter = new IntentFilter(Intent.ACTION_USER_INITIALIZE);
-            filter.addAction(Intent.ACTION_USER_REMOVED);
-            mContext.registerReceiverForAllUsers(userUpdateReceiver, filter, null, null);
-
-            // Setup receiver for device reboots or shutdowns.
-            filter = new IntentFilter(Intent.ACTION_REBOOT);
-            filter.addAction(Intent.ACTION_SHUTDOWN);
-            mContext.registerReceiverForAllUsers(shutdownEventReceiver, filter, null, null);
-
-            // Register death recipient.
-            List<BroadcastReceiver> broadcastReceivers =
-                    List.of(appUpdateReceiver, userUpdateReceiver, shutdownEventReceiver);
-            registerStatsdDeathRecipient(statsd, broadcastReceivers);
-
-            // Tell statsd that boot has completed. The signal may have already been sent, but since
-            // the signal-receiving function is idempotent, that's ok.
-            if (mBootCompleted.get()) {
-                statsd.bootCompleted();
-            }
-
-            // Pull the latest state of UID->app name, version mapping when statsd starts.
-            informAllUids(mContext);
-
-            Log.i(TAG, "Told statsd that StatsCompanionService is alive.");
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to inform statsd that statscompanion is ready", e);
-        }
-    }
-
-    private class StatsdDeathRecipient implements IBinder.DeathRecipient {
-
-        private final IStatsd mStatsd;
-        private final List<BroadcastReceiver> mReceiversToUnregister;
-
-        StatsdDeathRecipient(IStatsd statsd, List<BroadcastReceiver> receivers) {
-            mStatsd = statsd;
-            mReceiversToUnregister = receivers;
-        }
-
-        // It is possible for binderDied to be called after a restarted statsd calls statsdReady,
-        // but that's alright because the code does not assume an ordering of the two calls.
-        @Override
-        public void binderDied() {
-            Log.i(TAG, "Statsd is dead - erase all my knowledge, except pullers");
-            synchronized (sStatsdLock) {
-                long now = SystemClock.elapsedRealtime();
-                for (Long timeMillis : mDeathTimeMillis) {
-                    long ageMillis = now - timeMillis;
-                    if (ageMillis > MILLIS_IN_A_DAY) {
-                        mDeathTimeMillis.remove(timeMillis);
-                    }
-                }
-                for (Long timeMillis : mDeletedFiles.keySet()) {
-                    long ageMillis = now - timeMillis;
-                    if (ageMillis > MILLIS_IN_A_DAY * 7) {
-                        mDeletedFiles.remove(timeMillis);
-                    }
-                }
-                mDeathTimeMillis.add(now);
-                if (mDeathTimeMillis.size() >= DEATH_THRESHOLD) {
-                    mDeathTimeMillis.clear();
-                    File[] configs = new File(CONFIG_DIR).listFiles();
-                    if (configs != null && configs.length > 0) {
-                        String fileName = configs[0].getName();
-                        if (configs[0].delete()) {
-                            mDeletedFiles.put(now, fileName);
-                        }
-                    }
-                }
-
-                // Unregister receivers on death because receivers can only be unregistered once.
-                // Otherwise, an IllegalArgumentException is thrown.
-                for (BroadcastReceiver receiver: mReceiversToUnregister) {
-                    mContext.unregisterReceiver(receiver);
-                }
-
-                // It's possible for statsd to have restarted and called statsdReady, causing a new
-                // sStatsd binder object to be fetched, before the binderDied callback runs. Only
-                // call #statsdNotReadyLocked if that hasn't happened yet.
-                if (mStatsd == sStatsd) {
-                    statsdNotReadyLocked();
-                }
-            }
-        }
-    }
-
-    private void statsdNotReadyLocked() {
-        sStatsd = null;
-        mStatsManagerService.statsdNotReady();
-    }
-
-    void bootCompleted() {
-        mBootCompleted.set(true);
-        IStatsd statsd = getStatsdNonblocking();
-        if (statsd == null) {
-            // Statsd is not yet ready.
-            // Delay the boot completed ping to {@link #sayHiToStatsd()}
-            return;
-        }
-        try {
-            statsd.bootCompleted();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to notify statsd that boot completed");
-        }
-    }
-
-    @Override
-    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
-                != PackageManager.PERMISSION_GRANTED) {
-            return;
-        }
-
-        synchronized (sStatsdLock) {
-            writer.println("Number of configuration files deleted: " + mDeletedFiles.size());
-            if (mDeletedFiles.size() > 0) {
-                writer.println("  timestamp, deleted file name");
-            }
-            long lastBootMillis =
-                    SystemClock.currentThreadTimeMillis() - SystemClock.elapsedRealtime();
-            for (Long elapsedMillis : mDeletedFiles.keySet()) {
-                long deletionMillis = lastBootMillis + elapsedMillis;
-                writer.println("  " + deletionMillis + ", " + mDeletedFiles.get(elapsedMillis));
-            }
-        }
-    }
-}
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
deleted file mode 100644
index 1e3846b..0000000
--- a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
+++ /dev/null
@@ -1,668 +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.
- */
-
-package com.android.server.stats;
-
-import static com.android.server.stats.StatsCompanion.PendingIntentRef;
-
-import android.Manifest;
-import android.annotation.Nullable;
-import android.app.AppOpsManager;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.os.Binder;
-import android.os.IPullAtomCallback;
-import android.os.IStatsManagerService;
-import android.os.IStatsd;
-import android.os.PowerManager;
-import android.os.Process;
-import android.os.RemoteException;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * Service for {@link android.app.StatsManager}.
- *
- * @hide
- */
-public class StatsManagerService extends IStatsManagerService.Stub {
-
-    private static final String TAG = "StatsManagerService";
-    private static final boolean DEBUG = false;
-
-    private static final int STATSD_TIMEOUT_MILLIS = 5000;
-
-    private static final String USAGE_STATS_PERMISSION_OPS = "android:get_usage_stats";
-
-    @GuardedBy("mLock")
-    private IStatsd mStatsd;
-    private final Object mLock = new Object();
-
-    private StatsCompanionService mStatsCompanionService;
-    private Context mContext;
-
-    @GuardedBy("mLock")
-    private ArrayMap<ConfigKey, PendingIntentRef> mDataFetchPirMap = new ArrayMap<>();
-    @GuardedBy("mLock")
-    private ArrayMap<Integer, PendingIntentRef> mActiveConfigsPirMap = new ArrayMap<>();
-    @GuardedBy("mLock")
-    private ArrayMap<ConfigKey, ArrayMap<Long, PendingIntentRef>> mBroadcastSubscriberPirMap =
-            new ArrayMap<>();
-
-    public StatsManagerService(Context context) {
-        super();
-        mContext = context;
-    }
-
-    private static class ConfigKey {
-        private final int mUid;
-        private final long mConfigId;
-
-        ConfigKey(int uid, long configId) {
-            mUid = uid;
-            mConfigId = configId;
-        }
-
-        public int getUid() {
-            return mUid;
-        }
-
-        public long getConfigId() {
-            return mConfigId;
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(mUid, mConfigId);
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (obj instanceof ConfigKey) {
-                ConfigKey other = (ConfigKey) obj;
-                return this.mUid == other.getUid() && this.mConfigId == other.getConfigId();
-            }
-            return false;
-        }
-    }
-
-    private static class PullerKey {
-        private final int mUid;
-        private final int mAtomTag;
-
-        PullerKey(int uid, int atom) {
-            mUid = uid;
-            mAtomTag = atom;
-        }
-
-        public int getUid() {
-            return mUid;
-        }
-
-        public int getAtom() {
-            return mAtomTag;
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(mUid, mAtomTag);
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (obj instanceof PullerKey) {
-                PullerKey other = (PullerKey) obj;
-                return this.mUid == other.getUid() && this.mAtomTag == other.getAtom();
-            }
-            return false;
-        }
-    }
-
-    private static class PullerValue {
-        private final long mCoolDownMillis;
-        private final long mTimeoutMillis;
-        private final int[] mAdditiveFields;
-        private final IPullAtomCallback mCallback;
-
-        PullerValue(long coolDownMillis, long timeoutMillis, int[] additiveFields,
-                IPullAtomCallback callback) {
-            mCoolDownMillis = coolDownMillis;
-            mTimeoutMillis = timeoutMillis;
-            mAdditiveFields = additiveFields;
-            mCallback = callback;
-        }
-
-        public long getCoolDownMillis() {
-            return mCoolDownMillis;
-        }
-
-        public long getTimeoutMillis() {
-            return mTimeoutMillis;
-        }
-
-        public int[] getAdditiveFields() {
-            return mAdditiveFields;
-        }
-
-        public IPullAtomCallback getCallback() {
-            return mCallback;
-        }
-    }
-
-    private final ArrayMap<PullerKey, PullerValue> mPullers = new ArrayMap<>();
-
-    @Override
-    public void registerPullAtomCallback(int atomTag, long coolDownMillis, long timeoutMillis,
-            int[] additiveFields, IPullAtomCallback pullerCallback) {
-        enforceRegisterStatsPullAtomPermission();
-        if (pullerCallback == null) {
-            Log.w(TAG, "Puller callback is null for atom " + atomTag);
-            return;
-        }
-        int callingUid = Binder.getCallingUid();
-        PullerKey key = new PullerKey(callingUid, atomTag);
-        PullerValue val =
-                new PullerValue(coolDownMillis, timeoutMillis, additiveFields, pullerCallback);
-
-        // Always cache the puller in StatsManagerService. If statsd is down, we will register the
-        // puller when statsd comes back up.
-        synchronized (mLock) {
-            mPullers.put(key, val);
-        }
-
-        IStatsd statsd = getStatsdNonblocking();
-        if (statsd == null) {
-            return;
-        }
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            statsd.registerPullAtomCallback(callingUid, atomTag, coolDownMillis, timeoutMillis,
-                    additiveFields, pullerCallback);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to access statsd to register puller for atom " + atomTag);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    @Override
-    public void unregisterPullAtomCallback(int atomTag) {
-        enforceRegisterStatsPullAtomPermission();
-        int callingUid = Binder.getCallingUid();
-        PullerKey key = new PullerKey(callingUid, atomTag);
-
-        // Always remove the puller from StatsManagerService even if statsd is down. When statsd
-        // comes back up, we will not re-register the removed puller.
-        synchronized (mLock) {
-            mPullers.remove(key);
-        }
-
-        IStatsd statsd = getStatsdNonblocking();
-        if (statsd == null) {
-            return;
-        }
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            statsd.unregisterPullAtomCallback(callingUid, atomTag);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to access statsd to unregister puller for atom " + atomTag);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    @Override
-    public void setDataFetchOperation(long configId, PendingIntent pendingIntent,
-            String packageName) {
-        enforceDumpAndUsageStatsPermission(packageName);
-        int callingUid = Binder.getCallingUid();
-        final long token = Binder.clearCallingIdentity();
-        PendingIntentRef pir = new PendingIntentRef(pendingIntent, mContext);
-        ConfigKey key = new ConfigKey(callingUid, configId);
-        // We add the PIR to a map so we can reregister if statsd is unavailable.
-        synchronized (mLock) {
-            mDataFetchPirMap.put(key, pir);
-        }
-        try {
-            IStatsd statsd = getStatsdNonblocking();
-            if (statsd != null) {
-                statsd.setDataFetchOperation(configId, pir, callingUid);
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to setDataFetchOperation with statsd");
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    @Override
-    public void removeDataFetchOperation(long configId, String packageName) {
-        enforceDumpAndUsageStatsPermission(packageName);
-        int callingUid = Binder.getCallingUid();
-        final long token = Binder.clearCallingIdentity();
-        ConfigKey key = new ConfigKey(callingUid, configId);
-        synchronized (mLock) {
-            mDataFetchPirMap.remove(key);
-        }
-        try {
-            IStatsd statsd = getStatsdNonblocking();
-            if (statsd != null) {
-                statsd.removeDataFetchOperation(configId, callingUid);
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to removeDataFetchOperation with statsd");
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    @Override
-    public long[] setActiveConfigsChangedOperation(PendingIntent pendingIntent,
-            String packageName) {
-        enforceDumpAndUsageStatsPermission(packageName);
-        int callingUid = Binder.getCallingUid();
-        final long token = Binder.clearCallingIdentity();
-        PendingIntentRef pir = new PendingIntentRef(pendingIntent, mContext);
-        // We add the PIR to a map so we can reregister if statsd is unavailable.
-        synchronized (mLock) {
-            mActiveConfigsPirMap.put(callingUid, pir);
-        }
-        try {
-            IStatsd statsd = getStatsdNonblocking();
-            if (statsd != null) {
-                return statsd.setActiveConfigsChangedOperation(pir, callingUid);
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to setActiveConfigsChangedOperation with statsd");
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-        return new long[] {};
-    }
-
-    @Override
-    public void removeActiveConfigsChangedOperation(String packageName) {
-        enforceDumpAndUsageStatsPermission(packageName);
-        int callingUid = Binder.getCallingUid();
-        final long token = Binder.clearCallingIdentity();
-        synchronized (mLock) {
-            mActiveConfigsPirMap.remove(callingUid);
-        }
-        try {
-            IStatsd statsd = getStatsdNonblocking();
-            if (statsd != null) {
-                statsd.removeActiveConfigsChangedOperation(callingUid);
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to removeActiveConfigsChangedOperation with statsd");
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    @Override
-    public void setBroadcastSubscriber(long configId, long subscriberId,
-            PendingIntent pendingIntent, String packageName) {
-        enforceDumpAndUsageStatsPermission(packageName);
-        int callingUid = Binder.getCallingUid();
-        final long token = Binder.clearCallingIdentity();
-        PendingIntentRef pir = new PendingIntentRef(pendingIntent, mContext);
-        ConfigKey key = new ConfigKey(callingUid, configId);
-        // We add the PIR to a map so we can reregister if statsd is unavailable.
-        synchronized (mLock) {
-            ArrayMap<Long, PendingIntentRef> innerMap = mBroadcastSubscriberPirMap
-                    .getOrDefault(key, new ArrayMap<>());
-            innerMap.put(subscriberId, pir);
-            mBroadcastSubscriberPirMap.put(key, innerMap);
-        }
-        try {
-            IStatsd statsd = getStatsdNonblocking();
-            if (statsd != null) {
-                statsd.setBroadcastSubscriber(
-                        configId, subscriberId, pir, callingUid);
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to setBroadcastSubscriber with statsd");
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    @Override
-    public void unsetBroadcastSubscriber(long configId, long subscriberId, String packageName) {
-        enforceDumpAndUsageStatsPermission(packageName);
-        int callingUid = Binder.getCallingUid();
-        final long token = Binder.clearCallingIdentity();
-        ConfigKey key = new ConfigKey(callingUid, configId);
-        synchronized (mLock) {
-            ArrayMap<Long, PendingIntentRef> innerMap = mBroadcastSubscriberPirMap
-                    .getOrDefault(key, new ArrayMap<>());
-            innerMap.remove(subscriberId);
-            if (innerMap.isEmpty()) {
-                mBroadcastSubscriberPirMap.remove(key);
-            }
-        }
-        try {
-            IStatsd statsd = getStatsdNonblocking();
-            if (statsd != null) {
-                statsd.unsetBroadcastSubscriber(configId, subscriberId, callingUid);
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to unsetBroadcastSubscriber with statsd");
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    @Override
-    public long[] getRegisteredExperimentIds() throws IllegalStateException {
-        enforceDumpAndUsageStatsPermission(null);
-        final long token = Binder.clearCallingIdentity();
-        try {
-            IStatsd statsd = waitForStatsd();
-            if (statsd != null) {
-                return statsd.getRegisteredExperimentIds();
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to getRegisteredExperimentIds with statsd");
-            throw new IllegalStateException(e.getMessage(), e);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-        throw new IllegalStateException("Failed to connect to statsd to registerExperimentIds");
-    }
-
-    @Override
-    public byte[] getMetadata(String packageName) throws IllegalStateException {
-        enforceDumpAndUsageStatsPermission(packageName);
-        final long token = Binder.clearCallingIdentity();
-        try {
-            IStatsd statsd = waitForStatsd();
-            if (statsd != null) {
-                return statsd.getMetadata();
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to getMetadata with statsd");
-            throw new IllegalStateException(e.getMessage(), e);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-        throw new IllegalStateException("Failed to connect to statsd to getMetadata");
-    }
-
-    @Override
-    public byte[] getData(long key, String packageName) throws IllegalStateException {
-        enforceDumpAndUsageStatsPermission(packageName);
-        PowerManager powerManager = (PowerManager)
-                mContext.getSystemService(Context.POWER_SERVICE);
-        PowerManager.WakeLock wl = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
-                /*tag=*/ StatsManagerService.class.getCanonicalName());
-        int callingUid = Binder.getCallingUid();
-        final long token = Binder.clearCallingIdentity();
-        wl.acquire();
-        try {
-            IStatsd statsd = waitForStatsd();
-            if (statsd != null) {
-                return statsd.getData(key, callingUid);
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to getData with statsd");
-            throw new IllegalStateException(e.getMessage(), e);
-        } finally {
-            wl.release();
-            Binder.restoreCallingIdentity(token);
-        }
-        throw new IllegalStateException("Failed to connect to statsd to getData");
-    }
-
-    @Override
-    public void addConfiguration(long configId, byte[] config, String packageName)
-            throws IllegalStateException {
-        enforceDumpAndUsageStatsPermission(packageName);
-        int callingUid = Binder.getCallingUid();
-        final long token = Binder.clearCallingIdentity();
-        try {
-            IStatsd statsd = waitForStatsd();
-            if (statsd != null) {
-                statsd.addConfiguration(configId, config, callingUid);
-                return;
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to addConfiguration with statsd");
-            throw new IllegalStateException(e.getMessage(), e);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-        throw new IllegalStateException("Failed to connect to statsd to addConfig");
-    }
-
-    @Override
-    public void removeConfiguration(long configId, String packageName)
-            throws IllegalStateException {
-        enforceDumpAndUsageStatsPermission(packageName);
-        int callingUid = Binder.getCallingUid();
-        final long token = Binder.clearCallingIdentity();
-        try {
-            IStatsd statsd = waitForStatsd();
-            if (statsd != null) {
-                statsd.removeConfiguration(configId, callingUid);
-                return;
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to removeConfiguration with statsd");
-            throw new IllegalStateException(e.getMessage(), e);
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-        throw new IllegalStateException("Failed to connect to statsd to removeConfig");
-    }
-
-    void setStatsCompanionService(StatsCompanionService statsCompanionService) {
-        mStatsCompanionService = statsCompanionService;
-    }
-
-    /**
-     * Checks that the caller has both DUMP and PACKAGE_USAGE_STATS permissions. Also checks that
-     * the caller has USAGE_STATS_PERMISSION_OPS for the specified packageName if it is not null.
-     *
-     * @param packageName The packageName to check USAGE_STATS_PERMISSION_OPS.
-     */
-    private void enforceDumpAndUsageStatsPermission(@Nullable String packageName) {
-        int callingUid = Binder.getCallingUid();
-        int callingPid = Binder.getCallingPid();
-
-        if (callingPid == Process.myPid()) {
-            return;
-        }
-
-        mContext.enforceCallingPermission(Manifest.permission.DUMP, null);
-        mContext.enforceCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS, null);
-
-        if (packageName == null) {
-            return;
-        }
-        AppOpsManager appOpsManager = (AppOpsManager) mContext
-                .getSystemService(Context.APP_OPS_SERVICE);
-        switch (appOpsManager.noteOp(USAGE_STATS_PERMISSION_OPS,
-                Binder.getCallingUid(), packageName, null, null)) {
-            case AppOpsManager.MODE_ALLOWED:
-            case AppOpsManager.MODE_DEFAULT:
-                break;
-            default:
-                throw new SecurityException(
-                        String.format("UID %d / PID %d lacks app-op %s",
-                                callingUid, callingPid, USAGE_STATS_PERMISSION_OPS)
-                );
-        }
-    }
-
-    private void enforceRegisterStatsPullAtomPermission() {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.REGISTER_STATS_PULL_ATOM,
-                "Need REGISTER_STATS_PULL_ATOM permission.");
-    }
-
-
-    /**
-     * Clients should call this if blocking until statsd to be ready is desired
-     *
-     * @return IStatsd object if statsd becomes ready within the timeout, null otherwise.
-     */
-    private IStatsd waitForStatsd() {
-        synchronized (mLock) {
-            if (mStatsd == null) {
-                try {
-                    mLock.wait(STATSD_TIMEOUT_MILLIS);
-                } catch (InterruptedException e) {
-                    Log.e(TAG, "wait for statsd interrupted");
-                }
-            }
-            return mStatsd;
-        }
-    }
-
-    /**
-     * Clients should call this to receive a reference to statsd.
-     *
-     * @return IStatsd object if statsd is ready, null otherwise.
-     */
-    private IStatsd getStatsdNonblocking() {
-        synchronized (mLock) {
-            return mStatsd;
-        }
-    }
-
-    /**
-     * Called from {@link StatsCompanionService}.
-     *
-     * Tells StatsManagerService that Statsd is ready and updates
-     * Statsd with the contents of our local cache.
-     */
-    void statsdReady(IStatsd statsd) {
-        synchronized (mLock) {
-            mStatsd = statsd;
-            mLock.notify();
-        }
-        sayHiToStatsd(statsd);
-    }
-
-    /**
-     * Called from {@link StatsCompanionService}.
-     *
-     * Tells StatsManagerService that Statsd is no longer ready
-     * and we should no longer make binder calls with statsd.
-     */
-    void statsdNotReady() {
-        synchronized (mLock) {
-            mStatsd = null;
-        }
-    }
-
-    private void sayHiToStatsd(IStatsd statsd) {
-        if (statsd == null) {
-            return;
-        }
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            registerAllPullers(statsd);
-            registerAllDataFetchOperations(statsd);
-            registerAllActiveConfigsChangedOperations(statsd);
-            registerAllBroadcastSubscribers(statsd);
-        } catch (RemoteException e) {
-            Log.e(TAG, "StatsManager failed to (re-)register data with statsd");
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    // Pre-condition: the Binder calling identity has already been cleared
-    private void registerAllPullers(IStatsd statsd) throws RemoteException {
-        // Since we do not want to make an IPC with the lock held, we first create a copy of the
-        // data with the lock held before iterating through the map.
-        ArrayMap<PullerKey, PullerValue> pullersCopy;
-        synchronized (mLock) {
-            pullersCopy = new ArrayMap<>(mPullers);
-        }
-
-        for (Map.Entry<PullerKey, PullerValue> entry : pullersCopy.entrySet()) {
-            PullerKey key = entry.getKey();
-            PullerValue value = entry.getValue();
-            statsd.registerPullAtomCallback(key.getUid(), key.getAtom(), value.getCoolDownMillis(),
-                    value.getTimeoutMillis(), value.getAdditiveFields(), value.getCallback());
-        }
-        statsd.allPullersFromBootRegistered();
-    }
-
-    // Pre-condition: the Binder calling identity has already been cleared
-    private void registerAllDataFetchOperations(IStatsd statsd) throws RemoteException {
-        // Since we do not want to make an IPC with the lock held, we first create a copy of the
-        // data with the lock held before iterating through the map.
-        ArrayMap<ConfigKey, PendingIntentRef> dataFetchCopy;
-        synchronized (mLock) {
-            dataFetchCopy = new ArrayMap<>(mDataFetchPirMap);
-        }
-
-        for (Map.Entry<ConfigKey, PendingIntentRef> entry : dataFetchCopy.entrySet()) {
-            ConfigKey key = entry.getKey();
-            statsd.setDataFetchOperation(key.getConfigId(), entry.getValue(), key.getUid());
-        }
-    }
-
-    // Pre-condition: the Binder calling identity has already been cleared
-    private void registerAllActiveConfigsChangedOperations(IStatsd statsd) throws RemoteException {
-        // Since we do not want to make an IPC with the lock held, we first create a copy of the
-        // data with the lock held before iterating through the map.
-        ArrayMap<Integer, PendingIntentRef> activeConfigsChangedCopy;
-        synchronized (mLock) {
-            activeConfigsChangedCopy = new ArrayMap<>(mActiveConfigsPirMap);
-        }
-
-        for (Map.Entry<Integer, PendingIntentRef> entry : activeConfigsChangedCopy.entrySet()) {
-            statsd.setActiveConfigsChangedOperation(entry.getValue(), entry.getKey());
-        }
-    }
-
-    // Pre-condition: the Binder calling identity has already been cleared
-    private void registerAllBroadcastSubscribers(IStatsd statsd) throws RemoteException {
-        // Since we do not want to make an IPC with the lock held, we first create a deep copy of
-        // the data with the lock held before iterating through the map.
-        ArrayMap<ConfigKey, ArrayMap<Long, PendingIntentRef>> broadcastSubscriberCopy =
-                new ArrayMap<>();
-        synchronized (mLock) {
-            for (Map.Entry<ConfigKey, ArrayMap<Long, PendingIntentRef>> entry :
-                    mBroadcastSubscriberPirMap.entrySet()) {
-                broadcastSubscriberCopy.put(entry.getKey(), new ArrayMap(entry.getValue()));
-            }
-        }
-
-        for (Map.Entry<ConfigKey, ArrayMap<Long, PendingIntentRef>> entry :
-                mBroadcastSubscriberPirMap.entrySet()) {
-            ConfigKey configKey = entry.getKey();
-            for (Map.Entry<Long, PendingIntentRef> subscriberEntry : entry.getValue().entrySet()) {
-                statsd.setBroadcastSubscriber(configKey.getConfigId(), subscriberEntry.getKey(),
-                        subscriberEntry.getValue(), configKey.getUid());
-            }
-        }
-    }
-}
diff --git a/apex/statsd/statsd.rc b/apex/statsd/statsd.rc
deleted file mode 100644
index 605da2a..0000000
--- a/apex/statsd/statsd.rc
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-service statsd /apex/com.android.os.statsd/bin/statsd
-    class main
-    socket statsdw dgram+passcred 0222 statsd statsd
-    user statsd
-    group statsd log
-    writepid /dev/cpuset/system-background/tasks
diff --git a/apex/statsd/testing/Android.bp b/apex/statsd/testing/Android.bp
deleted file mode 100644
index a9cd0cc..0000000
--- a/apex/statsd/testing/Android.bp
+++ /dev/null
@@ -1,25 +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.
-
-apex_test {
-    name: "test_com.android.os.statsd",
-    visibility: [
-        "//system/apex/tests",
-    ],
-    defaults: ["com.android.os.statsd-defaults"],
-    manifest: "test_manifest.json",
-    file_contexts: ":com.android.os.statsd-file_contexts",
-    // Test APEX, should never be installed
-    installable: false,
-}
diff --git a/apex/statsd/testing/test_manifest.json b/apex/statsd/testing/test_manifest.json
deleted file mode 100644
index 57343d3..0000000
--- a/apex/statsd/testing/test_manifest.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-  "name": "com.android.os.statsd",
-  "version": 2147483647
-}
diff --git a/apex/statsd/tests/libstatspull/Android.bp b/apex/statsd/tests/libstatspull/Android.bp
deleted file mode 100644
index 05b3e04..0000000
--- a/apex/statsd/tests/libstatspull/Android.bp
+++ /dev/null
@@ -1,61 +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.
-
-android_test {
-    name: "LibStatsPullTests",
-    static_libs: [
-        "androidx.test.rules",
-        "platformprotoslite",
-        "statsdprotolite",
-        "truth-prebuilt",
-    ],
-    libs: [
-        "android.test.runner.stubs",
-        "android.test.base.stubs",
-    ],
-    jni_libs: [
-        "libstatspull_testhelper",
-    ],
-    srcs: [
-        "src/**/*.java",
-        "protos/**/*.proto",
-        ],
-    test_suites: [
-        "device-tests",
-        "mts",
-    ],
-    platform_apis: true,
-    privileged: true,
-    certificate: "platform",
-    compile_multilib: "both",
-}
-
-cc_library_shared {
-    name: "libstatspull_testhelper",
-    srcs: ["jni/stats_pull_helper.cpp"],
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
-    shared_libs: [
-        "libbinder_ndk",
-        "statsd-aidl-ndk_platform",
-    ],
-    static_libs: [
-        "libstatspull_private",
-        "libstatssocket_private",
-        "libutils",
-        "libcutils",
-    ],
-}
diff --git a/apex/statsd/tests/libstatspull/AndroidManifest.xml b/apex/statsd/tests/libstatspull/AndroidManifest.xml
deleted file mode 100644
index 0c669b0..0000000
--- a/apex/statsd/tests/libstatspull/AndroidManifest.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.internal.os.statsd.libstats" >
-
-
-    <uses-permission android:name="android.permission.DUMP" />
-    <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
-    <uses-permission android:name="android.permission.REGISTER_STATS_PULL_ATOM" />
-
-    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.internal.os.statsd.libstats"
-                     android:label="Tests for libstatspull">
-    </instrumentation>
-</manifest>
-
diff --git a/apex/statsd/tests/libstatspull/jni/stats_pull_helper.cpp b/apex/statsd/tests/libstatspull/jni/stats_pull_helper.cpp
deleted file mode 100644
index 166592d..0000000
--- a/apex/statsd/tests/libstatspull/jni/stats_pull_helper.cpp
+++ /dev/null
@@ -1,70 +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.
- */
-
-#include <jni.h>
-#include <log/log.h>
-#include <stats_event.h>
-#include <stats_pull_atom_callback.h>
-
-#include <chrono>
-#include <thread>
-
-using std::this_thread::sleep_for;
-
-namespace {
-static int32_t sAtomTag;
-static int32_t sPullReturnVal;
-static int64_t sLatencyMillis;
-static int32_t sAtomsPerPull;
-static int32_t sNumPulls = 0;
-
-static AStatsManager_PullAtomCallbackReturn pullAtomCallback(int32_t atomTag, AStatsEventList* data,
-                                                             void* /*cookie*/) {
-    sNumPulls++;
-    sleep_for(std::chrono::milliseconds(sLatencyMillis));
-    for (int i = 0; i < sAtomsPerPull; i++) {
-        AStatsEvent* event = AStatsEventList_addStatsEvent(data);
-        AStatsEvent_setAtomId(event, atomTag);
-        AStatsEvent_writeInt64(event, (int64_t) sNumPulls);
-        AStatsEvent_build(event);
-    }
-    return sPullReturnVal;
-}
-
-extern "C" JNIEXPORT void JNICALL
-Java_com_android_internal_os_statsd_libstats_LibStatsPullTests_setStatsPuller(
-        JNIEnv* /*env*/, jobject /* this */, jint atomTag, jlong timeoutMillis,
-        jlong coolDownMillis, jint pullRetVal, jlong latencyMillis, int atomsPerPull) {
-    sAtomTag = atomTag;
-    sPullReturnVal = pullRetVal;
-    sLatencyMillis = latencyMillis;
-    sAtomsPerPull = atomsPerPull;
-    sNumPulls = 0;
-    AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain();
-    AStatsManager_PullAtomMetadata_setCoolDownMillis(metadata, coolDownMillis);
-    AStatsManager_PullAtomMetadata_setTimeoutMillis(metadata, timeoutMillis);
-
-    AStatsManager_setPullAtomCallback(sAtomTag, metadata, &pullAtomCallback, nullptr);
-    AStatsManager_PullAtomMetadata_release(metadata);
-}
-
-extern "C" JNIEXPORT void JNICALL
-Java_com_android_internal_os_statsd_libstats_LibStatsPullTests_clearStatsPuller(JNIEnv* /*env*/,
-                                                                                jobject /* this */,
-                                                                                jint /*atomTag*/) {
-    AStatsManager_clearPullAtomCallback(sAtomTag);
-}
-} // namespace
diff --git a/apex/statsd/tests/libstatspull/protos/test_atoms.proto b/apex/statsd/tests/libstatspull/protos/test_atoms.proto
deleted file mode 100644
index 56c1b53..0000000
--- a/apex/statsd/tests/libstatspull/protos/test_atoms.proto
+++ /dev/null
@@ -1,32 +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.
- */
-syntax = "proto2";
-
-package com.android.internal.os.statsd.protos;
-
-option java_package = "com.android.internal.os.statsd.protos";
-option java_outer_classname = "TestAtoms";
-
-message PullCallbackAtomWrapper {
-  optional PullCallbackAtom pull_callback_atom = 150030;
-}
-
-message PullCallbackAtom {
-  optional int64 long_val = 1;
-}
-
-
-
diff --git a/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/LibStatsPullTests.java b/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/LibStatsPullTests.java
deleted file mode 100644
index 6108a32..0000000
--- a/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/LibStatsPullTests.java
+++ /dev/null
@@ -1,287 +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.
- */
-package com.android.internal.os.statsd.libstats;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.StatsManager;
-import android.content.Context;
-import android.util.Log;
-import android.util.StatsLog;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.os.StatsdConfigProto.AtomMatcher;
-import com.android.internal.os.StatsdConfigProto.FieldFilter;
-import com.android.internal.os.StatsdConfigProto.GaugeMetric;
-import com.android.internal.os.StatsdConfigProto.PullAtomPackages;
-import com.android.internal.os.StatsdConfigProto.SimpleAtomMatcher;
-import com.android.internal.os.StatsdConfigProto.StatsdConfig;
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-import com.android.internal.os.statsd.protos.TestAtoms;
-import com.android.os.AtomsProto.Atom;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-/**
- * Test puller registration.
- */
-@MediumTest
-@RunWith(AndroidJUnit4.class)
-public class LibStatsPullTests {
-    private static final String LOG_TAG = LibStatsPullTests.class.getSimpleName();
-    private static final int SHORT_SLEEP_MILLIS = 250;
-    private static final int LONG_SLEEP_MILLIS = 1_000;
-    private Context mContext;
-    private static final int PULL_ATOM_TAG = 150030;
-    private static final int APP_BREADCRUMB_LABEL = 3;
-    private static int sPullReturnValue;
-    private static long sConfigId;
-    private static long sPullLatencyMillis;
-    private static long sPullTimeoutMillis;
-    private static long sCoolDownMillis;
-    private static int sAtomsPerPull;
-
-    static {
-        System.loadLibrary("statspull_testhelper");
-    }
-
-    /**
-     * Setup the tests. Initialize shared data.
-     */
-    @Before
-    public void setup() {
-        mContext = InstrumentationRegistry.getTargetContext();
-        assertThat(InstrumentationRegistry.getInstrumentation()).isNotNull();
-        sPullReturnValue = StatsManager.PULL_SUCCESS;
-        sPullLatencyMillis = 0;
-        sPullTimeoutMillis = 10_000L;
-        sCoolDownMillis = 1_000L;
-        sAtomsPerPull = 1;
-    }
-
-    /**
-     * Teardown the tests.
-     */
-    @After
-    public void tearDown() throws Exception {
-        clearStatsPuller(PULL_ATOM_TAG);
-        StatsManager statsManager = (StatsManager) mContext.getSystemService(
-                Context.STATS_MANAGER);
-        statsManager.removeConfig(sConfigId);
-    }
-
-    /**
-     * Tests adding a puller callback and that pulls complete successfully.
-     */
-    @Test
-    public void testPullAtomCallbackRegistration() throws Exception {
-        StatsManager statsManager = (StatsManager) mContext.getSystemService(
-                Context.STATS_MANAGER);
-        // Upload a config that captures that pulled atom.
-        createAndAddConfigToStatsd(statsManager);
-
-        // Add the puller.
-        setStatsPuller(PULL_ATOM_TAG, sPullTimeoutMillis, sCoolDownMillis, sPullReturnValue,
-                sPullLatencyMillis, sAtomsPerPull);
-        Thread.sleep(SHORT_SLEEP_MILLIS);
-        StatsLog.logStart(APP_BREADCRUMB_LABEL);
-        // Let the current bucket finish.
-        Thread.sleep(LONG_SLEEP_MILLIS);
-        List<Atom> data = StatsConfigUtils.getGaugeMetricDataList(statsManager, sConfigId);
-        clearStatsPuller(PULL_ATOM_TAG);
-        assertThat(data.size()).isEqualTo(1);
-        TestAtoms.PullCallbackAtomWrapper atomWrapper = null;
-        try {
-            atomWrapper = TestAtoms.PullCallbackAtomWrapper.parser()
-                    .parseFrom(data.get(0).toByteArray());
-        } catch (Exception e) {
-            Log.e(LOG_TAG, "Failed to parse primitive atoms");
-        }
-        assertThat(atomWrapper).isNotNull();
-        assertThat(atomWrapper.hasPullCallbackAtom()).isTrue();
-        TestAtoms.PullCallbackAtom atom =
-                atomWrapper.getPullCallbackAtom();
-        assertThat(atom.getLongVal()).isEqualTo(1);
-    }
-
-    /**
-     * Tests that a failed pull is skipped.
-     */
-    @Test
-    public void testPullAtomCallbackFailure() throws Exception {
-        StatsManager statsManager = (StatsManager) mContext.getSystemService(
-                Context.STATS_MANAGER);
-        createAndAddConfigToStatsd(statsManager);
-        sPullReturnValue = StatsManager.PULL_SKIP;
-        // Add the puller.
-        setStatsPuller(PULL_ATOM_TAG, sPullTimeoutMillis, sCoolDownMillis, sPullReturnValue,
-                sPullLatencyMillis, sAtomsPerPull);
-        Thread.sleep(SHORT_SLEEP_MILLIS);
-        StatsLog.logStart(APP_BREADCRUMB_LABEL);
-        // Let the current bucket finish.
-        Thread.sleep(LONG_SLEEP_MILLIS);
-        List<Atom> data = StatsConfigUtils.getGaugeMetricDataList(statsManager, sConfigId);
-        clearStatsPuller(PULL_ATOM_TAG);
-        assertThat(data.size()).isEqualTo(0);
-    }
-
-    /**
-     * Tests that a pull that times out is skipped.
-     */
-    @Test
-    public void testPullAtomCallbackTimeout() throws Exception {
-        StatsManager statsManager = (StatsManager) mContext.getSystemService(
-                Context.STATS_MANAGER);
-        createAndAddConfigToStatsd(statsManager);
-        // The puller will sleep for 1.5 sec.
-        sPullLatencyMillis = 1_500;
-        // 1 second timeout
-        sPullTimeoutMillis = 1_000;
-
-        // Add the puller.
-        setStatsPuller(PULL_ATOM_TAG, sPullTimeoutMillis, sCoolDownMillis, sPullReturnValue,
-                sPullLatencyMillis, sAtomsPerPull);
-        Thread.sleep(SHORT_SLEEP_MILLIS);
-        StatsLog.logStart(APP_BREADCRUMB_LABEL);
-        // Let the current bucket finish and the pull timeout.
-        Thread.sleep(sPullLatencyMillis * 2);
-        List<Atom> data = StatsConfigUtils.getGaugeMetricDataList(statsManager, sConfigId);
-        clearStatsPuller(PULL_ATOM_TAG);
-        assertThat(data.size()).isEqualTo(0);
-    }
-
-    /**
-     * Tests that 2 pulls in quick succession use the cache instead of pulling again.
-     */
-    @Test
-    public void testPullAtomCallbackCache() throws Exception {
-        StatsManager statsManager = (StatsManager) mContext.getSystemService(
-                Context.STATS_MANAGER);
-        createAndAddConfigToStatsd(statsManager);
-
-        // Set the cooldown to 10 seconds
-        sCoolDownMillis = 10_000L;
-        // Add the puller.
-        setStatsPuller(PULL_ATOM_TAG, sPullTimeoutMillis, sCoolDownMillis, sPullReturnValue,
-                sPullLatencyMillis, sAtomsPerPull);
-
-        Thread.sleep(SHORT_SLEEP_MILLIS);
-        StatsLog.logStart(APP_BREADCRUMB_LABEL);
-        // Pull from cache.
-        StatsLog.logStart(APP_BREADCRUMB_LABEL);
-        Thread.sleep(LONG_SLEEP_MILLIS);
-        List<Atom> data = StatsConfigUtils.getGaugeMetricDataList(statsManager, sConfigId);
-        clearStatsPuller(PULL_ATOM_TAG);
-        assertThat(data.size()).isEqualTo(2);
-        for (int i = 0; i < data.size(); i++) {
-            TestAtoms.PullCallbackAtomWrapper atomWrapper = null;
-            try {
-                atomWrapper = TestAtoms.PullCallbackAtomWrapper.parser()
-                        .parseFrom(data.get(i).toByteArray());
-            } catch (Exception e) {
-                Log.e(LOG_TAG, "Failed to parse primitive atoms");
-            }
-            assertThat(atomWrapper).isNotNull();
-            assertThat(atomWrapper.hasPullCallbackAtom()).isTrue();
-            TestAtoms.PullCallbackAtom atom =
-                    atomWrapper.getPullCallbackAtom();
-            assertThat(atom.getLongVal()).isEqualTo(1);
-        }
-    }
-
-    /**
-     * Tests that a pull that returns 1000 stats events works properly.
-     */
-    @Test
-    public void testPullAtomCallbackStress() throws Exception {
-        StatsManager statsManager = (StatsManager) mContext.getSystemService(
-                Context.STATS_MANAGER);
-        // Upload a config that captures that pulled atom.
-        createAndAddConfigToStatsd(statsManager);
-        sAtomsPerPull = 1000;
-        // Add the puller.
-        setStatsPuller(PULL_ATOM_TAG, sPullTimeoutMillis, sCoolDownMillis, sPullReturnValue,
-                sPullLatencyMillis, sAtomsPerPull);
-
-        Thread.sleep(SHORT_SLEEP_MILLIS);
-        StatsLog.logStart(APP_BREADCRUMB_LABEL);
-        // Let the current bucket finish.
-        Thread.sleep(LONG_SLEEP_MILLIS);
-        List<Atom> data = StatsConfigUtils.getGaugeMetricDataList(statsManager, sConfigId);
-        clearStatsPuller(PULL_ATOM_TAG);
-        assertThat(data.size()).isEqualTo(sAtomsPerPull);
-
-        for (int i = 0; i < data.size(); i++) {
-            TestAtoms.PullCallbackAtomWrapper atomWrapper = null;
-            try {
-                atomWrapper = TestAtoms.PullCallbackAtomWrapper.parser()
-                        .parseFrom(data.get(i).toByteArray());
-            } catch (Exception e) {
-                Log.e(LOG_TAG, "Failed to parse primitive atoms");
-            }
-            assertThat(atomWrapper).isNotNull();
-            assertThat(atomWrapper.hasPullCallbackAtom()).isTrue();
-            TestAtoms.PullCallbackAtom atom =
-                    atomWrapper.getPullCallbackAtom();
-            assertThat(atom.getLongVal()).isEqualTo(1);
-        }
-    }
-
-    private void createAndAddConfigToStatsd(StatsManager statsManager) throws Exception {
-        sConfigId = System.currentTimeMillis();
-        long triggerMatcherId = sConfigId + 10;
-        long pullerMatcherId = sConfigId + 11;
-        long metricId = sConfigId + 100;
-        StatsdConfig config = StatsConfigUtils.getSimpleTestConfig(sConfigId)
-                .addAtomMatcher(
-                        StatsConfigUtils.getAppBreadcrumbMatcher(triggerMatcherId,
-                                APP_BREADCRUMB_LABEL))
-                .addAtomMatcher(AtomMatcher.newBuilder()
-                        .setId(pullerMatcherId)
-                        .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
-                                .setAtomId(PULL_ATOM_TAG))
-                )
-                .addGaugeMetric(GaugeMetric.newBuilder()
-                        .setId(metricId)
-                        .setWhat(pullerMatcherId)
-                        .setTriggerEvent(triggerMatcherId)
-                        .setGaugeFieldsFilter(FieldFilter.newBuilder().setIncludeAll(true))
-                        .setBucket(TimeUnit.CTS)
-                        .setSamplingType(GaugeMetric.SamplingType.FIRST_N_SAMPLES)
-                        .setMaxNumGaugeAtomsPerBucket(1000)
-                )
-                .addPullAtomPackages(PullAtomPackages.newBuilder()
-                        .setAtomId(PULL_ATOM_TAG)
-                        .addPackages(LibStatsPullTests.class.getPackage().getName()))
-                .build();
-        statsManager.addConfig(sConfigId, config.toByteArray());
-        assertThat(StatsConfigUtils.verifyValidConfigExists(statsManager, sConfigId)).isTrue();
-    }
-
-    private native void setStatsPuller(int atomTag, long timeoutMillis, long coolDownMillis,
-            int pullReturnVal, long latencyMillis, int atomPerPull);
-
-    private native void clearStatsPuller(int atomTag);
-}
-
diff --git a/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/StatsConfigUtils.java b/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/StatsConfigUtils.java
deleted file mode 100644
index b5afb94..0000000
--- a/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/StatsConfigUtils.java
+++ /dev/null
@@ -1,124 +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.
- */
-package com.android.internal.os.statsd.libstats;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.StatsManager;
-import android.util.Log;
-
-import com.android.internal.os.StatsdConfigProto.AtomMatcher;
-import com.android.internal.os.StatsdConfigProto.FieldValueMatcher;
-import com.android.internal.os.StatsdConfigProto.SimpleAtomMatcher;
-import com.android.internal.os.StatsdConfigProto.StatsdConfig;
-import com.android.os.AtomsProto.AppBreadcrumbReported;
-import com.android.os.AtomsProto.Atom;
-import com.android.os.StatsLog.ConfigMetricsReport;
-import com.android.os.StatsLog.ConfigMetricsReportList;
-import com.android.os.StatsLog.GaugeBucketInfo;
-import com.android.os.StatsLog.GaugeMetricData;
-import com.android.os.StatsLog.StatsLogReport;
-import com.android.os.StatsLog.StatsdStatsReport;
-import com.android.os.StatsLog.StatsdStatsReport.ConfigStats;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Util class for constructing statsd configs.
- */
-public class StatsConfigUtils {
-    public static final String TAG = "statsd.StatsConfigUtils";
-    public static final int SHORT_WAIT = 2_000; // 2 seconds.
-
-    /**
-     * @return An empty StatsdConfig in serialized proto format.
-     */
-    public static StatsdConfig.Builder getSimpleTestConfig(long configId) {
-        return StatsdConfig.newBuilder().setId(configId)
-                .addAllowedLogSource(StatsConfigUtils.class.getPackage().getName());
-    }
-
-
-    public static boolean verifyValidConfigExists(StatsManager statsManager, long configId) {
-        StatsdStatsReport report = null;
-        try {
-            report = StatsdStatsReport.parser().parseFrom(statsManager.getStatsMetadata());
-        } catch (Exception e) {
-            Log.e(TAG, "getMetadata failed", e);
-        }
-        assertThat(report).isNotNull();
-        boolean foundConfig = false;
-        for (ConfigStats configStats : report.getConfigStatsList()) {
-            if (configStats.getId() == configId && configStats.getIsValid()
-                    && configStats.getDeletionTimeSec() == 0) {
-                foundConfig = true;
-            }
-        }
-        return foundConfig;
-    }
-
-    public static AtomMatcher getAppBreadcrumbMatcher(long id, int label) {
-        return AtomMatcher.newBuilder()
-                .setId(id)
-                .setSimpleAtomMatcher(
-                        SimpleAtomMatcher.newBuilder()
-                                .setAtomId(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
-                                .addFieldValueMatcher(FieldValueMatcher.newBuilder()
-                                        .setField(AppBreadcrumbReported.LABEL_FIELD_NUMBER)
-                                        .setEqInt(label)
-                                )
-                )
-                .build();
-    }
-
-    public static ConfigMetricsReport getConfigMetricsReport(StatsManager statsManager,
-            long configId) {
-        ConfigMetricsReportList reportList = null;
-        try {
-            reportList = ConfigMetricsReportList.parser()
-                    .parseFrom(statsManager.getReports(configId));
-        } catch (Exception e) {
-            Log.e(TAG, "getData failed", e);
-        }
-        assertThat(reportList).isNotNull();
-        assertThat(reportList.getReportsCount()).isEqualTo(1);
-        ConfigMetricsReport report = reportList.getReports(0);
-        assertThat(report.getDumpReportReason())
-                .isEqualTo(ConfigMetricsReport.DumpReportReason.GET_DATA_CALLED);
-        return report;
-
-    }
-    public static List<Atom> getGaugeMetricDataList(ConfigMetricsReport report) {
-        List<Atom> data = new ArrayList<>();
-        for (StatsLogReport metric : report.getMetricsList()) {
-            for (GaugeMetricData gaugeMetricData : metric.getGaugeMetrics().getDataList()) {
-                for (GaugeBucketInfo bucketInfo : gaugeMetricData.getBucketInfoList()) {
-                    for (Atom atom : bucketInfo.getAtomList()) {
-                        data.add(atom);
-                    }
-                }
-            }
-        }
-        return data;
-    }
-
-    public static List<Atom> getGaugeMetricDataList(StatsManager statsManager, long configId) {
-        ConfigMetricsReport report = getConfigMetricsReport(statsManager, configId);
-        return getGaugeMetricDataList(report);
-    }
-}
-
diff --git a/api/OWNERS b/api/OWNERS
new file mode 100644
index 0000000..88d0b61
--- /dev/null
+++ b/api/OWNERS
@@ -0,0 +1 @@
+per-file Android.bp = file:platform/build/soong:/OWNERS
diff --git a/cmds/am/OWNERS b/cmds/am/OWNERS
new file mode 100644
index 0000000..72c0a9e
--- /dev/null
+++ b/cmds/am/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/am/OWNERS
diff --git a/cmds/appops/OWNERS b/cmds/appops/OWNERS
new file mode 100644
index 0000000..999ea0e
--- /dev/null
+++ b/cmds/appops/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/permission/OWNERS
diff --git a/cmds/backup/OWNERS b/cmds/backup/OWNERS
new file mode 100644
index 0000000..d99779e
--- /dev/null
+++ b/cmds/backup/OWNERS
@@ -0,0 +1 @@
+include /services/backup/OWNERS
diff --git a/cmds/bmgr/OWNERS b/cmds/bmgr/OWNERS
new file mode 100644
index 0000000..d99779e
--- /dev/null
+++ b/cmds/bmgr/OWNERS
@@ -0,0 +1 @@
+include /services/backup/OWNERS
diff --git a/cmds/bu/OWNERS b/cmds/bu/OWNERS
new file mode 100644
index 0000000..d99779e
--- /dev/null
+++ b/cmds/bu/OWNERS
@@ -0,0 +1 @@
+include /services/backup/OWNERS
diff --git a/cmds/dpm/OWNERS b/cmds/dpm/OWNERS
new file mode 100644
index 0000000..e95633a
--- /dev/null
+++ b/cmds/dpm/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/app/admin/OWNERS
diff --git a/cmds/ime/OWNERS b/cmds/ime/OWNERS
new file mode 100644
index 0000000..5deb2ce
--- /dev/null
+++ b/cmds/ime/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/inputmethod/OWNERS
diff --git a/cmds/incident/OWNERS b/cmds/incident/OWNERS
new file mode 100644
index 0000000..f766115
--- /dev/null
+++ b/cmds/incident/OWNERS
@@ -0,0 +1 @@
+include /cmds/incidentd/OWNERS
diff --git a/cmds/input/OWNERS b/cmds/input/OWNERS
new file mode 100644
index 0000000..d701f23
--- /dev/null
+++ b/cmds/input/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/hardware/input/OWNERS
diff --git a/cmds/locksettings/OWNERS b/cmds/locksettings/OWNERS
new file mode 100644
index 0000000..0a8dc8c
--- /dev/null
+++ b/cmds/locksettings/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/locksettings/OWNERS
diff --git a/cmds/pm/OWNERS b/cmds/pm/OWNERS
new file mode 100644
index 0000000..d825dfd
--- /dev/null
+++ b/cmds/pm/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/OWNERS
diff --git a/cmds/sm/OWNERS b/cmds/sm/OWNERS
new file mode 100644
index 0000000..6f9dbea
--- /dev/null
+++ b/cmds/sm/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/os/storage/OWNERS
diff --git a/cmds/statsd/.clang-format b/cmds/statsd/.clang-format
deleted file mode 100644
index cead3a0..0000000
--- a/cmds/statsd/.clang-format
+++ /dev/null
@@ -1,17 +0,0 @@
-BasedOnStyle: Google
-AllowShortIfStatementsOnASingleLine: true
-AllowShortFunctionsOnASingleLine: false
-AllowShortLoopsOnASingleLine: true
-BinPackArguments: true
-BinPackParameters: true
-ColumnLimit: 100
-CommentPragmas: NOLINT:.*
-ContinuationIndentWidth: 8
-DerivePointerAlignment: false
-IndentWidth: 4
-PointerAlignment: Left
-TabWidth: 4
-AccessModifierOffset: -4
-IncludeCategories:
-  - Regex:    '^"Log\.h"'
-    Priority:    -1
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
deleted file mode 100644
index d225497..0000000
--- a/cmds/statsd/Android.bp
+++ /dev/null
@@ -1,447 +0,0 @@
-//
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-cc_defaults {
-    name: "statsd_defaults",
-
-    srcs: [
-        "src/active_config_list.proto",
-        "src/anomaly/AlarmMonitor.cpp",
-        "src/anomaly/AlarmTracker.cpp",
-        "src/anomaly/AnomalyTracker.cpp",
-        "src/anomaly/DurationAnomalyTracker.cpp",
-        "src/anomaly/subscriber_util.cpp",
-        "src/condition/CombinationConditionTracker.cpp",
-        "src/condition/condition_util.cpp",
-        "src/condition/ConditionWizard.cpp",
-        "src/condition/SimpleConditionTracker.cpp",
-        "src/config/ConfigKey.cpp",
-        "src/config/ConfigListener.cpp",
-        "src/config/ConfigManager.cpp",
-        "src/experiment_ids.proto",
-        "src/external/Perfetto.cpp",
-        "src/external/PullResultReceiver.cpp",
-        "src/external/puller_util.cpp",
-        "src/external/StatsCallbackPuller.cpp",
-        "src/external/StatsPuller.cpp",
-        "src/external/StatsPullerManager.cpp",
-        "src/external/TrainInfoPuller.cpp",
-        "src/FieldValue.cpp",
-        "src/flags/flags.cpp",
-        "src/guardrail/StatsdStats.cpp",
-        "src/hash.cpp",
-        "src/HashableDimensionKey.cpp",
-        "src/logd/LogEvent.cpp",
-        "src/logd/LogEventQueue.cpp",
-        "src/matchers/CombinationAtomMatchingTracker.cpp",
-        "src/matchers/EventMatcherWizard.cpp",
-        "src/matchers/matcher_util.cpp",
-        "src/matchers/SimpleAtomMatchingTracker.cpp",
-        "src/metadata_util.cpp",
-        "src/metrics/CountMetricProducer.cpp",
-        "src/metrics/duration_helper/MaxDurationTracker.cpp",
-        "src/metrics/duration_helper/OringDurationTracker.cpp",
-        "src/metrics/DurationMetricProducer.cpp",
-        "src/metrics/EventMetricProducer.cpp",
-        "src/metrics/GaugeMetricProducer.cpp",
-        "src/metrics/MetricProducer.cpp",
-        "src/metrics/MetricsManager.cpp",
-        "src/metrics/parsing_utils/config_update_utils.cpp",
-        "src/metrics/parsing_utils/metrics_manager_util.cpp",
-        "src/metrics/ValueMetricProducer.cpp",
-        "src/packages/UidMap.cpp",
-        "src/shell/shell_config.proto",
-        "src/shell/ShellSubscriber.cpp",
-        "src/socket/StatsSocketListener.cpp",
-        "src/state/StateManager.cpp",
-        "src/state/StateTracker.cpp",
-        "src/stats_log_util.cpp",
-        "src/statscompanion_util.cpp",
-        "src/statsd_config.proto",
-        "src/statsd_metadata.proto",
-        "src/StatsLogProcessor.cpp",
-        "src/StatsService.cpp",
-        "src/storage/StorageManager.cpp",
-        "src/subscriber/IncidentdReporter.cpp",
-        "src/subscriber/SubscriberReporter.cpp",
-        "src/uid_data.proto",
-        "src/utils/MultiConditionTrigger.cpp",
-    ],
-
-    local_include_dirs: [
-        "src",
-    ],
-
-    static_libs: [
-        "libbase",
-        "libcutils",
-        "libgtest_prod",
-        "libprotoutil",
-        "libstatslog_statsd",
-        "libsysutils",
-        "libutils",
-        "server_configurable_flags",
-        "statsd-aidl-ndk_platform",
-    ],
-    shared_libs: [
-        "libbinder_ndk",
-        "libincident",
-        "liblog",
-    ],
-}
-
-genrule {
-    name: "statslog_statsd.h",
-    tools: ["stats-log-api-gen"],
-    cmd: "$(location stats-log-api-gen) --header $(genDir)/statslog_statsd.h --module statsd --namespace android,os,statsd,util",
-    out: [
-        "statslog_statsd.h",
-    ],
-}
-
-genrule {
-    name: "statslog_statsd.cpp",
-    tools: ["stats-log-api-gen"],
-    cmd: "$(location stats-log-api-gen) --cpp $(genDir)/statslog_statsd.cpp --module statsd --namespace android,os,statsd,util --importHeader statslog_statsd.h",
-    out: [
-        "statslog_statsd.cpp",
-    ],
-}
-
-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",
-        "libstatspull",
-    ],
-}
-
-cc_library_static {
-    name: "libstatslog_statsd",
-    generated_sources: ["statslog_statsd.cpp"],
-    generated_headers: ["statslog_statsd.h"],
-    export_generated_headers: ["statslog_statsd.h"],
-    apex_available: [
-        "com.android.os.statsd",
-        "test_com.android.os.statsd",
-    ],
-    shared_libs: [
-        "libstatssocket",
-        "libstatspull",
-    ],
-    export_shared_lib_headers: [
-        "libstatspull",
-    ],
-}
-
-// =========
-// statsd
-// =========
-
-cc_binary {
-    name: "statsd",
-    defaults: ["statsd_defaults"],
-
-    srcs: ["src/main.cpp"],
-
-    cflags: [
-        "-Wall",
-        "-Wextra",
-        "-Werror",
-        "-Wno-unused-parameter",
-        // optimize for size (protobuf glop can get big)
-        "-Os",
-        // "-g",
-        // "-O0",
-    ],
-
-    product_variables: {
-        eng: {
-            // Enable sanitizer ONLY on eng builds
-            //sanitize: {
-            //    address: true,
-            //},
-        },
-    },
-
-    proto: {
-        type: "lite",
-        static: true,
-    },
-    stl: "libc++_static",
-
-    shared_libs: [
-        "libstatssocket",
-    ],
-
-    apex_available: [
-        "com.android.os.statsd",
-        "test_com.android.os.statsd",
-    ],
-}
-
-// ==============
-// statsd_test
-// ==============
-
-cc_test {
-    name: "statsd_test",
-    defaults: ["statsd_defaults"],
-    test_suites: ["device-tests", "mts"],
-    test_config: "statsd_test.xml",
-
-    //TODO(b/153588990): Remove when the build system properly separates
-    //32bit and 64bit architectures.
-    compile_multilib: "both",
-    multilib: {
-        lib64: {
-            suffix: "64",
-        },
-        lib32: {
-            suffix: "32",
-        },
-    },
-
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wno-missing-field-initializers",
-        "-Wno-unused-variable",
-        "-Wno-unused-function",
-        "-Wno-unused-parameter",
-    ],
-
-    require_root: true,
-
-    srcs: [
-        // atom_field_options.proto needs field_options.proto, but that is
-        // not included in libprotobuf-cpp-lite, so compile it here.
-        ":libprotobuf-internal-protos",
-        ":libstats_internal_protos",
-
-        "src/shell/shell_data.proto",
-        "src/stats_log.proto",
-        "tests/AlarmMonitor_test.cpp",
-        "tests/anomaly/AlarmTracker_test.cpp",
-        "tests/anomaly/AnomalyTracker_test.cpp",
-        "tests/condition/CombinationConditionTracker_test.cpp",
-        "tests/condition/ConditionTimer_test.cpp",
-        "tests/condition/SimpleConditionTracker_test.cpp",
-        "tests/ConfigManager_test.cpp",
-        "tests/e2e/Alarm_e2e_test.cpp",
-        "tests/e2e/Anomaly_count_e2e_test.cpp",
-        "tests/e2e/Anomaly_duration_sum_e2e_test.cpp",
-        "tests/e2e/Attribution_e2e_test.cpp",
-        "tests/e2e/ConfigTtl_e2e_test.cpp",
-        "tests/e2e/ConfigUpdate_e2e_ab_test.cpp",
-        "tests/e2e/ConfigUpdate_e2e_test.cpp",
-        "tests/e2e/CountMetric_e2e_test.cpp",
-        "tests/e2e/DurationMetric_e2e_test.cpp",
-        "tests/e2e/GaugeMetric_e2e_pull_test.cpp",
-        "tests/e2e/GaugeMetric_e2e_push_test.cpp",
-        "tests/e2e/MetricActivation_e2e_test.cpp",
-        "tests/e2e/MetricConditionLink_e2e_test.cpp",
-        "tests/e2e/PartialBucket_e2e_test.cpp",
-        "tests/e2e/ValueMetric_pull_e2e_test.cpp",
-        "tests/e2e/WakelockDuration_e2e_test.cpp",
-        "tests/external/puller_util_test.cpp",
-        "tests/external/StatsCallbackPuller_test.cpp",
-        "tests/external/StatsPuller_test.cpp",
-        "tests/external/StatsPullerManager_test.cpp",
-        "tests/FieldValue_test.cpp",
-        "tests/guardrail/StatsdStats_test.cpp",
-        "tests/HashableDimensionKey_test.cpp",
-        "tests/indexed_priority_queue_test.cpp",
-        "tests/log_event/LogEventQueue_test.cpp",
-        "tests/LogEntryMatcher_test.cpp",
-        "tests/LogEvent_test.cpp",
-        "tests/metadata_util_test.cpp",
-        "tests/metrics/CountMetricProducer_test.cpp",
-        "tests/metrics/DurationMetricProducer_test.cpp",
-        "tests/metrics/EventMetricProducer_test.cpp",
-        "tests/metrics/GaugeMetricProducer_test.cpp",
-        "tests/metrics/MaxDurationTracker_test.cpp",
-        "tests/metrics/metrics_test_helper.cpp",
-        "tests/metrics/OringDurationTracker_test.cpp",
-        "tests/metrics/ValueMetricProducer_test.cpp",
-        "tests/metrics/parsing_utils/config_update_utils_test.cpp",
-        "tests/metrics/parsing_utils/metrics_manager_util_test.cpp",
-        "tests/MetricsManager_test.cpp",
-        "tests/shell/ShellSubscriber_test.cpp",
-        "tests/state/StateTracker_test.cpp",
-        "tests/statsd_test_util.cpp",
-        "tests/StatsLogProcessor_test.cpp",
-        "tests/StatsService_test.cpp",
-        "tests/storage/StorageManager_test.cpp",
-        "tests/UidMap_test.cpp",
-        "tests/utils/MultiConditionTrigger_test.cpp",
-    ],
-
-    static_libs: [
-        "libgmock",
-        "libplatformprotos",
-        "libstatslog_statsdtest",
-        "libstatssocket_private",
-    ],
-
-    proto: {
-        type: "lite",
-        include_dirs: [
-            "external/protobuf/src",
-            "frameworks/proto_logging/stats",
-        ],
-    },
-
-}
-
-//#############################
-// statsd micro benchmark
-//#############################
-
-cc_benchmark {
-    name: "statsd_benchmark",
-    defaults: ["statsd_defaults"],
-
-    srcs: [
-        // atom_field_options.proto needs field_options.proto, but that is
-        // not included in libprotobuf-cpp-lite, so compile it here.
-        ":libprotobuf-internal-protos",
-        ":libstats_internal_protos",
-
-        "benchmark/duration_metric_benchmark.cpp",
-        "benchmark/filter_value_benchmark.cpp",
-        "benchmark/get_dimensions_for_condition_benchmark.cpp",
-        "benchmark/hello_world_benchmark.cpp",
-        "benchmark/log_event_benchmark.cpp",
-        "benchmark/main.cpp",
-        "benchmark/metric_util.cpp",
-        "benchmark/stats_write_benchmark.cpp",
-        "src/stats_log.proto",
-    ],
-
-    proto: {
-        type: "lite",
-        include_dirs: [
-            "external/protobuf/src",
-            "frameworks/proto_logging/stats",
-        ],
-    },
-
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wno-unused-parameter",
-        "-Wno-unused-variable",
-        "-Wno-unused-function",
-
-        // Bug: http://b/29823425 Disable -Wvarargs for Clang update to r271374
-        "-Wno-varargs",
-    ],
-
-    static_libs: [
-        "libplatformprotos",
-        "libstatssocket_private",
-    ],
-
-    shared_libs: [
-        "libgtest_prod",
-        "libprotobuf-cpp-lite",
-        "libstatslog",
-    ],
-}
-
-// ====  java proto device library (for test only)  ==============================
-java_library {
-    name: "statsdprotolite",
-    sdk_version: "core_current",
-    proto: {
-        type: "lite",
-        include_dirs: [
-            "external/protobuf/src",
-            "frameworks/proto_logging/stats",
-        ],
-    },
-
-    srcs: [
-        ":libstats_atoms_proto",
-        "src/shell/shell_config.proto",
-        "src/shell/shell_data.proto",
-        "src/stats_log.proto",
-        "src/statsd_config.proto",
-    ],
-
-    static_libs: [
-        "platformprotoslite",
-    ],
-    // Protos have lots of MissingOverride and similar.
-    errorprone: {
-        javacflags: ["-XepDisableAllChecks"],
-    },
-}
-
-java_library {
-    name: "statsdprotonano",
-    sdk_version: "9",
-    proto: {
-        type: "nano",
-        output_params: ["store_unknown_fields=true"],
-        include_dirs: [
-            "external/protobuf/src",
-            "frameworks/proto_logging/stats",
-        ],
-    },
-    srcs: [
-        ":libstats_atoms_proto",
-        "src/shell/shell_config.proto",
-        "src/shell/shell_data.proto",
-        "src/stats_log.proto",
-        "src/statsd_config.proto",
-    ],
-    static_libs: [
-        "platformprotosnano",
-    ],
-    // Protos have lots of MissingOverride and similar.
-    errorprone: {
-        javacflags: ["-XepDisableAllChecks"],
-    },
-}
-
-// Filegroup for statsd config proto definition.
-filegroup {
-    name: "statsd-config-proto-def",
-    srcs: ["src/statsd_config.proto"],
-}
diff --git a/cmds/statsd/OWNERS b/cmds/statsd/OWNERS
deleted file mode 100644
index 4e4e119..0000000
--- a/cmds/statsd/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-baligh@google.com
diff --git a/cmds/statsd/TEST_MAPPING b/cmds/statsd/TEST_MAPPING
deleted file mode 100644
index a7a4cf1..0000000
--- a/cmds/statsd/TEST_MAPPING
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-  "presubmit" : [
-    {
-      "name" : "statsd_test"
-    }
-  ],
-
-  "postsubmit" : [
-    {
-      "name" : "CtsStatsdHostTestCases"
-    },
-    {
-      "name" : "GtsStatsdHostTestCases"
-    }
-  ]
-
-}
diff --git a/cmds/statsd/benchmark/duration_metric_benchmark.cpp b/cmds/statsd/benchmark/duration_metric_benchmark.cpp
deleted file mode 100644
index 2d315d9..0000000
--- a/cmds/statsd/benchmark/duration_metric_benchmark.cpp
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vector>
-#include "benchmark/benchmark.h"
-#include "FieldValue.h"
-#include "HashableDimensionKey.h"
-#include "logd/LogEvent.h"
-#include "stats_log_util.h"
-#include "metric_util.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using std::vector;
-
-static StatsdConfig CreateDurationMetricConfig_NoLink_AND_CombinationCondition(
-        DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) {
-    StatsdConfig config;
-    *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
-    *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
-    *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
-    *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
-    *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
-
-    auto scheduledJobPredicate = CreateScheduledJobPredicate();
-    auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
-    dimensions->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED);
-    dimensions->add_child()->set_field(2);  // job name field.
-
-    auto screenIsOffPredicate = CreateScreenIsOffPredicate();
-
-    auto isSyncingPredicate = CreateIsSyncingPredicate();
-    auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
-    *syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED,
-                                                          {Position::FIRST});
-    if (addExtraDimensionInCondition) {
-        syncDimension->add_child()->set_field(2 /* name field*/);
-    }
-
-    *config.add_predicate() = scheduledJobPredicate;
-    *config.add_predicate() = screenIsOffPredicate;
-    *config.add_predicate() = isSyncingPredicate;
-    auto combinationPredicate = config.add_predicate();
-    combinationPredicate->set_id(StringToId("CombinationPredicate"));
-    combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
-    addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
-    addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
-
-    auto metric = config.add_duration_metric();
-    metric->set_bucket(FIVE_MINUTES);
-    metric->set_id(StringToId("scheduledJob"));
-    metric->set_what(scheduledJobPredicate.id());
-    metric->set_condition(combinationPredicate->id());
-    metric->set_aggregation_type(aggregationType);
-    auto dimensionWhat = metric->mutable_dimensions_in_what();
-    dimensionWhat->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED);
-    dimensionWhat->add_child()->set_field(2);  // job name field.
-    *metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions(
-            android::util::SYNC_STATE_CHANGED, {Position::FIRST});
-    return config;
-}
-
-static StatsdConfig CreateDurationMetricConfig_Link_AND_CombinationCondition(
-        DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) {
-    StatsdConfig config;
-    *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
-    *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
-    *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
-    *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
-    *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
-
-    auto scheduledJobPredicate = CreateScheduledJobPredicate();
-    auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
-    *dimensions = CreateAttributionUidDimensions(
-                android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
-    dimensions->add_child()->set_field(2);  // job name field.
-
-    auto isSyncingPredicate = CreateIsSyncingPredicate();
-    auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
-    *syncDimension = CreateAttributionUidDimensions(
-            android::util::SYNC_STATE_CHANGED, {Position::FIRST});
-    if (addExtraDimensionInCondition) {
-        syncDimension->add_child()->set_field(2 /* name field*/);
-    }
-
-    auto screenIsOffPredicate = CreateScreenIsOffPredicate();
-
-    *config.add_predicate() = scheduledJobPredicate;
-    *config.add_predicate() = screenIsOffPredicate;
-    *config.add_predicate() = isSyncingPredicate;
-    auto combinationPredicate = config.add_predicate();
-    combinationPredicate->set_id(StringToId("CombinationPredicate"));
-    combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
-    addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
-    addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
-
-    auto metric = config.add_duration_metric();
-    metric->set_bucket(FIVE_MINUTES);
-    metric->set_id(StringToId("scheduledJob"));
-    metric->set_what(scheduledJobPredicate.id());
-    metric->set_condition(combinationPredicate->id());
-    metric->set_aggregation_type(aggregationType);
-    *metric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
-            android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
-
-    auto links = metric->add_links();
-    links->set_condition(isSyncingPredicate.id());
-    *links->mutable_fields_in_what() =
-            CreateAttributionUidDimensions(
-                android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
-    *links->mutable_fields_in_condition() =
-            CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
-    return config;
-}
-
-static void BM_DurationMetricNoLink(benchmark::State& state) {
-    ConfigKey cfgKey;
-    auto config = CreateDurationMetricConfig_NoLink_AND_CombinationCondition(
-            DurationMetric::SUM, false);
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-
-    std::vector<std::unique_ptr<LogEvent>> events;
-
-    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 11,
-                                                   android::view::DISPLAY_STATE_OFF));
-    events.push_back(
-            CreateScreenStateChangedEvent(bucketStartTimeNs + 40, android::view::DISPLAY_STATE_ON));
-
-    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 102,
-                                                   android::view::DISPLAY_STATE_OFF));
-    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 450,
-                                                   android::view::DISPLAY_STATE_ON));
-
-    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 650,
-                                                   android::view::DISPLAY_STATE_OFF));
-    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + bucketSizeNs + 100,
-                                                   android::view::DISPLAY_STATE_ON));
-
-    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + bucketSizeNs + 640,
-                                                   android::view::DISPLAY_STATE_OFF));
-    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + bucketSizeNs + 650,
-                                                   android::view::DISPLAY_STATE_ON));
-
-    vector<int> attributionUids1 = {9999};
-    vector<string> attributionTags1 = {""};
-    events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 2, attributionUids1,
-                                                  attributionTags1, "job0"));
-    events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + 101, attributionUids1,
-                                                   attributionTags1, "job0"));
-
-    events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 201, attributionUids1,
-                                                  attributionTags1, "job2"));
-    events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + 500, attributionUids1,
-                                                   attributionTags1, "job2"));
-
-    vector<int> attributionUids2 = {8888};
-    events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 600, attributionUids2,
-                                                  attributionTags1, "job2"));
-    events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + bucketSizeNs + 850,
-                                                   attributionUids2, attributionTags1, "job2"));
-
-    events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + bucketSizeNs + 600,
-                                                  attributionUids2, attributionTags1, "job1"));
-    events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + bucketSizeNs + 900,
-                                                   attributionUids2, attributionTags1, "job1"));
-
-    vector<int> attributionUids3 = {111, 222, 222};
-    vector<string> attributionTags3 = {"App1", "GMSCoreModule1", "GMSCoreModule2"};
-    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 10, attributionUids3,
-                                          attributionTags3, "ReadEmail"));
-    events.push_back(CreateSyncEndEvent(bucketStartTimeNs + 50, attributionUids3, attributionTags3,
-                                        "ReadEmail"));
-
-    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 200, attributionUids3,
-                                          attributionTags3, "ReadEmail"));
-    events.push_back(CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 300, attributionUids3,
-                                        attributionTags3, "ReadEmail"));
-
-    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 400, attributionUids3,
-                                          attributionTags3, "ReadDoc"));
-    events.push_back(CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs - 1, attributionUids3,
-                                        attributionTags3, "ReadDoc"));
-
-    vector<int> attributionUids4 = {333, 222, 555};
-    vector<string> attributionTags4 = {"App2", "GMSCoreModule1", "GMSCoreModule2"};
-    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 401, attributionUids4,
-                                          attributionTags4, "ReadEmail"));
-    events.push_back(CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 700, attributionUids4,
-                                        attributionTags4, "ReadEmail"));
-    sortLogEventsByTimestamp(&events);
-
-    while (state.KeepRunning()) {
-        auto processor = CreateStatsLogProcessor(
-                bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
-        for (const auto& event : events) {
-            processor->OnLogEvent(event.get());
-        }
-    }
-}
-
-BENCHMARK(BM_DurationMetricNoLink);
-
-
-static void BM_DurationMetricLink(benchmark::State& state) {
-    ConfigKey cfgKey;
-    auto config = CreateDurationMetricConfig_Link_AND_CombinationCondition(
-        DurationMetric::SUM, false);
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-
-    std::vector<std::unique_ptr<LogEvent>> events;
-
-    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 55,
-                                                   android::view::DISPLAY_STATE_OFF));
-    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 120,
-                                                   android::view::DISPLAY_STATE_ON));
-    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 121,
-                                                   android::view::DISPLAY_STATE_OFF));
-    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 450,
-                                                   android::view::DISPLAY_STATE_ON));
-
-    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 501,
-                                                   android::view::DISPLAY_STATE_OFF));
-    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + bucketSizeNs + 100,
-                                                   android::view::DISPLAY_STATE_ON));
-
-    vector<int> attributionUids1 = {111};
-    vector<string> attributionTags1 = {"App1"};
-    events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 1, attributionUids1,
-                                                  attributionTags1, "job1"));
-    events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + 101, attributionUids1,
-                                                   attributionTags1, "job1"));
-
-    vector<int> attributionUids2 = {333};
-    vector<string> attributionTags2 = {"App2"};
-    events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 201, attributionUids2,
-                                                  attributionTags2, "job2"));
-    events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + 500, attributionUids2,
-                                                   attributionTags2, "job2"));
-    events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 600, attributionUids2,
-                                                  attributionTags2, "job2"));
-    events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + bucketSizeNs + 850,
-                                                   attributionUids2, attributionTags2, "job2"));
-
-    vector<int> attributionUids3 = {444};
-    vector<string> attributionTags3 = {"App3"};
-    events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + bucketSizeNs - 2,
-                                                  attributionUids3, attributionTags3, "job3"));
-    events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + bucketSizeNs + 900,
-                                                   attributionUids3, attributionTags3, "job3"));
-
-    vector<int> attributionUids4 = {111, 222, 222};
-    vector<string> attributionTags4 = {"App1", "GMSCoreModule1", "GMSCoreModule2"};
-    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 50, attributionUids4,
-                                          attributionTags4, "ReadEmail"));
-    events.push_back(CreateSyncEndEvent(bucketStartTimeNs + 110, attributionUids4, attributionTags4,
-                                        "ReadEmail"));
-
-    vector<int> attributionUids5 = {333, 222, 555};
-    vector<string> attributionTags5 = {"App2", "GMSCoreModule1", "GMSCoreModule2"};
-    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 300, attributionUids5,
-                                          attributionTags5, "ReadEmail"));
-    events.push_back(CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 700, attributionUids5,
-                                        attributionTags5, "ReadEmail"));
-    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 400, attributionUids5,
-                                          attributionTags5, "ReadDoc"));
-    events.push_back(CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs - 1, attributionUids5,
-                                        attributionTags5, "ReadDoc"));
-
-    vector<int> attributionUids6 = {444, 222, 555};
-    vector<string> attributionTags6 = {"App3", "GMSCoreModule1", "GMSCoreModule2"};
-    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 550, attributionUids6,
-                                          attributionTags6, "ReadDoc"));
-    events.push_back(CreateSyncEndEvent(bucketStartTimeNs + 800, attributionUids6, attributionTags6,
-                                        "ReadDoc"));
-    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + bucketSizeNs - 1, attributionUids6,
-                                          attributionTags6, "ReadDoc"));
-    events.push_back(CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 700, attributionUids6,
-                                        attributionTags6, "ReadDoc"));
-    sortLogEventsByTimestamp(&events);
-
-    while (state.KeepRunning()) {
-        auto processor = CreateStatsLogProcessor(
-                bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
-        for (const auto& event : events) {
-            processor->OnLogEvent(event.get());
-        }
-    }
-}
-
-BENCHMARK(BM_DurationMetricLink);
-
-}  //  namespace statsd
-}  //  namespace os
-}  //  namespace android
diff --git a/cmds/statsd/benchmark/filter_value_benchmark.cpp b/cmds/statsd/benchmark/filter_value_benchmark.cpp
deleted file mode 100644
index 743ccc4..0000000
--- a/cmds/statsd/benchmark/filter_value_benchmark.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vector>
-
-#include "FieldValue.h"
-#include "HashableDimensionKey.h"
-#include "benchmark/benchmark.h"
-#include "logd/LogEvent.h"
-#include "metric_util.h"
-#include "stats_event.h"
-#include "stats_log_util.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using std::vector;
-
-static void createLogEventAndMatcher(LogEvent* event, FieldMatcher* field_matcher) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, 1);
-    AStatsEvent_overwriteTimestamp(statsEvent, 100000);
-
-    std::vector<int> attributionUids = {100, 100};
-    std::vector<string> attributionTags = {"LOCATION", "LOCATION"};
-    writeAttribution(statsEvent, attributionUids, attributionTags);
-
-    AStatsEvent_writeFloat(statsEvent, 3.2f);
-    AStatsEvent_writeString(statsEvent, "LOCATION");
-    AStatsEvent_writeInt64(statsEvent, 990);
-
-    parseStatsEventToLogEvent(statsEvent, event);
-
-    field_matcher->set_field(1);
-    auto child = field_matcher->add_child();
-    child->set_field(1);
-    child->set_position(FIRST);
-    child->add_child()->set_field(1);
-}
-
-static void BM_FilterValue(benchmark::State& state) {
-    LogEvent event(/*uid=*/0, /*pid=*/0);
-    FieldMatcher field_matcher;
-    createLogEventAndMatcher(&event, &field_matcher);
-
-    std::vector<Matcher> matchers;
-    translateFieldMatcher(field_matcher, &matchers);
-
-    while (state.KeepRunning()) {
-        HashableDimensionKey output;
-        filterValues(matchers, event.getValues(), &output);
-    }
-}
-
-BENCHMARK(BM_FilterValue);
-
-}  //  namespace statsd
-}  //  namespace os
-}  //  namespace android
diff --git a/cmds/statsd/benchmark/get_dimensions_for_condition_benchmark.cpp b/cmds/statsd/benchmark/get_dimensions_for_condition_benchmark.cpp
deleted file mode 100644
index 7a45565..0000000
--- a/cmds/statsd/benchmark/get_dimensions_for_condition_benchmark.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vector>
-
-#include "FieldValue.h"
-#include "HashableDimensionKey.h"
-#include "benchmark/benchmark.h"
-#include "logd/LogEvent.h"
-#include "metric_util.h"
-#include "stats_event.h"
-#include "stats_log_util.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using std::vector;
-
-static void createLogEventAndLink(LogEvent* event, Metric2Condition *link) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, 1);
-    AStatsEvent_overwriteTimestamp(statsEvent, 100000);
-
-    std::vector<int> attributionUids = {100, 100};
-    std::vector<string> attributionTags = {"LOCATION", "LOCATION"};
-    writeAttribution(statsEvent, attributionUids, attributionTags);
-
-    AStatsEvent_writeFloat(statsEvent, 3.2f);
-    AStatsEvent_writeString(statsEvent, "LOCATION");
-    AStatsEvent_writeInt64(statsEvent, 990);
-
-    parseStatsEventToLogEvent(statsEvent, event);
-
-    link->conditionId = 1;
-
-    FieldMatcher field_matcher;
-    field_matcher.set_field(event->GetTagId());
-    auto child = field_matcher.add_child();
-    child->set_field(1);
-    child->set_position(FIRST);
-    child->add_child()->set_field(1);
-
-    translateFieldMatcher(field_matcher, &link->metricFields);
-    field_matcher.set_field(event->GetTagId() + 1);
-    translateFieldMatcher(field_matcher, &link->conditionFields);
-}
-
-static void BM_GetDimensionInCondition(benchmark::State& state) {
-    Metric2Condition link;
-    LogEvent event(/*uid=*/0, /*pid=*/0);
-    createLogEventAndLink(&event, &link);
-
-    while (state.KeepRunning()) {
-        HashableDimensionKey output;
-        getDimensionForCondition(event.getValues(), link, &output);
-    }
-}
-
-BENCHMARK(BM_GetDimensionInCondition);
-
-
-}  //  namespace statsd
-}  //  namespace os
-}  //  namespace android
diff --git a/cmds/statsd/benchmark/hello_world_benchmark.cpp b/cmds/statsd/benchmark/hello_world_benchmark.cpp
deleted file mode 100644
index c732d39..0000000
--- a/cmds/statsd/benchmark/hello_world_benchmark.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "benchmark/benchmark.h"
-
-static void BM_StringCreation(benchmark::State& state) {
-    while (state.KeepRunning()) std::string empty_string;
-}
-// Register the function as a benchmark
-BENCHMARK(BM_StringCreation);
-
-// Define another benchmark
-static void BM_StringCopy(benchmark::State& state) {
-    std::string x = "hello";
-    while (state.KeepRunning()) std::string copy(x);
-}
-BENCHMARK(BM_StringCopy);
diff --git a/cmds/statsd/benchmark/log_event_benchmark.cpp b/cmds/statsd/benchmark/log_event_benchmark.cpp
deleted file mode 100644
index 057e00b..0000000
--- a/cmds/statsd/benchmark/log_event_benchmark.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vector>
-#include "benchmark/benchmark.h"
-#include "logd/LogEvent.h"
-#include "stats_event.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-static size_t createAndParseStatsEvent(uint8_t* msg) {
-    AStatsEvent* event = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(event, 100);
-    AStatsEvent_writeInt32(event, 2);
-    AStatsEvent_writeFloat(event, 2.0);
-    AStatsEvent_build(event);
-
-    size_t size;
-    uint8_t* buf = AStatsEvent_getBuffer(event, &size);
-    memcpy(msg, buf, size);
-    return size;
-}
-
-static void BM_LogEventCreation(benchmark::State& state) {
-    uint8_t msg[LOGGER_ENTRY_MAX_PAYLOAD];
-    size_t size = createAndParseStatsEvent(msg);
-    while (state.KeepRunning()) {
-        LogEvent event(/*uid=*/ 1000, /*pid=*/ 1001);
-        benchmark::DoNotOptimize(event.parseBuffer(msg, size));
-    }
-}
-BENCHMARK(BM_LogEventCreation);
-
-}  //  namespace statsd
-}  //  namespace os
-}  //  namespace android
diff --git a/cmds/statsd/benchmark/main.cpp b/cmds/statsd/benchmark/main.cpp
deleted file mode 100644
index 08921f3..0000000
--- a/cmds/statsd/benchmark/main.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <benchmark/benchmark.h>
-
-BENCHMARK_MAIN();
diff --git a/cmds/statsd/benchmark/metric_util.cpp b/cmds/statsd/benchmark/metric_util.cpp
deleted file mode 100644
index 89fd3d9..0000000
--- a/cmds/statsd/benchmark/metric_util.cpp
+++ /dev/null
@@ -1,379 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "metric_util.h"
-
-#include "stats_event.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-AtomMatcher CreateSimpleAtomMatcher(const string& name, int atomId) {
-    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(atomId);
-    return atom_matcher;
-}
-
-AtomMatcher CreateScheduledJobStateChangedAtomMatcher(const string& name,
-                                                      ScheduledJobStateChanged::State state) {
-    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);
-    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);
-    return atom_matcher;
-}
-
-AtomMatcher CreateStartScheduledJobAtomMatcher() {
-    return CreateScheduledJobStateChangedAtomMatcher("ScheduledJobStart",
-                                                     ScheduledJobStateChanged::STARTED);
-}
-
-AtomMatcher CreateFinishScheduledJobAtomMatcher() {
-    return CreateScheduledJobStateChangedAtomMatcher("ScheduledJobFinish",
-                                                     ScheduledJobStateChanged::FINISHED);
-}
-
-AtomMatcher CreateScreenBrightnessChangedAtomMatcher() {
-    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);
-    return atom_matcher;
-}
-
-AtomMatcher CreateUidProcessStateChangedAtomMatcher() {
-    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);
-    return atom_matcher;
-}
-
-AtomMatcher CreateWakelockStateChangedAtomMatcher(const string& name,
-                                                  WakelockStateChanged::State state) {
-    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);
-    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);
-    return atom_matcher;
-}
-
-AtomMatcher CreateAcquireWakelockAtomMatcher() {
-    return CreateWakelockStateChangedAtomMatcher("AcquireWakelock", WakelockStateChanged::ACQUIRE);
-}
-
-AtomMatcher CreateReleaseWakelockAtomMatcher() {
-    return CreateWakelockStateChangedAtomMatcher("ReleaseWakelock", WakelockStateChanged::RELEASE);
-}
-
-AtomMatcher CreateScreenStateChangedAtomMatcher(
-    const string& name, android::view::DisplayStateEnum state) {
-    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);
-    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);
-    return atom_matcher;
-}
-
-AtomMatcher CreateScreenTurnedOnAtomMatcher() {
-    return CreateScreenStateChangedAtomMatcher("ScreenTurnedOn",
-            android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-}
-
-AtomMatcher CreateScreenTurnedOffAtomMatcher() {
-    return CreateScreenStateChangedAtomMatcher("ScreenTurnedOff",
-            ::android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
-}
-
-AtomMatcher CreateSyncStateChangedAtomMatcher(
-    const string& name, SyncStateChanged::State state) {
-    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);
-    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);
-    return atom_matcher;
-}
-
-AtomMatcher CreateSyncStartAtomMatcher() {
-    return CreateSyncStateChangedAtomMatcher("SyncStart", SyncStateChanged::ON);
-}
-
-AtomMatcher CreateSyncEndAtomMatcher() {
-    return CreateSyncStateChangedAtomMatcher("SyncEnd", SyncStateChanged::OFF);
-}
-
-AtomMatcher CreateActivityForegroundStateChangedAtomMatcher(
-    const string& name, ActivityForegroundStateChanged::State state) {
-    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);
-    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);
-    return atom_matcher;
-}
-
-AtomMatcher CreateMoveToBackgroundAtomMatcher() {
-    return CreateActivityForegroundStateChangedAtomMatcher(
-        "MoveToBackground", ActivityForegroundStateChanged::BACKGROUND);
-}
-
-AtomMatcher CreateMoveToForegroundAtomMatcher() {
-    return CreateActivityForegroundStateChangedAtomMatcher(
-        "MoveToForeground", ActivityForegroundStateChanged::FOREGROUND);
-}
-
-Predicate CreateScheduledJobPredicate() {
-    Predicate predicate;
-    predicate.set_id(StringToId("ScheduledJobRunningPredicate"));
-    predicate.mutable_simple_predicate()->set_start(StringToId("ScheduledJobStart"));
-    predicate.mutable_simple_predicate()->set_stop(StringToId("ScheduledJobFinish"));
-    return predicate;
-}
-
-Predicate CreateBatterySaverModePredicate() {
-    Predicate predicate;
-    predicate.set_id(StringToId("BatterySaverIsOn"));
-    predicate.mutable_simple_predicate()->set_start(StringToId("BatterySaverModeStart"));
-    predicate.mutable_simple_predicate()->set_stop(StringToId("BatterySaverModeStop"));
-    return predicate;
-}
-
-Predicate CreateScreenIsOnPredicate() {
-    Predicate predicate;
-    predicate.set_id(StringToId("ScreenIsOn"));
-    predicate.mutable_simple_predicate()->set_start(StringToId("ScreenTurnedOn"));
-    predicate.mutable_simple_predicate()->set_stop(StringToId("ScreenTurnedOff"));
-    return predicate;
-}
-
-Predicate CreateScreenIsOffPredicate() {
-    Predicate predicate;
-    predicate.set_id(1111123);
-    predicate.mutable_simple_predicate()->set_start(StringToId("ScreenTurnedOff"));
-    predicate.mutable_simple_predicate()->set_stop(StringToId("ScreenTurnedOn"));
-    return predicate;
-}
-
-Predicate CreateHoldingWakelockPredicate() {
-    Predicate predicate;
-    predicate.set_id(StringToId("HoldingWakelock"));
-    predicate.mutable_simple_predicate()->set_start(StringToId("AcquireWakelock"));
-    predicate.mutable_simple_predicate()->set_stop(StringToId("ReleaseWakelock"));
-    return predicate;
-}
-
-Predicate CreateIsSyncingPredicate() {
-    Predicate predicate;
-    predicate.set_id(33333333333333);
-    predicate.mutable_simple_predicate()->set_start(StringToId("SyncStart"));
-    predicate.mutable_simple_predicate()->set_stop(StringToId("SyncEnd"));
-    return predicate;
-}
-
-Predicate CreateIsInBackgroundPredicate() {
-    Predicate predicate;
-    predicate.set_id(StringToId("IsInBackground"));
-    predicate.mutable_simple_predicate()->set_start(StringToId("MoveToBackground"));
-    predicate.mutable_simple_predicate()->set_stop(StringToId("MoveToForeground"));
-    return predicate;
-}
-
-void addPredicateToPredicateCombination(const Predicate& predicate,
-                                        Predicate* combinationPredicate) {
-    combinationPredicate->mutable_combination()->add_predicate(predicate.id());
-}
-
-FieldMatcher CreateAttributionUidDimensions(const int atomId,
-                                            const std::vector<Position>& positions) {
-    FieldMatcher dimensions;
-    dimensions.set_field(atomId);
-    for (const auto position : positions) {
-        auto child = dimensions.add_child();
-        child->set_field(1);
-        child->set_position(position);
-        child->add_child()->set_field(1);
-    }
-    return dimensions;
-}
-
-FieldMatcher CreateAttributionUidAndTagDimensions(const int atomId,
-                                                 const std::vector<Position>& positions) {
-    FieldMatcher dimensions;
-    dimensions.set_field(atomId);
-    for (const auto position : positions) {
-        auto child = dimensions.add_child();
-        child->set_field(1);
-        child->set_position(position);
-        child->add_child()->set_field(1);
-        child->add_child()->set_field(2);
-    }
-    return dimensions;
-}
-
-FieldMatcher CreateDimensions(const int atomId, const std::vector<int>& fields) {
-    FieldMatcher dimensions;
-    dimensions.set_field(atomId);
-    for (const int field : fields) {
-        dimensions.add_child()->set_field(field);
-    }
-    return dimensions;
-}
-
-void writeAttribution(AStatsEvent* statsEvent, const vector<int>& attributionUids,
-                      const vector<string>& attributionTags) {
-    vector<const char*> cTags(attributionTags.size());
-    for (int i = 0; i < cTags.size(); i++) {
-        cTags[i] = attributionTags[i].c_str();
-    }
-
-    AStatsEvent_writeAttributionChain(statsEvent,
-                                      reinterpret_cast<const uint32_t*>(attributionUids.data()),
-                                      cTags.data(), attributionUids.size());
-}
-
-void parseStatsEventToLogEvent(AStatsEvent* statsEvent, LogEvent* logEvent) {
-    AStatsEvent_build(statsEvent);
-
-    size_t size;
-    uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
-    logEvent->parseBuffer(buf, size);
-
-    AStatsEvent_release(statsEvent);
-}
-
-std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
-        uint64_t timestampNs, const android::view::DisplayStateEnum state) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, util::SCREEN_STATE_CHANGED);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-    AStatsEvent_writeInt32(statsEvent, state);
-
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-std::unique_ptr<LogEvent> CreateScheduledJobStateChangedEvent(
-        const vector<int>& attributionUids, const vector<string>& attributionTags,
-        const string& jobName, const ScheduledJobStateChanged::State state, uint64_t timestampNs) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, util::SCHEDULED_JOB_STATE_CHANGED);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-
-    writeAttribution(statsEvent, attributionUids, attributionTags);
-    AStatsEvent_writeString(statsEvent, jobName.c_str());
-    AStatsEvent_writeInt32(statsEvent, state);
-
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-std::unique_ptr<LogEvent> CreateStartScheduledJobEvent(uint64_t timestampNs,
-                                                       const vector<int>& attributionUids,
-                                                       const vector<string>& attributionTags,
-                                                       const string& jobName) {
-    return CreateScheduledJobStateChangedEvent(attributionUids, attributionTags, jobName,
-                                               ScheduledJobStateChanged::STARTED, timestampNs);
-}
-
-// Create log event when scheduled job finishes.
-std::unique_ptr<LogEvent> CreateFinishScheduledJobEvent(uint64_t timestampNs,
-                                                        const vector<int>& attributionUids,
-                                                        const vector<string>& attributionTags,
-                                                        const string& jobName) {
-    return CreateScheduledJobStateChangedEvent(attributionUids, attributionTags, jobName,
-                                               ScheduledJobStateChanged::FINISHED, timestampNs);
-}
-
-std::unique_ptr<LogEvent> CreateSyncStateChangedEvent(uint64_t timestampNs,
-                                                      const vector<int>& attributionUids,
-                                                      const vector<string>& attributionTags,
-                                                      const string& name,
-                                                      const SyncStateChanged::State state) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, util::SYNC_STATE_CHANGED);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-
-    writeAttribution(statsEvent, attributionUids, attributionTags);
-    AStatsEvent_writeString(statsEvent, name.c_str());
-    AStatsEvent_writeInt32(statsEvent, state);
-
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-std::unique_ptr<LogEvent> CreateSyncStartEvent(uint64_t timestampNs,
-                                               const vector<int>& attributionUids,
-                                               const vector<string>& attributionTags,
-                                               const string& name) {
-    return CreateSyncStateChangedEvent(timestampNs, attributionUids, attributionTags, name,
-                                       SyncStateChanged::ON);
-}
-
-std::unique_ptr<LogEvent> CreateSyncEndEvent(uint64_t timestampNs,
-                                             const vector<int>& attributionUids,
-                                             const vector<string>& attributionTags,
-                                             const string& name) {
-    return CreateSyncStateChangedEvent(timestampNs, attributionUids, attributionTags, name,
-                                       SyncStateChanged::OFF);
-}
-
-sp<StatsLogProcessor> CreateStatsLogProcessor(const long timeBaseSec, const StatsdConfig& config,
-                                              const ConfigKey& key) {
-    sp<UidMap> uidMap = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> periodicAlarmMonitor;
-    sp<StatsLogProcessor> processor =
-            new StatsLogProcessor(uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
-                                  timeBaseSec * NS_PER_SEC, [](const ConfigKey&) { return true; },
-                                  [](const int&, const vector<int64_t>&) { return true; });
-    processor->OnConfigUpdated(timeBaseSec * NS_PER_SEC, key, config);
-    return processor;
-}
-
-void sortLogEventsByTimestamp(std::vector<std::unique_ptr<LogEvent>> *events) {
-  std::sort(events->begin(), events->end(),
-            [](const std::unique_ptr<LogEvent>& a, const std::unique_ptr<LogEvent>& b) {
-              return a->GetElapsedTimestampNs() < b->GetElapsedTimestampNs();
-            });
-}
-
-int64_t StringToId(const string& str) {
-    return static_cast<int64_t>(std::hash<std::string>()(str));
-}
-
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/benchmark/metric_util.h b/cmds/statsd/benchmark/metric_util.h
deleted file mode 100644
index 3efaa85..0000000
--- a/cmds/statsd/benchmark/metric_util.h
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "src/StatsLogProcessor.h"
-#include "src/logd/LogEvent.h"
-#include "stats_event.h"
-#include "statslog.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// Create AtomMatcher proto to simply match a specific atom type.
-AtomMatcher CreateSimpleAtomMatcher(const string& name, int atomId);
-
-// Create AtomMatcher proto for scheduled job state changed.
-AtomMatcher CreateScheduledJobStateChangedAtomMatcher();
-
-// Create AtomMatcher proto for starting a scheduled job.
-AtomMatcher CreateStartScheduledJobAtomMatcher();
-
-// Create AtomMatcher proto for a scheduled job is done.
-AtomMatcher CreateFinishScheduledJobAtomMatcher();
-
-// Create AtomMatcher proto for screen brightness state changed.
-AtomMatcher CreateScreenBrightnessChangedAtomMatcher();
-
-// Create AtomMatcher proto for acquiring wakelock.
-AtomMatcher CreateAcquireWakelockAtomMatcher();
-
-// Create AtomMatcher proto for releasing wakelock.
-AtomMatcher CreateReleaseWakelockAtomMatcher() ;
-
-// Create AtomMatcher proto for screen turned on.
-AtomMatcher CreateScreenTurnedOnAtomMatcher();
-
-// Create AtomMatcher proto for screen turned off.
-AtomMatcher CreateScreenTurnedOffAtomMatcher();
-
-// Create AtomMatcher proto for app sync turned on.
-AtomMatcher CreateSyncStartAtomMatcher();
-
-// Create AtomMatcher proto for app sync turned off.
-AtomMatcher CreateSyncEndAtomMatcher();
-
-// Create AtomMatcher proto for app sync moves to background.
-AtomMatcher CreateMoveToBackgroundAtomMatcher();
-
-// Create AtomMatcher proto for app sync moves to foreground.
-AtomMatcher CreateMoveToForegroundAtomMatcher();
-
-// Create Predicate proto for screen is off.
-Predicate CreateScreenIsOffPredicate();
-
-// Create Predicate proto for a running scheduled job.
-Predicate CreateScheduledJobPredicate();
-
-// Create Predicate proto for holding wakelock.
-Predicate CreateHoldingWakelockPredicate();
-
-// Create a Predicate proto for app syncing.
-Predicate CreateIsSyncingPredicate();
-
-// Create a Predicate proto for app is in background.
-Predicate CreateIsInBackgroundPredicate();
-
-// Add a predicate to the predicate combination.
-void addPredicateToPredicateCombination(const Predicate& predicate, Predicate* combination);
-
-// Create dimensions from primitive fields.
-FieldMatcher CreateDimensions(const int atomId, const std::vector<int>& fields);
-
-// Create dimensions by attribution uid and tag.
-FieldMatcher CreateAttributionUidAndTagDimensions(const int atomId,
-                                                  const std::vector<Position>& positions);
-
-// Create dimensions by attribution uid only.
-FieldMatcher CreateAttributionUidDimensions(const int atomId,
-                                            const std::vector<Position>& positions);
-
-void writeAttribution(AStatsEvent* statsEvent, const vector<int>& attributionUids,
-                      const vector<string>& attributionTags);
-
-void parseStatsEventToLogEvent(AStatsEvent* statsEvent, LogEvent* logEvent);
-
-// Create log event for screen state changed.
-std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
-        uint64_t timestampNs, const android::view::DisplayStateEnum state);
-
-// Create log event when scheduled job starts.
-std::unique_ptr<LogEvent> CreateStartScheduledJobEvent(uint64_t timestampNs,
-                                                       const vector<int>& attributionUids,
-                                                       const vector<string>& attributionTags,
-                                                       const string& jobName);
-
-// Create log event when scheduled job finishes.
-std::unique_ptr<LogEvent> CreateFinishScheduledJobEvent(uint64_t timestampNs,
-                                                        const vector<int>& attributionUids,
-                                                        const vector<string>& attributionTags,
-                                                        const string& jobName);
-
-// Create log event when the app sync starts.
-std::unique_ptr<LogEvent> CreateSyncStartEvent(uint64_t timestampNs,
-                                               const vector<int>& attributionUids,
-                                               const vector<string>& attributionTags,
-                                               const string& name);
-
-// Create log event when the app sync ends.
-std::unique_ptr<LogEvent> CreateSyncEndEvent(uint64_t timestampNs,
-                                             const vector<int>& attributionUids,
-                                             const vector<string>& attributionTags,
-                                             const string& name);
-
-// Create a statsd log event processor upon the start time in seconds, config and key.
-sp<StatsLogProcessor> CreateStatsLogProcessor(const long timeBaseSec, const StatsdConfig& config,
-                                              const ConfigKey& key);
-
-// Util function to sort the log events by timestamp.
-void sortLogEventsByTimestamp(std::vector<std::unique_ptr<LogEvent>> *events);
-
-int64_t StringToId(const string& str);
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/benchmark/stats_write_benchmark.cpp b/cmds/statsd/benchmark/stats_write_benchmark.cpp
deleted file mode 100644
index f5a0cd5..0000000
--- a/cmds/statsd/benchmark/stats_write_benchmark.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "benchmark/benchmark.h"
-#include <statslog.h>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-static void BM_StatsWrite(benchmark::State& state) {
-    const char* reason = "test";
-    int64_t boot_end_time = 1234567;
-    int64_t total_duration = 100;
-    int64_t bootloader_duration = 10;
-    int64_t time_since_last_boot = 99999999;
-    while (state.KeepRunning()) {
-        android::util::stats_write(
-                android::util::BOOT_SEQUENCE_REPORTED, reason, reason,
-                boot_end_time, total_duration, bootloader_duration, time_since_last_boot);
-        total_duration++;
-    }
-}
-BENCHMARK(BM_StatsWrite);
-
-}  //  namespace statsd
-}  //  namespace os
-}  //  namespace android
diff --git a/cmds/statsd/src/FieldValue.cpp b/cmds/statsd/src/FieldValue.cpp
deleted file mode 100644
index c9ccfb9..0000000
--- a/cmds/statsd/src/FieldValue.cpp
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false
-#include "Log.h"
-#include "FieldValue.h"
-#include "HashableDimensionKey.h"
-#include "math.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-int32_t getEncodedField(int32_t pos[], int32_t depth, bool includeDepth) {
-    int32_t field = 0;
-    for (int32_t i = 0; i <= depth; i++) {
-        int32_t shiftBits = 8 * (kMaxLogDepth - i);
-        field |= (pos[i] << shiftBits);
-    }
-
-    if (includeDepth) {
-        field |= (depth << 24);
-    }
-    return field;
-}
-
-int32_t encodeMatcherMask(int32_t mask[], int32_t depth) {
-    return getEncodedField(mask, depth, false) | 0xff000000;
-}
-
-bool Field::matches(const Matcher& matcher) const {
-    if (mTag != matcher.mMatcher.getTag()) {
-        return false;
-    }
-    if ((mField & matcher.mMask) == matcher.mMatcher.getField()) {
-        return true;
-    }
-
-    if (matcher.hasAllPositionMatcher() &&
-        (mField & (matcher.mMask & kClearAllPositionMatcherMask)) == matcher.mMatcher.getField()) {
-        return true;
-    }
-
-    return false;
-}
-
-void translateFieldMatcher(int tag, const FieldMatcher& matcher, int depth, int* pos, int* mask,
-                           std::vector<Matcher>* output) {
-    if (depth > kMaxLogDepth) {
-        ALOGE("depth > 2");
-        return;
-    }
-
-    pos[depth] = matcher.field();
-    mask[depth] = 0x7f;
-
-    if (matcher.has_position()) {
-        depth++;
-        if (depth > 2) {
-            return;
-        }
-        switch (matcher.position()) {
-            case Position::ALL:
-                pos[depth] = 0x00;
-                mask[depth] = 0x7f;
-                break;
-            case Position::ANY:
-                pos[depth] = 0;
-                mask[depth] = 0;
-                break;
-            case Position::FIRST:
-                pos[depth] = 1;
-                mask[depth] = 0x7f;
-                break;
-            case Position::LAST:
-                pos[depth] = 0x80;
-                mask[depth] = 0x80;
-                break;
-            case Position::POSITION_UNKNOWN:
-                pos[depth] = 0;
-                mask[depth] = 0;
-                break;
-        }
-    }
-
-    if (matcher.child_size() == 0) {
-        output->push_back(Matcher(Field(tag, pos, depth), encodeMatcherMask(mask, depth)));
-    } else {
-        for (const auto& child : matcher.child()) {
-            translateFieldMatcher(tag, child, depth + 1, pos, mask, output);
-        }
-    }
-}
-
-void translateFieldMatcher(const FieldMatcher& matcher, std::vector<Matcher>* output) {
-    int pos[] = {1, 1, 1};
-    int mask[] = {0x7f, 0x7f, 0x7f};
-    int tag = matcher.field();
-    for (const auto& child : matcher.child()) {
-        translateFieldMatcher(tag, child, 0, pos, mask, output);
-    }
-}
-
-bool isAttributionUidField(const FieldValue& value) {
-    return isAttributionUidField(value.mField, value.mValue);
-}
-
-int32_t getUidIfExists(const FieldValue& value) {
-    // the field is uid field if the field is the uid field in attribution node
-    // or annotated as such in the atom
-    bool isUid = isAttributionUidField(value) || isUidField(value);
-    return isUid ? value.mValue.int_value : -1;
-}
-
-bool isAttributionUidField(const Field& field, const Value& value) {
-    int f = field.getField() & 0xff007f;
-    if (f == 0x10001 && value.getType() == INT) {
-        return true;
-    }
-    return false;
-}
-
-bool isUidField(const FieldValue& fieldValue) {
-    return fieldValue.mAnnotations.isUidField();
-}
-
-Value::Value(const Value& from) {
-    type = from.getType();
-    switch (type) {
-        case INT:
-            int_value = from.int_value;
-            break;
-        case LONG:
-            long_value = from.long_value;
-            break;
-        case FLOAT:
-            float_value = from.float_value;
-            break;
-        case DOUBLE:
-            double_value = from.double_value;
-            break;
-        case STRING:
-            str_value = from.str_value;
-            break;
-        case STORAGE:
-            storage_value = from.storage_value;
-            break;
-        default:
-            break;
-    }
-}
-
-std::string Value::toString() const {
-    switch (type) {
-        case INT:
-            return std::to_string(int_value) + "[I]";
-        case LONG:
-            return std::to_string(long_value) + "[L]";
-        case FLOAT:
-            return std::to_string(float_value) + "[F]";
-        case DOUBLE:
-            return std::to_string(double_value) + "[D]";
-        case STRING:
-            return str_value + "[S]";
-        case STORAGE:
-            return "bytes of size " + std::to_string(storage_value.size()) + "[ST]";
-        default:
-            return "[UNKNOWN]";
-    }
-}
-
-bool Value::isZero() const {
-    switch (type) {
-        case INT:
-            return int_value == 0;
-        case LONG:
-            return long_value == 0;
-        case FLOAT:
-            return fabs(float_value) <= std::numeric_limits<float>::epsilon();
-        case DOUBLE:
-            return fabs(double_value) <= std::numeric_limits<double>::epsilon();
-        case STRING:
-            return str_value.size() == 0;
-        case STORAGE:
-            return storage_value.size() == 0;
-        default:
-            return false;
-    }
-}
-
-bool Value::operator==(const Value& that) const {
-    if (type != that.getType()) return false;
-
-    switch (type) {
-        case INT:
-            return int_value == that.int_value;
-        case LONG:
-            return long_value == that.long_value;
-        case FLOAT:
-            return float_value == that.float_value;
-        case DOUBLE:
-            return double_value == that.double_value;
-        case STRING:
-            return str_value == that.str_value;
-        case STORAGE:
-            return storage_value == that.storage_value;
-        default:
-            return false;
-    }
-}
-
-bool Value::operator!=(const Value& that) const {
-    if (type != that.getType()) return true;
-    switch (type) {
-        case INT:
-            return int_value != that.int_value;
-        case LONG:
-            return long_value != that.long_value;
-        case FLOAT:
-            return float_value != that.float_value;
-        case DOUBLE:
-            return double_value != that.double_value;
-        case STRING:
-            return str_value != that.str_value;
-        case STORAGE:
-            return storage_value != that.storage_value;
-        default:
-            return false;
-    }
-}
-
-bool Value::operator<(const Value& that) const {
-    if (type != that.getType()) return type < that.getType();
-
-    switch (type) {
-        case INT:
-            return int_value < that.int_value;
-        case LONG:
-            return long_value < that.long_value;
-        case FLOAT:
-            return float_value < that.float_value;
-        case DOUBLE:
-            return double_value < that.double_value;
-        case STRING:
-            return str_value < that.str_value;
-        case STORAGE:
-            return storage_value < that.storage_value;
-        default:
-            return false;
-    }
-}
-
-bool Value::operator>(const Value& that) const {
-    if (type != that.getType()) return type > that.getType();
-
-    switch (type) {
-        case INT:
-            return int_value > that.int_value;
-        case LONG:
-            return long_value > that.long_value;
-        case FLOAT:
-            return float_value > that.float_value;
-        case DOUBLE:
-            return double_value > that.double_value;
-        case STRING:
-            return str_value > that.str_value;
-        case STORAGE:
-            return storage_value > that.storage_value;
-        default:
-            return false;
-    }
-}
-
-bool Value::operator>=(const Value& that) const {
-    if (type != that.getType()) return type >= that.getType();
-
-    switch (type) {
-        case INT:
-            return int_value >= that.int_value;
-        case LONG:
-            return long_value >= that.long_value;
-        case FLOAT:
-            return float_value >= that.float_value;
-        case DOUBLE:
-            return double_value >= that.double_value;
-        case STRING:
-            return str_value >= that.str_value;
-        case STORAGE:
-            return storage_value >= that.storage_value;
-        default:
-            return false;
-    }
-}
-
-Value Value::operator-(const Value& that) const {
-    Value v;
-    if (type != that.type) {
-        ALOGE("Can't operate on different value types, %d, %d", type, that.type);
-        return v;
-    }
-    if (type == STRING) {
-        ALOGE("Can't operate on string value type");
-        return v;
-    }
-
-    if (type == STORAGE) {
-        ALOGE("Can't operate on storage value type");
-        return v;
-    }
-
-    switch (type) {
-        case INT:
-            v.setInt(int_value - that.int_value);
-            break;
-        case LONG:
-            v.setLong(long_value - that.long_value);
-            break;
-        case FLOAT:
-            v.setFloat(float_value - that.float_value);
-            break;
-        case DOUBLE:
-            v.setDouble(double_value - that.double_value);
-            break;
-        default:
-            break;
-    }
-    return v;
-}
-
-Value& Value::operator=(const Value& that) {
-    type = that.type;
-    switch (type) {
-        case INT:
-            int_value = that.int_value;
-            break;
-        case LONG:
-            long_value = that.long_value;
-            break;
-        case FLOAT:
-            float_value = that.float_value;
-            break;
-        case DOUBLE:
-            double_value = that.double_value;
-            break;
-        case STRING:
-            str_value = that.str_value;
-            break;
-        case STORAGE:
-            storage_value = that.storage_value;
-            break;
-        default:
-            break;
-    }
-    return *this;
-}
-
-Value& Value::operator+=(const Value& that) {
-    if (type != that.type) {
-        ALOGE("Can't operate on different value types, %d, %d", type, that.type);
-        return *this;
-    }
-    if (type == STRING) {
-        ALOGE("Can't operate on string value type");
-        return *this;
-    }
-    if (type == STORAGE) {
-        ALOGE("Can't operate on storage value type");
-        return *this;
-    }
-
-    switch (type) {
-        case INT:
-            int_value += that.int_value;
-            break;
-        case LONG:
-            long_value += that.long_value;
-            break;
-        case FLOAT:
-            float_value += that.float_value;
-            break;
-        case DOUBLE:
-            double_value += that.double_value;
-            break;
-        default:
-            break;
-    }
-    return *this;
-}
-
-double Value::getDouble() const {
-    switch (type) {
-        case INT:
-            return int_value;
-        case LONG:
-            return long_value;
-        case FLOAT:
-            return float_value;
-        case DOUBLE:
-            return double_value;
-        default:
-            return 0;
-    }
-}
-
-bool equalDimensions(const std::vector<Matcher>& dimension_a,
-                     const std::vector<Matcher>& dimension_b) {
-    bool eq = dimension_a.size() == dimension_b.size();
-    for (size_t i = 0; eq && i < dimension_a.size(); ++i) {
-        if (dimension_b[i] != dimension_a[i]) {
-            eq = false;
-        }
-    }
-    return eq;
-}
-
-bool subsetDimensions(const std::vector<Matcher>& dimension_a,
-                      const std::vector<Matcher>& dimension_b) {
-    if (dimension_a.size() > dimension_b.size()) {
-        return false;
-    }
-    for (size_t i = 0; i < dimension_a.size(); ++i) {
-        bool found = false;
-        for (size_t j = 0; j < dimension_b.size(); ++j) {
-            if (dimension_a[i] == dimension_b[j]) {
-                found = true;
-            }
-        }
-        if (!found) {
-            return false;
-        }
-    }
-    return true;
-}
-
-bool HasPositionANY(const FieldMatcher& matcher) {
-    if (matcher.has_position() && matcher.position() == Position::ANY) {
-        return true;
-    }
-    for (const auto& child : matcher.child()) {
-        if (HasPositionANY(child)) {
-            return true;
-        }
-    }
-    return false;
-}
-
-bool HasPositionALL(const FieldMatcher& matcher) {
-    if (matcher.has_position() && matcher.position() == Position::ALL) {
-        return true;
-    }
-    for (const auto& child : matcher.child()) {
-        if (HasPositionALL(child)) {
-            return true;
-        }
-    }
-    return false;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/FieldValue.h b/cmds/statsd/src/FieldValue.h
deleted file mode 100644
index fd86e36..0000000
--- a/cmds/statsd/src/FieldValue.h
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "annotations.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class HashableDimensionKey;
-struct Matcher;
-struct Field;
-struct FieldValue;
-
-const int32_t kMaxLogDepth = 2;
-const int32_t kLastBitMask = 0x80;
-const int32_t kClearLastBitDeco = 0x7f;
-const int32_t kClearAllPositionMatcherMask = 0xffff00ff;
-
-enum Type { UNKNOWN, INT, LONG, FLOAT, DOUBLE, STRING, STORAGE };
-
-int32_t getEncodedField(int32_t pos[], int32_t depth, bool includeDepth);
-
-int32_t encodeMatcherMask(int32_t mask[], int32_t depth);
-
-// Get the encoded field for a leaf with a [field] number at depth 0;
-inline int32_t getSimpleField(size_t field) {
-    return ((int32_t)field << 8 * 2);
-}
-
-/**
- * Field is a wrapper class for 2 integers that represents the field of a log element in its Atom
- * proto.
- * [mTag]: the atom id.
- * [mField]: encoded path from the root (atom) to leaf.
- *
- * For example:
- * WakeLockStateChanged {
- *    repeated AttributionNode = 1;
- *    int state = 2;
- *    string tag = 3;
- * }
- * Read from logd, the items are structured as below:
- * [[[1000, "tag"], [2000, "tag2"],], 2,"hello"]
- *
- * When we read through the list, we will encode each field in a 32bit integer.
- * 8bit segments   |--------|--------|--------|--------|
- *                    Depth   field0 [L]field1 [L]field1
- *
- *  The first 8 bits are the depth of the field. for example, the uid 1000 has depth 2.
- *  The following 3 8-bit are for the item's position at each level.
- *  The first bit of each 8bits field is reserved to mark if the item is the last item at that level
- *  this is to make matching easier later.
- *
- *  The above wakelock event is translated into FieldValue pairs.
- *  0x02010101->1000
- *  0x02010182->tag
- *  0x02018201->2000
- *  0x02018282->tag2
- *  0x00020000->2
- *  0x00030000->"hello"
- *
- *  This encoding is the building block for the later operations.
- *  Please see the definition for Matcher below to see how the matching is done.
- */
-struct Field {
-private:
-    int32_t mTag;
-    int32_t mField;
-
-public:
-    Field() {}
-
-    Field(int32_t tag, int32_t pos[], int32_t depth) : mTag(tag) {
-        mField = getEncodedField(pos, depth, true);
-    }
-
-    Field(const Field& from) : mTag(from.getTag()), mField(from.getField()) {
-    }
-
-    Field(int32_t tag, int32_t field) : mTag(tag), mField(field){};
-
-    inline void setField(int32_t field) {
-        mField = field;
-    }
-
-    inline void setTag(int32_t tag) {
-        mTag = tag;
-    }
-
-    inline void decorateLastPos(int32_t depth) {
-        int32_t mask = kLastBitMask << 8 * (kMaxLogDepth - depth);
-        mField |= mask;
-    }
-
-    inline int32_t getTag() const {
-        return mTag;
-    }
-
-    inline int32_t getDepth() const {
-        return (mField >> 24);
-    }
-
-    inline int32_t getPath(int32_t depth) const {
-        if (depth > 2 || depth < 0) return 0;
-
-        int32_t field = (mField & 0x00ffffff);
-        int32_t mask = 0xffffffff;
-        return (field & (mask << 8 * (kMaxLogDepth - depth)));
-    }
-
-    inline int32_t getPrefix(int32_t depth) const {
-        if (depth == 0) return 0;
-        return getPath(depth - 1);
-    }
-
-    inline int32_t getField() const {
-        return mField;
-    }
-
-    inline int32_t getRawPosAtDepth(int32_t depth) const {
-        int32_t field = (mField & 0x00ffffff);
-        int32_t shift = 8 * (kMaxLogDepth - depth);
-        int32_t mask = 0xff << shift;
-
-        return (field & mask) >> shift;
-    }
-
-    inline int32_t getPosAtDepth(int32_t depth) const {
-        return getRawPosAtDepth(depth) & kClearLastBitDeco;
-    }
-
-    // Check if the first bit of the 8-bit segment for depth is 1
-    inline bool isLastPos(int32_t depth) const {
-        int32_t field = (mField & 0x00ffffff);
-        int32_t mask = kLastBitMask << 8 * (kMaxLogDepth - depth);
-        return (field & mask) != 0;
-    }
-
-    // if the 8-bit segment is all 0's
-    inline bool isAnyPosMatcher(int32_t depth) const {
-        return getDepth() >= depth && getRawPosAtDepth(depth) == 0;
-    }
-    // if the 8bit is 0x80 (1000 0000)
-    inline bool isLastPosMatcher(int32_t depth) const {
-        return getDepth() >= depth && getRawPosAtDepth(depth) == kLastBitMask;
-    }
-
-    inline bool operator==(const Field& that) const {
-        return mTag == that.getTag() && mField == that.getField();
-    };
-
-    inline bool operator!=(const Field& that) const {
-        return mTag != that.getTag() || mField != that.getField();
-    };
-
-    bool operator<(const Field& that) const {
-        if (mTag != that.getTag()) {
-            return mTag < that.getTag();
-        }
-
-        if (mField != that.getField()) {
-            return mField < that.getField();
-        }
-
-        return false;
-    }
-
-    bool matches(const Matcher& that) const;
-};
-
-/**
- * Matcher represents a leaf matcher in the FieldMatcher in statsd_config.
- *
- * It contains all information needed to match one or more leaf node.
- * All information is encoded in a Field(2 ints) and a bit mask(1 int).
- *
- * For example, to match the first/any/last uid field in attribution chain in Atom 10,
- * we have the following FieldMatcher in statsd_config
- *    FieldMatcher {
- *        field:10
- *         FieldMatcher {
- *              field:1
- *              position: any/last/first
- *              FieldMatcher {
- *                  field:1
- *              }
- *          }
- *     }
- *
- * We translate the FieldMatcher into a Field, and mask
- * First: [Matcher Field] 0x02010101  [Mask]0xff7f7f7f
- * Last:  [Matcher Field] 0x02018001  [Mask]0xff7f807f
- * Any:   [Matcher Field] 0x02010001  [Mask]0xff7f007f
- * All:   [Matcher Field] 0x02010001  [Mask]0xff7f7f7f
- *
- * [To match a log Field with a Matcher] we apply the bit mask to the log Field and check if
- * the result is equal to the Matcher Field. That's a bit wise AND operation + check if 2 ints are
- * equal. Nothing can beat the performance of this matching algorithm.
- *
- * TODO(b/110561213): ADD EXAMPLE HERE.
- */
-struct Matcher {
-    Matcher(const Field& matcher, int32_t mask) : mMatcher(matcher), mMask(mask){};
-
-    const Field mMatcher;
-    const int32_t mMask;
-
-    inline const Field& getMatcher() const {
-        return mMatcher;
-    }
-
-    inline int32_t getMask() const {
-        return mMask;
-    }
-
-    inline int32_t getRawMaskAtDepth(int32_t depth) const {
-        int32_t field = (mMask & 0x00ffffff);
-        int32_t shift = 8 * (kMaxLogDepth - depth);
-        int32_t mask = 0xff << shift;
-
-        return (field & mask) >> shift;
-    }
-
-    bool hasAllPositionMatcher() const {
-        return mMatcher.getDepth() == 2 && getRawMaskAtDepth(1) == 0x7f;
-    }
-
-    bool hasAnyPositionMatcher(int* prefix) const {
-        if (mMatcher.getDepth() == 2 && mMatcher.getRawPosAtDepth(1) == 0) {
-            (*prefix) = mMatcher.getPrefix(1);
-            return true;
-        }
-        return false;
-    }
-
-    inline bool operator!=(const Matcher& that) const {
-        return mMatcher != that.getMatcher() || mMask != that.getMask();
-    }
-
-    inline bool operator==(const Matcher& that) const {
-        return mMatcher == that.mMatcher && mMask == that.mMask;
-    }
-};
-
-inline Matcher getSimpleMatcher(int32_t tag, size_t field) {
-    return Matcher(Field(tag, getSimpleField(field)), 0xff7f0000);
-}
-
-inline Matcher getFirstUidMatcher(int32_t atomId) {
-    int32_t pos[] = {1, 1, 1};
-    return Matcher(Field(atomId, pos, 2), 0xff7f7f7f);
-}
-
-/**
- * A wrapper for a union type to contain multiple types of values.
- *
- */
-struct Value {
-    Value() : type(UNKNOWN) {}
-
-    Value(int32_t v) {
-        int_value = v;
-        type = INT;
-    }
-
-    Value(int64_t v) {
-        long_value = v;
-        type = LONG;
-    }
-
-    Value(float v) {
-        float_value = v;
-        type = FLOAT;
-    }
-
-    Value(double v) {
-        double_value = v;
-        type = DOUBLE;
-    }
-
-    Value(const std::string& v) {
-        str_value = v;
-        type = STRING;
-    }
-
-    Value(const std::vector<uint8_t>& v) {
-        storage_value = v;
-        type = STORAGE;
-    }
-
-    void setInt(int32_t v) {
-        int_value = v;
-        type = INT;
-    }
-
-    void setLong(int64_t v) {
-        long_value = v;
-        type = LONG;
-    }
-
-    void setFloat(float v) {
-        float_value = v;
-        type = FLOAT;
-    }
-
-    void setDouble(double v) {
-        double_value = v;
-        type = DOUBLE;
-    }
-
-    union {
-        int32_t int_value;
-        int64_t long_value;
-        float float_value;
-        double double_value;
-    };
-    std::string str_value;
-    std::vector<uint8_t> storage_value;
-
-    Type type;
-
-    std::string toString() const;
-
-    bool isZero() const;
-
-    Type getType() const {
-        return type;
-    }
-
-    double getDouble() const;
-
-    Value(const Value& from);
-
-    bool operator==(const Value& that) const;
-    bool operator!=(const Value& that) const;
-
-    bool operator<(const Value& that) const;
-    bool operator>(const Value& that) const;
-    bool operator>=(const Value& that) const;
-    Value operator-(const Value& that) const;
-    Value& operator+=(const Value& that);
-    Value& operator=(const Value& that);
-};
-
-class Annotations {
-public:
-    Annotations() {
-        setNested(true);  // Nested = true by default
-    }
-
-    // This enum stores where particular annotations can be found in the
-    // bitmask. Note that these pos do not correspond to annotation ids.
-    enum {
-        NESTED_POS = 0x0,
-        PRIMARY_POS = 0x1,
-        EXCLUSIVE_POS = 0x2,
-        UID_POS = 0x3
-    };
-
-    inline void setNested(bool nested) { setBitmaskAtPos(NESTED_POS, nested); }
-
-    inline void setPrimaryField(bool primary) { setBitmaskAtPos(PRIMARY_POS, primary); }
-
-    inline void setExclusiveState(bool exclusive) { setBitmaskAtPos(EXCLUSIVE_POS, exclusive); }
-
-    inline void setUidField(bool isUid) { setBitmaskAtPos(UID_POS, isUid); }
-
-    // Default value = false
-    inline bool isNested() const { return getValueFromBitmask(NESTED_POS); }
-
-    // Default value = false
-    inline bool isPrimaryField() const { return getValueFromBitmask(PRIMARY_POS); }
-
-    // Default value = false
-    inline bool isExclusiveState() const { return getValueFromBitmask(EXCLUSIVE_POS); }
-
-    // Default value = false
-    inline bool isUidField() const { return getValueFromBitmask(UID_POS); }
-
-private:
-    inline void setBitmaskAtPos(int pos, bool value) {
-        mBooleanBitmask &= ~(1 << pos); // clear
-        mBooleanBitmask |= (value << pos); // set
-    }
-
-    inline bool getValueFromBitmask(int pos) const {
-        return (mBooleanBitmask >> pos) & 0x1;
-    }
-
-    // This is a bitmask over all annotations stored in boolean form. Because
-    // there are only 4 booleans, just one byte is required.
-    uint8_t mBooleanBitmask = 0;
-};
-
-/**
- * Represents a log item, or a dimension item (They are essentially the same).
- */
-struct FieldValue {
-    FieldValue() {}
-    FieldValue(const Field& field, const Value& value) : mField(field), mValue(value) {
-    }
-    bool operator==(const FieldValue& that) const {
-        return mField == that.mField && mValue == that.mValue;
-    }
-    bool operator!=(const FieldValue& that) const {
-        return mField != that.mField || mValue != that.mValue;
-    }
-    bool operator<(const FieldValue& that) const {
-        if (mField != that.mField) {
-            return mField < that.mField;
-        }
-
-        if (mValue != that.mValue) {
-            return mValue < that.mValue;
-        }
-
-        return false;
-    }
-
-    Field mField;
-    Value mValue;
-    Annotations mAnnotations;
-};
-
-bool HasPositionANY(const FieldMatcher& matcher);
-bool HasPositionALL(const FieldMatcher& matcher);
-
-bool isAttributionUidField(const FieldValue& value);
-
-/* returns uid if the field is uid field, or -1 if the field is not a uid field */
-int getUidIfExists(const FieldValue& value);
-
-void translateFieldMatcher(const FieldMatcher& matcher, std::vector<Matcher>* output);
-
-bool isAttributionUidField(const Field& field, const Value& value);
-bool isUidField(const FieldValue& fieldValue);
-
-bool equalDimensions(const std::vector<Matcher>& dimension_a,
-                     const std::vector<Matcher>& dimension_b);
-
-// Returns true if dimension_a is a subset of dimension_b.
-bool subsetDimensions(const std::vector<Matcher>& dimension_a,
-                      const std::vector<Matcher>& dimension_b);
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp
deleted file mode 100644
index eba66e0..0000000
--- a/cmds/statsd/src/HashableDimensionKey.cpp
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "HashableDimensionKey.h"
-#include "FieldValue.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using std::string;
-using std::vector;
-using android::base::StringPrintf;
-
-// These constants must be kept in sync with those in StatsDimensionsValue.java
-const static int STATS_DIMENSIONS_VALUE_STRING_TYPE = 2;
-const static int STATS_DIMENSIONS_VALUE_INT_TYPE = 3;
-const static int STATS_DIMENSIONS_VALUE_LONG_TYPE = 4;
-// const static int STATS_DIMENSIONS_VALUE_BOOL_TYPE = 5; (commented out because
-// unused -- statsd does not correctly support bool types)
-const static int STATS_DIMENSIONS_VALUE_FLOAT_TYPE = 6;
-const static int STATS_DIMENSIONS_VALUE_TUPLE_TYPE = 7;
-
-/**
- * Recursive helper function that populates a parent StatsDimensionsValueParcel
- * with children StatsDimensionsValueParcels.
- *
- * \param parent parcel that will be populated with children
- * \param childDepth depth of children FieldValues
- * \param childPrefix expected FieldValue prefix of children
- * \param dims vector of FieldValues stored by HashableDimensionKey
- * \param index position in dims to start reading children from
- */
-static void populateStatsDimensionsValueParcelChildren(StatsDimensionsValueParcel& parent,
-                                                       int childDepth, int childPrefix,
-                                                       const vector<FieldValue>& dims,
-                                                       size_t& index) {
-    if (childDepth > 2) {
-        ALOGE("Depth > 2 not supported by StatsDimensionsValueParcel.");
-        return;
-    }
-
-    while (index < dims.size()) {
-        const FieldValue& dim = dims[index];
-        int fieldDepth = dim.mField.getDepth();
-        int fieldPrefix = dim.mField.getPrefix(childDepth);
-
-        StatsDimensionsValueParcel child;
-        child.field = dim.mField.getPosAtDepth(childDepth);
-
-        if (fieldDepth == childDepth && fieldPrefix == childPrefix) {
-            switch (dim.mValue.getType()) {
-                case INT:
-                    child.valueType = STATS_DIMENSIONS_VALUE_INT_TYPE;
-                    child.intValue = dim.mValue.int_value;
-                    break;
-                case LONG:
-                    child.valueType = STATS_DIMENSIONS_VALUE_LONG_TYPE;
-                    child.longValue = dim.mValue.long_value;
-                    break;
-                case FLOAT:
-                    child.valueType = STATS_DIMENSIONS_VALUE_FLOAT_TYPE;
-                    child.floatValue = dim.mValue.float_value;
-                    break;
-                case STRING:
-                    child.valueType = STATS_DIMENSIONS_VALUE_STRING_TYPE;
-                    child.stringValue = dim.mValue.str_value;
-                    break;
-                default:
-                    ALOGE("Encountered FieldValue with unsupported value type.");
-                    break;
-            }
-            index++;
-            parent.tupleValue.push_back(child);
-        } else if (fieldDepth > childDepth && fieldPrefix == childPrefix) {
-            // This FieldValue is not a child of the current parent, but it is
-            // an indirect descendant. Thus, create a direct child of TUPLE_TYPE
-            // and recurse to parcel the indirect descendants.
-            child.valueType = STATS_DIMENSIONS_VALUE_TUPLE_TYPE;
-            populateStatsDimensionsValueParcelChildren(child, childDepth + 1,
-                                                       dim.mField.getPrefix(childDepth + 1), dims,
-                                                       index);
-            parent.tupleValue.push_back(child);
-        } else {
-            return;
-        }
-    }
-}
-
-StatsDimensionsValueParcel HashableDimensionKey::toStatsDimensionsValueParcel() const {
-    StatsDimensionsValueParcel root;
-    if (mValues.size() == 0) {
-        return root;
-    }
-
-    root.field = mValues[0].mField.getTag();
-    root.valueType = STATS_DIMENSIONS_VALUE_TUPLE_TYPE;
-
-    // Children of the root correspond to top-level (depth = 0) FieldValues.
-    int childDepth = 0;
-    int childPrefix = 0;
-    size_t index = 0;
-    populateStatsDimensionsValueParcelChildren(root, childDepth, childPrefix, mValues, index);
-
-    return root;
-}
-
-android::hash_t hashDimension(const HashableDimensionKey& value) {
-    android::hash_t hash = 0;
-    for (const auto& fieldValue : value.getValues()) {
-        hash = android::JenkinsHashMix(hash, android::hash_type((int)fieldValue.mField.getField()));
-        hash = android::JenkinsHashMix(hash, android::hash_type((int)fieldValue.mField.getTag()));
-        hash = android::JenkinsHashMix(hash, android::hash_type((int)fieldValue.mValue.getType()));
-        switch (fieldValue.mValue.getType()) {
-            case INT:
-                hash = android::JenkinsHashMix(hash,
-                                               android::hash_type(fieldValue.mValue.int_value));
-                break;
-            case LONG:
-                hash = android::JenkinsHashMix(hash,
-                                               android::hash_type(fieldValue.mValue.long_value));
-                break;
-            case STRING:
-                hash = android::JenkinsHashMix(hash, static_cast<uint32_t>(std::hash<std::string>()(
-                                                             fieldValue.mValue.str_value)));
-                break;
-            case FLOAT: {
-                hash = android::JenkinsHashMix(hash,
-                                               android::hash_type(fieldValue.mValue.float_value));
-                break;
-            }
-            default:
-                break;
-        }
-    }
-    return JenkinsHashWhiten(hash);
-}
-
-bool filterValues(const Matcher& matcherField, const vector<FieldValue>& values,
-                  FieldValue* output) {
-    for (const auto& value : values) {
-        if (value.mField.matches(matcherField)) {
-            (*output) = value;
-            return true;
-        }
-    }
-    return false;
-}
-
-bool filterValues(const vector<Matcher>& matcherFields, const vector<FieldValue>& values,
-                  HashableDimensionKey* output) {
-    size_t num_matches = 0;
-    for (const auto& value : values) {
-        for (size_t i = 0; i < matcherFields.size(); ++i) {
-            const auto& matcher = matcherFields[i];
-            if (value.mField.matches(matcher)) {
-                output->addValue(value);
-                output->mutableValue(num_matches)->mField.setTag(value.mField.getTag());
-                output->mutableValue(num_matches)->mField.setField(
-                    value.mField.getField() & matcher.mMask);
-                num_matches++;
-            }
-        }
-    }
-    return num_matches > 0;
-}
-
-bool filterPrimaryKey(const std::vector<FieldValue>& values, HashableDimensionKey* output) {
-    size_t num_matches = 0;
-    const int32_t simpleFieldMask = 0xff7f0000;
-    const int32_t attributionUidFieldMask = 0xff7f7f7f;
-    for (const auto& value : values) {
-        if (value.mAnnotations.isPrimaryField()) {
-            output->addValue(value);
-            output->mutableValue(num_matches)->mField.setTag(value.mField.getTag());
-            const int32_t mask =
-                    isAttributionUidField(value) ? attributionUidFieldMask : simpleFieldMask;
-            output->mutableValue(num_matches)->mField.setField(value.mField.getField() & mask);
-            num_matches++;
-        }
-    }
-    return num_matches > 0;
-}
-
-void filterGaugeValues(const std::vector<Matcher>& matcherFields,
-                       const std::vector<FieldValue>& values, std::vector<FieldValue>* output) {
-    for (const auto& field : matcherFields) {
-        for (const auto& value : values) {
-            if (value.mField.matches(field)) {
-                output->push_back(value);
-            }
-        }
-    }
-}
-
-void getDimensionForCondition(const std::vector<FieldValue>& eventValues,
-                              const Metric2Condition& links,
-                              HashableDimensionKey* conditionDimension) {
-    // Get the dimension first by using dimension from what.
-    filterValues(links.metricFields, eventValues, conditionDimension);
-
-    size_t count = conditionDimension->getValues().size();
-    if (count != links.conditionFields.size()) {
-        return;
-    }
-
-    for (size_t i = 0; i < count; i++) {
-        conditionDimension->mutableValue(i)->mField.setField(
-                links.conditionFields[i].mMatcher.getField());
-        conditionDimension->mutableValue(i)->mField.setTag(
-                links.conditionFields[i].mMatcher.getTag());
-    }
-}
-
-void getDimensionForState(const std::vector<FieldValue>& eventValues, const Metric2State& link,
-                          HashableDimensionKey* statePrimaryKey) {
-    // First, get the dimension from the event using the "what" fields from the
-    // MetricStateLinks.
-    filterValues(link.metricFields, eventValues, statePrimaryKey);
-
-    // Then check that the statePrimaryKey size equals the number of state fields
-    size_t count = statePrimaryKey->getValues().size();
-    if (count != link.stateFields.size()) {
-        return;
-    }
-
-    // For each dimension Value in the statePrimaryKey, set the field and tag
-    // using the state atom fields from MetricStateLinks.
-    for (size_t i = 0; i < count; i++) {
-        statePrimaryKey->mutableValue(i)->mField.setField(link.stateFields[i].mMatcher.getField());
-        statePrimaryKey->mutableValue(i)->mField.setTag(link.stateFields[i].mMatcher.getTag());
-    }
-}
-
-bool containsLinkedStateValues(const HashableDimensionKey& whatKey,
-                               const HashableDimensionKey& primaryKey,
-                               const vector<Metric2State>& stateLinks, const int32_t stateAtomId) {
-    if (whatKey.getValues().size() < primaryKey.getValues().size()) {
-        ALOGE("Contains linked values false: whatKey is too small");
-        return false;
-    }
-
-    for (const auto& primaryValue : primaryKey.getValues()) {
-        bool found = false;
-        for (const auto& whatValue : whatKey.getValues()) {
-            if (linked(stateLinks, stateAtomId, primaryValue.mField, whatValue.mField) &&
-                primaryValue.mValue == whatValue.mValue) {
-                found = true;
-                break;
-            }
-        }
-        if (!found) {
-            return false;
-        }
-    }
-    return true;
-}
-
-bool linked(const vector<Metric2State>& stateLinks, const int32_t stateAtomId,
-            const Field& stateField, const Field& metricField) {
-    for (auto stateLink : stateLinks) {
-        if (stateLink.stateAtomId != stateAtomId) {
-            continue;
-        }
-
-        for (size_t i = 0; i < stateLink.stateFields.size(); i++) {
-            if (stateLink.stateFields[i].mMatcher == stateField &&
-                stateLink.metricFields[i].mMatcher == metricField) {
-                return true;
-            }
-        }
-    }
-    return false;
-}
-
-bool LessThan(const vector<FieldValue>& s1, const vector<FieldValue>& s2) {
-    if (s1.size() != s2.size()) {
-        return s1.size() < s2.size();
-    }
-
-    size_t count = s1.size();
-    for (size_t i = 0; i < count; i++) {
-        if (s1[i] != s2[i]) {
-            return s1[i] < s2[i];
-        }
-    }
-    return false;
-}
-
-bool HashableDimensionKey::operator!=(const HashableDimensionKey& that) const {
-    return !((*this) == that);
-}
-
-bool HashableDimensionKey::operator==(const HashableDimensionKey& that) const {
-    if (mValues.size() != that.getValues().size()) {
-        return false;
-    }
-    size_t count = mValues.size();
-    for (size_t i = 0; i < count; i++) {
-        if (mValues[i] != (that.getValues())[i]) {
-            return false;
-        }
-    }
-    return true;
-};
-
-bool HashableDimensionKey::operator<(const HashableDimensionKey& that) const {
-    return LessThan(getValues(), that.getValues());
-};
-
-bool HashableDimensionKey::contains(const HashableDimensionKey& that) const {
-    if (mValues.size() < that.getValues().size()) {
-        return false;
-    }
-
-    if (mValues.size() == that.getValues().size()) {
-        return (*this) == that;
-    }
-
-    for (const auto& value : that.getValues()) {
-        bool found = false;
-        for (const auto& myValue : mValues) {
-            if (value.mField == myValue.mField && value.mValue == myValue.mValue) {
-                found = true;
-                break;
-            }
-        }
-        if (!found) {
-            return false;
-        }
-    }
-
-    return true;
-}
-
-string HashableDimensionKey::toString() const {
-    std::string output;
-    for (const auto& value : mValues) {
-        output += StringPrintf("(%d)%#x->%s ", value.mField.getTag(), value.mField.getField(),
-                               value.mValue.toString().c_str());
-    }
-    return output;
-}
-
-bool MetricDimensionKey::operator==(const MetricDimensionKey& that) const {
-    return mDimensionKeyInWhat == that.getDimensionKeyInWhat() &&
-           mStateValuesKey == that.getStateValuesKey();
-};
-
-string MetricDimensionKey::toString() const {
-    return mDimensionKeyInWhat.toString() + mStateValuesKey.toString();
-}
-
-bool MetricDimensionKey::operator<(const MetricDimensionKey& that) const {
-    if (mDimensionKeyInWhat < that.getDimensionKeyInWhat()) {
-        return true;
-    } else if (that.getDimensionKeyInWhat() < mDimensionKeyInWhat) {
-        return false;
-    }
-
-    return mStateValuesKey < that.getStateValuesKey();
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/HashableDimensionKey.h b/cmds/statsd/src/HashableDimensionKey.h
deleted file mode 100644
index bd01100..0000000
--- a/cmds/statsd/src/HashableDimensionKey.h
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <aidl/android/os/StatsDimensionsValueParcel.h>
-#include <utils/JenkinsHash.h>
-#include <vector>
-#include "android-base/stringprintf.h"
-#include "FieldValue.h"
-#include "logd/LogEvent.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using ::aidl::android::os::StatsDimensionsValueParcel;
-
-struct Metric2Condition {
-    int64_t conditionId;
-    std::vector<Matcher> metricFields;
-    std::vector<Matcher> conditionFields;
-};
-
-struct Metric2State {
-    int32_t stateAtomId;
-    std::vector<Matcher> metricFields;
-    std::vector<Matcher> stateFields;
-};
-
-class HashableDimensionKey {
-public:
-    explicit HashableDimensionKey(const std::vector<FieldValue>& values) {
-        mValues = values;
-    }
-
-    HashableDimensionKey() {};
-
-    HashableDimensionKey(const HashableDimensionKey& that) : mValues(that.getValues()){};
-
-    inline void addValue(const FieldValue& value) {
-        mValues.push_back(value);
-    }
-
-    inline const std::vector<FieldValue>& getValues() const {
-        return mValues;
-    }
-
-    inline std::vector<FieldValue>* mutableValues() {
-        return &mValues;
-    }
-
-    inline FieldValue* mutableValue(size_t i) {
-        if (i >= 0 && i < mValues.size()) {
-            return &(mValues[i]);
-        }
-        return nullptr;
-    }
-
-    StatsDimensionsValueParcel toStatsDimensionsValueParcel() const;
-
-    std::string toString() const;
-
-    bool operator!=(const HashableDimensionKey& that) const;
-
-    bool operator==(const HashableDimensionKey& that) const;
-
-    bool operator<(const HashableDimensionKey& that) const;
-
-    bool contains(const HashableDimensionKey& that) const;
-
-private:
-    std::vector<FieldValue> mValues;
-};
-
-class MetricDimensionKey {
-public:
-    explicit MetricDimensionKey(const HashableDimensionKey& dimensionKeyInWhat,
-                                const HashableDimensionKey& stateValuesKey)
-        : mDimensionKeyInWhat(dimensionKeyInWhat), mStateValuesKey(stateValuesKey){};
-
-    MetricDimensionKey(){};
-
-    MetricDimensionKey(const MetricDimensionKey& that)
-        : mDimensionKeyInWhat(that.getDimensionKeyInWhat()),
-          mStateValuesKey(that.getStateValuesKey()){};
-
-    MetricDimensionKey& operator=(const MetricDimensionKey& from) = default;
-
-    std::string toString() const;
-
-    inline const HashableDimensionKey& getDimensionKeyInWhat() const {
-        return mDimensionKeyInWhat;
-    }
-
-    inline const HashableDimensionKey& getStateValuesKey() const {
-        return mStateValuesKey;
-    }
-
-    inline HashableDimensionKey* getMutableStateValuesKey() {
-        return &mStateValuesKey;
-    }
-
-    inline void setStateValuesKey(const HashableDimensionKey& key) {
-        mStateValuesKey = key;
-    }
-
-    bool hasStateValuesKey() const {
-        return mStateValuesKey.getValues().size() > 0;
-    }
-
-    bool operator==(const MetricDimensionKey& that) const;
-
-    bool operator<(const MetricDimensionKey& that) const;
-
-private:
-    HashableDimensionKey mDimensionKeyInWhat;
-    HashableDimensionKey mStateValuesKey;
-};
-
-android::hash_t hashDimension(const HashableDimensionKey& key);
-
-/**
- * Returns true if a FieldValue field matches the matcher field.
- * The value of the FieldValue is output.
- */
-bool filterValues(const Matcher& matcherField, const std::vector<FieldValue>& values,
-                  FieldValue* output);
-
-/**
- * Creating HashableDimensionKeys from FieldValues using matcher.
- *
- * This function may make modifications to the Field if the matcher has Position=FIRST,LAST or ALL
- * in it. This is because: for example, when we create dimension from last uid in attribution chain,
- * In one event, uid 1000 is at position 5 and it's the last
- * In another event, uid 1000 is at position 6, and it's the last
- * these 2 events should be mapped to the same dimension.  So we will remove the original position
- * from the dimension key for the uid field (by applying 0x80 bit mask).
- */
-bool filterValues(const std::vector<Matcher>& matcherFields, const std::vector<FieldValue>& values,
-                  HashableDimensionKey* output);
-
-/**
- * Creating HashableDimensionKeys from State Primary Keys in FieldValues.
- *
- * This function may make modifications to the Field if the matcher has Position=FIRST,LAST or ALL
- * in it. This is because: for example, when we create dimension from last uid in attribution chain,
- * In one event, uid 1000 is at position 5 and it's the last
- * In another event, uid 1000 is at position 6, and it's the last
- * these 2 events should be mapped to the same dimension.  So we will remove the original position
- * from the dimension key for the uid field (by applying 0x80 bit mask).
- */
-bool filterPrimaryKey(const std::vector<FieldValue>& values, HashableDimensionKey* output);
-
-/**
- * Filter the values from FieldValues using the matchers.
- *
- * In contrast to the above function, this function will not do any modification to the original
- * data. Considering it as taking a snapshot on the atom event.
- */
-void filterGaugeValues(const std::vector<Matcher>& matchers, const std::vector<FieldValue>& values,
-                       std::vector<FieldValue>* output);
-
-void getDimensionForCondition(const std::vector<FieldValue>& eventValues,
-                              const Metric2Condition& links,
-                              HashableDimensionKey* conditionDimension);
-
-/**
- * Get dimension values using metric's "what" fields and fill statePrimaryKey's
- * mField information using "state" fields.
- */
-void getDimensionForState(const std::vector<FieldValue>& eventValues, const Metric2State& link,
-                          HashableDimensionKey* statePrimaryKey);
-
-/**
- * Returns true if the primaryKey values are a subset of the whatKey values.
- * The values from the primaryKey come from the state atom, so we need to
- * check that a link exists between the state atom field and what atom field.
- *
- * Example:
- * whatKey = [Atom: 10, {uid: 1005, wakelock_name: "compose"}]
- * statePrimaryKey = [Atom: 27, {uid: 1005}]
- * Returns true IF one of the Metric2State links Atom 10's uid to Atom 27's uid
- *
- * Example:
- * whatKey = [Atom: 10, {uid: 1005, wakelock_name: "compose"}]
- * statePrimaryKey = [Atom: 59, {uid: 1005, package_name: "system"}]
- * Returns false
- */
-bool containsLinkedStateValues(const HashableDimensionKey& whatKey,
-                               const HashableDimensionKey& primaryKey,
-                               const std::vector<Metric2State>& stateLinks,
-                               const int32_t stateAtomId);
-
-/**
- * Returns true if there is a Metric2State link that links the stateField and
- * the metricField (they are equal fields from different atoms).
- */
-bool linked(const std::vector<Metric2State>& stateLinks, const int32_t stateAtomId,
-            const Field& stateField, const Field& metricField);
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-namespace std {
-
-using android::os::statsd::HashableDimensionKey;
-using android::os::statsd::MetricDimensionKey;
-
-template <>
-struct hash<HashableDimensionKey> {
-    std::size_t operator()(const HashableDimensionKey& key) const {
-        return hashDimension(key);
-    }
-};
-
-template <>
-struct hash<MetricDimensionKey> {
-    std::size_t operator()(const MetricDimensionKey& key) const {
-        android::hash_t hash = hashDimension(key.getDimensionKeyInWhat());
-        hash = android::JenkinsHashMix(hash, hashDimension(key.getStateValuesKey()));
-        return android::JenkinsHashWhiten(hash);
-    }
-};
-}  // namespace std
diff --git a/cmds/statsd/src/Log.h b/cmds/statsd/src/Log.h
deleted file mode 100644
index 87f4cba..0000000
--- a/cmds/statsd/src/Log.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * This file must be included at the top of the file. Other header files
- * occasionally include log.h, and if LOG_TAG isn't set when that happens
- * we'll get a preprocesser error when we try to define it here.
- */
-
-#pragma once
-
-#define LOG_TAG "statsd"
-
-#include <log/log.h>
-
-// Use the local value to turn on/off debug logs instead of using log.tag. properties.
-// The advantage is that in production compiler can remove the logging code if the local
-// DEBUG/VERBOSE is false.
-#define VLOG(...) \
-    if (DEBUG) ALOGD(__VA_ARGS__);
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
deleted file mode 100644
index c5d9f54..0000000
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ /dev/null
@@ -1,1147 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "StatsLogProcessor.h"
-
-#include <android-base/file.h>
-#include <cutils/multiuser.h>
-#include <frameworks/base/cmds/statsd/src/active_config_list.pb.h>
-#include <frameworks/base/cmds/statsd/src/experiment_ids.pb.h>
-
-#include "StatsService.h"
-#include "android-base/stringprintf.h"
-#include "external/StatsPullerManager.h"
-#include "flags/flags.h"
-#include "guardrail/StatsdStats.h"
-#include "logd/LogEvent.h"
-#include "metrics/CountMetricProducer.h"
-#include "state/StateManager.h"
-#include "stats_log_util.h"
-#include "stats_util.h"
-#include "statslog_statsd.h"
-#include "storage/StorageManager.h"
-
-using namespace android;
-using android::base::StringPrintf;
-using android::util::FIELD_COUNT_REPEATED;
-using android::util::FIELD_TYPE_BOOL;
-using android::util::FIELD_TYPE_FLOAT;
-using android::util::FIELD_TYPE_INT32;
-using android::util::FIELD_TYPE_INT64;
-using android::util::FIELD_TYPE_MESSAGE;
-using android::util::FIELD_TYPE_STRING;
-using android::util::ProtoOutputStream;
-using std::vector;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// for ConfigMetricsReportList
-const int FIELD_ID_CONFIG_KEY = 1;
-const int FIELD_ID_REPORTS = 2;
-// for ConfigKey
-const int FIELD_ID_UID = 1;
-const int FIELD_ID_ID = 2;
-// for ConfigMetricsReport
-// const int FIELD_ID_METRICS = 1; // written in MetricsManager.cpp
-const int FIELD_ID_UID_MAP = 2;
-const int FIELD_ID_LAST_REPORT_ELAPSED_NANOS = 3;
-const int FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS = 4;
-const int FIELD_ID_LAST_REPORT_WALL_CLOCK_NANOS = 5;
-const int FIELD_ID_CURRENT_REPORT_WALL_CLOCK_NANOS = 6;
-const int FIELD_ID_DUMP_REPORT_REASON = 8;
-const int FIELD_ID_STRINGS = 9;
-
-// for ActiveConfigList
-const int FIELD_ID_ACTIVE_CONFIG_LIST_CONFIG = 1;
-
-// for permissions checks
-constexpr const char* kPermissionDump = "android.permission.DUMP";
-constexpr const char* kPermissionUsage = "android.permission.PACKAGE_USAGE_STATS";
-
-#define NS_PER_HOUR 3600 * NS_PER_SEC
-
-#define STATS_ACTIVE_METRIC_DIR "/data/misc/stats-active-metric"
-#define STATS_METADATA_DIR "/data/misc/stats-metadata"
-
-// Cool down period for writing data to disk to avoid overwriting files.
-#define WRITE_DATA_COOL_DOWN_SEC 5
-
-StatsLogProcessor::StatsLogProcessor(const sp<UidMap>& uidMap,
-                                     const sp<StatsPullerManager>& pullerManager,
-                                     const sp<AlarmMonitor>& anomalyAlarmMonitor,
-                                     const sp<AlarmMonitor>& periodicAlarmMonitor,
-                                     const int64_t timeBaseNs,
-                                     const std::function<bool(const ConfigKey&)>& sendBroadcast,
-                                     const std::function<bool(
-                                            const int&, const vector<int64_t>&)>& activateBroadcast)
-    : mUidMap(uidMap),
-      mPullerManager(pullerManager),
-      mAnomalyAlarmMonitor(anomalyAlarmMonitor),
-      mPeriodicAlarmMonitor(periodicAlarmMonitor),
-      mSendBroadcast(sendBroadcast),
-      mSendActivationBroadcast(activateBroadcast),
-      mTimeBaseNs(timeBaseNs),
-      mLargestTimestampSeen(0),
-      mLastTimestampSeen(0) {
-    mPullerManager->ForceClearPullerCache();
-    StateManager::getInstance().updateLogSources(uidMap);
-}
-
-StatsLogProcessor::~StatsLogProcessor() {
-}
-
-static void flushProtoToBuffer(ProtoOutputStream& proto, vector<uint8_t>* outData) {
-    outData->clear();
-    outData->resize(proto.size());
-    size_t pos = 0;
-    sp<android::util::ProtoReader> reader = proto.data();
-    while (reader->readBuffer() != NULL) {
-        size_t toRead = reader->currentToRead();
-        std::memcpy(&((*outData)[pos]), reader->readBuffer(), toRead);
-        pos += toRead;
-        reader->move(toRead);
-    }
-}
-
-void StatsLogProcessor::processFiredAnomalyAlarmsLocked(
-        const int64_t& timestampNs,
-        unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet) {
-    for (const auto& itr : mMetricsManagers) {
-        itr.second->onAnomalyAlarmFired(timestampNs, alarmSet);
-    }
-}
-void StatsLogProcessor::onPeriodicAlarmFired(
-        const int64_t& timestampNs,
-        unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet) {
-
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-    for (const auto& itr : mMetricsManagers) {
-        itr.second->onPeriodicAlarmFired(timestampNs, alarmSet);
-    }
-}
-
-void StatsLogProcessor::mapIsolatedUidToHostUidIfNecessaryLocked(LogEvent* event) const {
-    if (std::pair<int, int> indexRange; event->hasAttributionChain(&indexRange)) {
-        vector<FieldValue>* const fieldValues = event->getMutableValues();
-        for (int i = indexRange.first; i <= indexRange.second; i++) {
-            FieldValue& fieldValue = fieldValues->at(i);
-            if (isAttributionUidField(fieldValue)) {
-                const int hostUid = mUidMap->getHostUidOrSelf(fieldValue.mValue.int_value);
-                fieldValue.mValue.setInt(hostUid);
-            }
-        }
-    } else {
-        int uidFieldIndex = event->getUidFieldIndex();
-        if (uidFieldIndex != -1) {
-           Value& value = (*event->getMutableValues())[uidFieldIndex].mValue;
-           const int hostUid = mUidMap->getHostUidOrSelf(value.int_value);
-           value.setInt(hostUid);
-        }
-    }
-}
-
-void StatsLogProcessor::onIsolatedUidChangedEventLocked(const LogEvent& event) {
-    status_t err = NO_ERROR, err2 = NO_ERROR, err3 = NO_ERROR;
-    bool is_create = event.GetBool(3, &err);
-    auto parent_uid = int(event.GetLong(1, &err2));
-    auto isolated_uid = int(event.GetLong(2, &err3));
-    if (err == NO_ERROR && err2 == NO_ERROR && err3 == NO_ERROR) {
-        if (is_create) {
-            mUidMap->assignIsolatedUid(isolated_uid, parent_uid);
-        } else {
-            mUidMap->removeIsolatedUid(isolated_uid);
-        }
-    } else {
-        ALOGE("Failed to parse uid in the isolated uid change event.");
-    }
-}
-
-void StatsLogProcessor::onBinaryPushStateChangedEventLocked(LogEvent* event) {
-    pid_t pid = event->GetPid();
-    uid_t uid = event->GetUid();
-    if (!checkPermissionForIds(kPermissionDump, pid, uid) ||
-        !checkPermissionForIds(kPermissionUsage, pid, uid)) {
-        return;
-    }
-    // The Get* functions don't modify the status on success, they only write in
-    // failure statuses, so we can use one status variable for all calls then
-    // check if it is no longer NO_ERROR.
-    status_t err = NO_ERROR;
-    InstallTrainInfo trainInfo;
-    trainInfo.trainName = string(event->GetString(1 /*train name field id*/, &err));
-    trainInfo.trainVersionCode = event->GetLong(2 /*train version field id*/, &err);
-    trainInfo.requiresStaging = event->GetBool(3 /*requires staging field id*/, &err);
-    trainInfo.rollbackEnabled = event->GetBool(4 /*rollback enabled field id*/, &err);
-    trainInfo.requiresLowLatencyMonitor =
-            event->GetBool(5 /*requires low latency monitor field id*/, &err);
-    trainInfo.status = int32_t(event->GetLong(6 /*state field id*/, &err));
-    std::vector<uint8_t> trainExperimentIdBytes =
-            event->GetStorage(7 /*experiment ids field id*/, &err);
-    bool is_rollback = event->GetBool(10 /*is rollback field id*/, &err);
-
-    if (err != NO_ERROR) {
-        ALOGE("Failed to parse fields in binary push state changed log event");
-        return;
-    }
-    ExperimentIds trainExperimentIds;
-    if (!trainExperimentIds.ParseFromArray(trainExperimentIdBytes.data(),
-                                           trainExperimentIdBytes.size())) {
-        ALOGE("Failed to parse experimentids in binary push state changed.");
-        return;
-    }
-    trainInfo.experimentIds = {trainExperimentIds.experiment_id().begin(),
-                               trainExperimentIds.experiment_id().end()};
-
-    // Update the train info on disk and get any data the logevent is missing.
-    getAndUpdateTrainInfoOnDisk(is_rollback, &trainInfo);
-
-    std::vector<uint8_t> trainExperimentIdProto;
-    writeExperimentIdsToProto(trainInfo.experimentIds, &trainExperimentIdProto);
-    int32_t userId = multiuser_get_user_id(uid);
-
-    event->updateValue(2 /*train version field id*/, trainInfo.trainVersionCode, LONG);
-    event->updateValue(7 /*experiment ids field id*/, trainExperimentIdProto, STORAGE);
-    event->updateValue(8 /*user id field id*/, userId, INT);
-
-    // If this event is a rollback event, then the following bits in the event
-    // are invalid and we will need to update them with the values we pulled
-    // from disk.
-    if (is_rollback) {
-        int bit = trainInfo.requiresStaging ? 1 : 0;
-        event->updateValue(3 /*requires staging field id*/, bit, INT);
-        bit = trainInfo.rollbackEnabled ? 1 : 0;
-        event->updateValue(4 /*rollback enabled field id*/, bit, INT);
-        bit = trainInfo.requiresLowLatencyMonitor ? 1 : 0;
-        event->updateValue(5 /*requires low latency monitor field id*/, bit, INT);
-    }
-}
-
-void StatsLogProcessor::getAndUpdateTrainInfoOnDisk(bool is_rollback,
-                                                    InstallTrainInfo* trainInfo) {
-    // If the train name is empty, we don't know which train to attribute the
-    // event to, so return early.
-    if (trainInfo->trainName.empty()) {
-        return;
-    }
-    bool readTrainInfoSuccess = false;
-    InstallTrainInfo trainInfoOnDisk;
-    readTrainInfoSuccess = StorageManager::readTrainInfo(trainInfo->trainName, trainInfoOnDisk);
-
-    bool resetExperimentIds = false;
-    if (readTrainInfoSuccess) {
-        // Keep the old train version if we received an empty version.
-        if (trainInfo->trainVersionCode == -1) {
-            trainInfo->trainVersionCode = trainInfoOnDisk.trainVersionCode;
-        } else if (trainInfo->trainVersionCode != trainInfoOnDisk.trainVersionCode) {
-            // Reset experiment ids if we receive a new non-empty train version.
-            resetExperimentIds = true;
-        }
-
-        // Reset if we received a different experiment id.
-        if (!trainInfo->experimentIds.empty() &&
-            (trainInfoOnDisk.experimentIds.empty() ||
-             trainInfo->experimentIds.at(0) != trainInfoOnDisk.experimentIds[0])) {
-            resetExperimentIds = true;
-        }
-    }
-
-    // Find the right experiment IDs
-    if ((!resetExperimentIds || is_rollback) && readTrainInfoSuccess) {
-        trainInfo->experimentIds = trainInfoOnDisk.experimentIds;
-    }
-
-    if (!trainInfo->experimentIds.empty()) {
-        int64_t firstId = trainInfo->experimentIds.at(0);
-        auto& ids = trainInfo->experimentIds;
-        switch (trainInfo->status) {
-            case android::os::statsd::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALL_SUCCESS:
-                if (find(ids.begin(), ids.end(), firstId + 1) == ids.end()) {
-                    ids.push_back(firstId + 1);
-                }
-                break;
-            case android::os::statsd::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALLER_ROLLBACK_INITIATED:
-                if (find(ids.begin(), ids.end(), firstId + 2) == ids.end()) {
-                    ids.push_back(firstId + 2);
-                }
-                break;
-            case android::os::statsd::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALLER_ROLLBACK_SUCCESS:
-                if (find(ids.begin(), ids.end(), firstId + 3) == ids.end()) {
-                    ids.push_back(firstId + 3);
-                }
-                break;
-        }
-    }
-
-    // If this event is a rollback event, the following fields are invalid and
-    // need to be replaced by the fields stored to disk.
-    if (is_rollback) {
-        trainInfo->requiresStaging = trainInfoOnDisk.requiresStaging;
-        trainInfo->rollbackEnabled = trainInfoOnDisk.rollbackEnabled;
-        trainInfo->requiresLowLatencyMonitor = trainInfoOnDisk.requiresLowLatencyMonitor;
-    }
-
-    StorageManager::writeTrainInfo(*trainInfo);
-}
-
-void StatsLogProcessor::onWatchdogRollbackOccurredLocked(LogEvent* event) {
-    pid_t pid = event->GetPid();
-    uid_t uid = event->GetUid();
-    if (!checkPermissionForIds(kPermissionDump, pid, uid) ||
-        !checkPermissionForIds(kPermissionUsage, pid, uid)) {
-        return;
-    }
-    // The Get* functions don't modify the status on success, they only write in
-    // failure statuses, so we can use one status variable for all calls then
-    // check if it is no longer NO_ERROR.
-    status_t err = NO_ERROR;
-    int32_t rollbackType = int32_t(event->GetInt(1 /*rollback type field id*/, &err));
-    string packageName = string(event->GetString(2 /*package name field id*/, &err));
-
-    if (err != NO_ERROR) {
-        ALOGE("Failed to parse fields in watchdog rollback occurred log event");
-        return;
-    }
-
-    vector<int64_t> experimentIds =
-        processWatchdogRollbackOccurred(rollbackType, packageName);
-    vector<uint8_t> experimentIdProto;
-    writeExperimentIdsToProto(experimentIds, &experimentIdProto);
-
-    event->updateValue(6 /*experiment ids field id*/, experimentIdProto, STORAGE);
-}
-
-vector<int64_t> StatsLogProcessor::processWatchdogRollbackOccurred(const int32_t rollbackTypeIn,
-                                                                    const string& packageNameIn) {
-    // If the package name is empty, we can't attribute it to any train, so
-    // return early.
-    if (packageNameIn.empty()) {
-      return vector<int64_t>();
-    }
-    bool readTrainInfoSuccess = false;
-    InstallTrainInfo trainInfoOnDisk;
-    // We use the package name of the event as the train name.
-    readTrainInfoSuccess = StorageManager::readTrainInfo(packageNameIn, trainInfoOnDisk);
-
-    if (!readTrainInfoSuccess) {
-        return vector<int64_t>();
-    }
-
-    if (trainInfoOnDisk.experimentIds.empty()) {
-        return vector<int64_t>();
-    }
-
-    int64_t firstId = trainInfoOnDisk.experimentIds[0];
-    auto& ids = trainInfoOnDisk.experimentIds;
-    switch (rollbackTypeIn) {
-      case android::os::statsd::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE:
-            if (find(ids.begin(), ids.end(), firstId + 4) == ids.end()) {
-                ids.push_back(firstId + 4);
-            }
-            StorageManager::writeTrainInfo(trainInfoOnDisk);
-            break;
-      case android::os::statsd::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS:
-            if (find(ids.begin(), ids.end(), firstId + 5) == ids.end()) {
-                ids.push_back(firstId + 5);
-            }
-            StorageManager::writeTrainInfo(trainInfoOnDisk);
-            break;
-    }
-
-    return trainInfoOnDisk.experimentIds;
-}
-
-void StatsLogProcessor::resetConfigs() {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-    resetConfigsLocked(getElapsedRealtimeNs());
-}
-
-void StatsLogProcessor::resetConfigsLocked(const int64_t timestampNs) {
-    std::vector<ConfigKey> configKeys;
-    for (auto it = mMetricsManagers.begin(); it != mMetricsManagers.end(); it++) {
-        configKeys.push_back(it->first);
-    }
-    resetConfigsLocked(timestampNs, configKeys);
-}
-
-void StatsLogProcessor::OnLogEvent(LogEvent* event) {
-    OnLogEvent(event, getElapsedRealtimeNs());
-}
-
-void StatsLogProcessor::OnLogEvent(LogEvent* event, int64_t elapsedRealtimeNs) {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-
-    // Tell StatsdStats about new event
-    const int64_t eventElapsedTimeNs = event->GetElapsedTimestampNs();
-    int atomId = event->GetTagId();
-    StatsdStats::getInstance().noteAtomLogged(atomId, eventElapsedTimeNs / NS_PER_SEC);
-    if (!event->isValid()) {
-        StatsdStats::getInstance().noteAtomError(atomId);
-        return;
-    }
-
-    // Hard-coded logic to update train info on disk and fill in any information
-    // this log event may be missing.
-    if (atomId == android::os::statsd::util::BINARY_PUSH_STATE_CHANGED) {
-        onBinaryPushStateChangedEventLocked(event);
-    }
-
-    // Hard-coded logic to update experiment ids on disk for certain rollback
-    // types and fill the rollback atom with experiment ids
-    if (atomId == android::os::statsd::util::WATCHDOG_ROLLBACK_OCCURRED) {
-        onWatchdogRollbackOccurredLocked(event);
-    }
-
-    if (mPrintAllLogs) {
-        ALOGI("%s", event->ToString().c_str());
-    }
-    resetIfConfigTtlExpiredLocked(eventElapsedTimeNs);
-
-    // Hard-coded logic to update the isolated uid's in the uid-map.
-    // The field numbers need to be currently updated by hand with atoms.proto
-    if (atomId == android::os::statsd::util::ISOLATED_UID_CHANGED) {
-        onIsolatedUidChangedEventLocked(*event);
-    } else {
-        // Map the isolated uid to host uid if necessary.
-        mapIsolatedUidToHostUidIfNecessaryLocked(event);
-    }
-
-    StateManager::getInstance().onLogEvent(*event);
-
-    if (mMetricsManagers.empty()) {
-        return;
-    }
-
-    bool fireAlarm = false;
-    {
-        std::lock_guard<std::mutex> anomalyLock(mAnomalyAlarmMutex);
-        if (mNextAnomalyAlarmTime != 0 &&
-            MillisToNano(mNextAnomalyAlarmTime) <= elapsedRealtimeNs) {
-            mNextAnomalyAlarmTime = 0;
-            VLOG("informing anomaly alarm at time %lld", (long long)elapsedRealtimeNs);
-            fireAlarm = true;
-        }
-    }
-    if (fireAlarm) {
-        informAnomalyAlarmFiredLocked(NanoToMillis(elapsedRealtimeNs));
-    }
-
-    int64_t curTimeSec = getElapsedRealtimeSec();
-    if (curTimeSec - mLastPullerCacheClearTimeSec > StatsdStats::kPullerCacheClearIntervalSec) {
-        mPullerManager->ClearPullerCacheIfNecessary(curTimeSec * NS_PER_SEC);
-        mLastPullerCacheClearTimeSec = curTimeSec;
-    }
-
-    std::unordered_set<int> uidsWithActiveConfigsChanged;
-    std::unordered_map<int, std::vector<int64_t>> activeConfigsPerUid;
-    // pass the event to metrics managers.
-    for (auto& pair : mMetricsManagers) {
-        int uid = pair.first.GetUid();
-        int64_t configId = pair.first.GetId();
-        bool isPrevActive = pair.second->isActive();
-        pair.second->onLogEvent(*event);
-        bool isCurActive = pair.second->isActive();
-        // Map all active configs by uid.
-        if (isCurActive) {
-            auto activeConfigs = activeConfigsPerUid.find(uid);
-            if (activeConfigs != activeConfigsPerUid.end()) {
-                activeConfigs->second.push_back(configId);
-            } else {
-                vector<int64_t> newActiveConfigs;
-                newActiveConfigs.push_back(configId);
-                activeConfigsPerUid[uid] = newActiveConfigs;
-            }
-        }
-        // The activation state of this config changed.
-        if (isPrevActive != isCurActive) {
-            VLOG("Active status changed for uid  %d", uid);
-            uidsWithActiveConfigsChanged.insert(uid);
-            StatsdStats::getInstance().noteActiveStatusChanged(pair.first, isCurActive);
-        }
-        flushIfNecessaryLocked(pair.first, *(pair.second));
-    }
-
-    // Don't use the event timestamp for the guardrail.
-    for (int uid : uidsWithActiveConfigsChanged) {
-        // Send broadcast so that receivers can pull data.
-        auto lastBroadcastTime = mLastActivationBroadcastTimes.find(uid);
-        if (lastBroadcastTime != mLastActivationBroadcastTimes.end()) {
-            if (elapsedRealtimeNs - lastBroadcastTime->second <
-                StatsdStats::kMinActivationBroadcastPeriodNs) {
-                StatsdStats::getInstance().noteActivationBroadcastGuardrailHit(uid);
-                VLOG("StatsD would've sent an activation broadcast but the rate limit stopped us.");
-                return;
-            }
-        }
-        auto activeConfigs = activeConfigsPerUid.find(uid);
-        if (activeConfigs != activeConfigsPerUid.end()) {
-            if (mSendActivationBroadcast(uid, activeConfigs->second)) {
-                VLOG("StatsD sent activation notice for uid %d", uid);
-                mLastActivationBroadcastTimes[uid] = elapsedRealtimeNs;
-            }
-        } else {
-            std::vector<int64_t> emptyActiveConfigs;
-            if (mSendActivationBroadcast(uid, emptyActiveConfigs)) {
-                VLOG("StatsD sent EMPTY activation notice for uid %d", uid);
-                mLastActivationBroadcastTimes[uid] = elapsedRealtimeNs;
-            }
-        }
-    }
-}
-
-void StatsLogProcessor::GetActiveConfigs(const int uid, vector<int64_t>& outActiveConfigs) {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-    GetActiveConfigsLocked(uid, outActiveConfigs);
-}
-
-void StatsLogProcessor::GetActiveConfigsLocked(const int uid, vector<int64_t>& outActiveConfigs) {
-    outActiveConfigs.clear();
-    for (auto& pair : mMetricsManagers) {
-        if (pair.first.GetUid() == uid && pair.second->isActive()) {
-            outActiveConfigs.push_back(pair.first.GetId());
-        }
-    }
-}
-
-void StatsLogProcessor::OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key,
-                                        const StatsdConfig& config) {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-    WriteDataToDiskLocked(key, timestampNs, CONFIG_UPDATED, NO_TIME_CONSTRAINTS);
-    bool modularUpdate = getFlagBool(PARTIAL_CONFIG_UPDATE_FLAG, "false");
-    OnConfigUpdatedLocked(timestampNs, key, config, modularUpdate);
-}
-
-void StatsLogProcessor::OnConfigUpdatedLocked(const int64_t timestampNs, const ConfigKey& key,
-                                              const StatsdConfig& config, bool modularUpdate) {
-    VLOG("Updated configuration for key %s", key.ToString().c_str());
-    // Create new config if this is not a modular update or if this is a new config.
-    const auto& it = mMetricsManagers.find(key);
-    bool configValid = false;
-    if (!modularUpdate || it == mMetricsManagers.end()) {
-        sp<MetricsManager> newMetricsManager =
-                new MetricsManager(key, config, mTimeBaseNs, timestampNs, mUidMap, mPullerManager,
-                                   mAnomalyAlarmMonitor, mPeriodicAlarmMonitor);
-        configValid = newMetricsManager->isConfigValid();
-        if (configValid) {
-            newMetricsManager->init();
-            mUidMap->OnConfigUpdated(key);
-            newMetricsManager->refreshTtl(timestampNs);
-            mMetricsManagers[key] = newMetricsManager;
-            VLOG("StatsdConfig valid");
-        }
-    } else {
-        // Preserve the existing MetricsManager, update necessary components and metadata in place.
-        configValid = it->second->updateConfig(config, mTimeBaseNs, timestampNs,
-                                               mAnomalyAlarmMonitor, mPeriodicAlarmMonitor);
-        if (configValid) {
-            mUidMap->OnConfigUpdated(key);
-        }
-    }
-    if (!configValid) {
-        // If there is any error in the config, don't use it.
-        // Remove any existing config with the same key.
-        ALOGE("StatsdConfig NOT valid");
-        mMetricsManagers.erase(key);
-    }
-}
-
-size_t StatsLogProcessor::GetMetricsSize(const ConfigKey& key) const {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-    auto it = mMetricsManagers.find(key);
-    if (it == mMetricsManagers.end()) {
-        ALOGW("Config source %s does not exist", key.ToString().c_str());
-        return 0;
-    }
-    return it->second->byteSize();
-}
-
-void StatsLogProcessor::dumpStates(int out, bool verbose) {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-    FILE* fout = fdopen(out, "w");
-    if (fout == NULL) {
-        return;
-    }
-    fprintf(fout, "MetricsManager count: %lu\n", (unsigned long)mMetricsManagers.size());
-    for (auto metricsManager : mMetricsManagers) {
-        metricsManager.second->dumpStates(fout, verbose);
-    }
-
-    fclose(fout);
-}
-
-/*
- * onDumpReport dumps serialized ConfigMetricsReportList into proto.
- */
-void StatsLogProcessor::onDumpReport(const ConfigKey& key, const int64_t dumpTimeStampNs,
-                                     const bool include_current_partial_bucket,
-                                     const bool erase_data,
-                                     const DumpReportReason dumpReportReason,
-                                     const DumpLatency dumpLatency,
-                                     ProtoOutputStream* proto) {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-
-    // Start of ConfigKey.
-    uint64_t configKeyToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_ID_CONFIG_KEY);
-    proto->write(FIELD_TYPE_INT32 | FIELD_ID_UID, key.GetUid());
-    proto->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)key.GetId());
-    proto->end(configKeyToken);
-    // End of ConfigKey.
-
-    bool keepFile = false;
-    auto it = mMetricsManagers.find(key);
-    if (it != mMetricsManagers.end() && it->second->shouldPersistLocalHistory()) {
-        keepFile = true;
-    }
-
-    // Then, check stats-data directory to see there's any file containing
-    // ConfigMetricsReport from previous shutdowns to concatenate to reports.
-    StorageManager::appendConfigMetricsReport(
-            key, proto, erase_data && !keepFile /* should remove file after appending it */,
-            dumpReportReason == ADB_DUMP /*if caller is adb*/);
-
-    if (it != mMetricsManagers.end()) {
-        // This allows another broadcast to be sent within the rate-limit period if we get close to
-        // filling the buffer again soon.
-        mLastBroadcastTimes.erase(key);
-
-        vector<uint8_t> buffer;
-        onConfigMetricsReportLocked(key, dumpTimeStampNs, include_current_partial_bucket,
-                                    erase_data, dumpReportReason, dumpLatency,
-                                    false /* is this data going to be saved on disk */, &buffer);
-        proto->write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS,
-                     reinterpret_cast<char*>(buffer.data()), buffer.size());
-    } else {
-        ALOGW("Config source %s does not exist", key.ToString().c_str());
-    }
-}
-
-/*
- * onDumpReport dumps serialized ConfigMetricsReportList into outData.
- */
-void StatsLogProcessor::onDumpReport(const ConfigKey& key, const int64_t dumpTimeStampNs,
-                                     const bool include_current_partial_bucket,
-                                     const bool erase_data,
-                                     const DumpReportReason dumpReportReason,
-                                     const DumpLatency dumpLatency,
-                                     vector<uint8_t>* outData) {
-    ProtoOutputStream proto;
-    onDumpReport(key, dumpTimeStampNs, include_current_partial_bucket, erase_data,
-                 dumpReportReason, dumpLatency, &proto);
-
-    if (outData != nullptr) {
-        flushProtoToBuffer(proto, outData);
-        VLOG("output data size %zu", outData->size());
-    }
-
-    StatsdStats::getInstance().noteMetricsReportSent(key, proto.size());
-}
-
-/*
- * onConfigMetricsReportLocked dumps serialized ConfigMetricsReport into outData.
- */
-void StatsLogProcessor::onConfigMetricsReportLocked(
-        const ConfigKey& key, const int64_t dumpTimeStampNs,
-        const bool include_current_partial_bucket, const bool erase_data,
-        const DumpReportReason dumpReportReason, const DumpLatency dumpLatency,
-        const bool dataSavedOnDisk, vector<uint8_t>* buffer) {
-    // We already checked whether key exists in mMetricsManagers in
-    // WriteDataToDisk.
-    auto it = mMetricsManagers.find(key);
-    if (it == mMetricsManagers.end()) {
-        return;
-    }
-    int64_t lastReportTimeNs = it->second->getLastReportTimeNs();
-    int64_t lastReportWallClockNs = it->second->getLastReportWallClockNs();
-
-    std::set<string> str_set;
-
-    ProtoOutputStream tempProto;
-    // First, fill in ConfigMetricsReport using current data on memory, which
-    // starts from filling in StatsLogReport's.
-    it->second->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, erase_data,
-                             dumpLatency, &str_set, &tempProto);
-
-    // Fill in UidMap if there is at least one metric to report.
-    // This skips the uid map if it's an empty config.
-    if (it->second->getNumMetrics() > 0) {
-        uint64_t uidMapToken = tempProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP);
-        mUidMap->appendUidMap(
-                dumpTimeStampNs, key, it->second->hashStringInReport() ? &str_set : nullptr,
-                it->second->versionStringsInReport(), it->second->installerInReport(), &tempProto);
-        tempProto.end(uidMapToken);
-    }
-
-    // Fill in the timestamps.
-    tempProto.write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_ELAPSED_NANOS,
-                    (long long)lastReportTimeNs);
-    tempProto.write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS,
-                    (long long)dumpTimeStampNs);
-    tempProto.write(FIELD_TYPE_INT64 | FIELD_ID_LAST_REPORT_WALL_CLOCK_NANOS,
-                    (long long)lastReportWallClockNs);
-    tempProto.write(FIELD_TYPE_INT64 | FIELD_ID_CURRENT_REPORT_WALL_CLOCK_NANOS,
-                    (long long)getWallClockNs());
-    // Dump report reason
-    tempProto.write(FIELD_TYPE_INT32 | FIELD_ID_DUMP_REPORT_REASON, dumpReportReason);
-
-    for (const auto& str : str_set) {
-        tempProto.write(FIELD_TYPE_STRING | FIELD_COUNT_REPEATED | FIELD_ID_STRINGS, str);
-    }
-
-    flushProtoToBuffer(tempProto, buffer);
-
-    // save buffer to disk if needed
-    if (erase_data && !dataSavedOnDisk && it->second->shouldPersistLocalHistory()) {
-        VLOG("save history to disk");
-        string file_name = StorageManager::getDataHistoryFileName((long)getWallClockSec(),
-                                                                  key.GetUid(), key.GetId());
-        StorageManager::writeFile(file_name.c_str(), buffer->data(), buffer->size());
-    }
-}
-
-void StatsLogProcessor::resetConfigsLocked(const int64_t timestampNs,
-                                           const std::vector<ConfigKey>& configs) {
-    for (const auto& key : configs) {
-        StatsdConfig config;
-        if (StorageManager::readConfigFromDisk(key, &config)) {
-            // Force a full update when resetting a config.
-            OnConfigUpdatedLocked(timestampNs, key, config, /*modularUpdate=*/false);
-            StatsdStats::getInstance().noteConfigReset(key);
-        } else {
-            ALOGE("Failed to read backup config from disk for : %s", key.ToString().c_str());
-            auto it = mMetricsManagers.find(key);
-            if (it != mMetricsManagers.end()) {
-                it->second->refreshTtl(timestampNs);
-            }
-        }
-    }
-}
-
-void StatsLogProcessor::resetIfConfigTtlExpiredLocked(const int64_t timestampNs) {
-    std::vector<ConfigKey> configKeysTtlExpired;
-    for (auto it = mMetricsManagers.begin(); it != mMetricsManagers.end(); it++) {
-        if (it->second != nullptr && !it->second->isInTtl(timestampNs)) {
-            configKeysTtlExpired.push_back(it->first);
-        }
-    }
-    if (configKeysTtlExpired.size() > 0) {
-        WriteDataToDiskLocked(CONFIG_RESET, NO_TIME_CONSTRAINTS);
-        resetConfigsLocked(timestampNs, configKeysTtlExpired);
-    }
-}
-
-void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-    auto it = mMetricsManagers.find(key);
-    if (it != mMetricsManagers.end()) {
-        WriteDataToDiskLocked(key, getElapsedRealtimeNs(), CONFIG_REMOVED,
-                              NO_TIME_CONSTRAINTS);
-        mMetricsManagers.erase(it);
-        mUidMap->OnConfigRemoved(key);
-    }
-    StatsdStats::getInstance().noteConfigRemoved(key);
-
-    mLastBroadcastTimes.erase(key);
-
-    int uid = key.GetUid();
-    bool lastConfigForUid = true;
-    for (auto it : mMetricsManagers) {
-        if (it.first.GetUid() == uid) {
-            lastConfigForUid = false;
-            break;
-        }
-    }
-    if (lastConfigForUid) {
-        mLastActivationBroadcastTimes.erase(uid);
-    }
-
-    if (mMetricsManagers.empty()) {
-        mPullerManager->ForceClearPullerCache();
-    }
-}
-
-void StatsLogProcessor::flushIfNecessaryLocked(const ConfigKey& key,
-                                               MetricsManager& metricsManager) {
-    int64_t elapsedRealtimeNs = getElapsedRealtimeNs();
-    auto lastCheckTime = mLastByteSizeTimes.find(key);
-    if (lastCheckTime != mLastByteSizeTimes.end()) {
-        if (elapsedRealtimeNs - lastCheckTime->second < StatsdStats::kMinByteSizeCheckPeriodNs) {
-            return;
-        }
-    }
-
-    // We suspect that the byteSize() computation is expensive, so we set a rate limit.
-    size_t totalBytes = metricsManager.byteSize();
-    mLastByteSizeTimes[key] = elapsedRealtimeNs;
-    bool requestDump = false;
-    if (totalBytes > StatsdStats::kMaxMetricsBytesPerConfig) {
-        // Too late. We need to start clearing data.
-        metricsManager.dropData(elapsedRealtimeNs);
-        StatsdStats::getInstance().noteDataDropped(key, totalBytes);
-        VLOG("StatsD had to toss out metrics for %s", key.ToString().c_str());
-    } else if ((totalBytes > StatsdStats::kBytesPerConfigTriggerGetData) ||
-               (mOnDiskDataConfigs.find(key) != mOnDiskDataConfigs.end())) {
-        // Request to send a broadcast if:
-        // 1. in memory data > threshold   OR
-        // 2. config has old data report on disk.
-        requestDump = true;
-    }
-
-    if (requestDump) {
-        // Send broadcast so that receivers can pull data.
-        auto lastBroadcastTime = mLastBroadcastTimes.find(key);
-        if (lastBroadcastTime != mLastBroadcastTimes.end()) {
-            if (elapsedRealtimeNs - lastBroadcastTime->second <
-                    StatsdStats::kMinBroadcastPeriodNs) {
-                VLOG("StatsD would've sent a broadcast but the rate limit stopped us.");
-                return;
-            }
-        }
-        if (mSendBroadcast(key)) {
-            mOnDiskDataConfigs.erase(key);
-            VLOG("StatsD triggered data fetch for %s", key.ToString().c_str());
-            mLastBroadcastTimes[key] = elapsedRealtimeNs;
-            StatsdStats::getInstance().noteBroadcastSent(key);
-        }
-    }
-}
-
-void StatsLogProcessor::WriteDataToDiskLocked(const ConfigKey& key,
-                                              const int64_t timestampNs,
-                                              const DumpReportReason dumpReportReason,
-                                              const DumpLatency dumpLatency) {
-    if (mMetricsManagers.find(key) == mMetricsManagers.end() ||
-        !mMetricsManagers.find(key)->second->shouldWriteToDisk()) {
-        return;
-    }
-    vector<uint8_t> buffer;
-    onConfigMetricsReportLocked(key, timestampNs, true /* include_current_partial_bucket*/,
-                                true /* erase_data */, dumpReportReason, dumpLatency, true,
-                                &buffer);
-    string file_name =
-            StorageManager::getDataFileName((long)getWallClockSec(), key.GetUid(), key.GetId());
-    StorageManager::writeFile(file_name.c_str(), buffer.data(), buffer.size());
-
-    // We were able to write the ConfigMetricsReport to disk, so we should trigger collection ASAP.
-    mOnDiskDataConfigs.insert(key);
-}
-
-void StatsLogProcessor::SaveActiveConfigsToDisk(int64_t currentTimeNs) {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-    const int64_t timeNs = getElapsedRealtimeNs();
-    // Do not write to disk if we already have in the last few seconds.
-    if (static_cast<unsigned long long> (timeNs) <
-            mLastActiveMetricsWriteNs + WRITE_DATA_COOL_DOWN_SEC * NS_PER_SEC) {
-        ALOGI("Statsd skipping writing active metrics to disk. Already wrote data in last %d seconds",
-                WRITE_DATA_COOL_DOWN_SEC);
-        return;
-    }
-    mLastActiveMetricsWriteNs = timeNs;
-
-    ProtoOutputStream proto;
-    WriteActiveConfigsToProtoOutputStreamLocked(currentTimeNs, DEVICE_SHUTDOWN, &proto);
-
-    string file_name = StringPrintf("%s/active_metrics", STATS_ACTIVE_METRIC_DIR);
-    StorageManager::deleteFile(file_name.c_str());
-    android::base::unique_fd fd(
-            open(file_name.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR));
-    if (fd == -1) {
-        ALOGE("Attempt to write %s but failed", file_name.c_str());
-        return;
-    }
-    proto.flush(fd.get());
-}
-
-void StatsLogProcessor::SaveMetadataToDisk(int64_t currentWallClockTimeNs,
-                                           int64_t systemElapsedTimeNs) {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-    // Do not write to disk if we already have in the last few seconds.
-    if (static_cast<unsigned long long> (systemElapsedTimeNs) <
-            mLastMetadataWriteNs + WRITE_DATA_COOL_DOWN_SEC * NS_PER_SEC) {
-        ALOGI("Statsd skipping writing metadata to disk. Already wrote data in last %d seconds",
-                WRITE_DATA_COOL_DOWN_SEC);
-        return;
-    }
-    mLastMetadataWriteNs = systemElapsedTimeNs;
-
-    metadata::StatsMetadataList metadataList;
-    WriteMetadataToProtoLocked(
-            currentWallClockTimeNs, systemElapsedTimeNs, &metadataList);
-
-    string file_name = StringPrintf("%s/metadata", STATS_METADATA_DIR);
-    StorageManager::deleteFile(file_name.c_str());
-
-    if (metadataList.stats_metadata_size() == 0) {
-        // Skip the write if we have nothing to write.
-        return;
-    }
-
-    std::string data;
-    metadataList.SerializeToString(&data);
-    StorageManager::writeFile(file_name.c_str(), data.c_str(), data.size());
-}
-
-void StatsLogProcessor::WriteMetadataToProto(int64_t currentWallClockTimeNs,
-                                             int64_t systemElapsedTimeNs,
-                                             metadata::StatsMetadataList* metadataList) {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-    WriteMetadataToProtoLocked(currentWallClockTimeNs, systemElapsedTimeNs, metadataList);
-}
-
-void StatsLogProcessor::WriteMetadataToProtoLocked(int64_t currentWallClockTimeNs,
-                                                   int64_t systemElapsedTimeNs,
-                                                   metadata::StatsMetadataList* metadataList) {
-    for (const auto& pair : mMetricsManagers) {
-        const sp<MetricsManager>& metricsManager = pair.second;
-        metadata::StatsMetadata* statsMetadata = metadataList->add_stats_metadata();
-        bool metadataWritten = metricsManager->writeMetadataToProto(currentWallClockTimeNs,
-                systemElapsedTimeNs, statsMetadata);
-        if (!metadataWritten) {
-            metadataList->mutable_stats_metadata()->RemoveLast();
-        }
-    }
-}
-
-void StatsLogProcessor::LoadMetadataFromDisk(int64_t currentWallClockTimeNs,
-                                             int64_t systemElapsedTimeNs) {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-    string file_name = StringPrintf("%s/metadata", STATS_METADATA_DIR);
-    int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC);
-    if (-1 == fd) {
-        VLOG("Attempt to read %s but failed", file_name.c_str());
-        StorageManager::deleteFile(file_name.c_str());
-        return;
-    }
-    string content;
-    if (!android::base::ReadFdToString(fd, &content)) {
-        ALOGE("Attempt to read %s but failed", file_name.c_str());
-        close(fd);
-        StorageManager::deleteFile(file_name.c_str());
-        return;
-    }
-
-    close(fd);
-
-    metadata::StatsMetadataList statsMetadataList;
-    if (!statsMetadataList.ParseFromString(content)) {
-        ALOGE("Attempt to read %s but failed; failed to metadata", file_name.c_str());
-        StorageManager::deleteFile(file_name.c_str());
-        return;
-    }
-    SetMetadataStateLocked(statsMetadataList, currentWallClockTimeNs, systemElapsedTimeNs);
-    StorageManager::deleteFile(file_name.c_str());
-}
-
-void StatsLogProcessor::SetMetadataState(const metadata::StatsMetadataList& statsMetadataList,
-                                         int64_t currentWallClockTimeNs,
-                                         int64_t systemElapsedTimeNs) {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-    SetMetadataStateLocked(statsMetadataList, currentWallClockTimeNs, systemElapsedTimeNs);
-}
-
-void StatsLogProcessor::SetMetadataStateLocked(
-        const metadata::StatsMetadataList& statsMetadataList,
-        int64_t currentWallClockTimeNs,
-        int64_t systemElapsedTimeNs) {
-    for (const metadata::StatsMetadata& metadata : statsMetadataList.stats_metadata()) {
-        ConfigKey key(metadata.config_key().uid(), metadata.config_key().config_id());
-        auto it = mMetricsManagers.find(key);
-        if (it == mMetricsManagers.end()) {
-            ALOGE("No config found for configKey %s", key.ToString().c_str());
-            continue;
-        }
-        VLOG("Setting metadata %s", key.ToString().c_str());
-        it->second->loadMetadata(metadata, currentWallClockTimeNs, systemElapsedTimeNs);
-    }
-    VLOG("Successfully loaded %d metadata.", statsMetadataList.stats_metadata_size());
-}
-
-void StatsLogProcessor::WriteActiveConfigsToProtoOutputStream(
-        int64_t currentTimeNs, const DumpReportReason reason, ProtoOutputStream* proto) {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-    WriteActiveConfigsToProtoOutputStreamLocked(currentTimeNs, reason, proto);
-}
-
-void StatsLogProcessor::WriteActiveConfigsToProtoOutputStreamLocked(
-        int64_t currentTimeNs,  const DumpReportReason reason, ProtoOutputStream* proto) {
-    for (const auto& pair : mMetricsManagers) {
-        const sp<MetricsManager>& metricsManager = pair.second;
-        uint64_t configToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                                     FIELD_ID_ACTIVE_CONFIG_LIST_CONFIG);
-        metricsManager->writeActiveConfigToProtoOutputStream(currentTimeNs, reason, proto);
-        proto->end(configToken);
-    }
-}
-void StatsLogProcessor::LoadActiveConfigsFromDisk() {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-    string file_name = StringPrintf("%s/active_metrics", STATS_ACTIVE_METRIC_DIR);
-    int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC);
-    if (-1 == fd) {
-        VLOG("Attempt to read %s but failed", file_name.c_str());
-        StorageManager::deleteFile(file_name.c_str());
-        return;
-    }
-    string content;
-    if (!android::base::ReadFdToString(fd, &content)) {
-        ALOGE("Attempt to read %s but failed", file_name.c_str());
-        close(fd);
-        StorageManager::deleteFile(file_name.c_str());
-        return;
-    }
-
-    close(fd);
-
-    ActiveConfigList activeConfigList;
-    if (!activeConfigList.ParseFromString(content)) {
-        ALOGE("Attempt to read %s but failed; failed to load active configs", file_name.c_str());
-        StorageManager::deleteFile(file_name.c_str());
-        return;
-    }
-    // Passing in mTimeBaseNs only works as long as we only load from disk is when statsd starts.
-    SetConfigsActiveStateLocked(activeConfigList, mTimeBaseNs);
-    StorageManager::deleteFile(file_name.c_str());
-}
-
-void StatsLogProcessor::SetConfigsActiveState(const ActiveConfigList& activeConfigList,
-                                                    int64_t currentTimeNs) {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-    SetConfigsActiveStateLocked(activeConfigList, currentTimeNs);
-}
-
-void StatsLogProcessor::SetConfigsActiveStateLocked(const ActiveConfigList& activeConfigList,
-                                                    int64_t currentTimeNs) {
-    for (int i = 0; i < activeConfigList.config_size(); i++) {
-        const auto& config = activeConfigList.config(i);
-        ConfigKey key(config.uid(), config.id());
-        auto it = mMetricsManagers.find(key);
-        if (it == mMetricsManagers.end()) {
-            ALOGE("No config found for config %s", key.ToString().c_str());
-            continue;
-        }
-        VLOG("Setting active config %s", key.ToString().c_str());
-        it->second->loadActiveConfig(config, currentTimeNs);
-    }
-    VLOG("Successfully loaded %d active configs.", activeConfigList.config_size());
-}
-
-void StatsLogProcessor::WriteDataToDiskLocked(const DumpReportReason dumpReportReason,
-                                              const DumpLatency dumpLatency) {
-    const int64_t timeNs = getElapsedRealtimeNs();
-    // Do not write to disk if we already have in the last few seconds.
-    // This is to avoid overwriting files that would have the same name if we
-    //   write twice in the same second.
-    if (static_cast<unsigned long long> (timeNs) <
-            mLastWriteTimeNs + WRITE_DATA_COOL_DOWN_SEC * NS_PER_SEC) {
-        ALOGI("Statsd skipping writing data to disk. Already wrote data in last %d seconds",
-                WRITE_DATA_COOL_DOWN_SEC);
-        return;
-    }
-    mLastWriteTimeNs = timeNs;
-    for (auto& pair : mMetricsManagers) {
-        WriteDataToDiskLocked(pair.first, timeNs, dumpReportReason, dumpLatency);
-    }
-}
-
-void StatsLogProcessor::WriteDataToDisk(const DumpReportReason dumpReportReason,
-                                        const DumpLatency dumpLatency) {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-    WriteDataToDiskLocked(dumpReportReason, dumpLatency);
-}
-
-void StatsLogProcessor::informPullAlarmFired(const int64_t timestampNs) {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-    mPullerManager->OnAlarmFired(timestampNs);
-}
-
-int64_t StatsLogProcessor::getLastReportTimeNs(const ConfigKey& key) {
-    auto it = mMetricsManagers.find(key);
-    if (it == mMetricsManagers.end()) {
-        return 0;
-    } else {
-        return it->second->getLastReportTimeNs();
-    }
-}
-
-void StatsLogProcessor::notifyAppUpgrade(const int64_t& eventTimeNs, const string& apk,
-                                         const int uid, const int64_t version) {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-    VLOG("Received app upgrade");
-    StateManager::getInstance().notifyAppChanged(apk, mUidMap);
-    for (const auto& it : mMetricsManagers) {
-        it.second->notifyAppUpgrade(eventTimeNs, apk, uid, version);
-    }
-}
-
-void StatsLogProcessor::notifyAppRemoved(const int64_t& eventTimeNs, const string& apk,
-                                         const int uid) {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-    VLOG("Received app removed");
-    StateManager::getInstance().notifyAppChanged(apk, mUidMap);
-    for (const auto& it : mMetricsManagers) {
-        it.second->notifyAppRemoved(eventTimeNs, apk, uid);
-    }
-}
-
-void StatsLogProcessor::onUidMapReceived(const int64_t& eventTimeNs) {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-    VLOG("Received uid map");
-    StateManager::getInstance().updateLogSources(mUidMap);
-    for (const auto& it : mMetricsManagers) {
-        it.second->onUidMapReceived(eventTimeNs);
-    }
-}
-
-void StatsLogProcessor::onStatsdInitCompleted(const int64_t& elapsedTimeNs) {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-    VLOG("Received boot completed signal");
-    for (const auto& it : mMetricsManagers) {
-        it.second->onStatsdInitCompleted(elapsedTimeNs);
-    }
-}
-
-void StatsLogProcessor::noteOnDiskData(const ConfigKey& key) {
-    std::lock_guard<std::mutex> lock(mMetricsMutex);
-    mOnDiskDataConfigs.insert(key);
-}
-
-void StatsLogProcessor::setAnomalyAlarm(const int64_t elapsedTimeMillis) {
-    std::lock_guard<std::mutex> lock(mAnomalyAlarmMutex);
-    mNextAnomalyAlarmTime = elapsedTimeMillis;
-}
-
-void StatsLogProcessor::cancelAnomalyAlarm() {
-    std::lock_guard<std::mutex> lock(mAnomalyAlarmMutex);
-    mNextAnomalyAlarmTime = 0;
-}
-
-void StatsLogProcessor::informAnomalyAlarmFiredLocked(const int64_t elapsedTimeMillis) {
-    VLOG("StatsService::informAlarmForSubscriberTriggeringFired was called");
-    std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet =
-            mAnomalyAlarmMonitor->popSoonerThan(static_cast<uint32_t>(elapsedTimeMillis / 1000));
-    if (alarmSet.size() > 0) {
-        VLOG("Found periodic alarm fired.");
-        processFiredAnomalyAlarmsLocked(MillisToNano(elapsedTimeMillis), alarmSet);
-    } else {
-        ALOGW("Cannot find an periodic alarm that fired. Perhaps it was recently cancelled.");
-    }
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
deleted file mode 100644
index a320b2f..0000000
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <gtest/gtest_prod.h>
-#include "config/ConfigListener.h"
-#include "logd/LogEvent.h"
-#include "metrics/MetricsManager.h"
-#include "packages/UidMap.h"
-#include "external/StatsPullerManager.h"
-
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "frameworks/base/cmds/statsd/src/statsd_metadata.pb.h"
-
-#include <stdio.h>
-#include <unordered_map>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-
-class StatsLogProcessor : public ConfigListener, public virtual PackageInfoListener {
-public:
-    StatsLogProcessor(const sp<UidMap>& uidMap, const sp<StatsPullerManager>& pullerManager,
-                      const sp<AlarmMonitor>& anomalyAlarmMonitor,
-                      const sp<AlarmMonitor>& subscriberTriggerAlarmMonitor,
-                      const int64_t timeBaseNs,
-                      const std::function<bool(const ConfigKey&)>& sendBroadcast,
-                      const std::function<bool(const int&,
-                                               const vector<int64_t>&)>& sendActivationBroadcast);
-    virtual ~StatsLogProcessor();
-
-    void OnLogEvent(LogEvent* event);
-
-    void OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key,
-                         const StatsdConfig& config);
-    void OnConfigRemoved(const ConfigKey& key);
-
-    size_t GetMetricsSize(const ConfigKey& key) const;
-
-    void GetActiveConfigs(const int uid, vector<int64_t>& outActiveConfigs);
-
-    void onDumpReport(const ConfigKey& key, const int64_t dumpTimeNs,
-                      const bool include_current_partial_bucket, const bool erase_data,
-                      const DumpReportReason dumpReportReason,
-                      const DumpLatency dumpLatency,
-                      vector<uint8_t>* outData);
-    void onDumpReport(const ConfigKey& key, const int64_t dumpTimeNs,
-                      const bool include_current_partial_bucket, const bool erase_data,
-                      const DumpReportReason dumpReportReason,
-                      const DumpLatency dumpLatency,
-                      ProtoOutputStream* proto);
-
-    /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies periodic alarmSet. */
-    void onPeriodicAlarmFired(
-            const int64_t& timestampNs,
-            unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet);
-
-    /* Flushes data to disk. Data on memory will be gone after written to disk. */
-    void WriteDataToDisk(const DumpReportReason dumpReportReason,
-                         const DumpLatency dumpLatency);
-
-    /* Persist configs containing metrics with active activations to disk. */
-    void SaveActiveConfigsToDisk(int64_t currentTimeNs);
-
-    /* Writes the current active status/ttl for all configs and metrics to ProtoOutputStream. */
-    void WriteActiveConfigsToProtoOutputStream(
-            int64_t currentTimeNs, const DumpReportReason reason, ProtoOutputStream* proto);
-
-    /* Load configs containing metrics with active activations from disk. */
-    void LoadActiveConfigsFromDisk();
-
-    /* Persist metadata for configs and metrics to disk. */
-    void SaveMetadataToDisk(int64_t currentWallClockTimeNs, int64_t systemElapsedTimeNs);
-
-    /* Writes the statsd metadata for all configs and metrics to StatsMetadataList. */
-    void WriteMetadataToProto(int64_t currentWallClockTimeNs,
-                              int64_t systemElapsedTimeNs,
-                              metadata::StatsMetadataList* metadataList);
-
-    /* Load stats metadata for configs and metrics from disk. */
-    void LoadMetadataFromDisk(int64_t currentWallClockTimeNs,
-                              int64_t systemElapsedTimeNs);
-
-    /* Sets the metadata for all configs and metrics */
-    void SetMetadataState(const metadata::StatsMetadataList& statsMetadataList,
-                          int64_t currentWallClockTimeNs,
-                          int64_t systemElapsedTimeNs);
-
-    /* Sets the active status/ttl for all configs and metrics to the status in ActiveConfigList. */
-    void SetConfigsActiveState(const ActiveConfigList& activeConfigList, int64_t currentTimeNs);
-
-    /* Notify all MetricsManagers of app upgrades */
-    void notifyAppUpgrade(const int64_t& eventTimeNs, const string& apk, const int uid,
-                          const int64_t version) override;
-
-    /* Notify all MetricsManagers of app removals */
-    void notifyAppRemoved(const int64_t& eventTimeNs, const string& apk, const int uid) override;
-
-    /* Notify all MetricsManagers of uid map snapshots received */
-    void onUidMapReceived(const int64_t& eventTimeNs) override;
-
-    /* Notify all metrics managers of boot completed
-     * This will force a bucket split when the boot is finished.
-     */
-    void onStatsdInitCompleted(const int64_t& elapsedTimeNs);
-
-    // Reset all configs.
-    void resetConfigs();
-
-    inline sp<UidMap> getUidMap() {
-        return mUidMap;
-    }
-
-    void dumpStates(int outFd, bool verbose);
-
-    void informPullAlarmFired(const int64_t timestampNs);
-
-    int64_t getLastReportTimeNs(const ConfigKey& key);
-
-    inline void setPrintLogs(bool enabled) {
-        std::lock_guard<std::mutex> lock(mMetricsMutex);
-        mPrintAllLogs = enabled;
-    }
-
-    // Add a specific config key to the possible configs to dump ASAP.
-    void noteOnDiskData(const ConfigKey& key);
-
-    void setAnomalyAlarm(const int64_t timeMillis);
-
-    void cancelAnomalyAlarm();
-
-private:
-    // For testing only.
-    inline sp<AlarmMonitor> getAnomalyAlarmMonitor() const {
-        return mAnomalyAlarmMonitor;
-    }
-
-    inline sp<AlarmMonitor> getPeriodicAlarmMonitor() const {
-        return mPeriodicAlarmMonitor;
-    }
-
-    mutable mutex mMetricsMutex;
-
-    // Guards mNextAnomalyAlarmTime. A separate mutex is needed because alarms are set/cancelled
-    // in the onLogEvent code path, which is locked by mMetricsMutex.
-    // DO NOT acquire mMetricsMutex while holding mAnomalyAlarmMutex. This can lead to a deadlock.
-    mutable mutex mAnomalyAlarmMutex;
-
-    std::unordered_map<ConfigKey, sp<MetricsManager>> mMetricsManagers;
-
-    std::unordered_map<ConfigKey, int64_t> mLastBroadcastTimes;
-
-    // Last time we sent a broadcast to this uid that the active configs had changed.
-    std::unordered_map<int, int64_t> mLastActivationBroadcastTimes;
-
-    // Tracks when we last checked the bytes consumed for each config key.
-    std::unordered_map<ConfigKey, int64_t> mLastByteSizeTimes;
-
-    // Tracks which config keys has metric reports on disk
-    std::set<ConfigKey> mOnDiskDataConfigs;
-
-    sp<UidMap> mUidMap;  // Reference to the UidMap to lookup app name and version for each uid.
-
-    sp<StatsPullerManager> mPullerManager;  // Reference to StatsPullerManager
-
-    sp<AlarmMonitor> mAnomalyAlarmMonitor;
-
-    sp<AlarmMonitor> mPeriodicAlarmMonitor;
-
-    void OnLogEvent(LogEvent* event, int64_t elapsedRealtimeNs);
-
-    void resetIfConfigTtlExpiredLocked(const int64_t timestampNs);
-
-    void OnConfigUpdatedLocked(const int64_t currentTimestampNs, const ConfigKey& key,
-                               const StatsdConfig& config, bool modularUpdate);
-
-    void GetActiveConfigsLocked(const int uid, vector<int64_t>& outActiveConfigs);
-
-    void WriteActiveConfigsToProtoOutputStreamLocked(
-            int64_t currentTimeNs, const DumpReportReason reason, ProtoOutputStream* proto);
-
-    void SetConfigsActiveStateLocked(const ActiveConfigList& activeConfigList,
-                                     int64_t currentTimeNs);
-
-    void SetMetadataStateLocked(const metadata::StatsMetadataList& statsMetadataList,
-                                int64_t currentWallClockTimeNs,
-                                int64_t systemElapsedTimeNs);
-
-    void WriteMetadataToProtoLocked(int64_t currentWallClockTimeNs,
-                                    int64_t systemElapsedTimeNs,
-                                    metadata::StatsMetadataList* metadataList);
-
-    void WriteDataToDiskLocked(const DumpReportReason dumpReportReason,
-                               const DumpLatency dumpLatency);
-
-    void WriteDataToDiskLocked(const ConfigKey& key, const int64_t timestampNs,
-                               const DumpReportReason dumpReportReason,
-                               const DumpLatency dumpLatency);
-
-    void onConfigMetricsReportLocked(
-            const ConfigKey& key, const int64_t dumpTimeStampNs,
-            const bool include_current_partial_bucket, const bool erase_data,
-            const DumpReportReason dumpReportReason, const DumpLatency dumpLatency,
-            /*if dataSavedToDisk is true, it indicates the caller will write the data to disk
-             (e.g., before reboot). So no need to further persist local history.*/
-            const bool dataSavedToDisk, vector<uint8_t>* proto);
-
-    /* Check if we should send a broadcast if approaching memory limits and if we're over, we
-     * actually delete the data. */
-    void flushIfNecessaryLocked(const ConfigKey& key, MetricsManager& metricsManager);
-
-    // Maps the isolated uid in the log event to host uid if the log event contains uid fields.
-    void mapIsolatedUidToHostUidIfNecessaryLocked(LogEvent* event) const;
-
-    // Handler over the isolated uid change event.
-    void onIsolatedUidChangedEventLocked(const LogEvent& event);
-
-    // Handler over the binary push state changed event.
-    void onBinaryPushStateChangedEventLocked(LogEvent* event);
-
-    // Handler over the watchdog rollback occurred event.
-    void onWatchdogRollbackOccurredLocked(LogEvent* event);
-
-    // Updates train info on disk based on binary push state changed info and
-    // write disk info into parameters.
-    void getAndUpdateTrainInfoOnDisk(bool is_rollback, InstallTrainInfo* trainInfoIn);
-
-    // Gets experiment ids on disk for associated train and updates them
-    // depending on rollback type. Then writes them back to disk and returns
-    // them.
-    std::vector<int64_t> processWatchdogRollbackOccurred(const int32_t rollbackTypeIn,
-                                                          const string& packageName);
-
-    // Reset all configs.
-    void resetConfigsLocked(const int64_t timestampNs);
-    // Reset the specified configs.
-    void resetConfigsLocked(const int64_t timestampNs, const std::vector<ConfigKey>& configs);
-
-    // An anomaly alarm should have fired.
-    // Check with anomaly alarm manager to find the alarms and process the result.
-    void informAnomalyAlarmFiredLocked(const int64_t elapsedTimeMillis);
-
-    /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */
-    void processFiredAnomalyAlarmsLocked(
-            const int64_t& timestampNs,
-            unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet);
-
-    // Function used to send a broadcast so that receiver for the config key can call getData
-    // to retrieve the stored data.
-    std::function<bool(const ConfigKey& key)> mSendBroadcast;
-
-    // Function used to send a broadcast so that receiver can be notified of which configs
-    // are currently active.
-    std::function<bool(const int& uid, const vector<int64_t>& configIds)> mSendActivationBroadcast;
-
-    const int64_t mTimeBaseNs;
-
-    // Largest timestamp of the events that we have processed.
-    int64_t mLargestTimestampSeen = 0;
-
-    int64_t mLastTimestampSeen = 0;
-
-    int64_t mLastPullerCacheClearTimeSec = 0;
-
-    // Last time we wrote data to disk.
-    int64_t mLastWriteTimeNs = 0;
-
-    // Last time we wrote active metrics to disk.
-    int64_t mLastActiveMetricsWriteNs = 0;
-
-    //Last time we wrote metadata to disk.
-    int64_t mLastMetadataWriteNs = 0;
-
-    // The time for the next anomaly alarm for alerts.
-    int64_t mNextAnomalyAlarmTime = 0;
-
-    bool mPrintAllLogs = false;
-
-    FRIEND_TEST(StatsLogProcessorTest, TestOutOfOrderLogs);
-    FRIEND_TEST(StatsLogProcessorTest, TestRateLimitByteSize);
-    FRIEND_TEST(StatsLogProcessorTest, TestRateLimitBroadcast);
-    FRIEND_TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge);
-    FRIEND_TEST(StatsLogProcessorTest, InvalidConfigRemoved);
-    FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
-    FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot);
-    FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations);
-    FRIEND_TEST(StatsLogProcessorTest,
-            TestActivationOnBootMultipleActivationsDifferentActivationTypes);
-    FRIEND_TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart);
-
-    FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration1);
-    FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration2);
-    FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration3);
-    FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration1);
-    FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration2);
-    FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration3);
-    FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks1);
-    FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks2);
-    FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid);
-    FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain);
-    FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent);
-    FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents);
-    FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm);
-    FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsWithActivation);
-    FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsNoCondition);
-    FRIEND_TEST(GaugeMetricE2eTest, TestConditionChangeToTrueSamplePulledEvents);
-
-    FRIEND_TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_single_bucket);
-    FRIEND_TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_multiple_buckets);
-    FRIEND_TEST(AnomalyDetectionE2eTest, TestCountMetric_save_refractory_to_disk_no_data_written);
-    FRIEND_TEST(AnomalyDetectionE2eTest, TestCountMetric_save_refractory_to_disk);
-    FRIEND_TEST(AnomalyDetectionE2eTest, TestCountMetric_load_refractory_from_disk);
-    FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket);
-    FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets);
-    FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period);
-
-    FRIEND_TEST(AlarmE2eTest, TestMultipleAlarms);
-    FRIEND_TEST(ConfigTtlE2eTest, TestCountMetric);
-    FRIEND_TEST(MetricActivationE2eTest, TestCountMetric);
-    FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation);
-    FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations);
-    FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithSameDeactivation);
-    FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations);
-
-    FRIEND_TEST(ConfigUpdateE2eAbTest, TestHashStrings);
-    FRIEND_TEST(ConfigUpdateE2eAbTest, TestUidMapVersionStringInstaller);
-    FRIEND_TEST(ConfigUpdateE2eAbTest, TestConfigTtl);
-
-    FRIEND_TEST(CountMetricE2eTest, TestInitialConditionChanges);
-    FRIEND_TEST(CountMetricE2eTest, TestSlicedState);
-    FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithMap);
-    FRIEND_TEST(CountMetricE2eTest, TestMultipleSlicedStates);
-    FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields);
-
-    FRIEND_TEST(DurationMetricE2eTest, TestOneBucket);
-    FRIEND_TEST(DurationMetricE2eTest, TestTwoBuckets);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithActivation);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithCondition);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithSlicedCondition);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithActivationAndSlicedCondition);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithSlicedState);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithConditionAndSlicedState);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithSlicedStateMapped);
-    FRIEND_TEST(DurationMetricE2eTest, TestSlicedStatePrimaryFieldsNotSubsetDimInWhat);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithSlicedStatePrimaryFieldsSubset);
-
-    FRIEND_TEST(ValueMetricE2eTest, TestInitialConditionChanges);
-    FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents);
-    FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm);
-    FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation);
-    FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState);
-    FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithDimensions);
-    FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithIncorrectDimensions);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
deleted file mode 100644
index 68c2dd5..0000000
--- a/cmds/statsd/src/StatsService.cpp
+++ /dev/null
@@ -1,1312 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "StatsService.h"
-#include "stats_log_util.h"
-#include "android-base/stringprintf.h"
-#include "config/ConfigKey.h"
-#include "config/ConfigManager.h"
-#include "guardrail/StatsdStats.h"
-#include "storage/StorageManager.h"
-#include "subscriber/SubscriberReporter.h"
-
-#include <android-base/file.h>
-#include <android-base/strings.h>
-#include <cutils/multiuser.h>
-#include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>
-#include <frameworks/base/cmds/statsd/src/uid_data.pb.h>
-#include <private/android_filesystem_config.h>
-#include <statslog_statsd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/system_properties.h>
-#include <unistd.h>
-#include <utils/String16.h>
-
-using namespace android;
-
-using android::base::StringPrintf;
-using android::util::FIELD_COUNT_REPEATED;
-using android::util::FIELD_TYPE_MESSAGE;
-
-using Status = ::ndk::ScopedAStatus;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-constexpr const char* kPermissionDump = "android.permission.DUMP";
-
-constexpr const char* kPermissionRegisterPullAtom = "android.permission.REGISTER_STATS_PULL_ATOM";
-
-#define STATS_SERVICE_DIR "/data/misc/stats-service"
-
-// for StatsDataDumpProto
-const int FIELD_ID_REPORTS_LIST = 1;
-
-static Status exception(int32_t code, const std::string& msg) {
-    ALOGE("%s (%d)", msg.c_str(), code);
-    return Status::fromExceptionCodeWithMessage(code, msg.c_str());
-}
-
-static bool checkPermission(const char* permission) {
-    pid_t pid = AIBinder_getCallingPid();
-    uid_t uid = AIBinder_getCallingUid();
-    return checkPermissionForIds(permission, pid, uid);
-}
-
-Status checkUid(uid_t expectedUid) {
-    uid_t uid = AIBinder_getCallingUid();
-    if (uid == expectedUid || uid == AID_ROOT) {
-        return Status::ok();
-    } else {
-        return exception(EX_SECURITY,
-                         StringPrintf("UID %d is not expected UID %d", uid, expectedUid));
-    }
-}
-
-#define ENFORCE_UID(uid) {                                        \
-    Status status = checkUid((uid));                              \
-    if (!status.isOk()) {                                         \
-        return status;                                            \
-    }                                                             \
-}
-
-StatsService::StatsService(const sp<Looper>& handlerLooper, shared_ptr<LogEventQueue> queue)
-    : mAnomalyAlarmMonitor(new AlarmMonitor(
-              MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
-              [this](const shared_ptr<IStatsCompanionService>& /*sc*/, int64_t timeMillis) {
-                  mProcessor->setAnomalyAlarm(timeMillis);
-                  StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
-              },
-              [this](const shared_ptr<IStatsCompanionService>& /*sc*/) {
-                  mProcessor->cancelAnomalyAlarm();
-                  StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
-              })),
-      mPeriodicAlarmMonitor(new AlarmMonitor(
-              MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
-              [](const shared_ptr<IStatsCompanionService>& sc, int64_t timeMillis) {
-                  if (sc != nullptr) {
-                      sc->setAlarmForSubscriberTriggering(timeMillis);
-                      StatsdStats::getInstance().noteRegisteredPeriodicAlarmChanged();
-                  }
-              },
-              [](const shared_ptr<IStatsCompanionService>& sc) {
-                  if (sc != nullptr) {
-                      sc->cancelAlarmForSubscriberTriggering();
-                      StatsdStats::getInstance().noteRegisteredPeriodicAlarmChanged();
-                  }
-              })),
-      mEventQueue(queue),
-      mBootCompleteTrigger({kBootCompleteTag, kUidMapReceivedTag, kAllPullersRegisteredTag},
-                           [this]() { mProcessor->onStatsdInitCompleted(getElapsedRealtimeNs()); }),
-      mStatsCompanionServiceDeathRecipient(
-              AIBinder_DeathRecipient_new(StatsService::statsCompanionServiceDied)) {
-    mUidMap = UidMap::getInstance();
-    mPullerManager = new StatsPullerManager();
-    StatsPuller::SetUidMap(mUidMap);
-    mConfigManager = new ConfigManager();
-    mProcessor = new StatsLogProcessor(
-            mUidMap, mPullerManager, mAnomalyAlarmMonitor, mPeriodicAlarmMonitor,
-            getElapsedRealtimeNs(),
-            [this](const ConfigKey& key) {
-                shared_ptr<IPendingIntentRef> receiver = mConfigManager->GetConfigReceiver(key);
-                if (receiver == nullptr) {
-                    VLOG("Could not find a broadcast receiver for %s", key.ToString().c_str());
-                    return false;
-                } else if (receiver->sendDataBroadcast(
-                           mProcessor->getLastReportTimeNs(key)).isOk()) {
-                    return true;
-                } else {
-                    VLOG("Failed to send a broadcast for receiver %s", key.ToString().c_str());
-                    return false;
-                }
-            },
-            [this](const int& uid, const vector<int64_t>& activeConfigs) {
-                shared_ptr<IPendingIntentRef> receiver =
-                    mConfigManager->GetActiveConfigsChangedReceiver(uid);
-                if (receiver == nullptr) {
-                    VLOG("Could not find receiver for uid %d", uid);
-                    return false;
-                } else if (receiver->sendActiveConfigsChangedBroadcast(activeConfigs).isOk()) {
-                    VLOG("StatsService::active configs broadcast succeeded for uid %d" , uid);
-                    return true;
-                } else {
-                    VLOG("StatsService::active configs broadcast failed for uid %d" , uid);
-                    return false;
-                }
-            });
-
-    mUidMap->setListener(mProcessor);
-    mConfigManager->AddListener(mProcessor);
-
-    init_system_properties();
-
-    if (mEventQueue != nullptr) {
-        std::thread pushedEventThread([this] { readLogs(); });
-        pushedEventThread.detach();
-    }
-}
-
-StatsService::~StatsService() {
-}
-
-/* Runs on a dedicated thread to process pushed events. */
-void StatsService::readLogs() {
-    // Read forever..... long live statsd
-    while (1) {
-        // Block until an event is available.
-        auto event = mEventQueue->waitPop();
-        // Pass it to StatsLogProcess to all configs/metrics
-        // At this point, the LogEventQueue is not blocked, so that the socketListener
-        // can read events from the socket and write to buffer to avoid data drop.
-        mProcessor->OnLogEvent(event.get());
-        // The ShellSubscriber is only used by shell for local debugging.
-        if (mShellSubscriber != nullptr) {
-            mShellSubscriber->onLogEvent(*event);
-        }
-    }
-}
-
-void StatsService::init_system_properties() {
-    mEngBuild = false;
-    const prop_info* buildType = __system_property_find("ro.build.type");
-    if (buildType != NULL) {
-        __system_property_read_callback(buildType, init_build_type_callback, this);
-    }
-}
-
-void StatsService::init_build_type_callback(void* cookie, const char* /*name*/, const char* value,
-                                            uint32_t serial) {
-    if (0 == strcmp("eng", value) || 0 == strcmp("userdebug", value)) {
-        reinterpret_cast<StatsService*>(cookie)->mEngBuild = true;
-    }
-}
-
-/**
- * Write data from statsd.
- * Format for statsdStats:  adb shell dumpsys stats --metadata [-v] [--proto]
- * Format for data report:  adb shell dumpsys stats [anything other than --metadata] [--proto]
- * Anything ending in --proto will be in proto format.
- * Anything without --metadata as the first argument will be report information.
- *     (bugreports call "adb shell dumpsys stats --dump-priority NORMAL -a --proto")
- * TODO: Come up with a more robust method of enacting <serviceutils/PriorityDumper.h>.
- */
-status_t StatsService::dump(int fd, const char** args, uint32_t numArgs) {
-    if (!checkPermission(kPermissionDump)) {
-        return PERMISSION_DENIED;
-    }
-
-    int lastArg = numArgs - 1;
-    bool asProto = false;
-    if (lastArg >= 0 && string(args[lastArg]) == "--proto") { // last argument
-        asProto = true;
-        lastArg--;
-    }
-    if (numArgs > 0 && string(args[0]) == "--metadata") { // first argument
-        // Request is to dump statsd stats.
-        bool verbose = false;
-        if (lastArg >= 0 && string(args[lastArg]) == "-v") {
-            verbose = true;
-            lastArg--;
-        }
-        dumpStatsdStats(fd, verbose, asProto);
-    } else {
-        // Request is to dump statsd report data.
-        if (asProto) {
-            dumpIncidentSection(fd);
-        } else {
-            dprintf(fd, "Non-proto format of stats data dump not available; see proto version.\n");
-        }
-    }
-
-    return NO_ERROR;
-}
-
-/**
- * Write debugging data about statsd in text or proto format.
- */
-void StatsService::dumpStatsdStats(int out, bool verbose, bool proto) {
-    if (proto) {
-        vector<uint8_t> data;
-        StatsdStats::getInstance().dumpStats(&data, false); // does not reset statsdStats.
-        for (size_t i = 0; i < data.size(); i ++) {
-            dprintf(out, "%c", data[i]);
-        }
-    } else {
-        StatsdStats::getInstance().dumpStats(out);
-        mProcessor->dumpStates(out, verbose);
-    }
-}
-
-/**
- * Write stats report data in StatsDataDumpProto incident section format.
- */
-void StatsService::dumpIncidentSection(int out) {
-    ProtoOutputStream proto;
-    for (const ConfigKey& configKey : mConfigManager->GetAllConfigKeys()) {
-        uint64_t reportsListToken =
-                proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS_LIST);
-        // Don't include the current bucket to avoid skipping buckets.
-        // If we need to include the current bucket later, consider changing to NO_TIME_CONSTRAINTS
-        // or other alternatives to avoid skipping buckets for pulled metrics.
-        mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(),
-                                 false /* includeCurrentBucket */, false /* erase_data */,
-                                 ADB_DUMP,
-                                 FAST,
-                                 &proto);
-        proto.end(reportsListToken);
-        proto.flush(out);
-        proto.clear();
-    }
-}
-
-/**
- * Implementation of the adb shell cmd stats command.
- */
-status_t StatsService::handleShellCommand(int in, int out, int err, const char** argv,
-                                          uint32_t argc) {
-    uid_t uid = AIBinder_getCallingUid();
-    if (uid != AID_ROOT && uid != AID_SHELL) {
-        return PERMISSION_DENIED;
-    }
-
-    Vector<String8> utf8Args;
-    utf8Args.setCapacity(argc);
-    for (uint32_t i = 0; i < argc; i++) {
-        utf8Args.push(String8(argv[i]));
-    }
-
-    if (argc >= 1) {
-        // adb shell cmd stats config ...
-        if (!utf8Args[0].compare(String8("config"))) {
-            return cmd_config(in, out, err, utf8Args);
-        }
-
-        if (!utf8Args[0].compare(String8("print-uid-map"))) {
-            return cmd_print_uid_map(out, utf8Args);
-        }
-
-        if (!utf8Args[0].compare(String8("dump-report"))) {
-            return cmd_dump_report(out, utf8Args);
-        }
-
-        if (!utf8Args[0].compare(String8("pull-source")) && argc > 1) {
-            return cmd_print_pulled_metrics(out, utf8Args);
-        }
-
-        if (!utf8Args[0].compare(String8("send-broadcast"))) {
-            return cmd_trigger_broadcast(out, utf8Args);
-        }
-
-        if (!utf8Args[0].compare(String8("print-stats"))) {
-            return cmd_print_stats(out, utf8Args);
-        }
-
-        if (!utf8Args[0].compare(String8("meminfo"))) {
-            return cmd_dump_memory_info(out);
-        }
-
-        if (!utf8Args[0].compare(String8("write-to-disk"))) {
-            return cmd_write_data_to_disk(out);
-        }
-
-        if (!utf8Args[0].compare(String8("log-app-breadcrumb"))) {
-            return cmd_log_app_breadcrumb(out, utf8Args);
-        }
-
-        if (!utf8Args[0].compare(String8("log-binary-push"))) {
-            return cmd_log_binary_push(out, utf8Args);
-        }
-
-        if (!utf8Args[0].compare(String8("clear-puller-cache"))) {
-            return cmd_clear_puller_cache(out);
-        }
-
-        if (!utf8Args[0].compare(String8("print-logs"))) {
-            return cmd_print_logs(out, utf8Args);
-        }
-
-        if (!utf8Args[0].compare(String8("send-active-configs"))) {
-            return cmd_trigger_active_config_broadcast(out, utf8Args);
-        }
-
-        if (!utf8Args[0].compare(String8("data-subscribe"))) {
-            {
-                std::lock_guard<std::mutex> lock(mShellSubscriberMutex);
-                if (mShellSubscriber == nullptr) {
-                    mShellSubscriber = new ShellSubscriber(mUidMap, mPullerManager);
-                }
-            }
-            int timeoutSec = -1;
-            if (argc >= 2) {
-                timeoutSec = atoi(utf8Args[1].c_str());
-            }
-            mShellSubscriber->startNewSubscription(in, out, timeoutSec);
-            return NO_ERROR;
-        }
-    }
-
-    print_cmd_help(out);
-    return NO_ERROR;
-}
-
-void StatsService::print_cmd_help(int out) {
-    dprintf(out,
-            "usage: adb shell cmd stats print-stats-log [tag_required] "
-            "[timestamp_nsec_optional]\n");
-    dprintf(out, "\n");
-    dprintf(out, "\n");
-    dprintf(out, "usage: adb shell cmd stats meminfo\n");
-    dprintf(out, "\n");
-    dprintf(out, "  Prints the malloc debug information. You need to run the following first: \n");
-    dprintf(out, "   # adb shell stop\n");
-    dprintf(out, "   # adb shell setprop libc.debug.malloc.program statsd \n");
-    dprintf(out, "   # adb shell setprop libc.debug.malloc.options backtrace \n");
-    dprintf(out, "   # adb shell start\n");
-    dprintf(out, "\n");
-    dprintf(out, "\n");
-    dprintf(out, "usage: adb shell cmd stats print-uid-map [PKG]\n");
-    dprintf(out, "\n");
-    dprintf(out, "  Prints the UID, app name, version mapping.\n");
-    dprintf(out, "  PKG           Optional package name to print the uids of the package\n");
-    dprintf(out, "\n");
-    dprintf(out, "\n");
-    dprintf(out, "usage: adb shell cmd stats pull-source ATOM_TAG [PACKAGE] \n");
-    dprintf(out, "\n");
-    dprintf(out, "  Prints the output of a pulled atom\n");
-    dprintf(out, "  UID           The atom to pull\n");
-    dprintf(out, "  PACKAGE       The package to pull from. Default is AID_SYSTEM\n");
-    dprintf(out, "\n");
-    dprintf(out, "\n");
-    dprintf(out, "usage: adb shell cmd stats write-to-disk \n");
-    dprintf(out, "\n");
-    dprintf(out, "  Flushes all data on memory to disk.\n");
-    dprintf(out, "\n");
-    dprintf(out, "\n");
-    dprintf(out, "usage: adb shell cmd stats log-app-breadcrumb [UID] LABEL STATE\n");
-    dprintf(out, "  Writes an AppBreadcrumbReported event to the statslog buffer.\n");
-    dprintf(out, "  UID           The uid to use. It is only possible to pass a UID\n");
-    dprintf(out, "                parameter on eng builds. If UID is omitted the calling\n");
-    dprintf(out, "                uid is used.\n");
-    dprintf(out, "  LABEL         Integer in [0, 15], as per atoms.proto.\n");
-    dprintf(out, "  STATE         Integer in [0, 3], as per atoms.proto.\n");
-    dprintf(out, "\n");
-    dprintf(out, "\n");
-    dprintf(out,
-            "usage: adb shell cmd stats log-binary-push NAME VERSION STAGING ROLLBACK_ENABLED "
-            "LOW_LATENCY STATE EXPERIMENT_IDS\n");
-    dprintf(out, "  Log a binary push state changed event.\n");
-    dprintf(out, "  NAME                The train name.\n");
-    dprintf(out, "  VERSION             The train version code.\n");
-    dprintf(out, "  STAGING             If this train requires a restart.\n");
-    dprintf(out, "  ROLLBACK_ENABLED    If rollback should be enabled for this install.\n");
-    dprintf(out, "  LOW_LATENCY         If the train requires low latency monitoring.\n");
-    dprintf(out, "  STATE               The status of the train push.\n");
-    dprintf(out, "                      Integer value of the enum in atoms.proto.\n");
-    dprintf(out, "  EXPERIMENT_IDS      Comma separated list of experiment ids.\n");
-    dprintf(out, "                      Leave blank for none.\n");
-    dprintf(out, "\n");
-    dprintf(out, "\n");
-    dprintf(out, "usage: adb shell cmd stats config remove [UID] [NAME]\n");
-    dprintf(out, "usage: adb shell cmd stats config update [UID] NAME\n");
-    dprintf(out, "\n");
-    dprintf(out, "  Adds, updates or removes a configuration. The proto should be in\n");
-    dprintf(out, "  wire-encoded protobuf format and passed via stdin. If no UID and name is\n");
-    dprintf(out, "  provided, then all configs will be removed from memory and disk.\n");
-    dprintf(out, "\n");
-    dprintf(out, "  UID           The uid to use. It is only possible to pass the UID\n");
-    dprintf(out, "                parameter on eng builds. If UID is omitted the calling\n");
-    dprintf(out, "                uid is used.\n");
-    dprintf(out, "  NAME          The per-uid name to use\n");
-    dprintf(out, "\n");
-    dprintf(out, "\n              *Note: If both UID and NAME are omitted then all configs will\n");
-    dprintf(out, "\n                     be removed from memory and disk!\n");
-    dprintf(out, "\n");
-    dprintf(out,
-            "usage: adb shell cmd stats dump-report [UID] NAME [--keep_data] "
-            "[--include_current_bucket] [--proto]\n");
-    dprintf(out, "  Dump all metric data for a configuration.\n");
-    dprintf(out, "  UID           The uid of the configuration. It is only possible to pass\n");
-    dprintf(out, "                the UID parameter on eng builds. If UID is omitted the\n");
-    dprintf(out, "                calling uid is used.\n");
-    dprintf(out, "  NAME          The name of the configuration\n");
-    dprintf(out, "  --keep_data   Do NOT erase the data upon dumping it.\n");
-    dprintf(out, "  --proto       Print proto binary.\n");
-    dprintf(out, "\n");
-    dprintf(out, "\n");
-    dprintf(out, "usage: adb shell cmd stats send-broadcast [UID] NAME\n");
-    dprintf(out, "  Send a broadcast that triggers the subscriber to fetch metrics.\n");
-    dprintf(out, "  UID           The uid of the configuration. It is only possible to pass\n");
-    dprintf(out, "                the UID parameter on eng builds. If UID is omitted the\n");
-    dprintf(out, "                calling uid is used.\n");
-    dprintf(out, "  NAME          The name of the configuration\n");
-    dprintf(out, "\n");
-    dprintf(out, "\n");
-    dprintf(out,
-            "usage: adb shell cmd stats send-active-configs [--uid=UID] [--configs] "
-            "[NAME1] [NAME2] [NAME3..]\n");
-    dprintf(out, "  Send a broadcast that informs the subscriber of the current active configs.\n");
-    dprintf(out, "  --uid=UID     The uid of the configurations. It is only possible to pass\n");
-    dprintf(out, "                the UID parameter on eng builds. If UID is omitted the\n");
-    dprintf(out, "                calling uid is used.\n");
-    dprintf(out, "  --configs     Send the list of configs in the name list instead of\n");
-    dprintf(out, "                the currently active configs\n");
-    dprintf(out, "  NAME LIST     List of configuration names to be included in the broadcast.\n");
-    dprintf(out, "\n");
-    dprintf(out, "\n");
-    dprintf(out, "usage: adb shell cmd stats print-stats\n");
-    dprintf(out, "  Prints some basic stats.\n");
-    dprintf(out, "  --proto       Print proto binary instead of string format.\n");
-    dprintf(out, "\n");
-    dprintf(out, "\n");
-    dprintf(out, "usage: adb shell cmd stats clear-puller-cache\n");
-    dprintf(out, "  Clear cached puller data.\n");
-    dprintf(out, "\n");
-    dprintf(out, "usage: adb shell cmd stats print-logs\n");
-    dprintf(out, "  Requires root privileges.\n");
-    dprintf(out, "  Can be disabled by calling adb shell cmd stats print-logs 0\n");
-}
-
-status_t StatsService::cmd_trigger_broadcast(int out, Vector<String8>& args) {
-    string name;
-    bool good = false;
-    int uid;
-    const int argCount = args.size();
-    if (argCount == 2) {
-        // Automatically pick the UID
-        uid = AIBinder_getCallingUid();
-        name.assign(args[1].c_str(), args[1].size());
-        good = true;
-    } else if (argCount == 3) {
-        good = getUidFromArgs(args, 1, uid);
-        if (!good) {
-            dprintf(out, "Invalid UID. Note that the metrics can only be dumped for "
-                         "other UIDs on eng or userdebug builds.\n");
-        }
-        name.assign(args[2].c_str(), args[2].size());
-    }
-    if (!good) {
-        print_cmd_help(out);
-        return UNKNOWN_ERROR;
-    }
-    ConfigKey key(uid, StrToInt64(name));
-    shared_ptr<IPendingIntentRef> receiver = mConfigManager->GetConfigReceiver(key);
-    if (receiver == nullptr) {
-        VLOG("Could not find receiver for %s, %s", args[1].c_str(), args[2].c_str());
-        return UNKNOWN_ERROR;
-    } else if (receiver->sendDataBroadcast(mProcessor->getLastReportTimeNs(key)).isOk()) {
-        VLOG("StatsService::trigger broadcast succeeded to %s, %s", args[1].c_str(),
-             args[2].c_str());
-    } else {
-        VLOG("StatsService::trigger broadcast failed to %s, %s", args[1].c_str(), args[2].c_str());
-        return UNKNOWN_ERROR;
-    }
-    return NO_ERROR;
-}
-
-status_t StatsService::cmd_trigger_active_config_broadcast(int out, Vector<String8>& args) {
-    const int argCount = args.size();
-    int uid;
-    vector<int64_t> configIds;
-    if (argCount == 1) {
-        // Automatically pick the uid and send a broadcast that has no active configs.
-        uid = AIBinder_getCallingUid();
-        mProcessor->GetActiveConfigs(uid, configIds);
-    } else {
-        int curArg = 1;
-        if(args[curArg].find("--uid=") == 0) {
-            string uidArgStr(args[curArg].c_str());
-            string uidStr = uidArgStr.substr(6);
-            if (!getUidFromString(uidStr.c_str(), uid)) {
-                dprintf(out, "Invalid UID. Note that the config can only be set for "
-                             "other UIDs on eng or userdebug builds.\n");
-                return UNKNOWN_ERROR;
-            }
-            curArg++;
-        } else {
-            uid = AIBinder_getCallingUid();
-        }
-        if (curArg == argCount || args[curArg] != "--configs") {
-            VLOG("Reached end of args, or specify configs not set. Sending actual active configs,");
-            mProcessor->GetActiveConfigs(uid, configIds);
-        } else {
-            // Flag specified, use the given list of configs.
-            curArg++;
-            for (int i = curArg; i < argCount; i++) {
-                char* endp;
-                int64_t configID = strtoll(args[i].c_str(), &endp, 10);
-                if (endp == args[i].c_str() || *endp != '\0') {
-                    dprintf(out, "Error parsing config ID.\n");
-                    return UNKNOWN_ERROR;
-                }
-                VLOG("Adding config id %ld", static_cast<long>(configID));
-                configIds.push_back(configID);
-            }
-        }
-    }
-    shared_ptr<IPendingIntentRef> receiver = mConfigManager->GetActiveConfigsChangedReceiver(uid);
-    if (receiver == nullptr) {
-        VLOG("Could not find receiver for uid %d", uid);
-        return UNKNOWN_ERROR;
-    } else if (receiver->sendActiveConfigsChangedBroadcast(configIds).isOk()) {
-        VLOG("StatsService::trigger active configs changed broadcast succeeded for uid %d" , uid);
-    } else {
-        VLOG("StatsService::trigger active configs changed broadcast failed for uid %d", uid);
-        return UNKNOWN_ERROR;
-    }
-    return NO_ERROR;
-}
-
-status_t StatsService::cmd_config(int in, int out, int err, Vector<String8>& args) {
-    const int argCount = args.size();
-    if (argCount >= 2) {
-        if (args[1] == "update" || args[1] == "remove") {
-            bool good = false;
-            int uid = -1;
-            string name;
-
-            if (argCount == 3) {
-                // Automatically pick the UID
-                uid = AIBinder_getCallingUid();
-                name.assign(args[2].c_str(), args[2].size());
-                good = true;
-            } else if (argCount == 4) {
-                good = getUidFromArgs(args, 2, uid);
-                if (!good) {
-                    dprintf(err, "Invalid UID. Note that the config can only be set for "
-                                 "other UIDs on eng or userdebug builds.\n");
-                }
-                name.assign(args[3].c_str(), args[3].size());
-            } else if (argCount == 2 && args[1] == "remove") {
-                good = true;
-            }
-
-            if (!good) {
-                // If arg parsing failed, print the help text and return an error.
-                print_cmd_help(out);
-                return UNKNOWN_ERROR;
-            }
-
-            if (args[1] == "update") {
-                char* endp;
-                int64_t configID = strtoll(name.c_str(), &endp, 10);
-                if (endp == name.c_str() || *endp != '\0') {
-                    dprintf(err, "Error parsing config ID.\n");
-                    return UNKNOWN_ERROR;
-                }
-
-                // Read stream into buffer.
-                string buffer;
-                if (!android::base::ReadFdToString(in, &buffer)) {
-                    dprintf(err, "Error reading stream for StatsConfig.\n");
-                    return UNKNOWN_ERROR;
-                }
-
-                // Parse buffer.
-                StatsdConfig config;
-                if (!config.ParseFromString(buffer)) {
-                    dprintf(err, "Error parsing proto stream for StatsConfig.\n");
-                    return UNKNOWN_ERROR;
-                }
-
-                // Add / update the config.
-                mConfigManager->UpdateConfig(ConfigKey(uid, configID), config);
-            } else {
-                if (argCount == 2) {
-                    cmd_remove_all_configs(out);
-                } else {
-                    // Remove the config.
-                    mConfigManager->RemoveConfig(ConfigKey(uid, StrToInt64(name)));
-                }
-            }
-
-            return NO_ERROR;
-        }
-    }
-    print_cmd_help(out);
-    return UNKNOWN_ERROR;
-}
-
-status_t StatsService::cmd_dump_report(int out, const Vector<String8>& args) {
-    if (mProcessor != nullptr) {
-        int argCount = args.size();
-        bool good = false;
-        bool proto = false;
-        bool includeCurrentBucket = false;
-        bool eraseData = true;
-        int uid;
-        string name;
-        if (!std::strcmp("--proto", args[argCount-1].c_str())) {
-            proto = true;
-            argCount -= 1;
-        }
-        if (!std::strcmp("--include_current_bucket", args[argCount-1].c_str())) {
-            includeCurrentBucket = true;
-            argCount -= 1;
-        }
-        if (!std::strcmp("--keep_data", args[argCount-1].c_str())) {
-            eraseData = false;
-            argCount -= 1;
-        }
-        if (argCount == 2) {
-            // Automatically pick the UID
-            uid = AIBinder_getCallingUid();
-            name.assign(args[1].c_str(), args[1].size());
-            good = true;
-        } else if (argCount == 3) {
-            good = getUidFromArgs(args, 1, uid);
-            if (!good) {
-                dprintf(out, "Invalid UID. Note that the metrics can only be dumped for "
-                             "other UIDs on eng or userdebug builds.\n");
-            }
-            name.assign(args[2].c_str(), args[2].size());
-        }
-        if (good) {
-            vector<uint8_t> data;
-            mProcessor->onDumpReport(ConfigKey(uid, StrToInt64(name)), getElapsedRealtimeNs(),
-                                     includeCurrentBucket, eraseData, ADB_DUMP,
-                                     NO_TIME_CONSTRAINTS,
-                                     &data);
-            if (proto) {
-                for (size_t i = 0; i < data.size(); i ++) {
-                    dprintf(out, "%c", data[i]);
-                }
-            } else {
-                dprintf(out, "Non-proto stats data dump not currently supported.\n");
-            }
-            return android::OK;
-        } else {
-            // If arg parsing failed, print the help text and return an error.
-            print_cmd_help(out);
-            return UNKNOWN_ERROR;
-        }
-    } else {
-        dprintf(out, "Log processor does not exist...\n");
-        return UNKNOWN_ERROR;
-    }
-}
-
-status_t StatsService::cmd_print_stats(int out, const Vector<String8>& args) {
-    int argCount = args.size();
-    bool proto = false;
-    if (!std::strcmp("--proto", args[argCount-1].c_str())) {
-        proto = true;
-        argCount -= 1;
-    }
-    StatsdStats& statsdStats = StatsdStats::getInstance();
-    if (proto) {
-        vector<uint8_t> data;
-        statsdStats.dumpStats(&data, false); // does not reset statsdStats.
-        for (size_t i = 0; i < data.size(); i ++) {
-            dprintf(out, "%c", data[i]);
-        }
-
-    } else {
-        vector<ConfigKey> configs = mConfigManager->GetAllConfigKeys();
-        for (const ConfigKey& key : configs) {
-            dprintf(out, "Config %s uses %zu bytes\n", key.ToString().c_str(),
-                    mProcessor->GetMetricsSize(key));
-        }
-        statsdStats.dumpStats(out);
-    }
-    return NO_ERROR;
-}
-
-status_t StatsService::cmd_print_uid_map(int out, const Vector<String8>& args) {
-    if (args.size() > 1) {
-        string pkg;
-        pkg.assign(args[1].c_str(), args[1].size());
-        auto uids = mUidMap->getAppUid(pkg);
-        dprintf(out, "%s -> [ ", pkg.c_str());
-        for (const auto& uid : uids) {
-            dprintf(out, "%d ", uid);
-        }
-        dprintf(out, "]\n");
-    } else {
-        mUidMap->printUidMap(out);
-    }
-    return NO_ERROR;
-}
-
-status_t StatsService::cmd_write_data_to_disk(int out) {
-    dprintf(out, "Writing data to disk\n");
-    mProcessor->WriteDataToDisk(ADB_DUMP, NO_TIME_CONSTRAINTS);
-    return NO_ERROR;
-}
-
-status_t StatsService::cmd_log_app_breadcrumb(int out, const Vector<String8>& args) {
-    bool good = false;
-    int32_t uid;
-    int32_t label;
-    int32_t state;
-    const int argCount = args.size();
-    if (argCount == 3) {
-        // Automatically pick the UID
-        uid = AIBinder_getCallingUid();
-        label = atoi(args[1].c_str());
-        state = atoi(args[2].c_str());
-        good = true;
-    } else if (argCount == 4) {
-        good = getUidFromArgs(args, 1, uid);
-        if (!good) {
-            dprintf(out,
-                    "Invalid UID. Note that selecting a UID for writing AppBreadcrumb can only be "
-                    "done for other UIDs on eng or userdebug builds.\n");
-        }
-        label = atoi(args[2].c_str());
-        state = atoi(args[3].c_str());
-    }
-    if (good) {
-        dprintf(out, "Logging AppBreadcrumbReported(%d, %d, %d) to statslog.\n", uid, label, state);
-        android::os::statsd::util::stats_write(
-                android::os::statsd::util::APP_BREADCRUMB_REPORTED, uid, label, state);
-    } else {
-        print_cmd_help(out);
-        return UNKNOWN_ERROR;
-    }
-    return NO_ERROR;
-}
-
-status_t StatsService::cmd_log_binary_push(int out, const Vector<String8>& args) {
-    // Security checks are done in the sendBinaryPushStateChanged atom.
-    const int argCount = args.size();
-    if (argCount != 7 && argCount != 8) {
-        dprintf(out, "Incorrect number of argument supplied\n");
-        return UNKNOWN_ERROR;
-    }
-    string trainName = string(args[1].c_str());
-    int64_t trainVersion = strtoll(args[2].c_str(), nullptr, 10);
-    int32_t state = atoi(args[6].c_str());
-    vector<int64_t> experimentIds;
-    if (argCount == 8) {
-        vector<string> experimentIdsString = android::base::Split(string(args[7].c_str()), ",");
-        for (string experimentIdString : experimentIdsString) {
-            int64_t experimentId = strtoll(experimentIdString.c_str(), nullptr, 10);
-            experimentIds.push_back(experimentId);
-        }
-    }
-    dprintf(out, "Logging BinaryPushStateChanged\n");
-    vector<uint8_t> experimentIdBytes;
-    writeExperimentIdsToProto(experimentIds, &experimentIdBytes);
-    LogEvent event(trainName, trainVersion, args[3], args[4], args[5], state, experimentIdBytes, 0);
-    mProcessor->OnLogEvent(&event);
-    return NO_ERROR;
-}
-
-status_t StatsService::cmd_print_pulled_metrics(int out, const Vector<String8>& args) {
-    int s = atoi(args[1].c_str());
-    vector<int32_t> uids;
-    if (args.size() > 2) {
-        string package = string(args[2].c_str());
-        auto it = UidMap::sAidToUidMapping.find(package);
-        if (it != UidMap::sAidToUidMapping.end()) {
-            uids.push_back(it->second);
-        } else {
-            set<int32_t> uids_set = mUidMap->getAppUid(package);
-            uids.insert(uids.end(), uids_set.begin(), uids_set.end());
-        }
-    } else {
-        uids.push_back(AID_SYSTEM);
-    }
-    vector<shared_ptr<LogEvent>> stats;
-    if (mPullerManager->Pull(s, uids, getElapsedRealtimeNs(), &stats)) {
-        for (const auto& it : stats) {
-            dprintf(out, "Pull from %d: %s\n", s, it->ToString().c_str());
-        }
-        dprintf(out, "Pull from %d: Received %zu elements\n", s, stats.size());
-        return NO_ERROR;
-    }
-    return UNKNOWN_ERROR;
-}
-
-status_t StatsService::cmd_remove_all_configs(int out) {
-    dprintf(out, "Removing all configs...\n");
-    VLOG("StatsService::cmd_remove_all_configs was called");
-    mConfigManager->RemoveAllConfigs();
-    StorageManager::deleteAllFiles(STATS_SERVICE_DIR);
-    return NO_ERROR;
-}
-
-status_t StatsService::cmd_dump_memory_info(int out) {
-    dprintf(out, "meminfo not available.\n");
-    return NO_ERROR;
-}
-
-status_t StatsService::cmd_clear_puller_cache(int out) {
-    VLOG("StatsService::cmd_clear_puller_cache with Pid %i, Uid %i",
-            AIBinder_getCallingPid(), AIBinder_getCallingUid());
-    if (checkPermission(kPermissionDump)) {
-        int cleared = mPullerManager->ForceClearPullerCache();
-        dprintf(out, "Puller removed %d cached data!\n", cleared);
-        return NO_ERROR;
-    } else {
-        return PERMISSION_DENIED;
-    }
-}
-
-status_t StatsService::cmd_print_logs(int out, const Vector<String8>& args) {
-    Status status = checkUid(AID_ROOT);
-    if (!status.isOk()) {
-        return PERMISSION_DENIED;
-    }
-
-    VLOG("StatsService::cmd_print_logs with pid %i, uid %i", AIBinder_getCallingPid(),
-         AIBinder_getCallingUid());
-    bool enabled = true;
-    if (args.size() >= 2) {
-        enabled = atoi(args[1].c_str()) != 0;
-    }
-    mProcessor->setPrintLogs(enabled);
-    return NO_ERROR;
-}
-
-bool StatsService::getUidFromArgs(const Vector<String8>& args, size_t uidArgIndex, int32_t& uid) {
-    return getUidFromString(args[uidArgIndex].c_str(), uid);
-}
-
-bool StatsService::getUidFromString(const char* s, int32_t& uid) {
-    if (*s == '\0') {
-        return false;
-    }
-    char* endc = NULL;
-    int64_t longUid = strtol(s, &endc, 0);
-    if (*endc != '\0') {
-        return false;
-    }
-    int32_t goodUid = static_cast<int32_t>(longUid);
-    if (longUid < 0 || static_cast<uint64_t>(longUid) != static_cast<uid_t>(goodUid)) {
-        return false;  // It was not of uid_t type.
-    }
-    uid = goodUid;
-
-    int32_t callingUid = AIBinder_getCallingUid();
-    return mEngBuild // UserDebug/EngBuild are allowed to impersonate uids.
-            || (callingUid == goodUid) // Anyone can 'impersonate' themselves.
-            || (callingUid == AID_ROOT && goodUid == AID_SHELL); // ROOT can impersonate SHELL.
-}
-
-Status StatsService::informAllUidData(const ScopedFileDescriptor& fd) {
-    ENFORCE_UID(AID_SYSTEM);
-    // Read stream into buffer.
-    string buffer;
-    if (!android::base::ReadFdToString(fd.get(), &buffer)) {
-        return exception(EX_ILLEGAL_ARGUMENT, "Failed to read all data from the pipe.");
-    }
-
-    // Parse buffer.
-    UidData uidData;
-    if (!uidData.ParseFromString(buffer)) {
-        return exception(EX_ILLEGAL_ARGUMENT, "Error parsing proto stream for UidData.");
-    }
-
-    vector<String16> versionStrings;
-    vector<String16> installers;
-    vector<String16> packageNames;
-    vector<int32_t> uids;
-    vector<int64_t> versions;
-
-    const auto numEntries = uidData.app_info_size();
-    versionStrings.reserve(numEntries);
-    installers.reserve(numEntries);
-    packageNames.reserve(numEntries);
-    uids.reserve(numEntries);
-    versions.reserve(numEntries);
-
-    for (const auto& appInfo: uidData.app_info()) {
-        packageNames.emplace_back(String16(appInfo.package_name().c_str()));
-        uids.push_back(appInfo.uid());
-        versions.push_back(appInfo.version());
-        versionStrings.emplace_back(String16(appInfo.version_string().c_str()));
-        installers.emplace_back(String16(appInfo.installer().c_str()));
-    }
-
-    mUidMap->updateMap(getElapsedRealtimeNs(),
-                       uids,
-                       versions,
-                       versionStrings,
-                       packageNames,
-                       installers);
-
-    mBootCompleteTrigger.markComplete(kUidMapReceivedTag);
-    VLOG("StatsService::informAllUidData UidData proto parsed successfully.");
-    return Status::ok();
-}
-
-Status StatsService::informOnePackage(const string& app, int32_t uid, int64_t version,
-                                      const string& versionString, const string& installer) {
-    ENFORCE_UID(AID_SYSTEM);
-
-    VLOG("StatsService::informOnePackage was called");
-    String16 utf16App = String16(app.c_str());
-    String16 utf16VersionString = String16(versionString.c_str());
-    String16 utf16Installer = String16(installer.c_str());
-
-    mUidMap->updateApp(getElapsedRealtimeNs(), utf16App, uid, version, utf16VersionString,
-                       utf16Installer);
-    return Status::ok();
-}
-
-Status StatsService::informOnePackageRemoved(const string& app, int32_t uid) {
-    ENFORCE_UID(AID_SYSTEM);
-
-    VLOG("StatsService::informOnePackageRemoved was called");
-    String16 utf16App = String16(app.c_str());
-    mUidMap->removeApp(getElapsedRealtimeNs(), utf16App, uid);
-    mConfigManager->RemoveConfigs(uid);
-    return Status::ok();
-}
-
-Status StatsService::informAlarmForSubscriberTriggeringFired() {
-    ENFORCE_UID(AID_SYSTEM);
-
-    VLOG("StatsService::informAlarmForSubscriberTriggeringFired was called");
-    int64_t currentTimeSec = getElapsedRealtimeSec();
-    std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet =
-            mPeriodicAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
-    if (alarmSet.size() > 0) {
-        VLOG("Found periodic alarm fired.");
-        mProcessor->onPeriodicAlarmFired(currentTimeSec * NS_PER_SEC, alarmSet);
-    } else {
-        ALOGW("Cannot find an periodic alarm that fired. Perhaps it was recently cancelled.");
-    }
-    return Status::ok();
-}
-
-Status StatsService::informPollAlarmFired() {
-    ENFORCE_UID(AID_SYSTEM);
-
-    VLOG("StatsService::informPollAlarmFired was called");
-    mProcessor->informPullAlarmFired(getElapsedRealtimeNs());
-    VLOG("StatsService::informPollAlarmFired succeeded");
-    return Status::ok();
-}
-
-Status StatsService::systemRunning() {
-    ENFORCE_UID(AID_SYSTEM);
-
-    // When system_server is up and running, schedule the dropbox task to run.
-    VLOG("StatsService::systemRunning");
-    sayHiToStatsCompanion();
-    return Status::ok();
-}
-
-Status StatsService::informDeviceShutdown() {
-    ENFORCE_UID(AID_SYSTEM);
-    VLOG("StatsService::informDeviceShutdown");
-    mProcessor->WriteDataToDisk(DEVICE_SHUTDOWN, FAST);
-    mProcessor->SaveActiveConfigsToDisk(getElapsedRealtimeNs());
-    mProcessor->SaveMetadataToDisk(getWallClockNs(), getElapsedRealtimeNs());
-    return Status::ok();
-}
-
-void StatsService::sayHiToStatsCompanion() {
-    shared_ptr<IStatsCompanionService> statsCompanion = getStatsCompanionService();
-    if (statsCompanion != nullptr) {
-        VLOG("Telling statsCompanion that statsd is ready");
-        statsCompanion->statsdReady();
-    } else {
-        VLOG("Could not access statsCompanion");
-    }
-}
-
-Status StatsService::statsCompanionReady() {
-    ENFORCE_UID(AID_SYSTEM);
-
-    VLOG("StatsService::statsCompanionReady was called");
-    shared_ptr<IStatsCompanionService> statsCompanion = getStatsCompanionService();
-    if (statsCompanion == nullptr) {
-        return exception(EX_NULL_POINTER,
-                         "StatsCompanion unavailable despite it contacting statsd.");
-    }
-    VLOG("StatsService::statsCompanionReady linking to statsCompanion.");
-    AIBinder_linkToDeath(statsCompanion->asBinder().get(),
-                         mStatsCompanionServiceDeathRecipient.get(), this);
-    mPullerManager->SetStatsCompanionService(statsCompanion);
-    mAnomalyAlarmMonitor->setStatsCompanionService(statsCompanion);
-    mPeriodicAlarmMonitor->setStatsCompanionService(statsCompanion);
-    return Status::ok();
-}
-
-Status StatsService::bootCompleted() {
-    ENFORCE_UID(AID_SYSTEM);
-
-    VLOG("StatsService::bootCompleted was called");
-    mBootCompleteTrigger.markComplete(kBootCompleteTag);
-    return Status::ok();
-}
-
-void StatsService::Startup() {
-    mConfigManager->Startup();
-    mProcessor->LoadActiveConfigsFromDisk();
-    mProcessor->LoadMetadataFromDisk(getWallClockNs(), getElapsedRealtimeNs());
-}
-
-void StatsService::Terminate() {
-    ALOGI("StatsService::Terminating");
-    if (mProcessor != nullptr) {
-        mProcessor->WriteDataToDisk(TERMINATION_SIGNAL_RECEIVED, FAST);
-        mProcessor->SaveActiveConfigsToDisk(getElapsedRealtimeNs());
-        mProcessor->SaveMetadataToDisk(getWallClockNs(), getElapsedRealtimeNs());
-    }
-}
-
-// Test only interface!!!
-void StatsService::OnLogEvent(LogEvent* event) {
-    mProcessor->OnLogEvent(event);
-    if (mShellSubscriber != nullptr) {
-        mShellSubscriber->onLogEvent(*event);
-    }
-}
-
-Status StatsService::getData(int64_t key, const int32_t callingUid, vector<uint8_t>* output) {
-    ENFORCE_UID(AID_SYSTEM);
-
-    VLOG("StatsService::getData with Uid %i", callingUid);
-    ConfigKey configKey(callingUid, key);
-    // The dump latency does not matter here since we do not include the current bucket, we do not
-    // need to pull any new data anyhow.
-    mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(), false /* include_current_bucket*/,
-                             true /* erase_data */, GET_DATA_CALLED, FAST, output);
-    return Status::ok();
-}
-
-Status StatsService::getMetadata(vector<uint8_t>* output) {
-    ENFORCE_UID(AID_SYSTEM);
-
-    StatsdStats::getInstance().dumpStats(output, false); // Don't reset the counters.
-    return Status::ok();
-}
-
-Status StatsService::addConfiguration(int64_t key, const vector <uint8_t>& config,
-                                      const int32_t callingUid) {
-    ENFORCE_UID(AID_SYSTEM);
-
-    if (addConfigurationChecked(callingUid, key, config)) {
-        return Status::ok();
-    } else {
-        return exception(EX_ILLEGAL_ARGUMENT, "Could not parse malformatted StatsdConfig.");
-    }
-}
-
-bool StatsService::addConfigurationChecked(int uid, int64_t key, const vector<uint8_t>& config) {
-    ConfigKey configKey(uid, key);
-    StatsdConfig cfg;
-    if (config.size() > 0) {  // If the config is empty, skip parsing.
-        if (!cfg.ParseFromArray(&config[0], config.size())) {
-            return false;
-        }
-    }
-    mConfigManager->UpdateConfig(configKey, cfg);
-    return true;
-}
-
-Status StatsService::removeDataFetchOperation(int64_t key,
-                                              const int32_t callingUid) {
-    ENFORCE_UID(AID_SYSTEM);
-    ConfigKey configKey(callingUid, key);
-    mConfigManager->RemoveConfigReceiver(configKey);
-    return Status::ok();
-}
-
-Status StatsService::setDataFetchOperation(int64_t key,
-                                           const shared_ptr<IPendingIntentRef>& pir,
-                                           const int32_t callingUid) {
-    ENFORCE_UID(AID_SYSTEM);
-
-    ConfigKey configKey(callingUid, key);
-    mConfigManager->SetConfigReceiver(configKey, pir);
-    if (StorageManager::hasConfigMetricsReport(configKey)) {
-        VLOG("StatsService::setDataFetchOperation marking configKey %s to dump reports on disk",
-             configKey.ToString().c_str());
-        mProcessor->noteOnDiskData(configKey);
-    }
-    return Status::ok();
-}
-
-Status StatsService::setActiveConfigsChangedOperation(const shared_ptr<IPendingIntentRef>& pir,
-                                                      const int32_t callingUid,
-                                                      vector<int64_t>* output) {
-    ENFORCE_UID(AID_SYSTEM);
-
-    mConfigManager->SetActiveConfigsChangedReceiver(callingUid, pir);
-    if (output != nullptr) {
-        mProcessor->GetActiveConfigs(callingUid, *output);
-    } else {
-        ALOGW("StatsService::setActiveConfigsChanged output was nullptr");
-    }
-    return Status::ok();
-}
-
-Status StatsService::removeActiveConfigsChangedOperation(const int32_t callingUid) {
-    ENFORCE_UID(AID_SYSTEM);
-
-    mConfigManager->RemoveActiveConfigsChangedReceiver(callingUid);
-    return Status::ok();
-}
-
-Status StatsService::removeConfiguration(int64_t key, const int32_t callingUid) {
-    ENFORCE_UID(AID_SYSTEM);
-
-    ConfigKey configKey(callingUid, key);
-    mConfigManager->RemoveConfig(configKey);
-    return Status::ok();
-}
-
-Status StatsService::setBroadcastSubscriber(int64_t configId,
-                                            int64_t subscriberId,
-                                            const shared_ptr<IPendingIntentRef>& pir,
-                                            const int32_t callingUid) {
-    ENFORCE_UID(AID_SYSTEM);
-
-    VLOG("StatsService::setBroadcastSubscriber called.");
-    ConfigKey configKey(callingUid, configId);
-    SubscriberReporter::getInstance()
-            .setBroadcastSubscriber(configKey, subscriberId, pir);
-    return Status::ok();
-}
-
-Status StatsService::unsetBroadcastSubscriber(int64_t configId,
-                                              int64_t subscriberId,
-                                              const int32_t callingUid) {
-    ENFORCE_UID(AID_SYSTEM);
-
-    VLOG("StatsService::unsetBroadcastSubscriber called.");
-    ConfigKey configKey(callingUid, configId);
-    SubscriberReporter::getInstance()
-            .unsetBroadcastSubscriber(configKey, subscriberId);
-    return Status::ok();
-}
-
-Status StatsService::allPullersFromBootRegistered() {
-    ENFORCE_UID(AID_SYSTEM);
-
-    VLOG("StatsService::allPullersFromBootRegistered was called");
-    mBootCompleteTrigger.markComplete(kAllPullersRegisteredTag);
-    return Status::ok();
-}
-
-Status StatsService::registerPullAtomCallback(int32_t uid, int32_t atomTag, int64_t coolDownMillis,
-                                              int64_t timeoutMillis,
-                                              const std::vector<int32_t>& additiveFields,
-                                              const shared_ptr<IPullAtomCallback>& pullerCallback) {
-    ENFORCE_UID(AID_SYSTEM);
-    VLOG("StatsService::registerPullAtomCallback called.");
-    mPullerManager->RegisterPullAtomCallback(uid, atomTag, MillisToNano(coolDownMillis),
-                                             MillisToNano(timeoutMillis), additiveFields,
-                                             pullerCallback);
-    return Status::ok();
-}
-
-Status StatsService::registerNativePullAtomCallback(
-        int32_t atomTag, int64_t coolDownMillis, int64_t timeoutMillis,
-        const std::vector<int32_t>& additiveFields,
-        const shared_ptr<IPullAtomCallback>& pullerCallback) {
-    if (!checkPermission(kPermissionRegisterPullAtom)) {
-        return exception(
-                EX_SECURITY,
-                StringPrintf("Uid %d does not have the %s permission when registering atom %d",
-                             AIBinder_getCallingUid(), kPermissionRegisterPullAtom, atomTag));
-    }
-    VLOG("StatsService::registerNativePullAtomCallback called.");
-    int32_t uid = AIBinder_getCallingUid();
-    mPullerManager->RegisterPullAtomCallback(uid, atomTag, MillisToNano(coolDownMillis),
-                                             MillisToNano(timeoutMillis), additiveFields,
-                                             pullerCallback);
-    return Status::ok();
-}
-
-Status StatsService::unregisterPullAtomCallback(int32_t uid, int32_t atomTag) {
-    ENFORCE_UID(AID_SYSTEM);
-    VLOG("StatsService::unregisterPullAtomCallback called.");
-    mPullerManager->UnregisterPullAtomCallback(uid, atomTag);
-    return Status::ok();
-}
-
-Status StatsService::unregisterNativePullAtomCallback(int32_t atomTag) {
-    if (!checkPermission(kPermissionRegisterPullAtom)) {
-        return exception(
-                EX_SECURITY,
-                StringPrintf("Uid %d does not have the %s permission when unregistering atom %d",
-                             AIBinder_getCallingUid(), kPermissionRegisterPullAtom, atomTag));
-    }
-    VLOG("StatsService::unregisterNativePullAtomCallback called.");
-    int32_t uid = AIBinder_getCallingUid();
-    mPullerManager->UnregisterPullAtomCallback(uid, atomTag);
-    return Status::ok();
-}
-
-Status StatsService::getRegisteredExperimentIds(std::vector<int64_t>* experimentIdsOut) {
-    ENFORCE_UID(AID_SYSTEM);
-    // TODO: add verifier permission
-
-    experimentIdsOut->clear();
-    // Read the latest train info
-    vector<InstallTrainInfo> trainInfoList = StorageManager::readAllTrainInfo();
-    if (trainInfoList.empty()) {
-        // No train info means no experiment IDs, return an empty list
-        return Status::ok();
-    }
-
-    // Copy the experiment IDs to the out vector
-    for (InstallTrainInfo& trainInfo : trainInfoList) {
-        experimentIdsOut->insert(experimentIdsOut->end(),
-                                 trainInfo.experimentIds.begin(),
-                                 trainInfo.experimentIds.end());
-    }
-    return Status::ok();
-}
-
-void StatsService::statsCompanionServiceDied(void* cookie) {
-    auto thiz = static_cast<StatsService*>(cookie);
-    thiz->statsCompanionServiceDiedImpl();
-}
-
-void StatsService::statsCompanionServiceDiedImpl() {
-    ALOGW("statscompanion service died");
-    StatsdStats::getInstance().noteSystemServerRestart(getWallClockSec());
-    if (mProcessor != nullptr) {
-        ALOGW("Reset statsd upon system server restarts.");
-        int64_t systemServerRestartNs = getElapsedRealtimeNs();
-        ProtoOutputStream activeConfigsProto;
-        mProcessor->WriteActiveConfigsToProtoOutputStream(systemServerRestartNs,
-                STATSCOMPANION_DIED, &activeConfigsProto);
-        metadata::StatsMetadataList metadataList;
-        mProcessor->WriteMetadataToProto(getWallClockNs(),
-                systemServerRestartNs, &metadataList);
-        mProcessor->WriteDataToDisk(STATSCOMPANION_DIED, FAST);
-        mProcessor->resetConfigs();
-
-        std::string serializedActiveConfigs;
-        if (activeConfigsProto.serializeToString(&serializedActiveConfigs)) {
-            ActiveConfigList activeConfigs;
-            if (activeConfigs.ParseFromString(serializedActiveConfigs)) {
-                mProcessor->SetConfigsActiveState(activeConfigs, systemServerRestartNs);
-            }
-        }
-        mProcessor->SetMetadataState(metadataList, getWallClockNs(), systemServerRestartNs);
-    }
-    mAnomalyAlarmMonitor->setStatsCompanionService(nullptr);
-    mPeriodicAlarmMonitor->setStatsCompanionService(nullptr);
-    mPullerManager->SetStatsCompanionService(nullptr);
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
deleted file mode 100644
index 479f4e8..0000000
--- a/cmds/statsd/src/StatsService.h
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef STATS_SERVICE_H
-#define STATS_SERVICE_H
-
-#include <aidl/android/os/BnStatsd.h>
-#include <aidl/android/os/IPendingIntentRef.h>
-#include <aidl/android/os/IPullAtomCallback.h>
-#include <gtest/gtest_prod.h>
-#include <utils/Looper.h>
-
-#include <mutex>
-
-#include "StatsLogProcessor.h"
-#include "anomaly/AlarmMonitor.h"
-#include "config/ConfigManager.h"
-#include "external/StatsPullerManager.h"
-#include "logd/LogEventQueue.h"
-#include "packages/UidMap.h"
-#include "shell/ShellSubscriber.h"
-#include "statscompanion_util.h"
-#include "utils/MultiConditionTrigger.h"
-
-using namespace android;
-using namespace android::os;
-using namespace std;
-
-using Status = ::ndk::ScopedAStatus;
-using aidl::android::os::BnStatsd;
-using aidl::android::os::IPendingIntentRef;
-using aidl::android::os::IPullAtomCallback;
-using ::ndk::ScopedAIBinder_DeathRecipient;
-using ::ndk::ScopedFileDescriptor;
-using std::shared_ptr;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class StatsService : public BnStatsd {
-public:
-    StatsService(const sp<Looper>& handlerLooper, std::shared_ptr<LogEventQueue> queue);
-    virtual ~StatsService();
-
-    /** The anomaly alarm registered with AlarmManager won't be updated by less than this. */
-    const uint32_t MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS = 5;
-
-    virtual status_t dump(int fd, const char** args, uint32_t numArgs) override;
-    virtual status_t handleShellCommand(int in, int out, int err, const char** argv,
-                                        uint32_t argc) override;
-
-    virtual Status systemRunning();
-    virtual Status statsCompanionReady();
-    virtual Status bootCompleted();
-    virtual Status informPollAlarmFired();
-    virtual Status informAlarmForSubscriberTriggeringFired();
-
-    virtual Status informAllUidData(const ScopedFileDescriptor& fd);
-    virtual Status informOnePackage(const string& app, int32_t uid, int64_t version,
-                                    const string& versionString, const string& installer);
-    virtual Status informOnePackageRemoved(const string& app, int32_t uid);
-    virtual Status informDeviceShutdown();
-
-    /**
-     * Called right before we start processing events.
-     */
-    void Startup();
-
-    /**
-     * Called when terminiation signal received.
-     */
-    void Terminate();
-
-    /**
-     * Test ONLY interface. In real world, StatsService reads from LogEventQueue.
-     */
-    virtual void OnLogEvent(LogEvent* event);
-
-    /**
-     * Binder call for clients to request data for this configuration key.
-     */
-    virtual Status getData(int64_t key,
-                           const int32_t callingUid,
-                           vector<uint8_t>* output) override;
-
-
-    /**
-     * Binder call for clients to get metadata across all configs in statsd.
-     */
-    virtual Status getMetadata(vector<uint8_t>* output) override;
-
-
-    /**
-     * Binder call to let clients send a configuration and indicate they're interested when they
-     * should requestData for this configuration.
-     */
-    virtual Status addConfiguration(int64_t key,
-                                    const vector<uint8_t>& config,
-                                    const int32_t callingUid) override;
-
-    /**
-     * Binder call to let clients register the data fetch operation for a configuration.
-     */
-    virtual Status setDataFetchOperation(int64_t key,
-                                         const shared_ptr<IPendingIntentRef>& pir,
-                                         const int32_t callingUid) override;
-
-    /**
-     * Binder call to remove the data fetch operation for the specified config key.
-     */
-    virtual Status removeDataFetchOperation(int64_t key,
-                                            const int32_t callingUid) override;
-
-    /**
-     * Binder call to let clients register the active configs changed operation.
-     */
-    virtual Status setActiveConfigsChangedOperation(const shared_ptr<IPendingIntentRef>& pir,
-                                                    const int32_t callingUid,
-                                                    vector<int64_t>* output) override;
-
-    /**
-     * Binder call to remove the active configs changed operation for the specified package..
-     */
-    virtual Status removeActiveConfigsChangedOperation(const int32_t callingUid) override;
-    /**
-     * Binder call to allow clients to remove the specified configuration.
-     */
-    virtual Status removeConfiguration(int64_t key,
-                                       const int32_t callingUid) override;
-
-    /**
-     * Binder call to associate the given config's subscriberId with the given pendingIntentRef.
-     */
-    virtual Status setBroadcastSubscriber(int64_t configId,
-                                          int64_t subscriberId,
-                                          const shared_ptr<IPendingIntentRef>& pir,
-                                          const int32_t callingUid) override;
-
-    /**
-     * Binder call to unassociate the given config's subscriberId with any pendingIntentRef.
-     */
-    virtual Status unsetBroadcastSubscriber(int64_t configId,
-                                            int64_t subscriberId,
-                                            const int32_t callingUid) override;
-
-    /** Inform statsCompanion that statsd is ready. */
-    virtual void sayHiToStatsCompanion();
-
-    /**
-     * Binder call to notify statsd that all pullers from boot have been registered.
-     */
-    virtual Status allPullersFromBootRegistered();
-
-    /**
-     * Binder call to register a callback function for a pulled atom.
-     */
-    virtual Status registerPullAtomCallback(
-            int32_t uid, int32_t atomTag, int64_t coolDownMillis, int64_t timeoutMillis,
-            const std::vector<int32_t>& additiveFields,
-            const shared_ptr<IPullAtomCallback>& pullerCallback) override;
-
-    /**
-     * Binder call to register a callback function for a pulled atom.
-     */
-    virtual Status registerNativePullAtomCallback(
-            int32_t atomTag, int64_t coolDownMillis, int64_t timeoutMillis,
-            const std::vector<int32_t>& additiveFields,
-            const shared_ptr<IPullAtomCallback>& pullerCallback) override;
-
-    /**
-     * Binder call to unregister any existing callback for the given uid and atom.
-     */
-    virtual Status unregisterPullAtomCallback(int32_t uid, int32_t atomTag) override;
-
-    /**
-     * Binder call to unregister any existing callback for the given atom and calling uid.
-     */
-    virtual Status unregisterNativePullAtomCallback(int32_t atomTag) override;
-
-    /**
-     * Binder call to get registered experiment IDs.
-     */
-    virtual Status getRegisteredExperimentIds(std::vector<int64_t>* expIdsOut);
-
-private:
-    /**
-     * Load system properties at init.
-     */
-    void init_system_properties();
-
-    /**
-     * Helper for loading system properties.
-     */
-    static void init_build_type_callback(void* cookie, const char* name, const char* value,
-                                         uint32_t serial);
-
-    /**
-     * Proto output of statsd report data dumpsys, wrapped in a StatsDataDumpProto.
-     */
-    void dumpIncidentSection(int outFd);
-
-    /**
-     * Text or proto output of statsdStats dumpsys.
-     */
-    void dumpStatsdStats(int outFd, bool verbose, bool proto);
-
-    /**
-     * Print usage information for the commands
-     */
-    void print_cmd_help(int out);
-
-    /* Runs on its dedicated thread to process pushed stats event from socket. */
-    void readLogs();
-
-    /**
-     * Trigger a broadcast.
-     */
-    status_t cmd_trigger_broadcast(int outFd, Vector<String8>& args);
-
-
-    /**
-     * Trigger an active configs changed broadcast.
-     */
-    status_t cmd_trigger_active_config_broadcast(int outFd, Vector<String8>& args);
-
-    /**
-     * Handle the config sub-command.
-     */
-    status_t cmd_config(int inFd, int outFd, int err, Vector<String8>& args);
-
-    /**
-     * Prints some basic stats to std out.
-     */
-    status_t cmd_print_stats(int outFd, const Vector<String8>& args);
-
-    /**
-     * Print the event log.
-     */
-    status_t cmd_dump_report(int outFd, const Vector<String8>& args);
-
-    /**
-     * Print the mapping of uids to package names.
-     */
-    status_t cmd_print_uid_map(int outFd, const Vector<String8>& args);
-
-    /**
-     * Flush the data to disk.
-     */
-    status_t cmd_write_data_to_disk(int outFd);
-
-    /**
-     * Write an AppBreadcrumbReported event to the StatsLog buffer, as if calling
-     * StatsLog.write(APP_BREADCRUMB_REPORTED).
-     */
-    status_t cmd_log_app_breadcrumb(int outFd, const Vector<String8>& args);
-
-    /**
-     * Write an BinaryPushStateChanged event, as if calling StatsLog.logBinaryPushStateChanged().
-     */
-    status_t cmd_log_binary_push(int outFd, const Vector<String8>& args);
-
-    /**
-     * Print contents of a pulled metrics source.
-     */
-    status_t cmd_print_pulled_metrics(int outFd, const Vector<String8>& args);
-
-    /**
-     * Removes all configs stored on disk and on memory.
-     */
-    status_t cmd_remove_all_configs(int outFd);
-
-    /*
-     * Dump memory usage by statsd.
-     */
-    status_t cmd_dump_memory_info(int outFd);
-
-    /*
-     * Clear all puller cached data
-     */
-    status_t cmd_clear_puller_cache(int outFd);
-
-    /**
-     * Print all stats logs received to logcat.
-     */
-    status_t cmd_print_logs(int outFd, const Vector<String8>& args);
-
-    /**
-     * Writes the value of args[uidArgIndex] into uid.
-     * Returns whether the uid is reasonable (type uid_t) and whether
-     * 1. it is equal to the calling uid, or
-     * 2. the device is mEngBuild, or
-     * 3. the caller is AID_ROOT and the uid is AID_SHELL (i.e. ROOT can impersonate SHELL).
-     */
-    bool getUidFromArgs(const Vector<String8>& args, size_t uidArgIndex, int32_t& uid);
-
-    /**
-     * Writes the value of uidSting into uid.
-     * Returns whether the uid is reasonable (type uid_t) and whether
-     * 1. it is equal to the calling uid, or
-     * 2. the device is mEngBuild, or
-     * 3. the caller is AID_ROOT and the uid is AID_SHELL (i.e. ROOT can impersonate SHELL).
-     */
-     bool getUidFromString(const char* uidString, int32_t& uid);
-
-    /**
-     * Adds a configuration after checking permissions and obtaining UID from binder call.
-     */
-    bool addConfigurationChecked(int uid, int64_t key, const vector<uint8_t>& config);
-
-    /**
-     * Update a configuration.
-     */
-    void set_config(int uid, const string& name, const StatsdConfig& config);
-
-    /**
-     * Death recipient callback that is called when StatsCompanionService dies.
-     * The cookie is a pointer to a StatsService object.
-     */
-    static void statsCompanionServiceDied(void* cookie);
-
-    /**
-     * Implementation of statsCompanionServiceDied.
-     */
-    void statsCompanionServiceDiedImpl();
-
-    /**
-     * Tracks the uid <--> package name mapping.
-     */
-    sp<UidMap> mUidMap;
-
-    /**
-     * Fetches external metrics
-     */
-    sp<StatsPullerManager> mPullerManager;
-
-    /**
-     * Tracks the configurations that have been passed to statsd.
-     */
-    sp<ConfigManager> mConfigManager;
-
-    /**
-     * The metrics recorder.
-     */
-    sp<StatsLogProcessor> mProcessor;
-
-    /**
-     * The alarm monitor for anomaly detection.
-     */
-    const sp<AlarmMonitor> mAnomalyAlarmMonitor;
-
-    /**
-     * The alarm monitor for alarms to directly trigger subscriber.
-     */
-    const sp<AlarmMonitor> mPeriodicAlarmMonitor;
-
-    /**
-     * Whether this is an eng build.
-     */
-    bool mEngBuild;
-
-    sp<ShellSubscriber> mShellSubscriber;
-
-    /**
-     * Mutex for setting the shell subscriber
-     */
-    mutable mutex mShellSubscriberMutex;
-    std::shared_ptr<LogEventQueue> mEventQueue;
-
-    MultiConditionTrigger mBootCompleteTrigger;
-    static const inline string kBootCompleteTag = "BOOT_COMPLETE";
-    static const inline string kUidMapReceivedTag = "UID_MAP";
-    static const inline string kAllPullersRegisteredTag = "PULLERS_REGISTERED";
-
-    ScopedAIBinder_DeathRecipient mStatsCompanionServiceDeathRecipient;
-
-    FRIEND_TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart);
-    FRIEND_TEST(StatsServiceTest, TestAddConfig_simple);
-    FRIEND_TEST(StatsServiceTest, TestAddConfig_empty);
-    FRIEND_TEST(StatsServiceTest, TestAddConfig_invalid);
-    FRIEND_TEST(StatsServiceTest, TestGetUidFromArgs);
-    FRIEND_TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp);
-    FRIEND_TEST(PartialBucketE2eTest, TestCountMetricSplitOnBoot);
-    FRIEND_TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade);
-    FRIEND_TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval);
-    FRIEND_TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit);
-    FRIEND_TEST(PartialBucketE2eTest, TestValueMetricOnBootWithoutMinPartialBucket);
-    FRIEND_TEST(PartialBucketE2eTest, TestValueMetricWithoutMinPartialBucket);
-    FRIEND_TEST(PartialBucketE2eTest, TestValueMetricWithMinPartialBucket);
-    FRIEND_TEST(PartialBucketE2eTest, TestGaugeMetricOnBootWithoutMinPartialBucket);
-    FRIEND_TEST(PartialBucketE2eTest, TestGaugeMetricWithoutMinPartialBucket);
-    FRIEND_TEST(PartialBucketE2eTest, TestGaugeMetricWithMinPartialBucket);
-
-    FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket);
-    FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets);
-    FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-#endif  // STATS_SERVICE_H
diff --git a/cmds/statsd/src/active_config_list.proto b/cmds/statsd/src/active_config_list.proto
deleted file mode 100644
index 9929833..0000000
--- a/cmds/statsd/src/active_config_list.proto
+++ /dev/null
@@ -1,57 +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.
- */
-
-syntax = "proto2";
-
-package android.os.statsd;
-option java_package = "com.android.os";
-option java_multiple_files = true;
-option java_outer_classname = "ActiveConfigProto";
-
-message ActiveEventActivation {
-    optional int32 atom_matcher_index = 1;
-
-    // Time left in activation. When this proto is loaded after device boot,
-    // the activation should be set to active for this duration.
-    // This field will only be set when the state is ACTIVE
-    optional int64 remaining_ttl_nanos = 2;
-
-    enum State {
-        UNNKNOWN = 0;
-        // This metric should activate for remaining_ttl_nanos when we load the activations.
-        ACTIVE = 1;
-        // When we load the activations, this metric should activate on next boot for the tll
-        // specified in the config.
-        ACTIVATE_ON_BOOT = 2;
-    }
-    optional State state = 3;
-}
-
-message ActiveMetric {
-    optional int64 id = 1;
-    repeated ActiveEventActivation activation = 2;
-}
-
-message ActiveConfig {
-    optional int64 id = 1;
-    optional int32 uid = 2;
-    repeated ActiveMetric metric = 3;
-}
-
-// all configs and their metrics on device.
-message ActiveConfigList {
-    repeated ActiveConfig config = 1;
-}
diff --git a/cmds/statsd/src/annotations.h b/cmds/statsd/src/annotations.h
deleted file mode 100644
index cf7f543..0000000
--- a/cmds/statsd/src/annotations.h
+++ /dev/null
@@ -1,33 +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.
- */
-
-#pragma once
-
-namespace android {
-namespace os {
-namespace statsd {
-
-const uint8_t ANNOTATION_ID_IS_UID = 1;
-const uint8_t ANNOTATION_ID_TRUNCATE_TIMESTAMP = 2;
-const uint8_t ANNOTATION_ID_PRIMARY_FIELD = 3;
-const uint8_t ANNOTATION_ID_EXCLUSIVE_STATE = 4;
-const uint8_t ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID = 5;
-const uint8_t ANNOTATION_ID_TRIGGER_STATE_RESET = 7;
-const uint8_t ANNOTATION_ID_STATE_NESTED = 8;
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/anomaly/AlarmMonitor.cpp b/cmds/statsd/src/anomaly/AlarmMonitor.cpp
deleted file mode 100644
index b632d04..0000000
--- a/cmds/statsd/src/anomaly/AlarmMonitor.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false
-#include "Log.h"
-
-#include "anomaly/AlarmMonitor.h"
-#include "guardrail/StatsdStats.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-AlarmMonitor::AlarmMonitor(
-        uint32_t minDiffToUpdateRegisteredAlarmTimeSec,
-        const std::function<void(const shared_ptr<IStatsCompanionService>&, int64_t)>& updateAlarm,
-        const std::function<void(const shared_ptr<IStatsCompanionService>&)>& cancelAlarm)
-    : mRegisteredAlarmTimeSec(0),
-      mMinUpdateTimeSec(minDiffToUpdateRegisteredAlarmTimeSec),
-      mUpdateAlarm(updateAlarm),
-      mCancelAlarm(cancelAlarm) {}
-
-AlarmMonitor::~AlarmMonitor() {}
-
-void AlarmMonitor::setStatsCompanionService(
-        shared_ptr<IStatsCompanionService> statsCompanionService) {
-    std::lock_guard<std::mutex> lock(mLock);
-    shared_ptr<IStatsCompanionService> tmpForLock = mStatsCompanionService;
-    mStatsCompanionService = statsCompanionService;
-    if (statsCompanionService == nullptr) {
-        VLOG("Erasing link to statsCompanionService");
-        return;
-    }
-    VLOG("Creating link to statsCompanionService");
-    const sp<const InternalAlarm> top = mPq.top();
-    if (top != nullptr) {
-        updateRegisteredAlarmTime_l(top->timestampSec);
-    }
-}
-
-void AlarmMonitor::add(sp<const InternalAlarm> alarm) {
-    std::lock_guard<std::mutex> lock(mLock);
-    if (alarm == nullptr) {
-        ALOGW("Asked to add a null alarm.");
-        return;
-    }
-    if (alarm->timestampSec < 1) {
-        // forbidden since a timestamp 0 is used to indicate no alarm registered
-        ALOGW("Asked to add a 0-time alarm.");
-        return;
-    }
-    // TODO(b/110563466): Ensure that refractory period is respected.
-    VLOG("Adding alarm with time %u", alarm->timestampSec);
-    mPq.push(alarm);
-    if (mRegisteredAlarmTimeSec < 1 ||
-        alarm->timestampSec + mMinUpdateTimeSec < mRegisteredAlarmTimeSec) {
-        updateRegisteredAlarmTime_l(alarm->timestampSec);
-    }
-}
-
-void AlarmMonitor::remove(sp<const InternalAlarm> alarm) {
-    std::lock_guard<std::mutex> lock(mLock);
-    if (alarm == nullptr) {
-        ALOGW("Asked to remove a null alarm.");
-        return;
-    }
-    VLOG("Removing alarm with time %u", alarm->timestampSec);
-    bool wasPresent = mPq.remove(alarm);
-    if (!wasPresent) return;
-    if (mPq.empty()) {
-        VLOG("Queue is empty. Cancel any alarm.");
-        cancelRegisteredAlarmTime_l();
-        return;
-    }
-    uint32_t soonestAlarmTimeSec = mPq.top()->timestampSec;
-    VLOG("Soonest alarm is %u", soonestAlarmTimeSec);
-    if (soonestAlarmTimeSec > mRegisteredAlarmTimeSec + mMinUpdateTimeSec) {
-        updateRegisteredAlarmTime_l(soonestAlarmTimeSec);
-    }
-}
-
-// More efficient than repeatedly calling remove(mPq.top()) since it batches the
-// updates to the registered alarm.
-unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> AlarmMonitor::popSoonerThan(
-        uint32_t timestampSec) {
-    VLOG("Removing alarms with time <= %u", timestampSec);
-    unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> oldAlarms;
-    std::lock_guard<std::mutex> lock(mLock);
-
-    for (sp<const InternalAlarm> t = mPq.top(); t != nullptr && t->timestampSec <= timestampSec;
-        t = mPq.top()) {
-        oldAlarms.insert(t);
-        mPq.pop();  // remove t
-    }
-    // Always update registered alarm time (if anything has changed).
-    if (!oldAlarms.empty()) {
-        if (mPq.empty()) {
-            VLOG("Queue is empty. Cancel any alarm.");
-            cancelRegisteredAlarmTime_l();
-        } else {
-            // Always update the registered alarm in this case (unlike remove()).
-            updateRegisteredAlarmTime_l(mPq.top()->timestampSec);
-        }
-    }
-    return oldAlarms;
-}
-
-void AlarmMonitor::updateRegisteredAlarmTime_l(uint32_t timestampSec) {
-    VLOG("Updating reg alarm time to %u", timestampSec);
-    mRegisteredAlarmTimeSec = timestampSec;
-    mUpdateAlarm(mStatsCompanionService, secToMs(mRegisteredAlarmTimeSec));
-}
-
-void AlarmMonitor::cancelRegisteredAlarmTime_l() {
-    VLOG("Cancelling reg alarm.");
-    mRegisteredAlarmTimeSec = 0;
-    mCancelAlarm(mStatsCompanionService);
-}
-
-int64_t AlarmMonitor::secToMs(uint32_t timeSec) {
-    return ((int64_t)timeSec) * 1000;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/anomaly/AlarmMonitor.h b/cmds/statsd/src/anomaly/AlarmMonitor.h
deleted file mode 100644
index 5c34e38..0000000
--- a/cmds/statsd/src/anomaly/AlarmMonitor.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "anomaly/indexed_priority_queue.h"
-
-#include <aidl/android/os/IStatsCompanionService.h>
-#include <utils/RefBase.h>
-
-#include <unordered_set>
-#include <vector>
-
-using namespace android;
-
-using aidl::android::os::IStatsCompanionService;
-using std::function;
-using std::shared_ptr;
-using std::unordered_set;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/**
- * Represents an alarm, associated with some aggregate metric, holding a
- * projected time at which the metric is expected to exceed its anomaly
- * threshold.
- * Timestamps are in seconds since epoch in a uint32, so will fail in year 2106.
- */
-struct InternalAlarm : public RefBase {
-    explicit InternalAlarm(uint32_t timestampSec) : timestampSec(timestampSec) {
-    }
-
-    const uint32_t timestampSec;
-
-    /** InternalAlarm a is smaller (higher priority) than b if its timestamp is sooner. */
-    struct SmallerTimestamp {
-        bool operator()(sp<const InternalAlarm> a, sp<const InternalAlarm> b) const {
-            return (a->timestampSec < b->timestampSec);
-        }
-    };
-};
-
-/**
- * Manages internal alarms that may get registered with the AlarmManager.
- */
-class AlarmMonitor : public RefBase {
-public:
-    /**
-     * @param minDiffToUpdateRegisteredAlarmTimeSec If the soonest alarm differs
-     * from the registered alarm by more than this amount, update the registered
-     * alarm.
-     */
-    AlarmMonitor(uint32_t minDiffToUpdateRegisteredAlarmTimeSec,
-                 const function<void(const shared_ptr<IStatsCompanionService>&, int64_t)>&
-                         updateAlarm,
-                 const function<void(const shared_ptr<IStatsCompanionService>&)>& cancelAlarm);
-    ~AlarmMonitor();
-
-    /**
-     * Tells AnomalyMonitor what IStatsCompanionService to use and, if
-     * applicable, immediately registers an existing alarm with it.
-     * If nullptr, AnomalyMonitor will continue to add/remove alarms, but won't
-     * update IStatsCompanionService (until such time as it is set non-null).
-     */
-    void setStatsCompanionService(shared_ptr<IStatsCompanionService> statsCompanionService);
-
-    /**
-     * Adds the given alarm (reference) to the queue.
-     */
-    void add(sp<const InternalAlarm> alarm);
-
-    /**
-     * Removes the given alarm (reference) from the queue.
-     * Note that alarm comparison is reference-based; if another alarm exists
-     * with the same timestampSec, that alarm will still remain in the queue.
-     */
-    void remove(sp<const InternalAlarm> alarm);
-
-    /**
-     * Returns and removes all alarms whose timestamp <= the given timestampSec.
-     * Always updates the registered alarm if return is non-empty.
-     */
-    unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> popSoonerThan(
-            uint32_t timestampSec);
-
-    /**
-     * Returns the projected alarm timestamp that is registered with
-     * StatsCompanionService. This may not be equal to the soonest alarm,
-     * but should be within minDiffToUpdateRegisteredAlarmTimeSec of it.
-     */
-    uint32_t getRegisteredAlarmTimeSec() const {
-        return mRegisteredAlarmTimeSec;
-    }
-
-private:
-    std::mutex mLock;
-
-    /**
-     * Timestamp (seconds since epoch) of the alarm registered with
-     * StatsCompanionService. This, in general, may not be equal to the soonest
-     * alarm stored in mPq, but should be within minUpdateTimeSec of it.
-     * A value of 0 indicates that no alarm is currently registered.
-     */
-    uint32_t mRegisteredAlarmTimeSec;
-
-    /**
-     * Priority queue of alarms, prioritized by soonest alarm.timestampSec.
-     */
-    indexed_priority_queue<InternalAlarm, InternalAlarm::SmallerTimestamp> mPq;
-
-    /**
-     * Binder interface for communicating with StatsCompanionService.
-     */
-    shared_ptr<IStatsCompanionService> mStatsCompanionService = nullptr;
-
-    /**
-     * Amount by which the soonest projected alarm must differ from
-     * mRegisteredAlarmTimeSec before updateRegisteredAlarmTime_l is called.
-     */
-    uint32_t mMinUpdateTimeSec;
-
-    /**
-     * Updates the alarm registered with StatsCompanionService to the given time.
-     * Also correspondingly updates mRegisteredAlarmTimeSec.
-     */
-    void updateRegisteredAlarmTime_l(uint32_t timestampSec);
-
-    /**
-     * Cancels the alarm registered with StatsCompanionService.
-     * Also correspondingly sets mRegisteredAlarmTimeSec to 0.
-     */
-    void cancelRegisteredAlarmTime_l();
-
-    /** Converts uint32 timestamp in seconds to a Java long in msec. */
-    int64_t secToMs(uint32_t timeSec);
-
-    // Callback function to update the alarm via StatsCompanionService.
-    std::function<void(const shared_ptr<IStatsCompanionService>, int64_t)> mUpdateAlarm;
-
-    // Callback function to cancel the alarm via StatsCompanionService.
-    std::function<void(const shared_ptr<IStatsCompanionService>)> mCancelAlarm;
-
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/anomaly/AlarmTracker.cpp b/cmds/statsd/src/anomaly/AlarmTracker.cpp
deleted file mode 100644
index 6d9beb8..0000000
--- a/cmds/statsd/src/anomaly/AlarmTracker.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "anomaly/AlarmTracker.h"
-#include "anomaly/subscriber_util.h"
-#include "HashableDimensionKey.h"
-#include "stats_util.h"
-#include "storage/StorageManager.h"
-
-#include <time.h>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-AlarmTracker::AlarmTracker(const int64_t startMillis,
-                           const int64_t currentMillis,
-                           const Alarm& alarm, const ConfigKey& configKey,
-                           const sp<AlarmMonitor>& alarmMonitor)
-    : mAlarmConfig(alarm),
-      mConfigKey(configKey),
-      mAlarmMonitor(alarmMonitor) {
-    VLOG("AlarmTracker() called");
-    mAlarmSec = (startMillis + mAlarmConfig.offset_millis()) / MS_PER_SEC;
-    // startMillis is the time statsd is created. We need to find the 1st alarm timestamp after
-    // the config is added to statsd.
-    mAlarmSec = findNextAlarmSec(currentMillis / MS_PER_SEC);  // round up
-    mInternalAlarm = new InternalAlarm{static_cast<uint32_t>(mAlarmSec)};
-    VLOG("AlarmTracker sets the periodic alarm at: %lld", (long long)mAlarmSec);
-    if (mAlarmMonitor != nullptr) {
-        mAlarmMonitor->add(mInternalAlarm);
-    }
-}
-
-AlarmTracker::~AlarmTracker() {
-    VLOG("~AlarmTracker() called");
-    if (mInternalAlarm != nullptr && mAlarmMonitor != nullptr) {
-        mAlarmMonitor->remove(mInternalAlarm);
-    }
-}
-
-void AlarmTracker::addSubscription(const Subscription& subscription) {
-    mSubscriptions.push_back(subscription);
-}
-
-int64_t AlarmTracker::findNextAlarmSec(int64_t currentTimeSec) {
-    if (currentTimeSec < mAlarmSec) {
-        return mAlarmSec;
-    }
-    int64_t periodsForward =
-        ((currentTimeSec - mAlarmSec) * MS_PER_SEC) / mAlarmConfig.period_millis() + 1;
-    return mAlarmSec + periodsForward * mAlarmConfig.period_millis() / MS_PER_SEC;
-}
-
-void AlarmTracker::informAlarmsFired(
-        const int64_t& timestampNs,
-        unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& firedAlarms) {
-    if (firedAlarms.empty() || mInternalAlarm == nullptr ||
-        firedAlarms.find(mInternalAlarm) == firedAlarms.end()) {
-        return;
-    }
-    if (!mSubscriptions.empty()) {
-        VLOG("AlarmTracker triggers the subscribers.");
-        triggerSubscribers(mAlarmConfig.id(), 0 /*metricId N/A*/, DEFAULT_METRIC_DIMENSION_KEY,
-                           0 /* metricValue N/A */, mConfigKey, mSubscriptions);
-    }
-    firedAlarms.erase(mInternalAlarm);
-    mAlarmSec = findNextAlarmSec((timestampNs-1) / NS_PER_SEC + 1); // round up
-    mInternalAlarm = new InternalAlarm{static_cast<uint32_t>(mAlarmSec)};
-    VLOG("AlarmTracker sets the periodic alarm at: %lld", (long long)mAlarmSec);
-    if (mAlarmMonitor != nullptr) {
-        mAlarmMonitor->add(mInternalAlarm);
-    }
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/anomaly/AlarmTracker.h b/cmds/statsd/src/anomaly/AlarmTracker.h
deleted file mode 100644
index 406086d..0000000
--- a/cmds/statsd/src/anomaly/AlarmTracker.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <gtest/gtest_prod.h>
-
-#include "AlarmMonitor.h"
-#include "config/ConfigKey.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"  // Alarm
-
-#include <stdlib.h>
-#include <utils/RefBase.h>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class AlarmTracker : public virtual RefBase {
-public:
-    AlarmTracker(const int64_t startMillis,
-                 const int64_t currentMillis,
-                 const Alarm& alarm, const ConfigKey& configKey,
-                 const sp<AlarmMonitor>& subscriberAlarmMonitor);
-
-    virtual ~AlarmTracker();
-
-    void onAlarmFired();
-
-    void addSubscription(const Subscription& subscription);
-
-    void informAlarmsFired(const int64_t& timestampNs,
-            unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& firedAlarms);
-
-protected:
-    // For test only. Returns the alarm timestamp in seconds. Otherwise returns 0.
-    inline int32_t getAlarmTimestampSec() const {
-        return mInternalAlarm == nullptr ? 0 : mInternalAlarm->timestampSec;
-    }
-
-    int64_t findNextAlarmSec(int64_t currentTimeMillis);
-
-    // statsd_config.proto Alarm message that defines this tracker.
-    const Alarm mAlarmConfig;
-
-    // A reference to the Alarm's config key.
-    const ConfigKey mConfigKey;
-
-    // The subscriptions that depend on this alarm.
-    std::vector<Subscription> mSubscriptions;
-
-    // Alarm monitor.
-    sp<AlarmMonitor> mAlarmMonitor;
-
-    // The current expected alarm time in seconds.
-    int64_t mAlarmSec;
-
-    // The current alarm.
-    sp<const InternalAlarm> mInternalAlarm;
-
-    FRIEND_TEST(AlarmTrackerTest, TestTriggerTimestamp);
-    FRIEND_TEST(AlarmE2eTest, TestMultipleAlarms);
-    FRIEND_TEST(ConfigUpdateTest, TestUpdateAlarms);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
deleted file mode 100644
index 6aa410b..0000000
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "AnomalyTracker.h"
-#include "external/Perfetto.h"
-#include "guardrail/StatsdStats.h"
-#include "metadata_util.h"
-#include "stats_log_util.h"
-#include "subscriber_util.h"
-#include "subscriber/IncidentdReporter.h"
-#include "subscriber/SubscriberReporter.h"
-
-#include <inttypes.h>
-#include <statslog_statsd.h>
-#include <time.h>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-AnomalyTracker::AnomalyTracker(const Alert& alert, const ConfigKey& configKey)
-        : mAlert(alert), mConfigKey(configKey), mNumOfPastBuckets(mAlert.num_buckets() - 1) {
-    VLOG("AnomalyTracker() called");
-    resetStorage();  // initialization
-}
-
-AnomalyTracker::~AnomalyTracker() {
-    VLOG("~AnomalyTracker() called");
-}
-
-void AnomalyTracker::onConfigUpdated() {
-    mSubscriptions.clear();
-}
-
-void AnomalyTracker::resetStorage() {
-    VLOG("resetStorage() called.");
-    mPastBuckets.clear();
-    // Excludes the current bucket.
-    mPastBuckets.resize(mNumOfPastBuckets);
-    mSumOverPastBuckets.clear();
-}
-
-size_t AnomalyTracker::index(int64_t bucketNum) const {
-    if (bucketNum < 0) {
-        ALOGE("index() was passed a negative bucket number (%lld)!", (long long)bucketNum);
-    }
-    return bucketNum % mNumOfPastBuckets;
-}
-
-void AnomalyTracker::advanceMostRecentBucketTo(const int64_t& bucketNum) {
-    VLOG("advanceMostRecentBucketTo() called.");
-    if (mNumOfPastBuckets <= 0) {
-        return;
-    }
-    if (bucketNum <= mMostRecentBucketNum) {
-        ALOGW("Cannot advance buckets backwards (bucketNum=%lld but mMostRecentBucketNum=%lld)",
-              (long long)bucketNum, (long long)mMostRecentBucketNum);
-        return;
-    }
-    // If in the future (i.e. buckets are ancient), just empty out all past info.
-    if (bucketNum >= mMostRecentBucketNum + mNumOfPastBuckets) {
-        resetStorage();
-        mMostRecentBucketNum = bucketNum;
-        return;
-    }
-
-    // Clear out space by emptying out old mPastBuckets[i] values and update mSumOverPastBuckets.
-    for (int64_t i = mMostRecentBucketNum + 1; i <= bucketNum; i++) {
-        const int idx = index(i);
-        subtractBucketFromSum(mPastBuckets[idx]);
-        mPastBuckets[idx] = nullptr;  // release (but not clear) the old bucket.
-    }
-    mMostRecentBucketNum = bucketNum;
-}
-
-void AnomalyTracker::addPastBucket(const MetricDimensionKey& key,
-                                   const int64_t& bucketValue,
-                                   const int64_t& bucketNum) {
-    VLOG("addPastBucket(bucketValue) called.");
-    if (mNumOfPastBuckets == 0 ||
-        bucketNum < 0 || bucketNum <= mMostRecentBucketNum - mNumOfPastBuckets) {
-        return;
-    }
-
-    const int bucketIndex = index(bucketNum);
-    if (bucketNum <= mMostRecentBucketNum && (mPastBuckets[bucketIndex] != nullptr)) {
-        // We need to insert into an already existing past bucket.
-        std::shared_ptr<DimToValMap>& bucket = mPastBuckets[bucketIndex];
-        auto itr = bucket->find(key);
-        if (itr != bucket->end()) {
-            // Old entry already exists; update it.
-            subtractValueFromSum(key, itr->second);
-            itr->second = bucketValue;
-        } else {
-            bucket->insert({key, bucketValue});
-        }
-        mSumOverPastBuckets[key] += bucketValue;
-    } else {
-        // Bucket does not exist yet (in future or was never made), so we must make it.
-        std::shared_ptr<DimToValMap> bucket = std::make_shared<DimToValMap>();
-        bucket->insert({key, bucketValue});
-        addPastBucket(bucket, bucketNum);
-    }
-}
-
-void AnomalyTracker::addPastBucket(std::shared_ptr<DimToValMap> bucket,
-                                   const int64_t& bucketNum) {
-    VLOG("addPastBucket(bucket) called.");
-    if (mNumOfPastBuckets == 0 ||
-            bucketNum < 0 || bucketNum <= mMostRecentBucketNum - mNumOfPastBuckets) {
-        return;
-    }
-
-    if (bucketNum <= mMostRecentBucketNum) {
-        // We are updating an old bucket, not adding a new one.
-        subtractBucketFromSum(mPastBuckets[index(bucketNum)]);
-    } else {
-        // Clear space for the new bucket to be at bucketNum.
-        advanceMostRecentBucketTo(bucketNum);
-    }
-    mPastBuckets[index(bucketNum)] = bucket;
-    addBucketToSum(bucket);
-}
-
-void AnomalyTracker::subtractBucketFromSum(const shared_ptr<DimToValMap>& bucket) {
-    if (bucket == nullptr) {
-        return;
-    }
-    for (const auto& keyValuePair : *bucket) {
-        subtractValueFromSum(keyValuePair.first, keyValuePair.second);
-    }
-}
-
-
-void AnomalyTracker::subtractValueFromSum(const MetricDimensionKey& key,
-                                          const int64_t& bucketValue) {
-    auto itr = mSumOverPastBuckets.find(key);
-    if (itr == mSumOverPastBuckets.end()) {
-        return;
-    }
-    itr->second -= bucketValue;
-    if (itr->second == 0) {
-        mSumOverPastBuckets.erase(itr);
-    }
-}
-
-void AnomalyTracker::addBucketToSum(const shared_ptr<DimToValMap>& bucket) {
-    if (bucket == nullptr) {
-        return;
-    }
-    // For each dimension present in the bucket, add its value to its corresponding sum.
-    for (const auto& keyValuePair : *bucket) {
-        mSumOverPastBuckets[keyValuePair.first] += keyValuePair.second;
-    }
-}
-
-int64_t AnomalyTracker::getPastBucketValue(const MetricDimensionKey& key,
-                                           const int64_t& bucketNum) const {
-    if (bucketNum < 0 || mMostRecentBucketNum < 0
-            || bucketNum <= mMostRecentBucketNum - mNumOfPastBuckets
-            || bucketNum > mMostRecentBucketNum) {
-        return 0;
-    }
-
-    const auto& bucket = mPastBuckets[index(bucketNum)];
-    if (bucket == nullptr) {
-        return 0;
-    }
-    const auto& itr = bucket->find(key);
-    return itr == bucket->end() ? 0 : itr->second;
-}
-
-int64_t AnomalyTracker::getSumOverPastBuckets(const MetricDimensionKey& key) const {
-    const auto& itr = mSumOverPastBuckets.find(key);
-    if (itr != mSumOverPastBuckets.end()) {
-        return itr->second;
-    }
-    return 0;
-}
-
-bool AnomalyTracker::detectAnomaly(const int64_t& currentBucketNum,
-                                   const MetricDimensionKey& key,
-                                   const int64_t& currentBucketValue) {
-
-    // currentBucketNum should be the next bucket after pastBuckets. If not, advance so that it is.
-    if (currentBucketNum > mMostRecentBucketNum + 1) {
-        advanceMostRecentBucketTo(currentBucketNum - 1);
-    }
-    return mAlert.has_trigger_if_sum_gt() &&
-           getSumOverPastBuckets(key) + currentBucketValue > mAlert.trigger_if_sum_gt();
-}
-
-void AnomalyTracker::declareAnomaly(const int64_t& timestampNs, int64_t metricId,
-                                    const MetricDimensionKey& key, int64_t metricValue) {
-    // TODO(b/110563466): Why receive timestamp? RefractoryPeriod should always be based on
-    // real time right now.
-    if (isInRefractoryPeriod(timestampNs, key)) {
-        VLOG("Skipping anomaly declaration since within refractory period");
-        return;
-    }
-    if (mAlert.has_refractory_period_secs()) {
-        mRefractoryPeriodEndsSec[key] = ((timestampNs + NS_PER_SEC - 1) / NS_PER_SEC) // round up
-                                        + mAlert.refractory_period_secs();
-        // TODO(b/110563466): If we had access to the bucket_size_millis, consider
-        // calling resetStorage()
-        // if (mAlert.refractory_period_secs() > mNumOfPastBuckets * bucketSizeNs) {resetStorage();}
-    }
-
-    if (!mSubscriptions.empty()) {
-        ALOGI("An anomaly (%" PRId64 ") %s has occurred! Informing subscribers.",
-                mAlert.id(), key.toString().c_str());
-        informSubscribers(key, metricId, metricValue);
-    } else {
-        ALOGI("An anomaly has occurred! (But no subscriber for that alert.)");
-    }
-
-    StatsdStats::getInstance().noteAnomalyDeclared(mConfigKey, mAlert.id());
-
-    // TODO(b/110564268): This should also take in the const MetricDimensionKey& key?
-    util::stats_write(util::ANOMALY_DETECTED, mConfigKey.GetUid(),
-                      mConfigKey.GetId(), mAlert.id());
-}
-
-void AnomalyTracker::detectAndDeclareAnomaly(const int64_t& timestampNs,
-                                             const int64_t& currBucketNum, int64_t metricId,
-                                             const MetricDimensionKey& key,
-                                             const int64_t& currentBucketValue) {
-    if (detectAnomaly(currBucketNum, key, currentBucketValue)) {
-        declareAnomaly(timestampNs, metricId, key, currentBucketValue);
-    }
-}
-
-bool AnomalyTracker::isInRefractoryPeriod(const int64_t& timestampNs,
-                                          const MetricDimensionKey& key) const {
-    const auto& it = mRefractoryPeriodEndsSec.find(key);
-    if (it != mRefractoryPeriodEndsSec.end()) {
-        return timestampNs < (it->second *  (int64_t)NS_PER_SEC);
-    }
-    return false;
-}
-
-std::pair<bool, uint64_t> AnomalyTracker::getProtoHash() const {
-    string serializedAlert;
-    if (!mAlert.SerializeToString(&serializedAlert)) {
-        ALOGW("Unable to serialize alert %lld", (long long)mAlert.id());
-        return {false, 0};
-    }
-    return {true, Hash64(serializedAlert)};
-}
-
-void AnomalyTracker::informSubscribers(const MetricDimensionKey& key, int64_t metric_id,
-                                       int64_t metricValue) {
-    triggerSubscribers(mAlert.id(), metric_id, key, metricValue, mConfigKey, mSubscriptions);
-}
-
-bool AnomalyTracker::writeAlertMetadataToProto(int64_t currentWallClockTimeNs,
-                                               int64_t systemElapsedTimeNs,
-                                               metadata::AlertMetadata* alertMetadata) {
-    bool metadataWritten = false;
-
-    if (mRefractoryPeriodEndsSec.empty()) {
-        return false;
-    }
-
-    for (const auto& it: mRefractoryPeriodEndsSec) {
-        // Do not write the timestamp to disk if it has already expired
-        if (it.second < systemElapsedTimeNs / NS_PER_SEC) {
-            continue;
-        }
-
-        metadataWritten = true;
-        if (alertMetadata->alert_dim_keyed_data_size() == 0) {
-            alertMetadata->set_alert_id(mAlert.id());
-        }
-
-        metadata::AlertDimensionKeyedData* keyedData = alertMetadata->add_alert_dim_keyed_data();
-        // We convert and write the refractory_end_sec to wall clock time because we do not know
-        // when statsd will start again.
-        int32_t refractoryEndWallClockSec = (int32_t) ((currentWallClockTimeNs / NS_PER_SEC) +
-                (it.second - systemElapsedTimeNs / NS_PER_SEC));
-
-        keyedData->set_last_refractory_ends_sec(refractoryEndWallClockSec);
-        writeMetricDimensionKeyToMetadataDimensionKey(
-                it.first, keyedData->mutable_dimension_key());
-    }
-
-    return metadataWritten;
-}
-
-void AnomalyTracker::loadAlertMetadata(
-        const metadata::AlertMetadata& alertMetadata,
-        int64_t currentWallClockTimeNs,
-        int64_t systemElapsedTimeNs) {
-    for (const metadata::AlertDimensionKeyedData& keyedData :
-            alertMetadata.alert_dim_keyed_data()) {
-        if ((uint64_t) keyedData.last_refractory_ends_sec() < currentWallClockTimeNs / NS_PER_SEC) {
-            // Do not update the timestamp if it has already expired.
-            continue;
-        }
-        MetricDimensionKey metricKey = loadMetricDimensionKeyFromProto(
-                keyedData.dimension_key());
-        int32_t refractoryPeriodEndsSec = (int32_t) keyedData.last_refractory_ends_sec() -
-                currentWallClockTimeNs / NS_PER_SEC + systemElapsedTimeNs / NS_PER_SEC;
-        mRefractoryPeriodEndsSec[metricKey] = refractoryPeriodEndsSec;
-    }
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h
deleted file mode 100644
index 9a578ee..0000000
--- a/cmds/statsd/src/anomaly/AnomalyTracker.h
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <gtest/gtest_prod.h>
-#include <stdlib.h>
-#include <utils/RefBase.h>
-
-#include "AlarmMonitor.h"
-#include "config/ConfigKey.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"    // Alert
-#include "frameworks/base/cmds/statsd/src/statsd_metadata.pb.h"  // AlertMetadata
-#include "hash.h"
-#include "stats_util.h"  // HashableDimensionKey and DimToValMap
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using std::shared_ptr;
-using std::unordered_map;
-
-// Does NOT allow negative values.
-class AnomalyTracker : public virtual RefBase {
-public:
-    AnomalyTracker(const Alert& alert, const ConfigKey& configKey);
-
-    virtual ~AnomalyTracker();
-
-    // Reset appropriate state on a config update. Clear subscriptions so they can be reset.
-    void onConfigUpdated();
-
-    // Add subscriptions that depend on this alert.
-    void addSubscription(const Subscription& subscription) {
-        mSubscriptions.push_back(subscription);
-    }
-
-    // Adds a bucket for the given bucketNum (index starting at 0).
-    // If a bucket for bucketNum already exists, it will be replaced.
-    // Also, advances to bucketNum (if not in the past), effectively filling any intervening
-    // buckets with 0s.
-    void addPastBucket(std::shared_ptr<DimToValMap> bucket, const int64_t& bucketNum);
-
-    // Inserts (or replaces) the bucket entry for the given bucketNum at the given key to be the
-    // given bucketValue. If the bucket does not exist, it will be created.
-    // Also, advances to bucketNum (if not in the past), effectively filling any intervening
-    // buckets with 0s.
-    void addPastBucket(const MetricDimensionKey& key, const int64_t& bucketValue,
-                       const int64_t& bucketNum);
-
-    // Returns true if, based on past buckets plus the new currentBucketValue (which generally
-    // represents the partially-filled current bucket), an anomaly has happened.
-    // Also advances to currBucketNum-1.
-    bool detectAnomaly(const int64_t& currBucketNum, const MetricDimensionKey& key,
-                       const int64_t& currentBucketValue);
-
-    // Informs incidentd about the detected alert.
-    void declareAnomaly(const int64_t& timestampNs, int64_t metricId, const MetricDimensionKey& key,
-                        int64_t metricValue);
-
-    // Detects if, based on past buckets plus the new currentBucketValue (which generally
-    // represents the partially-filled current bucket), an anomaly has happened, and if so,
-    // declares an anomaly and informs relevant subscribers.
-    // Also advances to currBucketNum-1.
-    void detectAndDeclareAnomaly(const int64_t& timestampNs, const int64_t& currBucketNum,
-                                 int64_t metricId, const MetricDimensionKey& key,
-                                 const int64_t& currentBucketValue);
-
-    // Init the AlarmMonitor which is shared across anomaly trackers.
-    virtual void setAlarmMonitor(const sp<AlarmMonitor>& alarmMonitor) {
-        return; // Base AnomalyTracker class has no need for the AlarmMonitor.
-    }
-
-    // Returns the sum of all past bucket values for the given dimension key.
-    int64_t getSumOverPastBuckets(const MetricDimensionKey& key) const;
-
-    // Returns the value for a past bucket, or 0 if that bucket doesn't exist.
-    int64_t getPastBucketValue(const MetricDimensionKey& key, const int64_t& bucketNum) const;
-
-    // Returns the anomaly threshold set in the configuration.
-    inline int64_t getAnomalyThreshold() const {
-        return mAlert.trigger_if_sum_gt();
-    }
-
-    // Returns the refractory period ending timestamp (in seconds) for the given key.
-    // Before this moment, any detected anomaly will be ignored.
-    // If there is no stored refractory period ending timestamp, returns 0.
-    uint32_t getRefractoryPeriodEndsSec(const MetricDimensionKey& key) const {
-        const auto& it = mRefractoryPeriodEndsSec.find(key);
-        return it != mRefractoryPeriodEndsSec.end() ? it->second : 0;
-    }
-
-    // Returns the (constant) number of past buckets this anomaly tracker can store.
-    inline int getNumOfPastBuckets() const {
-        return mNumOfPastBuckets;
-    }
-
-    std::pair<bool, uint64_t> getProtoHash() const;
-
-    // Sets an alarm for the given timestamp.
-    // Replaces previous alarm if one already exists.
-    virtual void startAlarm(const MetricDimensionKey& dimensionKey, const int64_t& eventTime) {
-        return;  // The base AnomalyTracker class doesn't have alarms.
-    }
-
-    // Stops the alarm.
-    // If it should have already fired, but hasn't yet (e.g. because the AlarmManager is delayed),
-    // declare the anomaly now.
-    virtual void stopAlarm(const MetricDimensionKey& dimensionKey, const int64_t& timestampNs) {
-        return;  // The base AnomalyTracker class doesn't have alarms.
-    }
-
-    // Stop all the alarms owned by this tracker. Does not declare any anomalies.
-    virtual void cancelAllAlarms() {
-        return;  // The base AnomalyTracker class doesn't have alarms.
-    }
-
-    // Declares an anomaly for each alarm in firedAlarms that belongs to this AnomalyTracker,
-    // and removes it from firedAlarms. Does NOT remove the alarm from the AlarmMonitor.
-    virtual void informAlarmsFired(const int64_t& timestampNs,
-            unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& firedAlarms) {
-        return; // The base AnomalyTracker class doesn't have alarms.
-    }
-
-    // Writes metadata of the alert (refractory_period_end_sec) to AlertMetadata.
-    // Returns true if at least one element is written to alertMetadata.
-    bool writeAlertMetadataToProto(
-            int64_t currentWallClockTimeNs,
-            int64_t systemElapsedTimeNs, metadata::AlertMetadata* alertMetadata);
-
-    void loadAlertMetadata(
-            const metadata::AlertMetadata& alertMetadata,
-            int64_t currentWallClockTimeNs,
-            int64_t systemElapsedTimeNs);
-
-protected:
-    // For testing only.
-    // Returns the alarm timestamp in seconds for the query dimension if it exists. Otherwise
-    // returns 0.
-    virtual uint32_t getAlarmTimestampSec(const MetricDimensionKey& dimensionKey) const {
-        return 0;   // The base AnomalyTracker class doesn't have alarms.
-    }
-
-    // statsd_config.proto Alert message that defines this tracker.
-    const Alert mAlert;
-
-    // The subscriptions that depend on this alert.
-    std::vector<Subscription> mSubscriptions;
-
-    // A reference to the Alert's config key.
-    const ConfigKey mConfigKey;
-
-    // Number of past buckets. One less than the total number of buckets needed
-    // for the anomaly detection (since the current bucket is not in the past).
-    const int mNumOfPastBuckets;
-
-    // Values for each of the past mNumOfPastBuckets buckets. Always of size mNumOfPastBuckets.
-    // mPastBuckets[i] can be null, meaning that no data is present in that bucket.
-    std::vector<shared_ptr<DimToValMap>> mPastBuckets;
-
-    // Cached sum over all existing buckets in mPastBuckets.
-    // Its buckets never contain entries of 0.
-    DimToValMap mSumOverPastBuckets;
-
-    // The bucket number of the last added bucket.
-    int64_t mMostRecentBucketNum = -1;
-
-    // Map from each dimension to the timestamp that its refractory period (if this anomaly was
-    // declared for that dimension) ends, in seconds. From this moment and onwards, anomalies
-    // can be declared again.
-    // Entries may be, but are not guaranteed to be, removed after the period is finished.
-    unordered_map<MetricDimensionKey, uint32_t> mRefractoryPeriodEndsSec;
-
-    // Advances mMostRecentBucketNum to bucketNum, deleting any data that is now too old.
-    // Specifically, since it is now too old, removes the data for
-    //   [mMostRecentBucketNum - mNumOfPastBuckets + 1, bucketNum - mNumOfPastBuckets].
-    void advanceMostRecentBucketTo(const int64_t& bucketNum);
-
-    // Add the information in the given bucket to mSumOverPastBuckets.
-    void addBucketToSum(const shared_ptr<DimToValMap>& bucket);
-
-    // Subtract the information in the given bucket from mSumOverPastBuckets
-    // and remove any items with value 0.
-    void subtractBucketFromSum(const shared_ptr<DimToValMap>& bucket);
-
-    // From mSumOverPastBuckets[key], subtracts bucketValue, removing it if it is now 0.
-    void subtractValueFromSum(const MetricDimensionKey& key, const int64_t& bucketValue);
-
-    // Returns true if in the refractory period, else false.
-    bool isInRefractoryPeriod(const int64_t& timestampNs, const MetricDimensionKey& key) const;
-
-    // Calculates the corresponding bucket index within the circular array.
-    // Requires bucketNum >= 0.
-    size_t index(int64_t bucketNum) const;
-
-    // Resets all bucket data. For use when all the data gets stale.
-    virtual void resetStorage();
-
-    // Informs the subscribers (incidentd, perfetto, broadcasts, etc) that an anomaly has occurred.
-    void informSubscribers(const MetricDimensionKey& key, int64_t metricId, int64_t metricValue);
-
-    FRIEND_TEST(AnomalyTrackerTest, TestConsecutiveBuckets);
-    FRIEND_TEST(AnomalyTrackerTest, TestSparseBuckets);
-    FRIEND_TEST(GaugeMetricProducerTest, TestAnomalyDetection);
-    FRIEND_TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced);
-    FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket);
-    FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets);
-    FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period);
-
-    FRIEND_TEST(ConfigUpdateTest, TestUpdateAlerts);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
deleted file mode 100644
index 2b56810..0000000
--- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "DurationAnomalyTracker.h"
-#include "guardrail/StatsdStats.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-DurationAnomalyTracker::DurationAnomalyTracker(const Alert& alert, const ConfigKey& configKey,
-                                               const sp<AlarmMonitor>& alarmMonitor)
-        : AnomalyTracker(alert, configKey), mAlarmMonitor(alarmMonitor) {
-    VLOG("DurationAnomalyTracker() called");
-}
-
-DurationAnomalyTracker::~DurationAnomalyTracker() {
-    VLOG("~DurationAnomalyTracker() called");
-    cancelAllAlarms();
-}
-
-void DurationAnomalyTracker::startAlarm(const MetricDimensionKey& dimensionKey,
-                                        const int64_t& timestampNs) {
-    // Alarms are stored in secs. Must round up, since if it fires early, it is ignored completely.
-    uint32_t timestampSec = static_cast<uint32_t>((timestampNs -1) / NS_PER_SEC) + 1; // round up
-    if (isInRefractoryPeriod(timestampNs, dimensionKey)) {
-        VLOG("Not setting anomaly alarm since it would fall in the refractory period.");
-        return;
-    }
-
-    auto itr = mAlarms.find(dimensionKey);
-    if (itr != mAlarms.end() && mAlarmMonitor != nullptr) {
-        mAlarmMonitor->remove(itr->second);
-    }
-
-    sp<const InternalAlarm> alarm = new InternalAlarm{timestampSec};
-    mAlarms[dimensionKey] = alarm;
-    if (mAlarmMonitor != nullptr) {
-        mAlarmMonitor->add(alarm);
-    }
-}
-
-void DurationAnomalyTracker::stopAlarm(const MetricDimensionKey& dimensionKey,
-                                       const int64_t& timestampNs) {
-    const auto itr = mAlarms.find(dimensionKey);
-    if (itr == mAlarms.end()) {
-        return;
-    }
-
-    // If the alarm is set in the past but hasn't fired yet (due to lag), catch it now.
-    if (itr->second != nullptr && timestampNs >= (int64_t)NS_PER_SEC * itr->second->timestampSec) {
-        declareAnomaly(timestampNs, mAlert.metric_id(), dimensionKey,
-                       mAlert.trigger_if_sum_gt() + (timestampNs / NS_PER_SEC) -
-                               itr->second->timestampSec);
-    }
-    if (mAlarmMonitor != nullptr) {
-        mAlarmMonitor->remove(itr->second);
-    }
-    mAlarms.erase(dimensionKey);
-}
-
-void DurationAnomalyTracker::cancelAllAlarms() {
-    if (mAlarmMonitor != nullptr) {
-        for (const auto& itr : mAlarms) {
-            mAlarmMonitor->remove(itr.second);
-        }
-    }
-    mAlarms.clear();
-}
-
-void DurationAnomalyTracker::informAlarmsFired(const int64_t& timestampNs,
-        unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& firedAlarms) {
-
-    if (firedAlarms.empty() || mAlarms.empty()) return;
-    // Find the intersection of firedAlarms and mAlarms.
-    // The for loop is inefficient, since it loops over all keys, but that's okay since it is very
-    // seldomly called. The alternative would be having InternalAlarms store information about the
-    // DurationAnomalyTracker and key, but that's a lot of data overhead to speed up something that
-    // is rarely ever called.
-    unordered_map<MetricDimensionKey, sp<const InternalAlarm>> matchedAlarms;
-    for (const auto& kv : mAlarms) {
-        if (firedAlarms.count(kv.second) > 0) {
-            matchedAlarms.insert({kv.first, kv.second});
-        }
-    }
-
-    // Now declare each of these alarms to have fired.
-    for (const auto& kv : matchedAlarms) {
-        declareAnomaly(
-                timestampNs, mAlert.metric_id(), kv.first,
-                mAlert.trigger_if_sum_gt() + (timestampNs / NS_PER_SEC) - kv.second->timestampSec);
-        mAlarms.erase(kv.first);
-        firedAlarms.erase(kv.second);  // No one else can also own it, so we're done with it.
-    }
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
deleted file mode 100644
index 4641914..0000000
--- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "AlarmMonitor.h"
-#include "AnomalyTracker.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using std::unordered_map;
-
-class DurationAnomalyTracker : public virtual AnomalyTracker {
-public:
-    DurationAnomalyTracker(const Alert& alert, const ConfigKey& configKey,
-                           const sp<AlarmMonitor>& alarmMonitor);
-
-    virtual ~DurationAnomalyTracker();
-
-    // Sets an alarm for the given timestamp.
-    // Replaces previous alarm if one already exists.
-    void startAlarm(const MetricDimensionKey& dimensionKey, const int64_t& eventTime) override;
-
-    // Stops the alarm.
-    // If it should have already fired, but hasn't yet (e.g. because the AlarmManager is delayed),
-    // declare the anomaly now.
-    void stopAlarm(const MetricDimensionKey& dimensionKey, const int64_t& timestampNs) override;
-
-    // Stop all the alarms owned by this tracker. Does not declare any anomalies.
-    void cancelAllAlarms() override;
-
-    // Declares an anomaly for each alarm in firedAlarms that belongs to this DurationAnomalyTracker
-    // and removes it from firedAlarms. The AlarmMonitor is not informed.
-    // Note that this will generally be called from a different thread from the other functions;
-    // the caller is responsible for thread safety.
-    void informAlarmsFired(const int64_t& timestampNs,
-            unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& firedAlarms) override;
-
-protected:
-    // Returns the alarm timestamp in seconds for the query dimension if it exists. Otherwise
-    // returns 0.
-    uint32_t getAlarmTimestampSec(const MetricDimensionKey& dimensionKey) const override {
-        auto it = mAlarms.find(dimensionKey);
-        return it == mAlarms.end() ? 0 : it->second->timestampSec;
-    }
-
-    // The alarms owned by this tracker. The alarm monitor also shares the alarm pointers when they
-    // are still active.
-    std::unordered_map<MetricDimensionKey, sp<const InternalAlarm>> mAlarms;
-
-    // Anomaly alarm monitor.
-    sp<AlarmMonitor> mAlarmMonitor;
-
-    FRIEND_TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp);
-    FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm);
-    FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm);
-    FRIEND_TEST(MaxDurationTrackerTest, TestAnomalyDetection);
-    FRIEND_TEST(MaxDurationTrackerTest, TestAnomalyPredictedTimestamp);
-    FRIEND_TEST(MaxDurationTrackerTest, TestAnomalyPredictedTimestamp_UpdatedOnStop);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/anomaly/indexed_priority_queue.h b/cmds/statsd/src/anomaly/indexed_priority_queue.h
deleted file mode 100644
index 99882d0..0000000
--- a/cmds/statsd/src/anomaly/indexed_priority_queue.h
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <utils/RefBase.h>
-#include <unordered_map>
-#include <vector>
-
-using namespace android;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/** Defines a hash function for sp<const AA>, returning the hash of the underlying pointer. */
-template <class AA>
-struct SpHash {
-    size_t operator()(const sp<const AA>& k) const {
-        return std::hash<const AA*>()(k.get());
-    }
-};
-
-/**
- * Min priority queue for generic type AA.
- * Unlike a regular priority queue, this class is also capable of removing interior elements.
- * @tparam Comparator must implement [bool operator()(sp<const AA> a, sp<const AA> b)], returning
- *    whether a should be closer to the top of the queue than b.
- */
-template <class AA, class Comparator>
-class indexed_priority_queue {
-public:
-    indexed_priority_queue();
-    /** Adds a into the priority queue. If already present or a==nullptr, does nothing. */
-    void push(sp<const AA> a);
-    /*
-     * Removes a from the priority queue. If not present or a==nullptr, does nothing.
-     * Returns true if a had been present (and is now removed), else false.
-     */
-    bool remove(sp<const AA> a);
-    /** Removes the top element, if there is one. */
-    void pop();
-    /** Removes all elements. */
-    void clear();
-    /** Returns whether priority queue contains a (not just a copy of a, but a itself). */
-    bool contains(sp<const AA> a) const;
-    /** Returns min element. Returns nullptr iff empty(). */
-    sp<const AA> top() const;
-    /** Returns number of elements in priority queue. */
-    size_t size() const {
-        return pq.size() - 1;
-    }  // pq is 1-indexed
-    /** Returns true iff priority queue is empty. */
-    bool empty() const {
-        return size() < 1;
-    }
-
-private:
-    /** Vector representing a min-heap (1-indexed, with nullptr at 0). */
-    std::vector<sp<const AA>> pq;
-    /** Mapping of each element in pq to its index in pq (i.e. the inverse of a=pq[i]). */
-    std::unordered_map<sp<const AA>, size_t, SpHash<AA>> indices;
-
-    void init();
-    void sift_up(size_t idx);
-    void sift_down(size_t idx);
-    /** Returns whether pq[idx1] is considered higher than pq[idx2], according to Comparator. */
-    bool higher(size_t idx1, size_t idx2) const;
-    void swap_indices(size_t i, size_t j);
-};
-
-// Implementation must be done in this file due to use of template.
-
-template <class AA, class Comparator>
-indexed_priority_queue<AA, Comparator>::indexed_priority_queue() {
-    init();
-}
-
-template <class AA, class Comparator>
-void indexed_priority_queue<AA, Comparator>::push(sp<const AA> a) {
-    if (a == nullptr) return;
-    if (contains(a)) return;
-    pq.push_back(a);
-    size_t idx = size();  // index of last element since 1-indexed
-    indices.insert({a, idx});
-    sift_up(idx);  // get the pq back in order
-}
-
-template <class AA, class Comparator>
-bool indexed_priority_queue<AA, Comparator>::remove(sp<const AA> a) {
-    if (a == nullptr) return false;
-    if (!contains(a)) return false;
-    size_t idx = indices[a];
-    if (idx >= pq.size()) {
-        return false;
-    }
-    if (idx == size()) {  // if a is the last element, i.e. at index idx == size() == (pq.size()-1)
-        pq.pop_back();
-        indices.erase(a);
-        return true;
-    }
-    // move last element (guaranteed not to be at idx) to idx, then delete a
-    sp<const AA> last_a = pq.back();
-    pq[idx] = last_a;
-    pq.pop_back();
-    indices[last_a] = idx;
-    indices.erase(a);
-
-    // get the heap back in order (since the element at idx is not in order)
-    sift_up(idx);
-    sift_down(idx);
-
-    return true;
-}
-
-// The same as, but slightly more efficient than, remove(top()).
-template <class AA, class Comparator>
-void indexed_priority_queue<AA, Comparator>::pop() {
-    sp<const AA> a = top();
-    if (a == nullptr) return;
-    const size_t idx = 1;
-    if (idx == size()) {  // if a is the last element
-        pq.pop_back();
-        indices.erase(a);
-        return;
-    }
-    // move last element (guaranteed not to be at idx) to idx, then delete a
-    sp<const AA> last_a = pq.back();
-    pq[idx] = last_a;
-    pq.pop_back();
-    indices[last_a] = idx;
-    indices.erase(a);
-
-    // get the heap back in order (since the element at idx is not in order)
-    sift_down(idx);
-}
-
-template <class AA, class Comparator>
-void indexed_priority_queue<AA, Comparator>::clear() {
-    pq.clear();
-    indices.clear();
-    init();
-}
-
-template <class AA, class Comparator>
-sp<const AA> indexed_priority_queue<AA, Comparator>::top() const {
-    if (empty()) return nullptr;
-    return pq[1];
-}
-
-template <class AA, class Comparator>
-void indexed_priority_queue<AA, Comparator>::init() {
-    pq.push_back(nullptr);         // so that pq is 1-indexed.
-    indices.insert({nullptr, 0});  // just to be consistent with pq.
-}
-
-template <class AA, class Comparator>
-void indexed_priority_queue<AA, Comparator>::sift_up(size_t idx) {
-    while (idx > 1) {
-        size_t parent = idx / 2;
-        if (higher(idx, parent))
-            swap_indices(idx, parent);
-        else
-            break;
-        idx = parent;
-    }
-}
-
-template <class AA, class Comparator>
-void indexed_priority_queue<AA, Comparator>::sift_down(size_t idx) {
-    while (2 * idx <= size()) {
-        size_t child = 2 * idx;
-        if (child < size() && higher(child + 1, child)) child++;
-        if (higher(child, idx))
-            swap_indices(child, idx);
-        else
-            break;
-        idx = child;
-    }
-}
-
-template <class AA, class Comparator>
-bool indexed_priority_queue<AA, Comparator>::higher(size_t idx1, size_t idx2) const {
-    if (!(0u < idx1 && idx1 < pq.size() && 0u < idx2 && idx2 < pq.size())) {
-        return false;  // got to do something.
-    }
-    return Comparator()(pq[idx1], pq[idx2]);
-}
-
-template <class AA, class Comparator>
-bool indexed_priority_queue<AA, Comparator>::contains(sp<const AA> a) const {
-    if (a == nullptr) return false;  // publicly, we pretend that nullptr is not actually in pq.
-    return indices.count(a) > 0;
-}
-
-template <class AA, class Comparator>
-void indexed_priority_queue<AA, Comparator>::swap_indices(size_t i, size_t j) {
-    if (!(0u < i && i < pq.size() && 0u < j && j < pq.size())) {
-        return;
-    }
-    sp<const AA> val_i = pq[i];
-    sp<const AA> val_j = pq[j];
-    pq[i] = val_j;
-    pq[j] = val_i;
-    indices[val_i] = j;
-    indices[val_j] = i;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/anomaly/subscriber_util.cpp b/cmds/statsd/src/anomaly/subscriber_util.cpp
deleted file mode 100644
index 5a4a41d..0000000
--- a/cmds/statsd/src/anomaly/subscriber_util.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "external/Perfetto.h"
-#include "subscriber/IncidentdReporter.h"
-#include "subscriber/SubscriberReporter.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-void triggerSubscribers(int64_t ruleId, int64_t metricId, const MetricDimensionKey& dimensionKey,
-                        int64_t metricValue, const ConfigKey& configKey,
-                        const std::vector<Subscription>& subscriptions) {
-    VLOG("informSubscribers called.");
-    if (subscriptions.empty()) {
-        VLOG("No Subscriptions were associated.");
-        return;
-    }
-
-    for (const Subscription& subscription : subscriptions) {
-        if (subscription.probability_of_informing() < 1
-                && ((float)rand() / (float)RAND_MAX) >= subscription.probability_of_informing()) {
-            // Note that due to float imprecision, 0.0 and 1.0 might not truly mean never/always.
-            // The config writer was advised to use -0.1 and 1.1 for never/always.
-            ALOGI("Fate decided that a subscriber would not be informed.");
-            continue;
-        }
-        switch (subscription.subscriber_information_case()) {
-            case Subscription::SubscriberInformationCase::kIncidentdDetails:
-                if (!GenerateIncidentReport(subscription.incidentd_details(), ruleId, metricId,
-                                            dimensionKey, metricValue, configKey)) {
-                    ALOGW("Failed to generate incident report.");
-                }
-                break;
-            case Subscription::SubscriberInformationCase::kPerfettoDetails:
-                if (!CollectPerfettoTraceAndUploadToDropbox(subscription.perfetto_details(),
-                                                            subscription.id(), ruleId, configKey)) {
-                    ALOGW("Failed to generate perfetto traces.");
-                }
-                break;
-            case Subscription::SubscriberInformationCase::kBroadcastSubscriberDetails:
-                SubscriberReporter::getInstance().alertBroadcastSubscriber(configKey, subscription,
-                                                                           dimensionKey);
-                break;
-            default:
-                break;
-        }
-    }
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/anomaly/subscriber_util.h b/cmds/statsd/src/anomaly/subscriber_util.h
deleted file mode 100644
index 1df3c89..0000000
--- a/cmds/statsd/src/anomaly/subscriber_util.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "config/ConfigKey.h"
-#include "HashableDimensionKey.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-void triggerSubscribers(const int64_t ruleId, const int64_t metricId,
-                        const MetricDimensionKey& dimensionKey, int64_t metricValue,
-                        const ConfigKey& configKey, const std::vector<Subscription>& subscriptions);
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.cpp b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
deleted file mode 100644
index 4574b2e..0000000
--- a/cmds/statsd/src/condition/CombinationConditionTracker.cpp
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-#include "CombinationConditionTracker.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using std::unordered_map;
-using std::vector;
-
-CombinationConditionTracker::CombinationConditionTracker(const int64_t& id, const int index,
-                                                         const uint64_t protoHash)
-    : ConditionTracker(id, index, protoHash) {
-    VLOG("creating CombinationConditionTracker %lld", (long long)mConditionId);
-}
-
-CombinationConditionTracker::~CombinationConditionTracker() {
-    VLOG("~CombinationConditionTracker() %lld", (long long)mConditionId);
-}
-
-bool CombinationConditionTracker::init(const vector<Predicate>& allConditionConfig,
-                                       const vector<sp<ConditionTracker>>& allConditionTrackers,
-                                       const unordered_map<int64_t, int>& conditionIdIndexMap,
-                                       vector<bool>& stack,
-                                       vector<ConditionState>& conditionCache) {
-    VLOG("Combination predicate init() %lld", (long long)mConditionId);
-    if (mInitialized) {
-        // All the children are guaranteed to be initialized, but the recursion is needed to
-        // fill the conditionCache properly, since another combination condition or metric
-        // might rely on this. The recursion is needed to compute the current condition.
-
-        // Init is called instead of isConditionMet so that the ConditionKey can be filled with the
-        // default key for sliced conditions, since we do not know all indirect descendants here.
-        for (const int childIndex : mChildren) {
-            if (conditionCache[childIndex] == ConditionState::kNotEvaluated) {
-                allConditionTrackers[childIndex]->init(allConditionConfig, allConditionTrackers,
-                                                       conditionIdIndexMap, stack, conditionCache);
-            }
-        }
-        conditionCache[mIndex] =
-                evaluateCombinationCondition(mChildren, mLogicalOperation, conditionCache);
-        return true;
-    }
-
-    // mark this node as visited in the recursion stack.
-    stack[mIndex] = true;
-
-    Predicate_Combination combinationCondition = allConditionConfig[mIndex].combination();
-
-    if (!combinationCondition.has_operation()) {
-        return false;
-    }
-    mLogicalOperation = combinationCondition.operation();
-
-    if (mLogicalOperation == LogicalOperation::NOT && combinationCondition.predicate_size() != 1) {
-        return false;
-    }
-
-    for (auto child : combinationCondition.predicate()) {
-        auto it = conditionIdIndexMap.find(child);
-
-        if (it == conditionIdIndexMap.end()) {
-            ALOGW("Predicate %lld not found in the config", (long long)child);
-            return false;
-        }
-
-        int childIndex = it->second;
-        const auto& childTracker = allConditionTrackers[childIndex];
-        // if the child is a visited node in the recursion -> circle detected.
-        if (stack[childIndex]) {
-            ALOGW("Circle detected!!!");
-            return false;
-        }
-
-        bool initChildSucceeded = childTracker->init(allConditionConfig, allConditionTrackers,
-                                                     conditionIdIndexMap, stack, conditionCache);
-
-        if (!initChildSucceeded) {
-            ALOGW("Child initialization failed %lld ", (long long)child);
-            return false;
-        } else {
-            VLOG("Child initialization success %lld ", (long long)child);
-        }
-
-        if (allConditionTrackers[childIndex]->isSliced()) {
-            setSliced(true);
-            mSlicedChildren.push_back(childIndex);
-        } else {
-            mUnSlicedChildren.push_back(childIndex);
-        }
-        mChildren.push_back(childIndex);
-        mTrackerIndex.insert(childTracker->getAtomMatchingTrackerIndex().begin(),
-                             childTracker->getAtomMatchingTrackerIndex().end());
-    }
-
-    mUnSlicedPartCondition =
-            evaluateCombinationCondition(mUnSlicedChildren, mLogicalOperation, conditionCache);
-    conditionCache[mIndex] =
-            evaluateCombinationCondition(mChildren, mLogicalOperation, conditionCache);
-
-    // unmark this node in the recursion stack.
-    stack[mIndex] = false;
-
-    mInitialized = true;
-
-    return true;
-}
-
-bool CombinationConditionTracker::onConfigUpdated(
-        const vector<Predicate>& allConditionProtos, const int index,
-        const vector<sp<ConditionTracker>>& allConditionTrackers,
-        const unordered_map<int64_t, int>& atomMatchingTrackerMap,
-        const unordered_map<int64_t, int>& conditionTrackerMap) {
-    ConditionTracker::onConfigUpdated(allConditionProtos, index, allConditionTrackers,
-                                      atomMatchingTrackerMap, conditionTrackerMap);
-    mTrackerIndex.clear();
-    mChildren.clear();
-    mUnSlicedChildren.clear();
-    mSlicedChildren.clear();
-    Predicate_Combination combinationCondition = allConditionProtos[mIndex].combination();
-
-    for (const int64_t child : combinationCondition.predicate()) {
-        const auto& it = conditionTrackerMap.find(child);
-
-        if (it == conditionTrackerMap.end()) {
-            ALOGW("Predicate %lld not found in the config", (long long)child);
-            return false;
-        }
-
-        int childIndex = it->second;
-        const sp<ConditionTracker>& childTracker = allConditionTrackers[childIndex];
-
-        // Ensures that the child's tracker indices are updated.
-        if (!childTracker->onConfigUpdated(allConditionProtos, childIndex, allConditionTrackers,
-                                           atomMatchingTrackerMap, conditionTrackerMap)) {
-            ALOGW("Child update failed %lld ", (long long)child);
-            return false;
-        }
-
-        if (allConditionTrackers[childIndex]->isSliced()) {
-            mSlicedChildren.push_back(childIndex);
-        } else {
-            mUnSlicedChildren.push_back(childIndex);
-        }
-        mChildren.push_back(childIndex);
-        mTrackerIndex.insert(childTracker->getAtomMatchingTrackerIndex().begin(),
-                             childTracker->getAtomMatchingTrackerIndex().end());
-    }
-    return true;
-}
-
-void CombinationConditionTracker::isConditionMet(
-        const ConditionKey& conditionParameters, const vector<sp<ConditionTracker>>& allConditions,
-        const bool isPartialLink,
-        vector<ConditionState>& conditionCache) const {
-    // So far, this is fine as there is at most one child having sliced output.
-    for (const int childIndex : mChildren) {
-        if (conditionCache[childIndex] == ConditionState::kNotEvaluated) {
-            allConditions[childIndex]->isConditionMet(conditionParameters, allConditions,
-                                                      isPartialLink,
-                                                      conditionCache);
-        }
-    }
-    conditionCache[mIndex] =
-            evaluateCombinationCondition(mChildren, mLogicalOperation, conditionCache);
-}
-
-void CombinationConditionTracker::evaluateCondition(
-        const LogEvent& event, const std::vector<MatchingState>& eventMatcherValues,
-        const std::vector<sp<ConditionTracker>>& mAllConditions,
-        std::vector<ConditionState>& nonSlicedConditionCache,
-        std::vector<bool>& conditionChangedCache) {
-    // value is up to date.
-    if (nonSlicedConditionCache[mIndex] != ConditionState::kNotEvaluated) {
-        return;
-    }
-
-    for (const int childIndex : mChildren) {
-        // So far, this is fine as there is at most one child having sliced output.
-        if (nonSlicedConditionCache[childIndex] == ConditionState::kNotEvaluated) {
-            const sp<ConditionTracker>& child = mAllConditions[childIndex];
-            child->evaluateCondition(event, eventMatcherValues, mAllConditions,
-                                     nonSlicedConditionCache, conditionChangedCache);
-        }
-    }
-
-    ConditionState newCondition =
-            evaluateCombinationCondition(mChildren, mLogicalOperation, nonSlicedConditionCache);
-    if (!mSliced) {
-        bool nonSlicedChanged = (mUnSlicedPartCondition != newCondition);
-        mUnSlicedPartCondition = newCondition;
-
-        nonSlicedConditionCache[mIndex] = mUnSlicedPartCondition;
-        conditionChangedCache[mIndex] = nonSlicedChanged;
-    } else {
-        mUnSlicedPartCondition = evaluateCombinationCondition(mUnSlicedChildren, mLogicalOperation,
-                                                              nonSlicedConditionCache);
-
-        for (const int childIndex : mChildren) {
-            // If any of the sliced condition in children condition changes, the combination
-            // condition may be changed too.
-            if (conditionChangedCache[childIndex]) {
-                conditionChangedCache[mIndex] = true;
-                break;
-            }
-        }
-        nonSlicedConditionCache[mIndex] = newCondition;
-        VLOG("CombinationPredicate %lld sliced may changed? %d", (long long)mConditionId,
-            conditionChangedCache[mIndex] == true);
-    }
-}
-
-bool CombinationConditionTracker::equalOutputDimensions(
-        const std::vector<sp<ConditionTracker>>& allConditions,
-        const vector<Matcher>& dimensions) const {
-    if (mSlicedChildren.size() != 1 ||
-        mSlicedChildren.front() >= (int)allConditions.size() ||
-        mLogicalOperation != LogicalOperation::AND) {
-        return false;
-    }
-    const sp<ConditionTracker>& slicedChild = allConditions.at(mSlicedChildren.front());
-    return slicedChild->equalOutputDimensions(allConditions, dimensions);
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.h b/cmds/statsd/src/condition/CombinationConditionTracker.h
deleted file mode 100644
index d355146..0000000
--- a/cmds/statsd/src/condition/CombinationConditionTracker.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef COMBINATION_CONDITION_TRACKER_H
-#define COMBINATION_CONDITION_TRACKER_H
-
-#include "ConditionTracker.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class CombinationConditionTracker : public ConditionTracker {
-public:
-    CombinationConditionTracker(const int64_t& id, const int index, const uint64_t protoHash);
-
-    ~CombinationConditionTracker();
-
-    bool init(const std::vector<Predicate>& allConditionConfig,
-              const std::vector<sp<ConditionTracker>>& allConditionTrackers,
-              const std::unordered_map<int64_t, int>& conditionIdIndexMap, std::vector<bool>& stack,
-              std::vector<ConditionState>& conditionCache) override;
-
-    bool onConfigUpdated(const std::vector<Predicate>& allConditionProtos, const int index,
-                         const std::vector<sp<ConditionTracker>>& allConditionTrackers,
-                         const std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
-                         const std::unordered_map<int64_t, int>& conditionTrackerMap) override;
-
-    void evaluateCondition(const LogEvent& event,
-                           const std::vector<MatchingState>& eventMatcherValues,
-                           const std::vector<sp<ConditionTracker>>& mAllConditions,
-                           std::vector<ConditionState>& conditionCache,
-                           std::vector<bool>& changedCache) override;
-
-    void isConditionMet(const ConditionKey& conditionParameters,
-                        const std::vector<sp<ConditionTracker>>& allConditions,
-                        const bool isPartialLink,
-                        std::vector<ConditionState>& conditionCache) const override;
-
-    // Only one child predicate can have dimension.
-    const std::set<HashableDimensionKey>* getChangedToTrueDimensions(
-            const std::vector<sp<ConditionTracker>>& allConditions) const override {
-        for (const auto& child : mChildren) {
-            auto result = allConditions[child]->getChangedToTrueDimensions(allConditions);
-            if (result != nullptr) {
-                return result;
-            }
-        }
-        return nullptr;
-    }
-
-    // Only one child predicate can have dimension.
-    const std::set<HashableDimensionKey>* getChangedToFalseDimensions(
-            const std::vector<sp<ConditionTracker>>& allConditions) const override {
-        for (const auto& child : mChildren) {
-            auto result = allConditions[child]->getChangedToFalseDimensions(allConditions);
-            if (result != nullptr) {
-                return result;
-            }
-        }
-        return nullptr;
-    }
-
-    bool IsSimpleCondition() const  override { return false; }
-
-    bool IsChangedDimensionTrackable() const  override {
-        return mLogicalOperation == LogicalOperation::AND && mSlicedChildren.size() == 1;
-    }
-
-    bool equalOutputDimensions(
-        const std::vector<sp<ConditionTracker>>& allConditions,
-        const vector<Matcher>& dimensions) const override;
-
-    const std::map<HashableDimensionKey, int>* getSlicedDimensionMap(
-            const std::vector<sp<ConditionTracker>>& allConditions) const override {
-        if (mSlicedChildren.size() == 1) {
-            return allConditions[mSlicedChildren.front()]->getSlicedDimensionMap(allConditions);
-        }
-        return nullptr;
-    }
-
-private:
-    LogicalOperation mLogicalOperation;
-
-    // Store index of the children Predicates.
-    // We don't store string name of the Children, because we want to get rid of the hash map to
-    // map the name to object. We don't want to store smart pointers to children, because it
-    // increases the risk of circular dependency and memory leak.
-    std::vector<int> mChildren;
-
-    std::vector<int> mSlicedChildren;
-    std::vector<int> mUnSlicedChildren;
-
-    FRIEND_TEST(ConfigUpdateTest, TestUpdateConditions);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-#endif  // COMBINATION_CONDITION_TRACKER_H
diff --git a/cmds/statsd/src/condition/ConditionTimer.h b/cmds/statsd/src/condition/ConditionTimer.h
deleted file mode 100644
index 1fbe252..0000000
--- a/cmds/statsd/src/condition/ConditionTimer.h
+++ /dev/null
@@ -1,107 +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.
- */
-#pragma once
-
-#include <gtest/gtest_prod.h>
-#include <stdint.h>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/**
- * A simple stopwatch to time the duration of condition being true.
- *
- * The owner of the stopwatch (MetricProducer) is responsible to notify the stopwatch when condition
- * changes (start/pause), and when to start a new bucket (a new lap basically). All timestamps
- * should be elapsedRealTime in nano seconds.
- *
- * Keep the timer simple and inline everything. This class is *NOT* thread safe. Caller is
- * responsible for thread safety.
- */
-class ConditionTimer {
-public:
-    explicit ConditionTimer(bool initCondition, int64_t bucketStartNs) : mCondition(initCondition) {
-        if (initCondition) {
-            mLastConditionChangeTimestampNs = bucketStartNs;
-        }
-    };
-
-    // Tracks how long the condition has been stayed true in the *current* bucket.
-    // When a new bucket is created, this value will be reset to 0.
-    int64_t mTimerNs = 0;
-
-    // Last elapsed real timestamp when condition changed.
-    int64_t mLastConditionChangeTimestampNs = 0;
-
-    bool mCondition = false;
-
-    int64_t newBucketStart(int64_t nextBucketStartNs) {
-        if (mCondition) {
-            // Normally, the next bucket happens after the last condition
-            // change. In this case, add the time between the condition becoming
-            // true to the next bucket start time.
-            // Otherwise, the next bucket start time is before the last
-            // condition change time, this means that the condition was false at
-            // the bucket boundary before the condition became true, so the
-            // timer should not get updated and the last condition change time
-            // remains as is.
-            if (nextBucketStartNs >= mLastConditionChangeTimestampNs) {
-                mTimerNs += (nextBucketStartNs - mLastConditionChangeTimestampNs);
-                mLastConditionChangeTimestampNs = nextBucketStartNs;
-            }
-        } else if (mLastConditionChangeTimestampNs > nextBucketStartNs) {
-            // The next bucket start time is before the last condition change
-            // time, this means that the condition was true at the bucket
-            // boundary before the condition became false, so adjust the timer
-            // to match how long the condition was true to the bucket boundary.
-            // This means remove the amount the condition stayed true in the
-            // next bucket from the current bucket.
-            mTimerNs -= (mLastConditionChangeTimestampNs - nextBucketStartNs);
-        }
-
-        int64_t temp = mTimerNs;
-        mTimerNs = 0;
-
-        if (!mCondition && (mLastConditionChangeTimestampNs > nextBucketStartNs)) {
-            // The next bucket start time is before the last condition change
-            // time, this means that the condition was true at the bucket
-            // boundary and remained true in the next bucket up to the condition
-            // change to false, so adjust the timer to match how long the
-            // condition stayed true in the next bucket (now the current bucket).
-            mTimerNs = mLastConditionChangeTimestampNs - nextBucketStartNs;
-        }
-        return temp;
-    }
-
-    void onConditionChanged(bool newCondition, int64_t timestampNs) {
-        if (newCondition == mCondition) {
-            return;
-        }
-        mCondition = newCondition;
-        if (newCondition == false) {
-            mTimerNs += (timestampNs - mLastConditionChangeTimestampNs);
-        }
-        mLastConditionChangeTimestampNs = timestampNs;
-    }
-
-    FRIEND_TEST(ConditionTimerTest, TestTimer_Inital_False);
-    FRIEND_TEST(ConditionTimerTest, TestTimer_Inital_True);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h
deleted file mode 100644
index 7af022a..0000000
--- a/cmds/statsd/src/condition/ConditionTracker.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "condition/condition_util.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "matchers/AtomMatchingTracker.h"
-#include "matchers/matcher_util.h"
-
-#include <utils/RefBase.h>
-
-#include <unordered_map>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class ConditionTracker : public virtual RefBase {
-public:
-    ConditionTracker(const int64_t& id, const int index, const uint64_t protoHash)
-        : mConditionId(id),
-          mIndex(index),
-          mInitialized(false),
-          mTrackerIndex(),
-          mUnSlicedPartCondition(ConditionState::kUnknown),
-          mSliced(false),
-          mProtoHash(protoHash){};
-
-    virtual ~ConditionTracker(){};
-
-    // Initialize this ConditionTracker. This initialization is done recursively (DFS). It can also
-    // be done in the constructor, but we do it separately because (1) easy to return a bool to
-    // indicate whether the initialization is successful. (2) makes unit test easier.
-    // This function can also be called on config updates, in which case it does nothing other than
-    // fill the condition cache with the current condition.
-    // allConditionConfig: the list of all Predicate config from statsd_config.
-    // allConditionTrackers: the list of all ConditionTrackers (this is needed because we may also
-    //                       need to call init() on child conditions)
-    // conditionIdIndexMap: the mapping from condition id to its index.
-    // stack: a bit map to keep track which nodes have been visited on the stack in the recursion.
-    // conditionCache: tracks initial conditions of all ConditionTrackers. returns the
-    //                        current condition if called on a config update.
-    virtual bool init(const std::vector<Predicate>& allConditionConfig,
-                      const std::vector<sp<ConditionTracker>>& allConditionTrackers,
-                      const std::unordered_map<int64_t, int>& conditionIdIndexMap,
-                      std::vector<bool>& stack, std::vector<ConditionState>& conditionCache) = 0;
-
-    // Update appropriate state on config updates. Primarily, all indices need to be updated.
-    // This predicate and all of its children are guaranteed to be preserved across the update.
-    // This function is recursive and will call onConfigUpdated on child conditions. It does not
-    // manage cycle detection since all preserved conditions should not have any cycles.
-    //
-    // allConditionProtos: the new predicates.
-    // index: the new index of this tracker in allConditionProtos and allConditionTrackers.
-    // allConditionTrackers: the list of all ConditionTrackers (this is needed because we may also
-    //                       need to call onConfigUpdated() on child conditions)
-    // atomMatchingTrackerMap: map of atom matcher id to index after the config update.
-    // conditionTrackerMap: map of condition tracker id to index after the config update.
-    // returns whether or not the update is successful.
-    virtual bool onConfigUpdated(const std::vector<Predicate>& allConditionProtos, const int index,
-                                 const std::vector<sp<ConditionTracker>>& allConditionTrackers,
-                                 const std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
-                                 const std::unordered_map<int64_t, int>& conditionTrackerMap) {
-        mIndex = index;
-        return true;
-    }
-
-    // evaluate current condition given the new event.
-    // event: the new log event
-    // eventMatcherValues: the results of the AtomMatchingTrackers. AtomMatchingTrackers always
-    //                     process event before ConditionTrackers, because ConditionTracker depends
-    //                     on AtomMatchingTrackers.
-    // mAllConditions: the list of all ConditionTracker
-    // conditionCache: the cached non-sliced condition of the ConditionTrackers for this new event.
-    // conditionChanged: the bit map to record whether the condition has changed.
-    //                   If the condition has dimension, then any sub condition changes will report
-    //                   conditionChanged.
-    virtual void evaluateCondition(const LogEvent& event,
-                                   const std::vector<MatchingState>& eventMatcherValues,
-                                   const std::vector<sp<ConditionTracker>>& mAllConditions,
-                                   std::vector<ConditionState>& conditionCache,
-                                   std::vector<bool>& conditionChanged) = 0;
-
-    // Query the condition with parameters.
-    // [conditionParameters]: a map from condition name to the HashableDimensionKey to query the
-    //                       condition.
-    // [allConditions]: all condition trackers. This is needed because the condition evaluation is
-    //                  done recursively
-    // [isPartialLink]: true if the link specified by 'conditionParameters' contains all the fields
-    //                  in the condition tracker output dimension.
-    // [conditionCache]: the cache holding the condition evaluation values.
-    virtual void isConditionMet(
-            const ConditionKey& conditionParameters,
-            const std::vector<sp<ConditionTracker>>& allConditions,
-            const bool isPartialLink,
-            std::vector<ConditionState>& conditionCache) const = 0;
-
-    // return the list of AtomMatchingTracker index that this ConditionTracker uses.
-    virtual const std::set<int>& getAtomMatchingTrackerIndex() const {
-        return mTrackerIndex;
-    }
-
-    virtual void setSliced(bool sliced) {
-        mSliced = mSliced | sliced;
-    }
-
-    inline bool isSliced() const {
-        return mSliced;
-    }
-
-    virtual const std::set<HashableDimensionKey>* getChangedToTrueDimensions(
-            const std::vector<sp<ConditionTracker>>& allConditions) const = 0;
-    virtual const std::set<HashableDimensionKey>* getChangedToFalseDimensions(
-            const std::vector<sp<ConditionTracker>>& allConditions) const = 0;
-
-    inline int64_t getConditionId() const {
-        return mConditionId;
-    }
-
-    inline uint64_t getProtoHash() const {
-        return mProtoHash;
-    }
-
-    virtual const std::map<HashableDimensionKey, int>* getSlicedDimensionMap(
-            const std::vector<sp<ConditionTracker>>& allConditions) const = 0;
-
-    virtual bool IsChangedDimensionTrackable() const = 0;
-
-    virtual bool IsSimpleCondition() const = 0;
-
-    virtual bool equalOutputDimensions(
-        const std::vector<sp<ConditionTracker>>& allConditions,
-        const vector<Matcher>& dimensions) const = 0;
-
-    // Return the current condition state of the unsliced part of the condition.
-    inline ConditionState getUnSlicedPartConditionState() const  {
-        return mUnSlicedPartCondition;
-    }
-
-protected:
-    const int64_t mConditionId;
-
-    // the index of this condition in the manager's condition list.
-    int mIndex;
-
-    // if it's properly initialized.
-    bool mInitialized;
-
-    // the list of AtomMatchingTracker index that this ConditionTracker uses.
-    std::set<int> mTrackerIndex;
-
-    // This variable is only used for CombinationConditionTrackers.
-    // SimpleConditionTrackers technically don't have an unsliced part because
-    // they are either sliced or unsliced.
-    //
-    // CombinationConditionTrackers have multiple children ConditionTrackers
-    // that can be a mixture of sliced or unsliced. This tracks the
-    // condition of the unsliced part of the combination condition.
-    ConditionState mUnSlicedPartCondition;
-
-    bool mSliced;
-
-    // Hash of the Predicate's proto bytes from StatsdConfig.
-    // Used to determine if the definition of this condition has changed across a config update.
-    const uint64_t mProtoHash;
-
-    FRIEND_TEST(ConfigUpdateTest, TestUpdateConditions);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/condition/ConditionWizard.cpp b/cmds/statsd/src/condition/ConditionWizard.cpp
deleted file mode 100644
index c542032..0000000
--- a/cmds/statsd/src/condition/ConditionWizard.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "ConditionWizard.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using std::vector;
-
-ConditionState ConditionWizard::query(const int index, const ConditionKey& parameters,
-                                      const bool isPartialLink) {
-    vector<ConditionState> cache(mAllConditions.size(), ConditionState::kNotEvaluated);
-
-    mAllConditions[index]->isConditionMet(
-        parameters, mAllConditions, isPartialLink,
-        cache);
-    return cache[index];
-}
-
-const set<HashableDimensionKey>* ConditionWizard::getChangedToTrueDimensions(
-        const int index) const {
-    return mAllConditions[index]->getChangedToTrueDimensions(mAllConditions);
-}
-
-const set<HashableDimensionKey>* ConditionWizard::getChangedToFalseDimensions(
-        const int index) const {
-    return mAllConditions[index]->getChangedToFalseDimensions(mAllConditions);
-}
-
-bool ConditionWizard::IsChangedDimensionTrackable(const int index) {
-    if (index >= 0 && index < (int)mAllConditions.size()) {
-        return mAllConditions[index]->IsChangedDimensionTrackable();
-    } else {
-        return false;
-    }
-}
-
-bool ConditionWizard::IsSimpleCondition(const int index) {
-    if (index >= 0 && index < (int)mAllConditions.size()) {
-        return mAllConditions[index]->IsSimpleCondition();
-    } else {
-        return false;
-    }
-}
-
-bool ConditionWizard::equalOutputDimensions(const int index, const vector<Matcher>& dimensions) {
-    if (index >= 0 && index < (int)mAllConditions.size()) {
-        return mAllConditions[index]->equalOutputDimensions(mAllConditions, dimensions);
-    } else {
-        return false;
-    }
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/condition/ConditionWizard.h b/cmds/statsd/src/condition/ConditionWizard.h
deleted file mode 100644
index 43db94c..0000000
--- a/cmds/statsd/src/condition/ConditionWizard.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CONDITION_WIZARD_H
-#define CONDITION_WIZARD_H
-
-#include "ConditionTracker.h"
-#include "condition_util.h"
-#include "stats_util.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// Held by MetricProducer, to query a condition state with input defined in MetricConditionLink.
-class ConditionWizard : public virtual android::RefBase {
-public:
-    ConditionWizard(){};  // for testing
-    explicit ConditionWizard(std::vector<sp<ConditionTracker>>& conditionTrackers)
-        : mAllConditions(conditionTrackers){};
-
-    virtual ~ConditionWizard(){};
-
-    // Query condition state, for a ConditionTracker at [conditionIndex], with [conditionParameters]
-    // [conditionParameters] mapping from condition name to the HashableDimensionKey to query the
-    //                       condition.
-    // The ConditionTracker at [conditionIndex] can be a CombinationConditionTracker. In this case,
-    // the conditionParameters contains the parameters for it's children SimpleConditionTrackers.
-    virtual ConditionState query(const int conditionIndex, const ConditionKey& conditionParameters,
-                                 const bool isPartialLink);
-
-    virtual const std::set<HashableDimensionKey>* getChangedToTrueDimensions(const int index) const;
-    virtual const std::set<HashableDimensionKey>* getChangedToFalseDimensions(
-            const int index) const;
-    bool equalOutputDimensions(const int index, const vector<Matcher>& dimensions);
-
-    bool IsChangedDimensionTrackable(const int index);
-    bool IsSimpleCondition(const int index);
-
-    ConditionState getUnSlicedPartConditionState(const int index) {
-        return mAllConditions[index]->getUnSlicedPartConditionState();
-    }
-
-    const std::map<HashableDimensionKey, int>* getSlicedDimensionMap(const int index) const {
-        return mAllConditions[index]->getSlicedDimensionMap(mAllConditions);
-    }
-
-private:
-    std::vector<sp<ConditionTracker>> mAllConditions;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#endif  // CONDITION_WIZARD_H
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
deleted file mode 100644
index 1dcc8f9..0000000
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "SimpleConditionTracker.h"
-#include "guardrail/StatsdStats.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using std::unordered_map;
-
-SimpleConditionTracker::SimpleConditionTracker(
-        const ConfigKey& key, const int64_t& id, const uint64_t protoHash, const int index,
-        const SimplePredicate& simplePredicate,
-        const unordered_map<int64_t, int>& atomMatchingTrackerMap)
-    : ConditionTracker(id, index, protoHash),
-      mConfigKey(key),
-      mContainANYPositionInInternalDimensions(false) {
-    VLOG("creating SimpleConditionTracker %lld", (long long)mConditionId);
-    mCountNesting = simplePredicate.count_nesting();
-
-    setMatcherIndices(simplePredicate, atomMatchingTrackerMap);
-
-    if (simplePredicate.has_dimensions()) {
-        translateFieldMatcher(simplePredicate.dimensions(), &mOutputDimensions);
-        if (mOutputDimensions.size() > 0) {
-            mSliced = true;
-        }
-        mContainANYPositionInInternalDimensions = HasPositionANY(simplePredicate.dimensions());
-    }
-
-    if (simplePredicate.initial_value() == SimplePredicate_InitialValue_FALSE) {
-        mInitialValue = ConditionState::kFalse;
-    } else {
-        mInitialValue = ConditionState::kUnknown;
-    }
-
-    mInitialized = true;
-}
-
-SimpleConditionTracker::~SimpleConditionTracker() {
-    VLOG("~SimpleConditionTracker()");
-}
-
-bool SimpleConditionTracker::init(const vector<Predicate>& allConditionConfig,
-                                  const vector<sp<ConditionTracker>>& allConditionTrackers,
-                                  const unordered_map<int64_t, int>& conditionIdIndexMap,
-                                  vector<bool>& stack, vector<ConditionState>& conditionCache) {
-    // SimpleConditionTracker does not have dependency on other conditions, thus we just return
-    // if the initialization was successful.
-    ConditionKey conditionKey;
-    if (mSliced) {
-        conditionKey[mConditionId] = DEFAULT_DIMENSION_KEY;
-    }
-    isConditionMet(conditionKey, allConditionTrackers, mSliced, conditionCache);
-    return mInitialized;
-}
-
-bool SimpleConditionTracker::onConfigUpdated(
-        const vector<Predicate>& allConditionProtos, const int index,
-        const vector<sp<ConditionTracker>>& allConditionTrackers,
-        const unordered_map<int64_t, int>& atomMatchingTrackerMap,
-        const unordered_map<int64_t, int>& conditionTrackerMap) {
-    ConditionTracker::onConfigUpdated(allConditionProtos, index, allConditionTrackers,
-                                      atomMatchingTrackerMap, conditionTrackerMap);
-    setMatcherIndices(allConditionProtos[index].simple_predicate(), atomMatchingTrackerMap);
-    return true;
-}
-
-void SimpleConditionTracker::setMatcherIndices(
-        const SimplePredicate& simplePredicate,
-        const unordered_map<int64_t, int>& atomMatchingTrackerMap) {
-    mTrackerIndex.clear();
-    if (simplePredicate.has_start()) {
-        auto pair = atomMatchingTrackerMap.find(simplePredicate.start());
-        if (pair == atomMatchingTrackerMap.end()) {
-            ALOGW("Start matcher %lld not found in the config", (long long)simplePredicate.start());
-            return;
-        }
-        mStartLogMatcherIndex = pair->second;
-        mTrackerIndex.insert(mStartLogMatcherIndex);
-    } else {
-        mStartLogMatcherIndex = -1;
-    }
-
-    if (simplePredicate.has_stop()) {
-        auto pair = atomMatchingTrackerMap.find(simplePredicate.stop());
-        if (pair == atomMatchingTrackerMap.end()) {
-            ALOGW("Stop matcher %lld not found in the config", (long long)simplePredicate.stop());
-            return;
-        }
-        mStopLogMatcherIndex = pair->second;
-        mTrackerIndex.insert(mStopLogMatcherIndex);
-    } else {
-        mStopLogMatcherIndex = -1;
-    }
-
-    if (simplePredicate.has_stop_all()) {
-        auto pair = atomMatchingTrackerMap.find(simplePredicate.stop_all());
-        if (pair == atomMatchingTrackerMap.end()) {
-            ALOGW("Stop all matcher %lld found in the config",
-                  (long long)simplePredicate.stop_all());
-            return;
-        }
-        mStopAllLogMatcherIndex = pair->second;
-        mTrackerIndex.insert(mStopAllLogMatcherIndex);
-    } else {
-        mStopAllLogMatcherIndex = -1;
-    }
-}
-
-void SimpleConditionTracker::dumpState() {
-    VLOG("%lld DUMP:", (long long)mConditionId);
-    for (const auto& pair : mSlicedConditionState) {
-        VLOG("\t%s : %d", pair.first.toString().c_str(), pair.second);
-    }
-
-    VLOG("Changed to true keys: \n");
-    for (const auto& key : mLastChangedToTrueDimensions) {
-        VLOG("%s", key.toString().c_str());
-    }
-    VLOG("Changed to false keys: \n");
-    for (const auto& key : mLastChangedToFalseDimensions) {
-        VLOG("%s", key.toString().c_str());
-    }
-}
-
-void SimpleConditionTracker::handleStopAll(std::vector<ConditionState>& conditionCache,
-                                           std::vector<bool>& conditionChangedCache) {
-    // Unless the default condition is false, and there was nothing started, otherwise we have
-    // triggered a condition change.
-    conditionChangedCache[mIndex] =
-            (mInitialValue == ConditionState::kFalse && mSlicedConditionState.empty()) ? false
-                                                                                           : true;
-
-    for (const auto& cond : mSlicedConditionState) {
-        if (cond.second > 0) {
-            mLastChangedToFalseDimensions.insert(cond.first);
-        }
-    }
-
-    // After StopAll, we know everything has stopped. From now on, default condition is false.
-    mInitialValue = ConditionState::kFalse;
-    mSlicedConditionState.clear();
-    conditionCache[mIndex] = ConditionState::kFalse;
-}
-
-bool SimpleConditionTracker::hitGuardRail(const HashableDimensionKey& newKey) {
-    if (!mSliced || mSlicedConditionState.find(newKey) != mSlicedConditionState.end()) {
-        // if the condition is not sliced or the key is not new, we are good!
-        return false;
-    }
-    // 1. Report the tuple count if the tuple count > soft limit
-    if (mSlicedConditionState.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
-        size_t newTupleCount = mSlicedConditionState.size() + 1;
-        StatsdStats::getInstance().noteConditionDimensionSize(mConfigKey, mConditionId, newTupleCount);
-        // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
-        if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
-            ALOGE("Predicate %lld dropping data for dimension key %s",
-                (long long)mConditionId, newKey.toString().c_str());
-            return true;
-        }
-    }
-    return false;
-}
-
-void SimpleConditionTracker::handleConditionEvent(const HashableDimensionKey& outputKey,
-                                                  bool matchStart, ConditionState* conditionCache,
-                                                  bool* conditionChangedCache) {
-    bool changed = false;
-    auto outputIt = mSlicedConditionState.find(outputKey);
-    ConditionState newCondition;
-    if (hitGuardRail(outputKey)) {
-        (*conditionChangedCache) = false;
-        // Tells the caller it's evaluated.
-        (*conditionCache) = ConditionState::kUnknown;
-        return;
-    }
-    if (outputIt == mSlicedConditionState.end()) {
-        // We get a new output key.
-        newCondition = matchStart ? ConditionState::kTrue : ConditionState::kFalse;
-        if (matchStart && mInitialValue != ConditionState::kTrue) {
-            mSlicedConditionState[outputKey] = 1;
-            changed = true;
-            mLastChangedToTrueDimensions.insert(outputKey);
-        } else if (mInitialValue != ConditionState::kFalse) {
-            // it's a stop and we don't have history about it.
-            // If the default condition is not false, it means this stop is valuable to us.
-            mSlicedConditionState[outputKey] = 0;
-            mLastChangedToFalseDimensions.insert(outputKey);
-            changed = true;
-        }
-    } else {
-        // we have history about this output key.
-        auto& startedCount = outputIt->second;
-        // assign the old value first.
-        newCondition = startedCount > 0 ? ConditionState::kTrue : ConditionState::kFalse;
-        if (matchStart) {
-            if (startedCount == 0) {
-                mLastChangedToTrueDimensions.insert(outputKey);
-                // This condition for this output key will change from false -> true
-                changed = true;
-            }
-
-            // it's ok to do ++ here, even if we don't count nesting. The >1 counts will be treated
-            // as 1 if not counting nesting.
-            startedCount++;
-            newCondition = ConditionState::kTrue;
-        } else {
-            // This is a stop event.
-            if (startedCount > 0) {
-                if (mCountNesting) {
-                    startedCount--;
-                    if (startedCount == 0) {
-                        newCondition = ConditionState::kFalse;
-                    }
-                } else {
-                    // not counting nesting, so ignore the number of starts, stop now.
-                    startedCount = 0;
-                    newCondition = ConditionState::kFalse;
-                }
-                // if everything has stopped for this output key, condition true -> false;
-                if (startedCount == 0) {
-                    mLastChangedToFalseDimensions.insert(outputKey);
-                    changed = true;
-                }
-            }
-
-            // if default condition is false, it means we don't need to keep the false values.
-            if (mInitialValue == ConditionState::kFalse && startedCount == 0) {
-                mSlicedConditionState.erase(outputIt);
-                VLOG("erase key %s", outputKey.toString().c_str());
-            }
-        }
-    }
-
-    // dump all dimensions for debugging
-    if (DEBUG) {
-        dumpState();
-    }
-
-    (*conditionChangedCache) = changed;
-    (*conditionCache) = newCondition;
-
-    VLOG("SimplePredicate %lld nonSlicedChange? %d", (long long)mConditionId,
-         conditionChangedCache[mIndex] == true);
-}
-
-void SimpleConditionTracker::evaluateCondition(
-        const LogEvent& event,
-        const vector<MatchingState>& eventMatcherValues,
-        const vector<sp<ConditionTracker>>& mAllConditions,
-        vector<ConditionState>& conditionCache,
-        vector<bool>& conditionChangedCache) {
-    if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
-        // it has been evaluated.
-        VLOG("Yes, already evaluated, %lld %d",
-            (long long)mConditionId, conditionCache[mIndex]);
-        return;
-    }
-    mLastChangedToTrueDimensions.clear();
-    mLastChangedToFalseDimensions.clear();
-
-    if (mStopAllLogMatcherIndex >= 0 && mStopAllLogMatcherIndex < int(eventMatcherValues.size()) &&
-        eventMatcherValues[mStopAllLogMatcherIndex] == MatchingState::kMatched) {
-        handleStopAll(conditionCache, conditionChangedCache);
-        return;
-    }
-
-    int matchedState = -1;
-    // Note: The order to evaluate the following start, stop, stop_all matters.
-    // The priority of overwrite is stop_all > stop > start.
-    if (mStartLogMatcherIndex >= 0 &&
-        eventMatcherValues[mStartLogMatcherIndex] == MatchingState::kMatched) {
-        matchedState = 1;
-    }
-
-    if (mStopLogMatcherIndex >= 0 &&
-        eventMatcherValues[mStopLogMatcherIndex] == MatchingState::kMatched) {
-        matchedState = 0;
-    }
-
-    if (matchedState < 0) {
-        // The event doesn't match this condition. So we just report existing condition values.
-        conditionChangedCache[mIndex] = false;
-        if (mSliced) {
-            // if the condition result is sliced. The overall condition is true if any of the sliced
-            // condition is true
-            conditionCache[mIndex] = mInitialValue;
-            for (const auto& slicedCondition : mSlicedConditionState) {
-                if (slicedCondition.second > 0) {
-                    conditionCache[mIndex] = ConditionState::kTrue;
-                    break;
-                }
-            }
-        } else {
-            const auto& itr = mSlicedConditionState.find(DEFAULT_DIMENSION_KEY);
-            if (itr == mSlicedConditionState.end()) {
-                // condition not sliced, but we haven't seen the matched start or stop yet. so
-                // return initial value.
-                conditionCache[mIndex] = mInitialValue;
-            } else {
-                // return the cached condition.
-                conditionCache[mIndex] =
-                        itr->second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
-            }
-        }
-        return;
-    }
-
-    ConditionState overallState = mInitialValue;
-    bool overallChanged = false;
-
-    if (mOutputDimensions.size() == 0) {
-        handleConditionEvent(DEFAULT_DIMENSION_KEY, matchedState == 1, &overallState,
-                             &overallChanged);
-    } else if (!mContainANYPositionInInternalDimensions) {
-        HashableDimensionKey outputValue;
-        filterValues(mOutputDimensions, event.getValues(), &outputValue);
-
-        // If this event has multiple nodes in the attribution chain,  this log event probably will
-        // generate multiple dimensions. If so, we will find if the condition changes for any
-        // dimension and ask the corresponding metric producer to verify whether the actual sliced
-        // condition has changed or not.
-        // A high level assumption is that a predicate is either sliced or unsliced. We will never
-        // have both sliced and unsliced version of a predicate.
-        handleConditionEvent(outputValue, matchedState == 1, &overallState, &overallChanged);
-    } else {
-        ALOGE("The condition tracker should not be sliced by ANY position matcher.");
-    }
-    conditionCache[mIndex] = overallState;
-    conditionChangedCache[mIndex] = overallChanged;
-}
-
-void SimpleConditionTracker::isConditionMet(
-        const ConditionKey& conditionParameters, const vector<sp<ConditionTracker>>& allConditions,
-        const bool isPartialLink,
-        vector<ConditionState>& conditionCache) const {
-
-    if (conditionCache[mIndex] != ConditionState::kNotEvaluated) {
-        // it has been evaluated.
-        VLOG("Yes, already evaluated, %lld %d",
-            (long long)mConditionId, conditionCache[mIndex]);
-        return;
-    }
-    const auto pair = conditionParameters.find(mConditionId);
-
-    if (pair == conditionParameters.end()) {
-        ConditionState conditionState = ConditionState::kNotEvaluated;
-        conditionState = conditionState | mInitialValue;
-        if (!mSliced) {
-            const auto& itr = mSlicedConditionState.find(DEFAULT_DIMENSION_KEY);
-            if (itr != mSlicedConditionState.end()) {
-                ConditionState sliceState =
-                    itr->second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
-                conditionState = conditionState | sliceState;
-            }
-        }
-        conditionCache[mIndex] = conditionState;
-        return;
-    }
-
-    ConditionState conditionState = ConditionState::kNotEvaluated;
-    const HashableDimensionKey& key = pair->second;
-    if (isPartialLink) {
-        // For unseen key, check whether the require dimensions are subset of sliced condition
-        // output.
-        conditionState = conditionState | mInitialValue;
-        for (const auto& slice : mSlicedConditionState) {
-            ConditionState sliceState =
-                slice.second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
-            if (slice.first.contains(key)) {
-                conditionState = conditionState | sliceState;
-            }
-        }
-    } else {
-        auto startedCountIt = mSlicedConditionState.find(key);
-        conditionState = conditionState | mInitialValue;
-        if (startedCountIt != mSlicedConditionState.end()) {
-            ConditionState sliceState =
-                startedCountIt->second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
-            conditionState = conditionState | sliceState;
-        }
-
-    }
-    conditionCache[mIndex] = conditionState;
-    VLOG("Predicate %lld return %d", (long long)mConditionId, conditionCache[mIndex]);
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.h b/cmds/statsd/src/condition/SimpleConditionTracker.h
deleted file mode 100644
index 2fbc8a7..0000000
--- a/cmds/statsd/src/condition/SimpleConditionTracker.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SIMPLE_CONDITION_TRACKER_H
-#define SIMPLE_CONDITION_TRACKER_H
-
-#include <gtest/gtest_prod.h>
-#include "ConditionTracker.h"
-#include "config/ConfigKey.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "stats_util.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class SimpleConditionTracker : public ConditionTracker {
-public:
-    SimpleConditionTracker(const ConfigKey& key, const int64_t& id, const uint64_t protoHash,
-                           const int index, const SimplePredicate& simplePredicate,
-                           const std::unordered_map<int64_t, int>& atomMatchingTrackerMap);
-
-    ~SimpleConditionTracker();
-
-    bool init(const std::vector<Predicate>& allConditionConfig,
-              const std::vector<sp<ConditionTracker>>& allConditionTrackers,
-              const std::unordered_map<int64_t, int>& conditionIdIndexMap, std::vector<bool>& stack,
-              std::vector<ConditionState>& conditionCache) override;
-
-    bool onConfigUpdated(const std::vector<Predicate>& allConditionProtos, const int index,
-                         const std::vector<sp<ConditionTracker>>& allConditionTrackers,
-                         const std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
-                         const std::unordered_map<int64_t, int>& conditionTrackerMap) override;
-
-    void evaluateCondition(const LogEvent& event,
-                           const std::vector<MatchingState>& eventMatcherValues,
-                           const std::vector<sp<ConditionTracker>>& mAllConditions,
-                           std::vector<ConditionState>& conditionCache,
-                           std::vector<bool>& changedCache) override;
-
-    void isConditionMet(const ConditionKey& conditionParameters,
-                        const std::vector<sp<ConditionTracker>>& allConditions,
-                        const bool isPartialLink,
-                        std::vector<ConditionState>& conditionCache) const override;
-
-    virtual const std::set<HashableDimensionKey>* getChangedToTrueDimensions(
-            const std::vector<sp<ConditionTracker>>& allConditions) const {
-        if (mSliced) {
-            return &mLastChangedToTrueDimensions;
-        } else {
-            return nullptr;
-        }
-    }
-
-    virtual const std::set<HashableDimensionKey>* getChangedToFalseDimensions(
-            const std::vector<sp<ConditionTracker>>& allConditions) const {
-        if (mSliced) {
-            return &mLastChangedToFalseDimensions;
-        } else {
-            return nullptr;
-        }
-    }
-
-    const std::map<HashableDimensionKey, int>* getSlicedDimensionMap(
-            const std::vector<sp<ConditionTracker>>& allConditions) const override {
-        return &mSlicedConditionState;
-    }
-
-    bool IsChangedDimensionTrackable() const  override { return true; }
-
-    bool IsSimpleCondition() const  override { return true; }
-
-    bool equalOutputDimensions(
-        const std::vector<sp<ConditionTracker>>& allConditions,
-        const vector<Matcher>& dimensions) const override {
-            return equalDimensions(mOutputDimensions, dimensions);
-    }
-
-private:
-    const ConfigKey mConfigKey;
-    // The index of the LogEventMatcher which defines the start.
-    int mStartLogMatcherIndex;
-
-    // The index of the LogEventMatcher which defines the end.
-    int mStopLogMatcherIndex;
-
-    // if the start end needs to be nested.
-    bool mCountNesting;
-
-    // The index of the LogEventMatcher which defines the stop all.
-    int mStopAllLogMatcherIndex;
-
-    ConditionState mInitialValue;
-
-    std::vector<Matcher> mOutputDimensions;
-
-    bool mContainANYPositionInInternalDimensions;
-
-    std::set<HashableDimensionKey> mLastChangedToTrueDimensions;
-    std::set<HashableDimensionKey> mLastChangedToFalseDimensions;
-
-    std::map<HashableDimensionKey, int> mSlicedConditionState;
-
-    void setMatcherIndices(const SimplePredicate& predicate,
-                           const std::unordered_map<int64_t, int>& logTrackerMap);
-
-    void handleStopAll(std::vector<ConditionState>& conditionCache,
-                       std::vector<bool>& changedCache);
-
-    void handleConditionEvent(const HashableDimensionKey& outputKey, bool matchStart,
-                              ConditionState* conditionCache, bool* changedCache);
-
-    bool hitGuardRail(const HashableDimensionKey& newKey);
-
-    void dumpState();
-
-    FRIEND_TEST(SimpleConditionTrackerTest, TestSlicedCondition);
-    FRIEND_TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim);
-    FRIEND_TEST(SimpleConditionTrackerTest, TestStopAll);
-    FRIEND_TEST(ConfigUpdateTest, TestUpdateConditions);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-#endif  // SIMPLE_CONDITION_TRACKER_H
diff --git a/cmds/statsd/src/condition/condition_util.cpp b/cmds/statsd/src/condition/condition_util.cpp
deleted file mode 100644
index 60b8c53..0000000
--- a/cmds/statsd/src/condition/condition_util.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Log.h"
-
-#include "condition_util.h"
-
-#include "../matchers/matcher_util.h"
-#include "ConditionTracker.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "stats_util.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using std::vector;
-
-
-ConditionState evaluateCombinationCondition(const std::vector<int>& children,
-                                            const LogicalOperation& operation,
-                                            const std::vector<ConditionState>& conditionCache) {
-    ConditionState newCondition;
-
-    bool hasUnknown = false;
-    bool hasFalse = false;
-    bool hasTrue = false;
-
-    for (auto childIndex : children) {
-        ConditionState childState = conditionCache[childIndex];
-        if (childState == ConditionState::kUnknown) {
-            hasUnknown = true;
-            break;
-        }
-        if (childState == ConditionState::kFalse) {
-            hasFalse = true;
-        }
-        if (childState == ConditionState::kTrue) {
-            hasTrue = true;
-        }
-    }
-
-    // If any child condition is in unknown state, the condition is unknown too.
-    if (hasUnknown) {
-        return ConditionState::kUnknown;
-    }
-
-    switch (operation) {
-        case LogicalOperation::AND: {
-            newCondition = hasFalse ? ConditionState::kFalse : ConditionState::kTrue;
-            break;
-        }
-        case LogicalOperation::OR: {
-            newCondition = hasTrue ? ConditionState::kTrue : ConditionState::kFalse;
-            break;
-        }
-        case LogicalOperation::NOT:
-            newCondition = children.empty() ? ConditionState::kUnknown :
-                              ((conditionCache[children[0]] == ConditionState::kFalse) ?
-                                  ConditionState::kTrue : ConditionState::kFalse);
-            break;
-        case LogicalOperation::NAND:
-            newCondition = hasFalse ? ConditionState::kTrue : ConditionState::kFalse;
-            break;
-        case LogicalOperation::NOR:
-            newCondition = hasTrue ? ConditionState::kFalse : ConditionState::kTrue;
-            break;
-        case LogicalOperation::LOGICAL_OPERATION_UNSPECIFIED:
-            newCondition = ConditionState::kFalse;
-            break;
-    }
-    return newCondition;
-}
-
-ConditionState operator|(ConditionState l, ConditionState r) {
-    return l >= r ? l : r;
-}
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/condition/condition_util.h b/cmds/statsd/src/condition/condition_util.h
deleted file mode 100644
index fed90ec..0000000
--- a/cmds/statsd/src/condition/condition_util.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CONDITION_UTIL_H
-#define CONDITION_UTIL_H
-
-#include <vector>
-#include "../matchers/matcher_util.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-enum ConditionState {
-    kNotEvaluated = -2,
-    kUnknown = -1,
-    kFalse = 0,
-    kTrue = 1,
-};
-
-ConditionState operator|(ConditionState l, ConditionState r);
-
-ConditionState evaluateCombinationCondition(const std::vector<int>& children,
-                                            const LogicalOperation& operation,
-                                            const std::vector<ConditionState>& conditionCache);
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#endif  // CONDITION_UTIL_H
diff --git a/cmds/statsd/src/config/ConfigKey.cpp b/cmds/statsd/src/config/ConfigKey.cpp
deleted file mode 100644
index 4a2bd27..0000000
--- a/cmds/statsd/src/config/ConfigKey.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "config/ConfigKey.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-ConfigKey::ConfigKey() {
-}
-
-ConfigKey::ConfigKey(const ConfigKey& that) : mId(that.mId), mUid(that.mUid) {
-}
-
-ConfigKey::ConfigKey(int uid, const int64_t& id) : mId(id), mUid(uid) {
-}
-
-ConfigKey::~ConfigKey() {
-}
-
-string ConfigKey::ToString() const {
-    string s;
-    s += "(" + std::to_string(mUid) + " " + std::to_string(mId) + ")";
-    return s;
-}
-
-
-int64_t StrToInt64(const string& str) {
-    char* endp;
-    int64_t value;
-    value = strtoll(str.c_str(), &endp, 0);
-    if (endp == str.c_str() || *endp != '\0') {
-        value = 0;
-    }
-    return value;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/config/ConfigKey.h b/cmds/statsd/src/config/ConfigKey.h
deleted file mode 100644
index 4cc9393..0000000
--- a/cmds/statsd/src/config/ConfigKey.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-
-#include <string>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using std::hash;
-using std::string;
-
-/**
- * Uniquely identifies a configuration.
- */
-class ConfigKey {
-public:
-    ConfigKey();
-    ConfigKey(const ConfigKey& that);
-    ConfigKey(int uid, const int64_t& id);
-    ~ConfigKey();
-
-    inline int GetUid() const {
-        return mUid;
-    }
-    inline const int64_t& GetId() const {
-        return mId;
-    }
-
-    inline bool operator<(const ConfigKey& that) const {
-        if (mUid < that.mUid) {
-            return true;
-        }
-        if (mUid > that.mUid) {
-            return false;
-        }
-        return mId < that.mId;
-    };
-
-    inline bool operator==(const ConfigKey& that) const {
-        return mUid == that.mUid && mId == that.mId;
-    };
-
-    string ToString() const;
-
-private:
-    int64_t mId;
-    int mUid;
-};
-
-int64_t StrToInt64(const string& str);
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-/**
- * A hash function for ConfigKey so it can be used for unordered_map/set.
- * Unfortunately this has to go in std namespace because C++ is fun!
- */
-namespace std {
-
-using android::os::statsd::ConfigKey;
-
-template <>
-struct hash<ConfigKey> {
-    std::size_t operator()(const ConfigKey& key) const {
-        return (7 * key.GetUid()) ^ ((hash<long long>()(key.GetId())));
-    }
-};
-
-}  // namespace std
diff --git a/cmds/statsd/src/config/ConfigListener.cpp b/cmds/statsd/src/config/ConfigListener.cpp
deleted file mode 100644
index 21a3f16..0000000
--- a/cmds/statsd/src/config/ConfigListener.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "config/ConfigListener.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-ConfigListener::ConfigListener() {
-}
-
-ConfigListener::~ConfigListener() {
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/config/ConfigListener.h b/cmds/statsd/src/config/ConfigListener.h
deleted file mode 100644
index dcd5e52..0000000
--- a/cmds/statsd/src/config/ConfigListener.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "config/ConfigKey.h"
-
-#include <utils/RefBase.h>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using android::RefBase;
-
-/**
- * Callback for different subsystems inside statsd to implement to find out
- * when a configuration has been added, updated or removed.
- */
-class ConfigListener : public virtual RefBase {
-public:
-    ConfigListener();
-    virtual ~ConfigListener();
-
-    /**
-     * A configuration was added or updated.
-     */
-    virtual void OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key,
-                                 const StatsdConfig& config) = 0;
-
-    /**
-     * A configuration was removed.
-     */
-    virtual void OnConfigRemoved(const ConfigKey& key) = 0;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
deleted file mode 100644
index 13020e0..0000000
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "config/ConfigManager.h"
-#include "storage/StorageManager.h"
-
-#include "guardrail/StatsdStats.h"
-#include "stats_log_util.h"
-#include "stats_util.h"
-#include "stats_log_util.h"
-
-#include <stdio.h>
-#include <vector>
-#include "android-base/stringprintf.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using std::pair;
-using std::string;
-using std::vector;
-
-#define STATS_SERVICE_DIR "/data/misc/stats-service"
-
-using android::base::StringPrintf;
-using std::unique_ptr;
-
-struct ConfigReceiverDeathCookie {
-    ConfigReceiverDeathCookie(const wp<ConfigManager>& configManager, const ConfigKey& configKey,
-                              const shared_ptr<IPendingIntentRef>& pir) :
-            mConfigManager(configManager), mConfigKey(configKey), mPir(pir) {
-    }
-
-    wp<ConfigManager> mConfigManager;
-    ConfigKey mConfigKey;
-    shared_ptr<IPendingIntentRef> mPir;
-};
-
-void ConfigManager::configReceiverDied(void* cookie) {
-    auto cookie_ = static_cast<ConfigReceiverDeathCookie*>(cookie);
-    sp<ConfigManager> thiz = cookie_->mConfigManager.promote();
-    if (!thiz) {
-        return;
-    }
-
-    ConfigKey& configKey = cookie_->mConfigKey;
-    shared_ptr<IPendingIntentRef>& pir = cookie_->mPir;
-
-    // Erase the mapping from the config key to the config receiver (pir) if the
-    // mapping still exists.
-    lock_guard<mutex> lock(thiz->mMutex);
-    auto it = thiz->mConfigReceivers.find(configKey);
-    if (it != thiz->mConfigReceivers.end() && it->second == pir) {
-        thiz->mConfigReceivers.erase(configKey);
-    }
-
-    // The death recipient corresponding to this specific pir can never be
-    // triggered again, so free up resources.
-    delete cookie_;
-}
-
-struct ActiveConfigChangedReceiverDeathCookie {
-    ActiveConfigChangedReceiverDeathCookie(const wp<ConfigManager>& configManager, const int uid,
-                                           const shared_ptr<IPendingIntentRef>& pir) :
-            mConfigManager(configManager), mUid(uid), mPir(pir) {
-    }
-
-    wp<ConfigManager> mConfigManager;
-    int mUid;
-    shared_ptr<IPendingIntentRef> mPir;
-};
-
-void ConfigManager::activeConfigChangedReceiverDied(void* cookie) {
-    auto cookie_ = static_cast<ActiveConfigChangedReceiverDeathCookie*>(cookie);
-    sp<ConfigManager> thiz = cookie_->mConfigManager.promote();
-    if (!thiz) {
-        return;
-    }
-
-    int uid = cookie_->mUid;
-    shared_ptr<IPendingIntentRef>& pir = cookie_->mPir;
-
-    // Erase the mapping from the config key to the active config changed
-    // receiver (pir) if the mapping still exists.
-    lock_guard<mutex> lock(thiz->mMutex);
-    auto it = thiz->mActiveConfigsChangedReceivers.find(uid);
-    if (it != thiz->mActiveConfigsChangedReceivers.end() && it->second == pir) {
-        thiz->mActiveConfigsChangedReceivers.erase(uid);
-    }
-
-    // The death recipient corresponding to this specific pir can never
-    // be triggered again, so free up resources.
-    delete cookie_;
-}
-
-ConfigManager::ConfigManager() :
-    mConfigReceiverDeathRecipient(AIBinder_DeathRecipient_new(configReceiverDied)),
-    mActiveConfigChangedReceiverDeathRecipient(
-            AIBinder_DeathRecipient_new(activeConfigChangedReceiverDied)) {
-}
-
-ConfigManager::~ConfigManager() {
-}
-
-void ConfigManager::Startup() {
-    map<ConfigKey, StatsdConfig> configsFromDisk;
-    StorageManager::readConfigFromDisk(configsFromDisk);
-    for (const auto& pair : configsFromDisk) {
-        UpdateConfig(pair.first, pair.second);
-    }
-}
-
-void ConfigManager::StartupForTest() {
-    // No-op function to avoid reading configs from disks for tests.
-}
-
-void ConfigManager::AddListener(const sp<ConfigListener>& listener) {
-    lock_guard<mutex> lock(mMutex);
-    mListeners.push_back(listener);
-}
-
-void ConfigManager::UpdateConfig(const ConfigKey& key, const StatsdConfig& config) {
-    vector<sp<ConfigListener>> broadcastList;
-    {
-        lock_guard <mutex> lock(mMutex);
-
-        const int numBytes = config.ByteSize();
-        vector<uint8_t> buffer(numBytes);
-        config.SerializeToArray(&buffer[0], numBytes);
-
-        auto uidIt = mConfigs.find(key.GetUid());
-        // GuardRail: Limit the number of configs per uid.
-        if (uidIt != mConfigs.end()) {
-            auto it = uidIt->second.find(key);
-            if (it == uidIt->second.end() &&
-                uidIt->second.size() >= StatsdStats::kMaxConfigCountPerUid) {
-                ALOGE("ConfigManager: uid %d has exceeded the config count limit", key.GetUid());
-                return;
-            }
-        }
-
-        // Check if it's a duplicate config.
-        if (uidIt != mConfigs.end() && uidIt->second.find(key) != uidIt->second.end() &&
-            StorageManager::hasIdenticalConfig(key, buffer)) {
-            // This is a duplicate config.
-            ALOGI("ConfigManager This is a duplicate config %s", key.ToString().c_str());
-            // Update saved file on disk. We still update timestamp of file when
-            // there exists a duplicate configuration to avoid garbage collection.
-            update_saved_configs_locked(key, buffer, numBytes);
-            return;
-        }
-
-        // Update saved file on disk.
-        update_saved_configs_locked(key, buffer, numBytes);
-
-        // Add to set.
-        mConfigs[key.GetUid()].insert(key);
-
-        for (const sp<ConfigListener>& listener : mListeners) {
-            broadcastList.push_back(listener);
-        }
-    }
-
-    const int64_t timestampNs = getElapsedRealtimeNs();
-    // Tell everyone
-    for (const sp<ConfigListener>& listener : broadcastList) {
-        listener->OnConfigUpdated(timestampNs, key, config);
-    }
-}
-
-void ConfigManager::SetConfigReceiver(const ConfigKey& key,
-                                      const shared_ptr<IPendingIntentRef>& pir) {
-    lock_guard<mutex> lock(mMutex);
-    mConfigReceivers[key] = pir;
-    AIBinder_linkToDeath(pir->asBinder().get(), mConfigReceiverDeathRecipient.get(),
-                         new ConfigReceiverDeathCookie(this, key, pir));
-}
-
-void ConfigManager::RemoveConfigReceiver(const ConfigKey& key) {
-    lock_guard<mutex> lock(mMutex);
-    mConfigReceivers.erase(key);
-}
-
-void ConfigManager::SetActiveConfigsChangedReceiver(const int uid,
-                                                    const shared_ptr<IPendingIntentRef>& pir) {
-    {
-        lock_guard<mutex> lock(mMutex);
-        mActiveConfigsChangedReceivers[uid] = pir;
-    }
-    AIBinder_linkToDeath(pir->asBinder().get(), mActiveConfigChangedReceiverDeathRecipient.get(),
-                         new ActiveConfigChangedReceiverDeathCookie(this, uid, pir));
-}
-
-void ConfigManager::RemoveActiveConfigsChangedReceiver(const int uid) {
-    lock_guard<mutex> lock(mMutex);
-    mActiveConfigsChangedReceivers.erase(uid);
-}
-
-void ConfigManager::RemoveConfig(const ConfigKey& key) {
-    vector<sp<ConfigListener>> broadcastList;
-    {
-        lock_guard <mutex> lock(mMutex);
-
-        auto uid = key.GetUid();
-        auto uidIt = mConfigs.find(uid);
-        if (uidIt != mConfigs.end() && uidIt->second.find(key) != uidIt->second.end()) {
-            // Remove from map
-            uidIt->second.erase(key);
-
-            for (const sp<ConfigListener>& listener : mListeners) {
-                broadcastList.push_back(listener);
-            }
-        }
-
-        // Remove from disk. There can still be a lingering file on disk so we check
-        // whether or not the config was on memory.
-        remove_saved_configs(key);
-    }
-
-    for (const sp<ConfigListener>& listener:broadcastList) {
-        listener->OnConfigRemoved(key);
-    }
-}
-
-void ConfigManager::remove_saved_configs(const ConfigKey& key) {
-    string suffix = StringPrintf("%d_%lld", key.GetUid(), (long long)key.GetId());
-    StorageManager::deleteSuffixedFiles(STATS_SERVICE_DIR, suffix.c_str());
-}
-
-void ConfigManager::RemoveConfigs(int uid) {
-    vector<ConfigKey> removed;
-    vector<sp<ConfigListener>> broadcastList;
-    {
-        lock_guard <mutex> lock(mMutex);
-
-        auto uidIt = mConfigs.find(uid);
-        if (uidIt == mConfigs.end()) {
-            return;
-        }
-
-        for (auto it = uidIt->second.begin(); it != uidIt->second.end(); ++it) {
-            // Remove from map
-                remove_saved_configs(*it);
-                removed.push_back(*it);
-        }
-
-        mConfigs.erase(uidIt);
-
-        for (const sp<ConfigListener>& listener : mListeners) {
-            broadcastList.push_back(listener);
-        }
-    }
-
-    // Remove separately so if they do anything in the callback they can't mess up our iteration.
-    for (auto& key : removed) {
-        // Tell everyone
-        for (const sp<ConfigListener>& listener:broadcastList) {
-            listener->OnConfigRemoved(key);
-        }
-    }
-}
-
-void ConfigManager::RemoveAllConfigs() {
-    vector<ConfigKey> removed;
-    vector<sp<ConfigListener>> broadcastList;
-    {
-        lock_guard <mutex> lock(mMutex);
-
-        for (auto uidIt = mConfigs.begin(); uidIt != mConfigs.end();) {
-            for (auto it = uidIt->second.begin(); it != uidIt->second.end();) {
-                // Remove from map
-                removed.push_back(*it);
-                it = uidIt->second.erase(it);
-            }
-            uidIt = mConfigs.erase(uidIt);
-        }
-
-        for (const sp<ConfigListener>& listener : mListeners) {
-            broadcastList.push_back(listener);
-        }
-    }
-
-    // Remove separately so if they do anything in the callback they can't mess up our iteration.
-    for (auto& key : removed) {
-        // Tell everyone
-        for (const sp<ConfigListener>& listener:broadcastList) {
-            listener->OnConfigRemoved(key);
-        }
-    }
-}
-
-vector<ConfigKey> ConfigManager::GetAllConfigKeys() const {
-    lock_guard<mutex> lock(mMutex);
-
-    vector<ConfigKey> ret;
-    for (auto uidIt = mConfigs.cbegin(); uidIt != mConfigs.cend(); ++uidIt) {
-        for (auto it = uidIt->second.cbegin(); it != uidIt->second.cend(); ++it) {
-            ret.push_back(*it);
-        }
-    }
-    return ret;
-}
-
-const shared_ptr<IPendingIntentRef> ConfigManager::GetConfigReceiver(const ConfigKey& key) const {
-    lock_guard<mutex> lock(mMutex);
-
-    auto it = mConfigReceivers.find(key);
-    if (it == mConfigReceivers.end()) {
-        return nullptr;
-    } else {
-        return it->second;
-    }
-}
-
-const shared_ptr<IPendingIntentRef> ConfigManager::GetActiveConfigsChangedReceiver(const int uid)
-        const {
-    lock_guard<mutex> lock(mMutex);
-
-    auto it = mActiveConfigsChangedReceivers.find(uid);
-    if (it == mActiveConfigsChangedReceivers.end()) {
-        return nullptr;
-    } else {
-        return it->second;
-    }
-}
-
-void ConfigManager::Dump(FILE* out) {
-    lock_guard<mutex> lock(mMutex);
-
-    fprintf(out, "CONFIGURATIONS\n");
-    fprintf(out, "     uid name\n");
-    for (auto uidIt = mConfigs.cbegin(); uidIt != mConfigs.cend(); ++uidIt) {
-        for (auto it = uidIt->second.cbegin(); it != uidIt->second.cend(); ++it) {
-            fprintf(out, "  %6d %lld\n", it->GetUid(), (long long)it->GetId());
-            auto receiverIt = mConfigReceivers.find(*it);
-            if (receiverIt != mConfigReceivers.end()) {
-                fprintf(out, "    -> received by PendingIntent as binder\n");
-            }
-        }
-    }
-}
-
-void ConfigManager::update_saved_configs_locked(const ConfigKey& key,
-                                                const vector<uint8_t>& buffer,
-                                                const int numBytes) {
-    // If there is a pre-existing config with same key we should first delete it.
-    remove_saved_configs(key);
-
-    // Then we save the latest config.
-    string file_name =
-        StringPrintf("%s/%ld_%d_%lld", STATS_SERVICE_DIR, time(nullptr),
-                     key.GetUid(), (long long)key.GetId());
-    StorageManager::writeFile(file_name.c_str(), &buffer[0], numBytes);
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h
deleted file mode 100644
index bef057f..0000000
--- a/cmds/statsd/src/config/ConfigManager.h
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "config/ConfigKey.h"
-#include "config/ConfigListener.h"
-
-#include <aidl/android/os/IPendingIntentRef.h>
-#include <mutex>
-#include <string>
-
-#include <stdio.h>
-
-using aidl::android::os::IPendingIntentRef;
-using std::shared_ptr;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/**
- * Keeps track of which configurations have been set from various sources.
- */
-class ConfigManager : public virtual android::RefBase {
-public:
-    ConfigManager();
-    virtual ~ConfigManager();
-
-    /**
-     * Initialize ConfigListener by reading from disk and get updates.
-     */
-    void Startup();
-
-    /*
-     * No-op initializer for tests.
-     */
-    void StartupForTest();
-
-    /**
-     * Someone else wants to know about the configs.
-     */
-    void AddListener(const sp<ConfigListener>& listener);
-
-    /**
-     * A configuration was added or updated.
-     *
-     * Reports this to listeners.
-     */
-    void UpdateConfig(const ConfigKey& key, const StatsdConfig& data);
-
-    /**
-     * Sets the broadcast receiver for a configuration key.
-     */
-    void SetConfigReceiver(const ConfigKey& key, const shared_ptr<IPendingIntentRef>& pir);
-
-    /**
-     * Returns the package name and class name representing the broadcast receiver for this config.
-     */
-    const shared_ptr<IPendingIntentRef> GetConfigReceiver(const ConfigKey& key) const;
-
-    /**
-     * Returns all config keys registered.
-     */
-    std::vector<ConfigKey> GetAllConfigKeys() const;
-
-    /**
-     * Erase any broadcast receiver associated with this config key.
-     */
-    void RemoveConfigReceiver(const ConfigKey& key);
-
-    /**
-     * Sets the broadcast receiver that is notified whenever the list of active configs
-     * changes for this uid.
-     */
-    void SetActiveConfigsChangedReceiver(const int uid, const shared_ptr<IPendingIntentRef>& pir);
-
-    /**
-     * Returns the broadcast receiver for active configs changed for this uid.
-     */
-
-    const shared_ptr<IPendingIntentRef> GetActiveConfigsChangedReceiver(const int uid) const;
-
-    /**
-     * Erase any active configs changed broadcast receiver associated with this uid.
-     */
-    void RemoveActiveConfigsChangedReceiver(const int uid);
-
-    /**
-     * A configuration was removed.
-     *
-     * Reports this to listeners.
-     */
-    void RemoveConfig(const ConfigKey& key);
-
-    /**
-     * Remove all of the configs for the given uid.
-     */
-    void RemoveConfigs(int uid);
-
-    /**
-     * Remove all of the configs from memory.
-     */
-    void RemoveAllConfigs();
-
-    /**
-     * Text dump of our state for debugging.
-     */
-    void Dump(FILE* out);
-
-private:
-    mutable std::mutex mMutex;
-
-    /**
-     * Save the configs to disk.
-     */
-    void update_saved_configs_locked(const ConfigKey& key,
-                                     const std::vector<uint8_t>& buffer,
-                                     const int numBytes);
-
-    /**
-     * Remove saved configs from disk.
-     */
-    void remove_saved_configs(const ConfigKey& key);
-
-    /**
-     * Maps from uid to the config keys that have been set.
-     */
-    std::map<int, std::set<ConfigKey>> mConfigs;
-
-    /**
-     * Each config key can be subscribed by up to one receiver, specified as IPendingIntentRef.
-     */
-    std::map<ConfigKey, shared_ptr<IPendingIntentRef>> mConfigReceivers;
-
-    /**
-     * Each uid can be subscribed by up to one receiver to notify that the list of active configs
-     * for this uid has changed. The receiver is specified as IPendingIntentRef.
-     */
-     std::map<int, shared_ptr<IPendingIntentRef>> mActiveConfigsChangedReceivers;
-
-    /**
-     * The ConfigListeners that will be told about changes.
-     */
-    std::vector<sp<ConfigListener>> mListeners;
-
-    // Death recipients that are triggered when the host process holding an
-    // IPendingIntentRef dies.
-    ::ndk::ScopedAIBinder_DeathRecipient mConfigReceiverDeathRecipient;
-    ::ndk::ScopedAIBinder_DeathRecipient mActiveConfigChangedReceiverDeathRecipient;
-
-    /**
-     * Death recipient callback that is called when a config receiver dies.
-     * The cookie is a pointer to a ConfigReceiverDeathCookie.
-     */
-    static void configReceiverDied(void* cookie);
-
-    /**
-     * Death recipient callback that is called when an active config changed
-     * receiver dies. The cookie is a pointer to an
-     * ActiveConfigChangedReceiverDeathCookie.
-     */
-    static void activeConfigChangedReceiverDied(void* cookie);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/experiment_ids.proto b/cmds/statsd/src/experiment_ids.proto
deleted file mode 100644
index c203631..0000000
--- a/cmds/statsd/src/experiment_ids.proto
+++ /dev/null
@@ -1,29 +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.
- */
-
-syntax = "proto2";
-
-package android.os.statsd;
-
-option java_package = "com.android.internal.os";
-option java_outer_classname = "ExperimentIdsProto";
-
-// StatsLogProcessor uses the proto to parse experiment ids from
-// BinaryPushStateChanged atoms. This needs to be in sync with
-// TrainExperimentIds in atoms.proto.
-message ExperimentIds {
-    repeated int64 experiment_id = 1;
-}
diff --git a/cmds/statsd/src/external/Perfetto.cpp b/cmds/statsd/src/external/Perfetto.cpp
deleted file mode 100644
index 85b660e..0000000
--- a/cmds/statsd/src/external/Perfetto.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "config/ConfigKey.h"
-#include "Log.h"
-
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"  // Alert
-
-#include <android-base/unique_fd.h>
-#include <inttypes.h>
-#include <sys/wait.h>
-
-#include <string>
-
-namespace {
-const char kDropboxTag[] = "perfetto";
-}
-
-namespace android {
-namespace os {
-namespace statsd {
-
-bool CollectPerfettoTraceAndUploadToDropbox(const PerfettoDetails& config,
-                                            int64_t subscription_id,
-                                            int64_t alert_id,
-                                            const ConfigKey& configKey) {
-    VLOG("Starting trace collection through perfetto");
-
-    if (!config.has_trace_config()) {
-        ALOGE("The perfetto trace config is empty, aborting");
-        return false;
-    }
-
-    char subscriptionId[25];
-    char alertId[25];
-    char configId[25];
-    char configUid[25];
-    snprintf(subscriptionId, sizeof(subscriptionId), "%" PRId64, subscription_id);
-    snprintf(alertId, sizeof(alertId), "%" PRId64, alert_id);
-    snprintf(configId, sizeof(configId), "%" PRId64, configKey.GetId());
-    snprintf(configUid, sizeof(configUid), "%d", configKey.GetUid());
-
-    android::base::unique_fd readPipe;
-    android::base::unique_fd writePipe;
-    if (!android::base::Pipe(&readPipe, &writePipe)) {
-        ALOGE("pipe() failed while calling the Perfetto client: %s", strerror(errno));
-        return false;
-    }
-
-    pid_t pid = fork();
-    if (pid < 0) {
-        ALOGE("fork() failed while calling the Perfetto client: %s", strerror(errno));
-        return false;
-    }
-
-    if (pid == 0) {
-        // Child process.
-
-        // No malloc calls or library calls after this point. Remember that even
-        // ALOGx (aka android_printLog()) can use dynamic memory for vsprintf().
-
-        writePipe.reset();  // Close the write end (owned by the main process).
-
-        // Replace stdin with |readPipe| so the main process can write into it.
-        if (dup2(readPipe.get(), STDIN_FILENO) < 0) _exit(1);
-        readPipe.reset();
-
-        // Replace stdout/stderr with /dev/null and close any other file
-        // descriptor. This is to avoid SELinux complaining about perfetto
-        // trying to access files accidentally left open by statsd (i.e. files
-        // that have been opened without the O_CLOEXEC flag).
-        int devNullFd = open("/dev/null", O_RDWR | O_CLOEXEC);
-        if (dup2(devNullFd, STDOUT_FILENO) < 0) _exit(2);
-        if (dup2(devNullFd, STDERR_FILENO) < 0) _exit(3);
-        close(devNullFd);
-        for (int i = 0; i < 1024; i++) {
-            if (i != STDIN_FILENO && i != STDOUT_FILENO && i != STDERR_FILENO) close(i);
-        }
-
-        execl("/system/bin/perfetto", "perfetto", "--background", "--config", "-", "--dropbox",
-              kDropboxTag, "--alert-id", alertId, "--config-id", configId, "--config-uid",
-              configUid, "--subscription-id", subscriptionId, nullptr);
-
-        // execl() doesn't return in case of success, if we get here something
-        // failed.
-        _exit(4);
-    }
-
-    // Main process.
-
-    readPipe.reset();  // Close the read end (owned by the child process).
-
-    // Using fdopen() because fwrite() has the right logic to chunking write()
-    // over a pipe (see __sfvwrite()).
-    FILE* writePipeStream = android::base::Fdopen(std::move(writePipe), "wb");
-    if (!writePipeStream) {
-        ALOGE("fdopen() failed while calling the Perfetto client: %s", strerror(errno));
-        return false;
-    }
-
-    const std::string& cfgProto = config.trace_config();
-    size_t bytesWritten = fwrite(cfgProto.data(), 1, cfgProto.size(), writePipeStream);
-    fclose(writePipeStream);
-    if (bytesWritten != cfgProto.size() || cfgProto.size() == 0) {
-        ALOGE("fwrite() failed (ret: %zd) while calling the Perfetto client: %s", bytesWritten,
-              strerror(errno));
-        return false;
-    }
-
-    // This does NOT wait for the full duration of the trace. It just waits until
-    // the process has read the config from stdin and detached.
-    int childStatus = 0;
-    waitpid(pid, &childStatus, 0);
-    if (!WIFEXITED(childStatus) || WEXITSTATUS(childStatus) != 0) {
-        ALOGE("Child process failed (0x%x) while calling the Perfetto client", childStatus);
-        return false;
-    }
-
-    VLOG("CollectPerfettoTraceAndUploadToDropbox() succeeded");
-    return true;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/external/Perfetto.h b/cmds/statsd/src/external/Perfetto.h
deleted file mode 100644
index 095782a..0000000
--- a/cmds/statsd/src/external/Perfetto.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class ConfigKey;
-class PerfettoDetails;  // Declared in statsd_config.pb.h
-
-// Starts the collection of a Perfetto trace with the given |config|.
-// The trace is uploaded to Dropbox by the perfetto cmdline util once done.
-// This method returns immediately after passing the config and does NOT wait
-// for the full duration of the trace.
-bool CollectPerfettoTraceAndUploadToDropbox(const PerfettoDetails& config,
-                                            int64_t subscription_id,
-                                            int64_t alert_id,
-                                            const ConfigKey& configKey);
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/external/PullDataReceiver.h b/cmds/statsd/src/external/PullDataReceiver.h
deleted file mode 100644
index dd5c0cf..0000000
--- a/cmds/statsd/src/external/PullDataReceiver.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <utils/RefBase.h>
-#include "StatsPuller.h"
-#include "logd/LogEvent.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class PullDataReceiver : virtual public RefBase{
- public:
-  virtual ~PullDataReceiver() {}
-  /**
-   * @param data The pulled data.
-   * @param pullSuccess Whether the pull succeeded. If the pull does not succeed, the data for the
-   * bucket should be invalidated.
-   * @param originalPullTimeNs This is when all the pulls have been initiated (elapsed time).
-   */
-  virtual void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data, 
-                            bool pullSuccess, int64_t originalPullTimeNs) = 0;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/external/PullResultReceiver.cpp b/cmds/statsd/src/external/PullResultReceiver.cpp
deleted file mode 100644
index 8aa4792..0000000
--- a/cmds/statsd/src/external/PullResultReceiver.cpp
+++ /dev/null
@@ -1,39 +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.
- */
-
-#include "PullResultReceiver.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-PullResultReceiver::PullResultReceiver(
-        std::function<void(int32_t, bool, const vector<StatsEventParcel>&)> pullFinishCb)
-    : pullFinishCallback(std::move(pullFinishCb)) {
-}
-
-Status PullResultReceiver::pullFinished(int32_t atomTag, bool success,
-                                        const vector<StatsEventParcel>& output) {
-    pullFinishCallback(atomTag, success, output);
-    return Status::ok();
-}
-
-PullResultReceiver::~PullResultReceiver() {
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/external/PullResultReceiver.h b/cmds/statsd/src/external/PullResultReceiver.h
deleted file mode 100644
index ceaae80..0000000
--- a/cmds/statsd/src/external/PullResultReceiver.h
+++ /dev/null
@@ -1,48 +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.
- */
-
-#include <aidl/android/os/BnPullAtomResultReceiver.h>
-#include <aidl/android/util/StatsEventParcel.h>
-
-using namespace std;
-
-using Status = ::ndk::ScopedAStatus;
-using aidl::android::os::BnPullAtomResultReceiver;
-using aidl::android::util::StatsEventParcel;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class PullResultReceiver : public BnPullAtomResultReceiver {
-public:
-    PullResultReceiver(function<void(int32_t, bool, const vector<StatsEventParcel>&)>
-                               pullFinishCallback);
-    ~PullResultReceiver();
-
-    /**
-     * Binder call for finishing a pull.
-     */
-    Status pullFinished(int32_t atomTag, bool success,
-                        const vector<StatsEventParcel>& output) override;
-
-private:
-    function<void(int32_t, bool, const vector<StatsEventParcel>&)> pullFinishCallback;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/external/PullUidProvider.h b/cmds/statsd/src/external/PullUidProvider.h
deleted file mode 100644
index 2318c50..0000000
--- a/cmds/statsd/src/external/PullUidProvider.h
+++ /dev/null
@@ -1,39 +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.
- */
-#pragma once
-
-#include <utils/RefBase.h>
-
-#include "StatsPuller.h"
-#include "logd/LogEvent.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class PullUidProvider : virtual public RefBase {
-public:
-    virtual ~PullUidProvider() {}
-
-    /**
-     * @param atomId The atom for which to get the uids.
-     */
-    virtual vector<int32_t> getPullAtomUids(int32_t atomId) = 0;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/external/StatsCallbackPuller.cpp b/cmds/statsd/src/external/StatsCallbackPuller.cpp
deleted file mode 100644
index 78e6f09..0000000
--- a/cmds/statsd/src/external/StatsCallbackPuller.cpp
+++ /dev/null
@@ -1,116 +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.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "StatsCallbackPuller.h"
-#include "PullResultReceiver.h"
-#include "StatsPullerManager.h"
-#include "logd/LogEvent.h"
-#include "stats_log_util.h"
-
-#include <aidl/android/util/StatsEventParcel.h>
-
-using namespace std;
-
-using Status = ::ndk::ScopedAStatus;
-using aidl::android::util::StatsEventParcel;
-using ::ndk::SharedRefBase;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-StatsCallbackPuller::StatsCallbackPuller(int tagId, const shared_ptr<IPullAtomCallback>& callback,
-                                         const int64_t coolDownNs, int64_t timeoutNs,
-                                         const vector<int> additiveFields)
-    : StatsPuller(tagId, coolDownNs, timeoutNs, additiveFields), mCallback(callback) {
-    VLOG("StatsCallbackPuller created for tag %d", tagId);
-}
-
-bool StatsCallbackPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
-    VLOG("StatsCallbackPuller called for tag %d", mTagId);
-    if(mCallback == nullptr) {
-        ALOGW("No callback registered");
-        return false;
-    }
-
-    // Shared variables needed in the result receiver.
-    shared_ptr<mutex> cv_mutex = make_shared<mutex>();
-    shared_ptr<condition_variable> cv = make_shared<condition_variable>();
-    shared_ptr<bool> pullFinish = make_shared<bool>(false);
-    shared_ptr<bool> pullSuccess = make_shared<bool>(false);
-    shared_ptr<vector<shared_ptr<LogEvent>>> sharedData =
-            make_shared<vector<shared_ptr<LogEvent>>>();
-
-    shared_ptr<PullResultReceiver> resultReceiver = SharedRefBase::make<PullResultReceiver>(
-            [cv_mutex, cv, pullFinish, pullSuccess, sharedData](
-                    int32_t atomTag, bool success, const vector<StatsEventParcel>& output) {
-                // This is the result of the pull, executing in a statsd binder thread.
-                // The pull could have taken a long time, and we should only modify
-                // data (the output param) if the pointer is in scope and the pull did not time out.
-                {
-                    lock_guard<mutex> lk(*cv_mutex);
-                    for (const StatsEventParcel& parcel: output) {
-                        shared_ptr<LogEvent> event = make_shared<LogEvent>(/*uid=*/-1, /*pid=*/-1);
-                        bool valid = event->parseBuffer((uint8_t*)parcel.buffer.data(),
-                                                        parcel.buffer.size());
-                        if (valid) {
-                            sharedData->push_back(event);
-                        } else {
-                            StatsdStats::getInstance().noteAtomError(event->GetTagId(),
-                                                                     /*pull=*/true);
-                        }
-                    }
-                    *pullSuccess = success;
-                    *pullFinish = true;
-                }
-                cv->notify_one();
-            });
-
-    // Initiate the pull. This is a oneway call to a different process, except
-    // in unit tests. In process calls are not oneway.
-    Status status = mCallback->onPullAtom(mTagId, resultReceiver);
-    if (!status.isOk()) {
-        StatsdStats::getInstance().notePullBinderCallFailed(mTagId);
-        return false;
-    }
-
-    {
-        unique_lock<mutex> unique_lk(*cv_mutex);
-        // Wait until the pull finishes, or until the pull timeout.
-        cv->wait_for(unique_lk, chrono::nanoseconds(mPullTimeoutNs),
-                     [pullFinish] { return *pullFinish; });
-        if (!*pullFinish) {
-            // Note: The parent stats puller will also note that there was a timeout and that the
-            // cache should be cleared. Once we migrate all pullers to this callback, we could
-            // consolidate the logic.
-            return true;
-        } else {
-            // Only copy the data if we did not timeout and the pull was successful.
-            if (*pullSuccess) {
-                *data = std::move(*sharedData);
-            }
-            VLOG("StatsCallbackPuller::pull succeeded for %d", mTagId);
-            return *pullSuccess;
-        }
-    }
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/external/StatsCallbackPuller.h b/cmds/statsd/src/external/StatsCallbackPuller.h
deleted file mode 100644
index e82e8bb..0000000
--- a/cmds/statsd/src/external/StatsCallbackPuller.h
+++ /dev/null
@@ -1,46 +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.
- */
-
-#pragma once
-
-#include <aidl/android/os/IPullAtomCallback.h>
-#include "StatsPuller.h"
-
-using aidl::android::os::IPullAtomCallback;
-using std::shared_ptr;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class StatsCallbackPuller : public StatsPuller {
-public:
-    explicit StatsCallbackPuller(int tagId, const shared_ptr<IPullAtomCallback>& callback,
-                                 const int64_t coolDownNs, const int64_t timeoutNs,
-                                 const std::vector<int> additiveFields);
-
-private:
-    bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
-    const shared_ptr<IPullAtomCallback> mCallback;
-
-    FRIEND_TEST(StatsCallbackPullerTest, PullFail);
-    FRIEND_TEST(StatsCallbackPullerTest, PullSuccess);
-    FRIEND_TEST(StatsCallbackPullerTest, PullTimeout);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/external/StatsPuller.cpp b/cmds/statsd/src/external/StatsPuller.cpp
deleted file mode 100644
index bb5d0a6..0000000
--- a/cmds/statsd/src/external/StatsPuller.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "StatsPuller.h"
-#include "StatsPullerManager.h"
-#include "guardrail/StatsdStats.h"
-#include "puller_util.h"
-#include "stats_log_util.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using std::lock_guard;
-
-sp<UidMap> StatsPuller::mUidMap = nullptr;
-void StatsPuller::SetUidMap(const sp<UidMap>& uidMap) { mUidMap = uidMap; }
-
-StatsPuller::StatsPuller(const int tagId, const int64_t coolDownNs, const int64_t pullTimeoutNs,
-                         const std::vector<int> additiveFields)
-    : mTagId(tagId),
-      mPullTimeoutNs(pullTimeoutNs),
-      mCoolDownNs(coolDownNs),
-      mAdditiveFields(additiveFields),
-      mLastPullTimeNs(0),
-      mLastEventTimeNs(0) {
-}
-
-bool StatsPuller::Pull(const int64_t eventTimeNs, std::vector<std::shared_ptr<LogEvent>>* data) {
-    lock_guard<std::mutex> lock(mLock);
-    const int64_t elapsedTimeNs = getElapsedRealtimeNs();
-    const int64_t systemUptimeMillis = getSystemUptimeMillis();
-    StatsdStats::getInstance().notePull(mTagId);
-    const bool shouldUseCache =
-            (mLastEventTimeNs == eventTimeNs) || (elapsedTimeNs - mLastPullTimeNs < mCoolDownNs);
-    if (shouldUseCache) {
-        if (mHasGoodData) {
-            (*data) = mCachedData;
-            StatsdStats::getInstance().notePullFromCache(mTagId);
-
-        }
-        return mHasGoodData;
-    }
-    if (mLastPullTimeNs > 0) {
-        StatsdStats::getInstance().updateMinPullIntervalSec(
-                mTagId, (elapsedTimeNs - mLastPullTimeNs) / NS_PER_SEC);
-    }
-    mCachedData.clear();
-    mLastPullTimeNs = elapsedTimeNs;
-    mLastEventTimeNs = eventTimeNs;
-    mHasGoodData = PullInternal(&mCachedData);
-    if (!mHasGoodData) {
-        return mHasGoodData;
-    }
-    const int64_t pullElapsedDurationNs = getElapsedRealtimeNs() - elapsedTimeNs;
-    const int64_t pullSystemUptimeDurationMillis = getSystemUptimeMillis() - systemUptimeMillis;
-    StatsdStats::getInstance().notePullTime(mTagId, pullElapsedDurationNs);
-    const bool pullTimeOut = pullElapsedDurationNs > mPullTimeoutNs;
-    if (pullTimeOut) {
-        // Something went wrong. Discard the data.
-        mCachedData.clear();
-        mHasGoodData = false;
-        StatsdStats::getInstance().notePullTimeout(
-                mTagId, pullSystemUptimeDurationMillis, NanoToMillis(pullElapsedDurationNs));
-        ALOGW("Pull for atom %d exceeds timeout %lld nano seconds.", mTagId,
-              (long long)pullElapsedDurationNs);
-        return mHasGoodData;
-    }
-
-    if (mCachedData.size() > 0) {
-        mapAndMergeIsolatedUidsToHostUid(mCachedData, mUidMap, mTagId, mAdditiveFields);
-    }
-
-    if (mCachedData.empty()) {
-        VLOG("Data pulled is empty");
-        StatsdStats::getInstance().noteEmptyData(mTagId);
-    }
-
-    (*data) = mCachedData;
-    return mHasGoodData;
-}
-
-int StatsPuller::ForceClearCache() {
-    return clearCache();
-}
-
-int StatsPuller::clearCache() {
-    lock_guard<std::mutex> lock(mLock);
-    return clearCacheLocked();
-}
-
-int StatsPuller::clearCacheLocked() {
-    int ret = mCachedData.size();
-    mCachedData.clear();
-    mLastPullTimeNs = 0;
-    mLastEventTimeNs = 0;
-    return ret;
-}
-
-int StatsPuller::ClearCacheIfNecessary(int64_t timestampNs) {
-    if (timestampNs - mLastPullTimeNs > mCoolDownNs) {
-        return clearCache();
-    } else {
-        return 0;
-    }
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/external/StatsPuller.h b/cmds/statsd/src/external/StatsPuller.h
deleted file mode 100644
index 470d15e..0000000
--- a/cmds/statsd/src/external/StatsPuller.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <aidl/android/os/IStatsCompanionService.h>
-#include <utils/RefBase.h>
-#include <mutex>
-#include <vector>
-#include "packages/UidMap.h"
-
-#include "guardrail/StatsdStats.h"
-#include "logd/LogEvent.h"
-#include "puller_util.h"
-
-using aidl::android::os::IStatsCompanionService;
-using std::shared_ptr;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class StatsPuller : public virtual RefBase {
-public:
-    explicit StatsPuller(const int tagId,
-                         const int64_t coolDownNs = NS_PER_SEC,
-                         const int64_t pullTimeoutNs = StatsdStats::kPullMaxDelayNs,
-                         const std::vector<int> additiveFields = std::vector<int>());
-
-    virtual ~StatsPuller() {}
-
-    // Pulls the most recent data.
-    // The data may be served from cache if consecutive pulls come within
-    // predefined cooldown time.
-    // Returns true if the pull was successful.
-    // Returns false when
-    //   1) the pull fails
-    //   2) pull takes longer than mPullTimeoutNs (intrinsic to puller)
-    // If a metric wants to make any change to the data, like timestamps, it
-    // should make a copy as this data may be shared with multiple metrics.
-    bool Pull(const int64_t eventTimeNs, std::vector<std::shared_ptr<LogEvent>>* data);
-
-    // Clear cache immediately
-    int ForceClearCache();
-
-    // Clear cache if elapsed time is more than cooldown time
-    int ClearCacheIfNecessary(int64_t timestampNs);
-
-    static void SetUidMap(const sp<UidMap>& uidMap);
-
-    virtual void SetStatsCompanionService(
-            shared_ptr<IStatsCompanionService> statsCompanionService) {};
-
-protected:
-    const int mTagId;
-
-    // Max time allowed to pull this atom.
-    // We cannot reliably kill a pull thread. So we don't terminate the puller.
-    // The data is discarded if the pull takes longer than this and mHasGoodData
-    // marked as false.
-    const int64_t mPullTimeoutNs = StatsdStats::kPullMaxDelayNs;
-
-private:
-    mutable std::mutex mLock;
-
-    // Real puller impl.
-    virtual bool PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) = 0;
-
-    bool mHasGoodData = false;
-
-    // Minimum time before this puller does actual pull again.
-    // Pullers can cause significant impact to system health and battery.
-    // So that we don't pull too frequently.
-    // If a pull request comes before cooldown, a cached version from previous pull
-    // will be returned.
-    const int64_t mCoolDownNs = 1 * NS_PER_SEC;
-
-    // The field numbers of the fields that need to be summed when merging
-    // isolated uid with host uid.
-    const std::vector<int> mAdditiveFields;
-
-    int64_t mLastPullTimeNs;
-
-    // All pulls happen due to an event (app upgrade, bucket boundary, condition change, etc).
-    // If multiple pulls need to be done at the same event time, we will always use the cache after
-    // the first pull.
-    int64_t mLastEventTimeNs;
-
-    // Cache of data from last pull. If next request comes before cool down finishes,
-    // cached data will be returned.
-    // Cached data is cleared when
-    //   1) A pull fails
-    //   2) A new pull request comes after cooldown time.
-    //   3) clearCache is called.
-    std::vector<std::shared_ptr<LogEvent>> mCachedData;
-
-    int clearCache();
-
-    int clearCacheLocked();
-
-    static sp<UidMap> mUidMap;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
deleted file mode 100644
index 8334b6b..0000000
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ /dev/null
@@ -1,371 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false
-#include "Log.h"
-
-#include "StatsPullerManager.h"
-
-#include <cutils/log.h>
-#include <math.h>
-#include <stdint.h>
-
-#include <algorithm>
-#include <iostream>
-
-#include "../StatsService.h"
-#include "../logd/LogEvent.h"
-#include "../stats_log_util.h"
-#include "../statscompanion_util.h"
-#include "StatsCallbackPuller.h"
-#include "TrainInfoPuller.h"
-#include "statslog_statsd.h"
-
-using std::shared_ptr;
-using std::vector;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// Stores the puller as a wp to avoid holding a reference in case it is unregistered and
-// pullAtomCallbackDied is never called.
-struct PullAtomCallbackDeathCookie {
-    PullAtomCallbackDeathCookie(const wp<StatsPullerManager>& pullerManager,
-                                const PullerKey& pullerKey, const wp<StatsPuller>& puller) :
-            mPullerManager(pullerManager), mPullerKey(pullerKey), mPuller(puller) {
-    }
-
-    wp<StatsPullerManager> mPullerManager;
-    PullerKey mPullerKey;
-    wp<StatsPuller> mPuller;
-};
-
-void StatsPullerManager::pullAtomCallbackDied(void* cookie) {
-    PullAtomCallbackDeathCookie* cookie_ = static_cast<PullAtomCallbackDeathCookie*>(cookie);
-    sp<StatsPullerManager> thiz = cookie_->mPullerManager.promote();
-    if (!thiz) {
-        return;
-    }
-
-    const PullerKey& pullerKey = cookie_->mPullerKey;
-    wp<StatsPuller> puller = cookie_->mPuller;
-
-    // Erase the mapping from the puller key to the puller if the mapping still exists.
-    // Note that we are removing the StatsPuller object, which internally holds the binder
-    // IPullAtomCallback. However, each new registration creates a new StatsPuller, so this works.
-    lock_guard<mutex> lock(thiz->mLock);
-    const auto& it = thiz->kAllPullAtomInfo.find(pullerKey);
-    if (it != thiz->kAllPullAtomInfo.end() && puller != nullptr && puller == it->second) {
-        StatsdStats::getInstance().notePullerCallbackRegistrationChanged(pullerKey.atomTag,
-                                                                         /*registered=*/false);
-        thiz->kAllPullAtomInfo.erase(pullerKey);
-    }
-    // The death recipient corresponding to this specific IPullAtomCallback can never
-    // be triggered again, so free up resources.
-    delete cookie_;
-}
-
-// Values smaller than this may require to update the alarm.
-const int64_t NO_ALARM_UPDATE = INT64_MAX;
-
-StatsPullerManager::StatsPullerManager()
-    : kAllPullAtomInfo({
-              // TrainInfo.
-              {{.atomTag = util::TRAIN_INFO, .uid = AID_STATSD}, new TrainInfoPuller()},
-      }),
-      mNextPullTimeNs(NO_ALARM_UPDATE),
-      mPullAtomCallbackDeathRecipient(AIBinder_DeathRecipient_new(pullAtomCallbackDied)) {
-}
-
-bool StatsPullerManager::Pull(int tagId, const ConfigKey& configKey, const int64_t eventTimeNs,
-                              vector<shared_ptr<LogEvent>>* data) {
-    std::lock_guard<std::mutex> _l(mLock);
-    return PullLocked(tagId, configKey, eventTimeNs, data);
-}
-
-bool StatsPullerManager::Pull(int tagId, const vector<int32_t>& uids, const int64_t eventTimeNs,
-                              vector<std::shared_ptr<LogEvent>>* data) {
-    std::lock_guard<std::mutex> _l(mLock);
-    return PullLocked(tagId, uids, eventTimeNs, data);
-}
-
-bool StatsPullerManager::PullLocked(int tagId, const ConfigKey& configKey,
-                                    const int64_t eventTimeNs, vector<shared_ptr<LogEvent>>* data) {
-    vector<int32_t> uids;
-    const auto& uidProviderIt = mPullUidProviders.find(configKey);
-    if (uidProviderIt == mPullUidProviders.end()) {
-        ALOGE("Error pulling tag %d. No pull uid provider for config key %s", tagId,
-              configKey.ToString().c_str());
-        StatsdStats::getInstance().notePullUidProviderNotFound(tagId);
-        return false;
-    }
-    sp<PullUidProvider> pullUidProvider = uidProviderIt->second.promote();
-    if (pullUidProvider == nullptr) {
-        ALOGE("Error pulling tag %d, pull uid provider for config %s is gone.", tagId,
-              configKey.ToString().c_str());
-        StatsdStats::getInstance().notePullUidProviderNotFound(tagId);
-        return false;
-    }
-    uids = pullUidProvider->getPullAtomUids(tagId);
-    return PullLocked(tagId, uids, eventTimeNs, data);
-}
-
-bool StatsPullerManager::PullLocked(int tagId, const vector<int32_t>& uids,
-                                    const int64_t eventTimeNs, vector<shared_ptr<LogEvent>>* data) {
-    VLOG("Initiating pulling %d", tagId);
-    for (int32_t uid : uids) {
-        PullerKey key = {.atomTag = tagId, .uid = uid};
-        auto pullerIt = kAllPullAtomInfo.find(key);
-        if (pullerIt != kAllPullAtomInfo.end()) {
-            bool ret = pullerIt->second->Pull(eventTimeNs, data);
-            VLOG("pulled %zu items", data->size());
-            if (!ret) {
-                StatsdStats::getInstance().notePullFailed(tagId);
-            }
-            return ret;
-        }
-    }
-    StatsdStats::getInstance().notePullerNotFound(tagId);
-    ALOGW("StatsPullerManager: Unknown tagId %d", tagId);
-    return false;  // Return early since we don't know what to pull.
-}
-
-bool StatsPullerManager::PullerForMatcherExists(int tagId) const {
-    // Pulled atoms might be registered after we parse the config, so just make sure the id is in
-    // an appropriate range.
-    return isVendorPulledAtom(tagId) || isPulledAtom(tagId);
-}
-
-void StatsPullerManager::updateAlarmLocked() {
-    if (mNextPullTimeNs == NO_ALARM_UPDATE) {
-        VLOG("No need to set alarms. Skipping");
-        return;
-    }
-
-    // TODO(b/151045771): do not hold a lock while making a binder call
-    if (mStatsCompanionService != nullptr) {
-        mStatsCompanionService->setPullingAlarm(mNextPullTimeNs / 1000000);
-    } else {
-        VLOG("StatsCompanionService not available. Alarm not set.");
-    }
-    return;
-}
-
-void StatsPullerManager::SetStatsCompanionService(
-        shared_ptr<IStatsCompanionService> statsCompanionService) {
-    std::lock_guard<std::mutex> _l(mLock);
-    shared_ptr<IStatsCompanionService> tmpForLock = mStatsCompanionService;
-    mStatsCompanionService = statsCompanionService;
-    for (const auto& pulledAtom : kAllPullAtomInfo) {
-        pulledAtom.second->SetStatsCompanionService(statsCompanionService);
-    }
-    if (mStatsCompanionService != nullptr) {
-        updateAlarmLocked();
-    }
-}
-
-void StatsPullerManager::RegisterReceiver(int tagId, const ConfigKey& configKey,
-                                          wp<PullDataReceiver> receiver, int64_t nextPullTimeNs,
-                                          int64_t intervalNs) {
-    std::lock_guard<std::mutex> _l(mLock);
-    auto& receivers = mReceivers[{.atomTag = tagId, .configKey = configKey}];
-    for (auto it = receivers.begin(); it != receivers.end(); it++) {
-        if (it->receiver == receiver) {
-            VLOG("Receiver already registered of %d", (int)receivers.size());
-            return;
-        }
-    }
-    ReceiverInfo receiverInfo;
-    receiverInfo.receiver = receiver;
-
-    // Round it to the nearest minutes. This is the limit of alarm manager.
-    // In practice, we should always have larger buckets.
-    int64_t roundedIntervalNs = intervalNs / NS_PER_SEC / 60 * NS_PER_SEC * 60;
-    // Scheduled pulling should be at least 1 min apart.
-    // This can be lower in cts tests, in which case we round it to 1 min.
-    if (roundedIntervalNs < 60 * (int64_t)NS_PER_SEC) {
-        roundedIntervalNs = 60 * (int64_t)NS_PER_SEC;
-    }
-
-    receiverInfo.intervalNs = roundedIntervalNs;
-    receiverInfo.nextPullTimeNs = nextPullTimeNs;
-    receivers.push_back(receiverInfo);
-
-    // There is only one alarm for all pulled events. So only set it to the smallest denom.
-    if (nextPullTimeNs < mNextPullTimeNs) {
-        VLOG("Updating next pull time %lld", (long long)mNextPullTimeNs);
-        mNextPullTimeNs = nextPullTimeNs;
-        updateAlarmLocked();
-    }
-    VLOG("Puller for tagId %d registered of %d", tagId, (int)receivers.size());
-}
-
-void StatsPullerManager::UnRegisterReceiver(int tagId, const ConfigKey& configKey,
-                                            wp<PullDataReceiver> receiver) {
-    std::lock_guard<std::mutex> _l(mLock);
-    auto receiversIt = mReceivers.find({.atomTag = tagId, .configKey = configKey});
-    if (receiversIt == mReceivers.end()) {
-        VLOG("Unknown pull code or no receivers: %d", tagId);
-        return;
-    }
-    std::list<ReceiverInfo>& receivers = receiversIt->second;
-    for (auto it = receivers.begin(); it != receivers.end(); it++) {
-        if (receiver == it->receiver) {
-            receivers.erase(it);
-            VLOG("Puller for tagId %d unregistered of %d", tagId, (int)receivers.size());
-            return;
-        }
-    }
-}
-
-void StatsPullerManager::RegisterPullUidProvider(const ConfigKey& configKey,
-                                                 wp<PullUidProvider> provider) {
-    std::lock_guard<std::mutex> _l(mLock);
-    mPullUidProviders[configKey] = provider;
-}
-
-void StatsPullerManager::UnregisterPullUidProvider(const ConfigKey& configKey,
-                                                   wp<PullUidProvider> provider) {
-    std::lock_guard<std::mutex> _l(mLock);
-    const auto& it = mPullUidProviders.find(configKey);
-    if (it != mPullUidProviders.end() && it->second == provider) {
-        mPullUidProviders.erase(it);
-    }
-}
-
-void StatsPullerManager::OnAlarmFired(int64_t elapsedTimeNs) {
-    std::lock_guard<std::mutex> _l(mLock);
-    int64_t wallClockNs = getWallClockNs();
-
-    int64_t minNextPullTimeNs = NO_ALARM_UPDATE;
-
-    vector<pair<const ReceiverKey*, vector<ReceiverInfo*>>> needToPull;
-    for (auto& pair : mReceivers) {
-        vector<ReceiverInfo*> receivers;
-        if (pair.second.size() != 0) {
-            for (ReceiverInfo& receiverInfo : pair.second) {
-                if (receiverInfo.nextPullTimeNs <= elapsedTimeNs) {
-                    receivers.push_back(&receiverInfo);
-                } else {
-                    if (receiverInfo.nextPullTimeNs < minNextPullTimeNs) {
-                        minNextPullTimeNs = receiverInfo.nextPullTimeNs;
-                    }
-                }
-            }
-            if (receivers.size() > 0) {
-                needToPull.push_back(make_pair(&pair.first, receivers));
-            }
-        }
-    }
-    for (const auto& pullInfo : needToPull) {
-        vector<shared_ptr<LogEvent>> data;
-        bool pullSuccess = PullLocked(pullInfo.first->atomTag, pullInfo.first->configKey,
-                                      elapsedTimeNs, &data);
-        if (!pullSuccess) {
-            VLOG("pull failed at %lld, will try again later", (long long)elapsedTimeNs);
-        }
-
-        // Convention is to mark pull atom timestamp at request time.
-        // If we pull at t0, puller starts at t1, finishes at t2, and send back
-        // at t3, we mark t0 as its timestamp, which should correspond to its
-        // triggering event, such as condition change at t0.
-        // Here the triggering event is alarm fired from AlarmManager.
-        // In ValueMetricProducer and GaugeMetricProducer we do same thing
-        // when pull on condition change, etc.
-        for (auto& event : data) {
-            event->setElapsedTimestampNs(elapsedTimeNs);
-            event->setLogdWallClockTimestampNs(wallClockNs);
-        }
-
-        for (const auto& receiverInfo : pullInfo.second) {
-            sp<PullDataReceiver> receiverPtr = receiverInfo->receiver.promote();
-            if (receiverPtr != nullptr) {
-                receiverPtr->onDataPulled(data, pullSuccess, elapsedTimeNs);
-                // We may have just come out of a coma, compute next pull time.
-                int numBucketsAhead =
-                        (elapsedTimeNs - receiverInfo->nextPullTimeNs) / receiverInfo->intervalNs;
-                receiverInfo->nextPullTimeNs += (numBucketsAhead + 1) * receiverInfo->intervalNs;
-                if (receiverInfo->nextPullTimeNs < minNextPullTimeNs) {
-                    minNextPullTimeNs = receiverInfo->nextPullTimeNs;
-                }
-            } else {
-                VLOG("receiver already gone.");
-            }
-        }
-    }
-
-    VLOG("mNextPullTimeNs: %lld updated to %lld", (long long)mNextPullTimeNs,
-         (long long)minNextPullTimeNs);
-    mNextPullTimeNs = minNextPullTimeNs;
-    updateAlarmLocked();
-}
-
-int StatsPullerManager::ForceClearPullerCache() {
-    std::lock_guard<std::mutex> _l(mLock);
-    int totalCleared = 0;
-    for (const auto& pulledAtom : kAllPullAtomInfo) {
-        totalCleared += pulledAtom.second->ForceClearCache();
-    }
-    return totalCleared;
-}
-
-int StatsPullerManager::ClearPullerCacheIfNecessary(int64_t timestampNs) {
-    std::lock_guard<std::mutex> _l(mLock);
-    int totalCleared = 0;
-    for (const auto& pulledAtom : kAllPullAtomInfo) {
-        totalCleared += pulledAtom.second->ClearCacheIfNecessary(timestampNs);
-    }
-    return totalCleared;
-}
-
-void StatsPullerManager::RegisterPullAtomCallback(const int uid, const int32_t atomTag,
-                                                  const int64_t coolDownNs, const int64_t timeoutNs,
-                                                  const vector<int32_t>& additiveFields,
-                                                  const shared_ptr<IPullAtomCallback>& callback) {
-    std::lock_guard<std::mutex> _l(mLock);
-    VLOG("RegisterPullerCallback: adding puller for tag %d", atomTag);
-
-    if (callback == nullptr) {
-        ALOGW("SetPullAtomCallback called with null callback for atom %d.", atomTag);
-        return;
-    }
-
-    StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/true);
-    int64_t actualCoolDownNs = coolDownNs < kMinCoolDownNs ? kMinCoolDownNs : coolDownNs;
-    int64_t actualTimeoutNs = timeoutNs > kMaxTimeoutNs ? kMaxTimeoutNs : timeoutNs;
-
-    sp<StatsCallbackPuller> puller = new StatsCallbackPuller(atomTag, callback, actualCoolDownNs,
-                                                             actualTimeoutNs, additiveFields);
-    PullerKey key = {.atomTag = atomTag, .uid = uid};
-    AIBinder_linkToDeath(callback->asBinder().get(), mPullAtomCallbackDeathRecipient.get(),
-                         new PullAtomCallbackDeathCookie(this, key, puller));
-    kAllPullAtomInfo[key] = puller;
-}
-
-void StatsPullerManager::UnregisterPullAtomCallback(const int uid, const int32_t atomTag) {
-    std::lock_guard<std::mutex> _l(mLock);
-    PullerKey key = {.atomTag = atomTag, .uid = uid};
-    if (kAllPullAtomInfo.find(key) != kAllPullAtomInfo.end()) {
-        StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag,
-                                                                         /*registered=*/false);
-        kAllPullAtomInfo.erase(key);
-    }
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h
deleted file mode 100644
index 489cbdb..0000000
--- a/cmds/statsd/src/external/StatsPullerManager.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <aidl/android/os/IPullAtomCallback.h>
-#include <aidl/android/os/IStatsCompanionService.h>
-#include <utils/RefBase.h>
-
-#include <list>
-#include <vector>
-
-#include "PullDataReceiver.h"
-#include "PullUidProvider.h"
-#include "StatsPuller.h"
-#include "guardrail/StatsdStats.h"
-#include "logd/LogEvent.h"
-#include "packages/UidMap.h"
-
-using aidl::android::os::IPullAtomCallback;
-using aidl::android::os::IStatsCompanionService;
-using std::shared_ptr;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-typedef struct PullerKey {
-    // The uid of the process that registers this puller.
-    const int uid = -1;
-    // The atom that this puller is for.
-    const int atomTag;
-
-    bool operator<(const PullerKey& that) const {
-        if (uid < that.uid) {
-            return true;
-        }
-        if (uid > that.uid) {
-            return false;
-        }
-        return atomTag < that.atomTag;
-    };
-
-    bool operator==(const PullerKey& that) const {
-        return uid == that.uid && atomTag == that.atomTag;
-    };
-} PullerKey;
-
-class StatsPullerManager : public virtual RefBase {
-public:
-    StatsPullerManager();
-
-    virtual ~StatsPullerManager() {
-    }
-
-
-    // Registers a receiver for tagId. It will be pulled on the nextPullTimeNs
-    // and then every intervalNs thereafter.
-    virtual void RegisterReceiver(int tagId, const ConfigKey& configKey,
-                                  wp<PullDataReceiver> receiver, int64_t nextPullTimeNs,
-                                  int64_t intervalNs);
-
-    // Stop listening on a tagId.
-    virtual void UnRegisterReceiver(int tagId, const ConfigKey& configKey,
-                                    wp<PullDataReceiver> receiver);
-
-    // Registers a pull uid provider for the config key. When pulling atoms, it will be used to
-    // determine which uids to pull from.
-    virtual void RegisterPullUidProvider(const ConfigKey& configKey, wp<PullUidProvider> provider);
-
-    // Unregister a pull uid provider.
-    virtual void UnregisterPullUidProvider(const ConfigKey& configKey,
-                                           wp<PullUidProvider> provider);
-
-    // Verify if we know how to pull for this matcher
-    bool PullerForMatcherExists(int tagId) const;
-
-    void OnAlarmFired(int64_t elapsedTimeNs);
-
-    // Pulls the most recent data.
-    // The data may be served from cache if consecutive pulls come within
-    // mCoolDownNs.
-    // Returns true if the pull was successful.
-    // Returns false when
-    //   1) the pull fails
-    //   2) pull takes longer than mPullTimeoutNs (intrinsic to puller)
-    //   3) Either a PullUidProvider was not registered for the config, or the there was no puller
-    //      registered for any of the uids for this atom.
-    // If the metric wants to make any change to the data, like timestamps, they
-    // should make a copy as this data may be shared with multiple metrics.
-    virtual bool Pull(int tagId, const ConfigKey& configKey, const int64_t eventTimeNs,
-                      vector<std::shared_ptr<LogEvent>>* data);
-
-    // Same as above, but directly specify the allowed uids to pull from.
-    virtual bool Pull(int tagId, const vector<int32_t>& uids, const int64_t eventTimeNs,
-                      vector<std::shared_ptr<LogEvent>>* data);
-
-    // Clear pull data cache immediately.
-    int ForceClearPullerCache();
-
-    // Clear pull data cache if it is beyond respective cool down time.
-    int ClearPullerCacheIfNecessary(int64_t timestampNs);
-
-    void SetStatsCompanionService(shared_ptr<IStatsCompanionService> statsCompanionService);
-
-    void RegisterPullAtomCallback(const int uid, const int32_t atomTag, const int64_t coolDownNs,
-                                  const int64_t timeoutNs, const vector<int32_t>& additiveFields,
-                                  const shared_ptr<IPullAtomCallback>& callback);
-
-    void UnregisterPullAtomCallback(const int uid, const int32_t atomTag);
-
-    std::map<const PullerKey, sp<StatsPuller>> kAllPullAtomInfo;
-
-private:
-    const static int64_t kMinCoolDownNs = NS_PER_SEC;
-    const static int64_t kMaxTimeoutNs = 10 * NS_PER_SEC;
-    shared_ptr<IStatsCompanionService> mStatsCompanionService = nullptr;
-
-    // A struct containing an atom id and a Config Key
-    typedef struct ReceiverKey {
-        const int atomTag;
-        const ConfigKey configKey;
-
-        inline bool operator<(const ReceiverKey& that) const {
-            return atomTag == that.atomTag ? configKey < that.configKey : atomTag < that.atomTag;
-        }
-    } ReceiverKey;
-
-    typedef struct {
-        int64_t nextPullTimeNs;
-        int64_t intervalNs;
-        wp<PullDataReceiver> receiver;
-    } ReceiverInfo;
-
-    // mapping from Receiver Key to receivers
-    std::map<ReceiverKey, std::list<ReceiverInfo>> mReceivers;
-
-    // mapping from Config Key to the PullUidProvider for that config
-    std::map<ConfigKey, wp<PullUidProvider>> mPullUidProviders;
-
-    bool PullLocked(int tagId, const ConfigKey& configKey, const int64_t eventTimeNs,
-                    vector<std::shared_ptr<LogEvent>>* data);
-
-    bool PullLocked(int tagId, const vector<int32_t>& uids, const int64_t eventTimeNs,
-                    vector<std::shared_ptr<LogEvent>>* data);
-
-    // locks for data receiver and StatsCompanionService changes
-    std::mutex mLock;
-
-    void updateAlarmLocked();
-
-    int64_t mNextPullTimeNs;
-
-    // Death recipient that is triggered when the process holding the IPullAtomCallback has died.
-    ::ndk::ScopedAIBinder_DeathRecipient mPullAtomCallbackDeathRecipient;
-
-    /**
-     * Death recipient callback that is called when a pull atom callback dies.
-     * The cookie is a pointer to a PullAtomCallbackDeathCookie.
-     */
-    static void pullAtomCallbackDied(void* cookie);
-
-    FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents);
-    FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm);
-    FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsWithActivation);
-    FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsNoCondition);
-    FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents);
-    FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm);
-    FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation);
-
-    FRIEND_TEST(StatsLogProcessorTest, TestPullUidProviderSetOnConfigUpdate);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/external/TrainInfoPuller.cpp b/cmds/statsd/src/external/TrainInfoPuller.cpp
deleted file mode 100644
index 3837f4a..0000000
--- a/cmds/statsd/src/external/TrainInfoPuller.cpp
+++ /dev/null
@@ -1,55 +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.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "external/StatsPuller.h"
-
-#include "TrainInfoPuller.h"
-#include "logd/LogEvent.h"
-#include "stats_log_util.h"
-#include "statslog_statsd.h"
-#include "storage/StorageManager.h"
-
-using std::make_shared;
-using std::shared_ptr;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-TrainInfoPuller::TrainInfoPuller() :
-    StatsPuller(util::TRAIN_INFO) {
-}
-
-bool TrainInfoPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
-    vector<InstallTrainInfo> trainInfoList =
-        StorageManager::readAllTrainInfo();
-    if (trainInfoList.empty()) {
-        ALOGW("Train info was empty.");
-        return true;
-    }
-    for (InstallTrainInfo& trainInfo : trainInfoList) {
-        auto event = make_shared<LogEvent>(getWallClockNs(), getElapsedRealtimeNs(), trainInfo);
-        data->push_back(event);
-    }
-    return true;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/external/TrainInfoPuller.h b/cmds/statsd/src/external/TrainInfoPuller.h
deleted file mode 100644
index 615d023..0000000
--- a/cmds/statsd/src/external/TrainInfoPuller.h
+++ /dev/null
@@ -1,38 +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.
- */
-
-#pragma once
-
-#include "StatsPuller.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/**
- * Reads train info from disk.
- */
-class TrainInfoPuller : public StatsPuller {
- public:
-  TrainInfoPuller();
-
- private:
-  bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/external/puller_util.cpp b/cmds/statsd/src/external/puller_util.cpp
deleted file mode 100644
index aa99d00..0000000
--- a/cmds/statsd/src/external/puller_util.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "puller_util.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using namespace std;
-
-/**
- * Process all data and merge isolated with host if necessary.
- * For example:
- *   NetworkBytesAtom {
- *       int uid = 1;
- *       State process_state = 2;
- *       int byte_send = 3;
- *       int byte_recv = 4;
- *   }
- *   additive fields are {3, 4}
- * If we pulled the following events (uid1_child is an isolated uid which maps to uid1):
- * [uid1, fg, 100, 200]
- * [uid1_child, fg, 100, 200]
- * [uid1, bg, 100, 200]
- *
- * We want to merge them and results should be:
- * [uid1, fg, 200, 400]
- * [uid1, bg, 100, 200]
- *
- * All atoms should be of the same tagId. All fields should be present.
- */
-void mapAndMergeIsolatedUidsToHostUid(vector<shared_ptr<LogEvent>>& data, const sp<UidMap>& uidMap,
-                                      int tagId, const vector<int>& additiveFieldsVec) {
-    // Check the first LogEvent for attribution chain or a uid field as either all atoms with this
-    // tagId have them or none of them do.
-    std::pair<int, int> attrIndexRange;
-    const bool hasAttributionChain = data[0]->hasAttributionChain(&attrIndexRange);
-    bool hasUidField = (data[0]->getUidFieldIndex() != -1);
-
-    if (!hasAttributionChain && !hasUidField) {
-        VLOG("No uid or attribution chain to merge, atom %d", tagId);
-        return;
-    }
-
-    // 1. Map all isolated uid in-place to host uid
-    for (shared_ptr<LogEvent>& event : data) {
-        if (event->GetTagId() != tagId) {
-            ALOGE("Wrong atom. Expecting %d, got %d", tagId, event->GetTagId());
-            return;
-        }
-        if (hasAttributionChain) {
-            vector<FieldValue>* const fieldValues = event->getMutableValues();
-            for (int i = attrIndexRange.first; i <= attrIndexRange.second; i++) {
-                FieldValue& fieldValue = fieldValues->at(i);
-                if (isAttributionUidField(fieldValue)) {
-                    const int hostUid = uidMap->getHostUidOrSelf(fieldValue.mValue.int_value);
-                    fieldValue.mValue.setInt(hostUid);
-                }
-            }
-        } else {
-            int uidFieldIndex = event->getUidFieldIndex();
-            if (uidFieldIndex != -1) {
-                Value& value = (*event->getMutableValues())[uidFieldIndex].mValue;
-                const int hostUid = uidMap->getHostUidOrSelf(value.int_value);
-                value.setInt(hostUid);
-            } else {
-                ALOGE("Malformed log, uid not found. %s", event->ToString().c_str());
-            }
-        }
-    }
-
-    // 2. sort the data, bit-wise
-    sort(data.begin(), data.end(),
-         [](const shared_ptr<LogEvent>& lhs, const shared_ptr<LogEvent>& rhs) {
-             if (lhs->size() != rhs->size()) {
-                 return lhs->size() < rhs->size();
-             }
-             const std::vector<FieldValue>& lhsValues = lhs->getValues();
-             const std::vector<FieldValue>& rhsValues = rhs->getValues();
-             for (int i = 0; i < (int)lhs->size(); i++) {
-                 if (lhsValues[i] != rhsValues[i]) {
-                     return lhsValues[i] < rhsValues[i];
-                 }
-             }
-             return false;
-         });
-
-    vector<shared_ptr<LogEvent>> mergedData;
-    const set<int> additiveFields(additiveFieldsVec.begin(), additiveFieldsVec.end());
-    bool needMerge = true;
-
-    // 3. do the merge.
-    // The loop invariant is this: for every event, check if it differs on
-    // non-additive fields, or have different attribution chain length.
-    // If so, no need to merge, add itself to the result.
-    // Otherwise, merge the value onto the one immediately next to it.
-    for (int i = 0; i < (int)data.size() - 1; i++) {
-        // Size different, must be different chains.
-        if (data[i]->size() != data[i + 1]->size()) {
-            mergedData.push_back(data[i]);
-            continue;
-        }
-        vector<FieldValue>* lhsValues = data[i]->getMutableValues();
-        vector<FieldValue>* rhsValues = data[i + 1]->getMutableValues();
-        needMerge = true;
-        for (int p = 0; p < (int)lhsValues->size(); p++) {
-            if ((*lhsValues)[p] != (*rhsValues)[p]) {
-                int pos = (*lhsValues)[p].mField.getPosAtDepth(0);
-                // Differ on non-additive field, abort.
-                if (additiveFields.find(pos) == additiveFields.end()) {
-                    needMerge = false;
-                    break;
-                }
-            }
-        }
-        if (!needMerge) {
-            mergedData.push_back(data[i]);
-            continue;
-        }
-        // This should be infrequent operation.
-        for (int p = 0; p < (int)lhsValues->size(); p++) {
-            int pos = (*lhsValues)[p].mField.getPosAtDepth(0);
-            if (additiveFields.find(pos) != additiveFields.end()) {
-                (*rhsValues)[p].mValue += (*lhsValues)[p].mValue;
-            }
-        }
-    }
-    mergedData.push_back(data.back());
-
-    data.clear();
-    data = mergedData;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/external/puller_util.h b/cmds/statsd/src/external/puller_util.h
deleted file mode 100644
index afcf68c..0000000
--- a/cmds/statsd/src/external/puller_util.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <vector>
-#include "StatsPuller.h"
-#include "logd/LogEvent.h"
-#include "packages/UidMap.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-void mapAndMergeIsolatedUidsToHostUid(std::vector<std::shared_ptr<LogEvent>>& data,
-                                      const sp<UidMap>& uidMap, int tagId,
-                                      const vector<int>& additiveFieldsVec);
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/flags/flags.cpp b/cmds/statsd/src/flags/flags.cpp
deleted file mode 100644
index e9fceda..0000000
--- a/cmds/statsd/src/flags/flags.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "flags.h"
-
-#include <server_configurable_flags/get_flags.h>
-
-using server_configurable_flags::GetServerConfigurableFlag;
-using std::string;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-string getFlagString(const string& flagName, const string& defaultValue) {
-    return GetServerConfigurableFlag(STATSD_NATIVE_NAMESPACE, flagName, defaultValue);
-}
-
-bool getFlagBool(const string& flagName, const string& defaultValue) {
-    return getFlagString(flagName, defaultValue) == "true";
-}
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/flags/flags.h b/cmds/statsd/src/flags/flags.h
deleted file mode 100644
index 213e1a4..0000000
--- a/cmds/statsd/src/flags/flags.h
+++ /dev/null
@@ -1,36 +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.
- */
-
-#pragma once
-
-#include <string>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-const std::string STATSD_NATIVE_NAMESPACE = "statsd_native";
-
-const std::string PARTIAL_CONFIG_UPDATE_FLAG = "partial_config_update";
-
-std::string getFlagString(const std::string& flagName, const std::string& defaultValue);
-
-// Returns true IFF flagName has a value of "true".
-bool getFlagBool(const std::string& flagName, const std::string& defaultValue);
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
deleted file mode 100644
index 6e89038..0000000
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ /dev/null
@@ -1,1101 +0,0 @@
-/*
- * Copyright 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "StatsdStats.h"
-
-#include <android/util/ProtoOutputStream.h>
-#include "../stats_log_util.h"
-#include "statslog_statsd.h"
-#include "storage/StorageManager.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using android::util::FIELD_COUNT_REPEATED;
-using android::util::FIELD_TYPE_BOOL;
-using android::util::FIELD_TYPE_FLOAT;
-using android::util::FIELD_TYPE_INT32;
-using android::util::FIELD_TYPE_INT64;
-using android::util::FIELD_TYPE_MESSAGE;
-using android::util::FIELD_TYPE_STRING;
-using android::util::ProtoOutputStream;
-using std::lock_guard;
-using std::shared_ptr;
-using std::string;
-using std::to_string;
-using std::vector;
-
-const int FIELD_ID_BEGIN_TIME = 1;
-const int FIELD_ID_END_TIME = 2;
-const int FIELD_ID_CONFIG_STATS = 3;
-const int FIELD_ID_ATOM_STATS = 7;
-const int FIELD_ID_UIDMAP_STATS = 8;
-const int FIELD_ID_ANOMALY_ALARM_STATS = 9;
-const int FIELD_ID_PERIODIC_ALARM_STATS = 12;
-const int FIELD_ID_SYSTEM_SERVER_RESTART = 15;
-const int FIELD_ID_LOGGER_ERROR_STATS = 16;
-const int FIELD_ID_OVERFLOW = 18;
-const int FIELD_ID_ACTIVATION_BROADCAST_GUARDRAIL = 19;
-
-const int FIELD_ID_ATOM_STATS_TAG = 1;
-const int FIELD_ID_ATOM_STATS_COUNT = 2;
-const int FIELD_ID_ATOM_STATS_ERROR_COUNT = 3;
-
-const int FIELD_ID_ANOMALY_ALARMS_REGISTERED = 1;
-const int FIELD_ID_PERIODIC_ALARMS_REGISTERED = 1;
-
-const int FIELD_ID_LOG_LOSS_STATS_TIME = 1;
-const int FIELD_ID_LOG_LOSS_STATS_COUNT = 2;
-const int FIELD_ID_LOG_LOSS_STATS_ERROR = 3;
-const int FIELD_ID_LOG_LOSS_STATS_TAG = 4;
-const int FIELD_ID_LOG_LOSS_STATS_UID = 5;
-const int FIELD_ID_LOG_LOSS_STATS_PID = 6;
-
-const int FIELD_ID_OVERFLOW_COUNT = 1;
-const int FIELD_ID_OVERFLOW_MAX_HISTORY = 2;
-const int FIELD_ID_OVERFLOW_MIN_HISTORY = 3;
-
-const int FIELD_ID_CONFIG_STATS_UID = 1;
-const int FIELD_ID_CONFIG_STATS_ID = 2;
-const int FIELD_ID_CONFIG_STATS_CREATION = 3;
-const int FIELD_ID_CONFIG_STATS_RESET = 19;
-const int FIELD_ID_CONFIG_STATS_DELETION = 4;
-const int FIELD_ID_CONFIG_STATS_METRIC_COUNT = 5;
-const int FIELD_ID_CONFIG_STATS_CONDITION_COUNT = 6;
-const int FIELD_ID_CONFIG_STATS_MATCHER_COUNT = 7;
-const int FIELD_ID_CONFIG_STATS_ALERT_COUNT = 8;
-const int FIELD_ID_CONFIG_STATS_VALID = 9;
-const int FIELD_ID_CONFIG_STATS_BROADCAST = 10;
-const int FIELD_ID_CONFIG_STATS_DATA_DROP_TIME = 11;
-const int FIELD_ID_CONFIG_STATS_DATA_DROP_BYTES = 21;
-const int FIELD_ID_CONFIG_STATS_DUMP_REPORT_TIME = 12;
-const int FIELD_ID_CONFIG_STATS_DUMP_REPORT_BYTES = 20;
-const int FIELD_ID_CONFIG_STATS_MATCHER_STATS = 13;
-const int FIELD_ID_CONFIG_STATS_CONDITION_STATS = 14;
-const int FIELD_ID_CONFIG_STATS_METRIC_STATS = 15;
-const int FIELD_ID_CONFIG_STATS_ALERT_STATS = 16;
-const int FIELD_ID_CONFIG_STATS_METRIC_DIMENSION_IN_CONDITION_STATS = 17;
-const int FIELD_ID_CONFIG_STATS_ANNOTATION = 18;
-const int FIELD_ID_CONFIG_STATS_ACTIVATION = 22;
-const int FIELD_ID_CONFIG_STATS_DEACTIVATION = 23;
-const int FIELD_ID_CONFIG_STATS_ANNOTATION_INT64 = 1;
-const int FIELD_ID_CONFIG_STATS_ANNOTATION_INT32 = 2;
-
-const int FIELD_ID_MATCHER_STATS_ID = 1;
-const int FIELD_ID_MATCHER_STATS_COUNT = 2;
-const int FIELD_ID_CONDITION_STATS_ID = 1;
-const int FIELD_ID_CONDITION_STATS_COUNT = 2;
-const int FIELD_ID_METRIC_STATS_ID = 1;
-const int FIELD_ID_METRIC_STATS_COUNT = 2;
-const int FIELD_ID_ALERT_STATS_ID = 1;
-const int FIELD_ID_ALERT_STATS_COUNT = 2;
-
-const int FIELD_ID_UID_MAP_CHANGES = 1;
-const int FIELD_ID_UID_MAP_BYTES_USED = 2;
-const int FIELD_ID_UID_MAP_DROPPED_CHANGES = 3;
-const int FIELD_ID_UID_MAP_DELETED_APPS = 4;
-
-const int FIELD_ID_ACTIVATION_BROADCAST_GUARDRAIL_UID = 1;
-const int FIELD_ID_ACTIVATION_BROADCAST_GUARDRAIL_TIME = 2;
-
-const std::map<int, std::pair<size_t, size_t>> StatsdStats::kAtomDimensionKeySizeLimitMap = {
-        {util::BINDER_CALLS, {6000, 10000}},
-        {util::LOOPER_STATS, {1500, 2500}},
-        {util::CPU_TIME_PER_UID_FREQ, {6000, 10000}},
-};
-
-StatsdStats::StatsdStats() {
-    mPushedAtomStats.resize(kMaxPushedAtomId + 1);
-    mStartTimeSec = getWallClockSec();
-}
-
-StatsdStats& StatsdStats::getInstance() {
-    static StatsdStats statsInstance;
-    return statsInstance;
-}
-
-void StatsdStats::addToIceBoxLocked(shared_ptr<ConfigStats>& stats) {
-    // The size of mIceBox grows strictly by one at a time. It won't be > kMaxIceBoxSize.
-    if (mIceBox.size() == kMaxIceBoxSize) {
-        mIceBox.pop_front();
-    }
-    mIceBox.push_back(stats);
-}
-
-void StatsdStats::noteConfigReceived(
-        const ConfigKey& key, int metricsCount, int conditionsCount, int matchersCount,
-        int alertsCount, const std::list<std::pair<const int64_t, const int32_t>>& annotations,
-        bool isValid) {
-    lock_guard<std::mutex> lock(mLock);
-    int32_t nowTimeSec = getWallClockSec();
-
-    // If there is an existing config for the same key, icebox the old config.
-    noteConfigRemovedInternalLocked(key);
-
-    shared_ptr<ConfigStats> configStats = std::make_shared<ConfigStats>();
-    configStats->uid = key.GetUid();
-    configStats->id = key.GetId();
-    configStats->creation_time_sec = nowTimeSec;
-    configStats->metric_count = metricsCount;
-    configStats->condition_count = conditionsCount;
-    configStats->matcher_count = matchersCount;
-    configStats->alert_count = alertsCount;
-    configStats->is_valid = isValid;
-    for (auto& v : annotations) {
-        configStats->annotations.emplace_back(v);
-    }
-
-    if (isValid) {
-        mConfigStats[key] = configStats;
-    } else {
-        configStats->deletion_time_sec = nowTimeSec;
-        addToIceBoxLocked(configStats);
-    }
-}
-
-void StatsdStats::noteConfigRemovedInternalLocked(const ConfigKey& key) {
-    auto it = mConfigStats.find(key);
-    if (it != mConfigStats.end()) {
-        int32_t nowTimeSec = getWallClockSec();
-        it->second->deletion_time_sec = nowTimeSec;
-        addToIceBoxLocked(it->second);
-        mConfigStats.erase(it);
-    }
-}
-
-void StatsdStats::noteConfigRemoved(const ConfigKey& key) {
-    lock_guard<std::mutex> lock(mLock);
-    noteConfigRemovedInternalLocked(key);
-}
-
-void StatsdStats::noteConfigResetInternalLocked(const ConfigKey& key) {
-    auto it = mConfigStats.find(key);
-    if (it != mConfigStats.end()) {
-        it->second->reset_time_sec = getWallClockSec();
-    }
-}
-
-void StatsdStats::noteConfigReset(const ConfigKey& key) {
-    lock_guard<std::mutex> lock(mLock);
-    noteConfigResetInternalLocked(key);
-}
-
-void StatsdStats::noteLogLost(int32_t wallClockTimeSec, int32_t count, int32_t lastError,
-                              int32_t lastTag, int32_t uid, int32_t pid) {
-    lock_guard<std::mutex> lock(mLock);
-    if (mLogLossStats.size() == kMaxLoggerErrors) {
-        mLogLossStats.pop_front();
-    }
-    mLogLossStats.emplace_back(wallClockTimeSec, count, lastError, lastTag, uid, pid);
-}
-
-void StatsdStats::noteBroadcastSent(const ConfigKey& key) {
-    noteBroadcastSent(key, getWallClockSec());
-}
-
-void StatsdStats::noteBroadcastSent(const ConfigKey& key, int32_t timeSec) {
-    lock_guard<std::mutex> lock(mLock);
-    auto it = mConfigStats.find(key);
-    if (it == mConfigStats.end()) {
-        ALOGE("Config key %s not found!", key.ToString().c_str());
-        return;
-    }
-    if (it->second->broadcast_sent_time_sec.size() == kMaxTimestampCount) {
-        it->second->broadcast_sent_time_sec.pop_front();
-    }
-    it->second->broadcast_sent_time_sec.push_back(timeSec);
-}
-
-void StatsdStats::noteActiveStatusChanged(const ConfigKey& key, bool activated) {
-    noteActiveStatusChanged(key, activated, getWallClockSec());
-}
-
-void StatsdStats::noteActiveStatusChanged(const ConfigKey& key, bool activated, int32_t timeSec) {
-    lock_guard<std::mutex> lock(mLock);
-    auto it = mConfigStats.find(key);
-    if (it == mConfigStats.end()) {
-        ALOGE("Config key %s not found!", key.ToString().c_str());
-        return;
-    }
-    auto& vec = activated ? it->second->activation_time_sec
-                          : it->second->deactivation_time_sec;
-    if (vec.size() == kMaxTimestampCount) {
-        vec.pop_front();
-    }
-    vec.push_back(timeSec);
-}
-
-void StatsdStats::noteActivationBroadcastGuardrailHit(const int uid) {
-    noteActivationBroadcastGuardrailHit(uid, getWallClockSec());
-}
-
-void StatsdStats::noteActivationBroadcastGuardrailHit(const int uid, const int32_t timeSec) {
-    lock_guard<std::mutex> lock(mLock);
-    auto& guardrailTimes = mActivationBroadcastGuardrailStats[uid];
-    if (guardrailTimes.size() == kMaxTimestampCount) {
-        guardrailTimes.pop_front();
-    }
-    guardrailTimes.push_back(timeSec);
-}
-
-void StatsdStats::noteDataDropped(const ConfigKey& key, const size_t totalBytes) {
-    noteDataDropped(key, totalBytes, getWallClockSec());
-}
-
-void StatsdStats::noteEventQueueOverflow(int64_t oldestEventTimestampNs) {
-    lock_guard<std::mutex> lock(mLock);
-
-    mOverflowCount++;
-
-    int64_t history = getElapsedRealtimeNs() - oldestEventTimestampNs;
-
-    if (history > mMaxQueueHistoryNs) {
-        mMaxQueueHistoryNs = history;
-    }
-
-    if (history < mMinQueueHistoryNs) {
-        mMinQueueHistoryNs = history;
-    }
-}
-
-void StatsdStats::noteDataDropped(const ConfigKey& key, const size_t totalBytes, int32_t timeSec) {
-    lock_guard<std::mutex> lock(mLock);
-    auto it = mConfigStats.find(key);
-    if (it == mConfigStats.end()) {
-        ALOGE("Config key %s not found!", key.ToString().c_str());
-        return;
-    }
-    if (it->second->data_drop_time_sec.size() == kMaxTimestampCount) {
-        it->second->data_drop_time_sec.pop_front();
-        it->second->data_drop_bytes.pop_front();
-    }
-    it->second->data_drop_time_sec.push_back(timeSec);
-    it->second->data_drop_bytes.push_back(totalBytes);
-}
-
-void StatsdStats::noteMetricsReportSent(const ConfigKey& key, const size_t num_bytes) {
-    noteMetricsReportSent(key, num_bytes, getWallClockSec());
-}
-
-void StatsdStats::noteMetricsReportSent(const ConfigKey& key, const size_t num_bytes,
-                                        int32_t timeSec) {
-    lock_guard<std::mutex> lock(mLock);
-    auto it = mConfigStats.find(key);
-    if (it == mConfigStats.end()) {
-        ALOGE("Config key %s not found!", key.ToString().c_str());
-        return;
-    }
-    if (it->second->dump_report_stats.size() == kMaxTimestampCount) {
-        it->second->dump_report_stats.pop_front();
-    }
-    it->second->dump_report_stats.push_back(std::make_pair(timeSec, num_bytes));
-}
-
-void StatsdStats::noteUidMapDropped(int deltas) {
-    lock_guard<std::mutex> lock(mLock);
-    mUidMapStats.dropped_changes += mUidMapStats.dropped_changes + deltas;
-}
-
-void StatsdStats::noteUidMapAppDeletionDropped() {
-    lock_guard<std::mutex> lock(mLock);
-    mUidMapStats.deleted_apps++;
-}
-
-void StatsdStats::setUidMapChanges(int changes) {
-    lock_guard<std::mutex> lock(mLock);
-    mUidMapStats.changes = changes;
-}
-
-void StatsdStats::setCurrentUidMapMemory(int bytes) {
-    lock_guard<std::mutex> lock(mLock);
-    mUidMapStats.bytes_used = bytes;
-}
-
-void StatsdStats::noteConditionDimensionSize(const ConfigKey& key, const int64_t& id, int size) {
-    lock_guard<std::mutex> lock(mLock);
-    // if name doesn't exist before, it will create the key with count 0.
-    auto statsIt = mConfigStats.find(key);
-    if (statsIt == mConfigStats.end()) {
-        return;
-    }
-
-    auto& conditionSizeMap = statsIt->second->condition_stats;
-    if (size > conditionSizeMap[id]) {
-        conditionSizeMap[id] = size;
-    }
-}
-
-void StatsdStats::noteMetricDimensionSize(const ConfigKey& key, const int64_t& id, int size) {
-    lock_guard<std::mutex> lock(mLock);
-    // if name doesn't exist before, it will create the key with count 0.
-    auto statsIt = mConfigStats.find(key);
-    if (statsIt == mConfigStats.end()) {
-        return;
-    }
-    auto& metricsDimensionMap = statsIt->second->metric_stats;
-    if (size > metricsDimensionMap[id]) {
-        metricsDimensionMap[id] = size;
-    }
-}
-
-void StatsdStats::noteMetricDimensionInConditionSize(
-        const ConfigKey& key, const int64_t& id, int size) {
-    lock_guard<std::mutex> lock(mLock);
-    // if name doesn't exist before, it will create the key with count 0.
-    auto statsIt = mConfigStats.find(key);
-    if (statsIt == mConfigStats.end()) {
-        return;
-    }
-    auto& metricsDimensionMap = statsIt->second->metric_dimension_in_condition_stats;
-    if (size > metricsDimensionMap[id]) {
-        metricsDimensionMap[id] = size;
-    }
-}
-
-void StatsdStats::noteMatcherMatched(const ConfigKey& key, const int64_t& id) {
-    lock_guard<std::mutex> lock(mLock);
-
-    auto statsIt = mConfigStats.find(key);
-    if (statsIt == mConfigStats.end()) {
-        return;
-    }
-    statsIt->second->matcher_stats[id]++;
-}
-
-void StatsdStats::noteAnomalyDeclared(const ConfigKey& key, const int64_t& id) {
-    lock_guard<std::mutex> lock(mLock);
-    auto statsIt = mConfigStats.find(key);
-    if (statsIt == mConfigStats.end()) {
-        return;
-    }
-    statsIt->second->alert_stats[id]++;
-}
-
-void StatsdStats::noteRegisteredAnomalyAlarmChanged() {
-    lock_guard<std::mutex> lock(mLock);
-    mAnomalyAlarmRegisteredStats++;
-}
-
-void StatsdStats::noteRegisteredPeriodicAlarmChanged() {
-    lock_guard<std::mutex> lock(mLock);
-    mPeriodicAlarmRegisteredStats++;
-}
-
-void StatsdStats::updateMinPullIntervalSec(int pullAtomId, long intervalSec) {
-    lock_guard<std::mutex> lock(mLock);
-    mPulledAtomStats[pullAtomId].minPullIntervalSec =
-            std::min(mPulledAtomStats[pullAtomId].minPullIntervalSec, intervalSec);
-}
-
-void StatsdStats::notePull(int pullAtomId) {
-    lock_guard<std::mutex> lock(mLock);
-    mPulledAtomStats[pullAtomId].totalPull++;
-}
-
-void StatsdStats::notePullFromCache(int pullAtomId) {
-    lock_guard<std::mutex> lock(mLock);
-    mPulledAtomStats[pullAtomId].totalPullFromCache++;
-}
-
-void StatsdStats::notePullTime(int pullAtomId, int64_t pullTimeNs) {
-    lock_guard<std::mutex> lock(mLock);
-    auto& pullStats = mPulledAtomStats[pullAtomId];
-    pullStats.maxPullTimeNs = std::max(pullStats.maxPullTimeNs, pullTimeNs);
-    pullStats.avgPullTimeNs = (pullStats.avgPullTimeNs * pullStats.numPullTime + pullTimeNs) /
-                              (pullStats.numPullTime + 1);
-    pullStats.numPullTime += 1;
-}
-
-void StatsdStats::notePullDelay(int pullAtomId, int64_t pullDelayNs) {
-    lock_guard<std::mutex> lock(mLock);
-    auto& pullStats = mPulledAtomStats[pullAtomId];
-    pullStats.maxPullDelayNs = std::max(pullStats.maxPullDelayNs, pullDelayNs);
-    pullStats.avgPullDelayNs =
-        (pullStats.avgPullDelayNs * pullStats.numPullDelay + pullDelayNs) /
-            (pullStats.numPullDelay + 1);
-    pullStats.numPullDelay += 1;
-}
-
-void StatsdStats::notePullDataError(int pullAtomId) {
-    lock_guard<std::mutex> lock(mLock);
-    mPulledAtomStats[pullAtomId].dataError++;
-}
-
-void StatsdStats::notePullTimeout(int pullAtomId,
-                                  int64_t pullUptimeMillis,
-                                  int64_t pullElapsedMillis) {
-    lock_guard<std::mutex> lock(mLock);
-    PulledAtomStats& pulledAtomStats = mPulledAtomStats[pullAtomId];
-    pulledAtomStats.pullTimeout++;
-
-    if (pulledAtomStats.pullTimeoutMetadata.size() == kMaxTimestampCount) {
-        pulledAtomStats.pullTimeoutMetadata.pop_front();
-    }
-
-    pulledAtomStats.pullTimeoutMetadata.emplace_back(pullUptimeMillis, pullElapsedMillis);
-}
-
-void StatsdStats::notePullExceedMaxDelay(int pullAtomId) {
-    lock_guard<std::mutex> lock(mLock);
-    mPulledAtomStats[pullAtomId].pullExceedMaxDelay++;
-}
-
-void StatsdStats::noteAtomLogged(int atomId, int32_t timeSec) {
-    lock_guard<std::mutex> lock(mLock);
-
-    if (atomId <= kMaxPushedAtomId) {
-        mPushedAtomStats[atomId]++;
-    } else {
-        if (mNonPlatformPushedAtomStats.size() < kMaxNonPlatformPushedAtoms) {
-            mNonPlatformPushedAtomStats[atomId]++;
-        }
-    }
-}
-
-void StatsdStats::noteSystemServerRestart(int32_t timeSec) {
-    lock_guard<std::mutex> lock(mLock);
-
-    if (mSystemServerRestartSec.size() == kMaxSystemServerRestarts) {
-        mSystemServerRestartSec.pop_front();
-    }
-    mSystemServerRestartSec.push_back(timeSec);
-}
-
-void StatsdStats::notePullFailed(int atomId) {
-    lock_guard<std::mutex> lock(mLock);
-    mPulledAtomStats[atomId].pullFailed++;
-}
-
-void StatsdStats::notePullUidProviderNotFound(int atomId) {
-    lock_guard<std::mutex> lock(mLock);
-    mPulledAtomStats[atomId].pullUidProviderNotFound++;
-}
-
-void StatsdStats::notePullerNotFound(int atomId) {
-    lock_guard<std::mutex> lock(mLock);
-    mPulledAtomStats[atomId].pullerNotFound++;
-}
-
-void StatsdStats::notePullBinderCallFailed(int atomId) {
-    lock_guard<std::mutex> lock(mLock);
-    mPulledAtomStats[atomId].binderCallFailCount++;
-}
-
-void StatsdStats::noteEmptyData(int atomId) {
-    lock_guard<std::mutex> lock(mLock);
-    mPulledAtomStats[atomId].emptyData++;
-}
-
-void StatsdStats::notePullerCallbackRegistrationChanged(int atomId, bool registered) {
-    lock_guard<std::mutex> lock(mLock);
-    if (registered) {
-        mPulledAtomStats[atomId].registeredCount++;
-    } else {
-        mPulledAtomStats[atomId].unregisteredCount++;
-    }
-}
-
-void StatsdStats::noteHardDimensionLimitReached(int64_t metricId) {
-    lock_guard<std::mutex> lock(mLock);
-    getAtomMetricStats(metricId).hardDimensionLimitReached++;
-}
-
-void StatsdStats::noteLateLogEventSkipped(int64_t metricId) {
-    lock_guard<std::mutex> lock(mLock);
-    getAtomMetricStats(metricId).lateLogEventSkipped++;
-}
-
-void StatsdStats::noteSkippedForwardBuckets(int64_t metricId) {
-    lock_guard<std::mutex> lock(mLock);
-    getAtomMetricStats(metricId).skippedForwardBuckets++;
-}
-
-void StatsdStats::noteBadValueType(int64_t metricId) {
-    lock_guard<std::mutex> lock(mLock);
-    getAtomMetricStats(metricId).badValueType++;
-}
-
-void StatsdStats::noteBucketDropped(int64_t metricId) {
-    lock_guard<std::mutex> lock(mLock);
-    getAtomMetricStats(metricId).bucketDropped++;
-}
-
-void StatsdStats::noteBucketUnknownCondition(int64_t metricId) {
-    lock_guard<std::mutex> lock(mLock);
-    getAtomMetricStats(metricId).bucketUnknownCondition++;
-}
-
-void StatsdStats::noteConditionChangeInNextBucket(int64_t metricId) {
-    lock_guard<std::mutex> lock(mLock);
-    getAtomMetricStats(metricId).conditionChangeInNextBucket++;
-}
-
-void StatsdStats::noteInvalidatedBucket(int64_t metricId) {
-    lock_guard<std::mutex> lock(mLock);
-    getAtomMetricStats(metricId).invalidatedBucket++;
-}
-
-void StatsdStats::noteBucketCount(int64_t metricId) {
-    lock_guard<std::mutex> lock(mLock);
-    getAtomMetricStats(metricId).bucketCount++;
-}
-
-void StatsdStats::noteBucketBoundaryDelayNs(int64_t metricId, int64_t timeDelayNs) {
-    lock_guard<std::mutex> lock(mLock);
-    AtomMetricStats& pullStats = getAtomMetricStats(metricId);
-    pullStats.maxBucketBoundaryDelayNs =
-            std::max(pullStats.maxBucketBoundaryDelayNs, timeDelayNs);
-    pullStats.minBucketBoundaryDelayNs =
-            std::min(pullStats.minBucketBoundaryDelayNs, timeDelayNs);
-}
-
-void StatsdStats::noteAtomError(int atomTag, bool pull) {
-    lock_guard<std::mutex> lock(mLock);
-    if (pull) {
-        mPulledAtomStats[atomTag].atomErrorCount++;
-        return;
-    }
-
-    bool present = (mPushedAtomErrorStats.find(atomTag) != mPushedAtomErrorStats.end());
-    bool full = (mPushedAtomErrorStats.size() >= (size_t)kMaxPushedAtomErrorStatsSize);
-    if (!full || present) {
-        mPushedAtomErrorStats[atomTag]++;
-    }
-}
-
-StatsdStats::AtomMetricStats& StatsdStats::getAtomMetricStats(int64_t metricId) {
-    auto atomMetricStatsIter = mAtomMetricStats.find(metricId);
-    if (atomMetricStatsIter != mAtomMetricStats.end()) {
-        return atomMetricStatsIter->second;
-    }
-    auto emplaceResult = mAtomMetricStats.emplace(metricId, AtomMetricStats());
-    return emplaceResult.first->second;
-}
-
-void StatsdStats::reset() {
-    lock_guard<std::mutex> lock(mLock);
-    resetInternalLocked();
-}
-
-void StatsdStats::resetInternalLocked() {
-    // Reset the historical data, but keep the active ConfigStats
-    mStartTimeSec = getWallClockSec();
-    mIceBox.clear();
-    std::fill(mPushedAtomStats.begin(), mPushedAtomStats.end(), 0);
-    mNonPlatformPushedAtomStats.clear();
-    mAnomalyAlarmRegisteredStats = 0;
-    mPeriodicAlarmRegisteredStats = 0;
-    mSystemServerRestartSec.clear();
-    mLogLossStats.clear();
-    mOverflowCount = 0;
-    mMinQueueHistoryNs = kInt64Max;
-    mMaxQueueHistoryNs = 0;
-    for (auto& config : mConfigStats) {
-        config.second->broadcast_sent_time_sec.clear();
-        config.second->activation_time_sec.clear();
-        config.second->deactivation_time_sec.clear();
-        config.second->data_drop_time_sec.clear();
-        config.second->data_drop_bytes.clear();
-        config.second->dump_report_stats.clear();
-        config.second->annotations.clear();
-        config.second->matcher_stats.clear();
-        config.second->condition_stats.clear();
-        config.second->metric_stats.clear();
-        config.second->metric_dimension_in_condition_stats.clear();
-        config.second->alert_stats.clear();
-    }
-    for (auto& pullStats : mPulledAtomStats) {
-        pullStats.second.totalPull = 0;
-        pullStats.second.totalPullFromCache = 0;
-        pullStats.second.minPullIntervalSec = LONG_MAX;
-        pullStats.second.avgPullTimeNs = 0;
-        pullStats.second.maxPullTimeNs = 0;
-        pullStats.second.numPullTime = 0;
-        pullStats.second.avgPullDelayNs = 0;
-        pullStats.second.maxPullDelayNs = 0;
-        pullStats.second.numPullDelay = 0;
-        pullStats.second.dataError = 0;
-        pullStats.second.pullTimeout = 0;
-        pullStats.second.pullExceedMaxDelay = 0;
-        pullStats.second.pullFailed = 0;
-        pullStats.second.pullUidProviderNotFound = 0;
-        pullStats.second.pullerNotFound = 0;
-        pullStats.second.registeredCount = 0;
-        pullStats.second.unregisteredCount = 0;
-        pullStats.second.atomErrorCount = 0;
-        pullStats.second.binderCallFailCount = 0;
-        pullStats.second.pullTimeoutMetadata.clear();
-    }
-    mAtomMetricStats.clear();
-    mActivationBroadcastGuardrailStats.clear();
-    mPushedAtomErrorStats.clear();
-}
-
-string buildTimeString(int64_t timeSec) {
-    time_t t = timeSec;
-    struct tm* tm = localtime(&t);
-    char timeBuffer[80];
-    strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %I:%M%p", tm);
-    return string(timeBuffer);
-}
-
-int StatsdStats::getPushedAtomErrors(int atomId) const {
-    const auto& it = mPushedAtomErrorStats.find(atomId);
-    if (it != mPushedAtomErrorStats.end()) {
-        return it->second;
-    } else {
-        return 0;
-    }
-}
-
-void StatsdStats::dumpStats(int out) const {
-    lock_guard<std::mutex> lock(mLock);
-    time_t t = mStartTimeSec;
-    struct tm* tm = localtime(&t);
-    char timeBuffer[80];
-    strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %I:%M%p\n", tm);
-    dprintf(out, "Stats collection start second: %s\n", timeBuffer);
-    dprintf(out, "%lu Config in icebox: \n", (unsigned long)mIceBox.size());
-    for (const auto& configStats : mIceBox) {
-        dprintf(out,
-                "Config {%d_%lld}: creation=%d, deletion=%d, reset=%d, #metric=%d, #condition=%d, "
-                "#matcher=%d, #alert=%d,  valid=%d\n",
-                configStats->uid, (long long)configStats->id, configStats->creation_time_sec,
-                configStats->deletion_time_sec, configStats->reset_time_sec,
-                configStats->metric_count, configStats->condition_count, configStats->matcher_count,
-                configStats->alert_count, configStats->is_valid);
-
-        for (const auto& broadcastTime : configStats->broadcast_sent_time_sec) {
-            dprintf(out, "\tbroadcast time: %d\n", broadcastTime);
-        }
-
-        for (const int& activationTime : configStats->activation_time_sec) {
-            dprintf(out, "\tactivation time: %d\n", activationTime);
-        }
-
-        for (const int& deactivationTime : configStats->deactivation_time_sec) {
-            dprintf(out, "\tdeactivation time: %d\n", deactivationTime);
-        }
-
-        auto dropTimePtr = configStats->data_drop_time_sec.begin();
-        auto dropBytesPtr = configStats->data_drop_bytes.begin();
-        for (int i = 0; i < (int)configStats->data_drop_time_sec.size();
-             i++, dropTimePtr++, dropBytesPtr++) {
-            dprintf(out, "\tdata drop time: %d with size %lld", *dropTimePtr,
-                    (long long)*dropBytesPtr);
-        }
-    }
-    dprintf(out, "%lu Active Configs\n", (unsigned long)mConfigStats.size());
-    for (auto& pair : mConfigStats) {
-        auto& configStats = pair.second;
-        dprintf(out,
-                "Config {%d-%lld}: creation=%d, deletion=%d, #metric=%d, #condition=%d, "
-                "#matcher=%d, #alert=%d,  valid=%d\n",
-                configStats->uid, (long long)configStats->id, configStats->creation_time_sec,
-                configStats->deletion_time_sec, configStats->metric_count,
-                configStats->condition_count, configStats->matcher_count, configStats->alert_count,
-                configStats->is_valid);
-        for (const auto& annotation : configStats->annotations) {
-            dprintf(out, "\tannotation: %lld, %d\n", (long long)annotation.first,
-                    annotation.second);
-        }
-
-        for (const auto& broadcastTime : configStats->broadcast_sent_time_sec) {
-            dprintf(out, "\tbroadcast time: %s(%lld)\n", buildTimeString(broadcastTime).c_str(),
-                    (long long)broadcastTime);
-        }
-
-        for (const int& activationTime : configStats->activation_time_sec) {
-            dprintf(out, "\tactivation time: %d\n", activationTime);
-        }
-
-        for (const int& deactivationTime : configStats->deactivation_time_sec) {
-            dprintf(out, "\tdeactivation time: %d\n", deactivationTime);
-        }
-
-        auto dropTimePtr = configStats->data_drop_time_sec.begin();
-        auto dropBytesPtr = configStats->data_drop_bytes.begin();
-        for (int i = 0; i < (int)configStats->data_drop_time_sec.size();
-             i++, dropTimePtr++, dropBytesPtr++) {
-            dprintf(out, "\tdata drop time: %s(%lld) with %lld bytes\n",
-                    buildTimeString(*dropTimePtr).c_str(), (long long)*dropTimePtr,
-                    (long long)*dropBytesPtr);
-        }
-
-        for (const auto& dump : configStats->dump_report_stats) {
-            dprintf(out, "\tdump report time: %s(%lld) bytes: %lld\n",
-                    buildTimeString(dump.first).c_str(), (long long)dump.first,
-                    (long long)dump.second);
-        }
-
-        for (const auto& stats : pair.second->matcher_stats) {
-            dprintf(out, "matcher %lld matched %d times\n", (long long)stats.first, stats.second);
-        }
-
-        for (const auto& stats : pair.second->condition_stats) {
-            dprintf(out, "condition %lld max output tuple size %d\n", (long long)stats.first,
-                    stats.second);
-        }
-
-        for (const auto& stats : pair.second->condition_stats) {
-            dprintf(out, "metrics %lld max output tuple size %d\n", (long long)stats.first,
-                    stats.second);
-        }
-
-        for (const auto& stats : pair.second->alert_stats) {
-            dprintf(out, "alert %lld declared %d times\n", (long long)stats.first, stats.second);
-        }
-    }
-    dprintf(out, "********Disk Usage stats***********\n");
-    StorageManager::printStats(out);
-    dprintf(out, "********Pushed Atom stats***********\n");
-    const size_t atomCounts = mPushedAtomStats.size();
-    for (size_t i = 2; i < atomCounts; i++) {
-        if (mPushedAtomStats[i] > 0) {
-            dprintf(out, "Atom %zu->(total count)%d, (error count)%d\n", i, mPushedAtomStats[i],
-                    getPushedAtomErrors((int)i));
-        }
-    }
-    for (const auto& pair : mNonPlatformPushedAtomStats) {
-        dprintf(out, "Atom %d->(total count)%d, (error count)%d\n", pair.first, pair.second,
-                getPushedAtomErrors(pair.first));
-    }
-
-    dprintf(out, "********Pulled Atom stats***********\n");
-    for (const auto& pair : mPulledAtomStats) {
-        dprintf(out,
-                "Atom %d->(total pull)%ld, (pull from cache)%ld, "
-                "(pull failed)%ld, (min pull interval)%ld \n"
-                "  (average pull time nanos)%lld, (max pull time nanos)%lld, (average pull delay "
-                "nanos)%lld, "
-                "  (max pull delay nanos)%lld, (data error)%ld\n"
-                "  (pull timeout)%ld, (pull exceed max delay)%ld"
-                "  (no uid provider count)%ld, (no puller found count)%ld\n"
-                "  (registered count) %ld, (unregistered count) %ld"
-                "  (atom error count) %d\n",
-                (int)pair.first, (long)pair.second.totalPull, (long)pair.second.totalPullFromCache,
-                (long)pair.second.pullFailed, (long)pair.second.minPullIntervalSec,
-                (long long)pair.second.avgPullTimeNs, (long long)pair.second.maxPullTimeNs,
-                (long long)pair.second.avgPullDelayNs, (long long)pair.second.maxPullDelayNs,
-                pair.second.dataError, pair.second.pullTimeout, pair.second.pullExceedMaxDelay,
-                pair.second.pullUidProviderNotFound, pair.second.pullerNotFound,
-                pair.second.registeredCount, pair.second.unregisteredCount,
-                pair.second.atomErrorCount);
-        if (pair.second.pullTimeoutMetadata.size() > 0) {
-            string uptimeMillis = "(pull timeout system uptime millis) ";
-            string pullTimeoutMillis = "(pull timeout elapsed time millis) ";
-            for (const auto& stats : pair.second.pullTimeoutMetadata) {
-                uptimeMillis.append(to_string(stats.pullTimeoutUptimeMillis)).append(",");;
-                pullTimeoutMillis.append(to_string(stats.pullTimeoutElapsedMillis)).append(",");
-            }
-            uptimeMillis.pop_back();
-            uptimeMillis.push_back('\n');
-            pullTimeoutMillis.pop_back();
-            pullTimeoutMillis.push_back('\n');
-            dprintf(out, "%s", uptimeMillis.c_str());
-            dprintf(out, "%s", pullTimeoutMillis.c_str());
-        }
-    }
-
-    if (mAnomalyAlarmRegisteredStats > 0) {
-        dprintf(out, "********AnomalyAlarmStats stats***********\n");
-        dprintf(out, "Anomaly alarm registrations: %d\n", mAnomalyAlarmRegisteredStats);
-    }
-
-    if (mPeriodicAlarmRegisteredStats > 0) {
-        dprintf(out, "********SubscriberAlarmStats stats***********\n");
-        dprintf(out, "Subscriber alarm registrations: %d\n", mPeriodicAlarmRegisteredStats);
-    }
-
-    dprintf(out, "UID map stats: bytes=%d, changes=%d, deleted=%d, changes lost=%d\n",
-            mUidMapStats.bytes_used, mUidMapStats.changes, mUidMapStats.deleted_apps,
-            mUidMapStats.dropped_changes);
-
-    for (const auto& restart : mSystemServerRestartSec) {
-        dprintf(out, "System server restarts at %s(%lld)\n", buildTimeString(restart).c_str(),
-                (long long)restart);
-    }
-
-    for (const auto& loss : mLogLossStats) {
-        dprintf(out,
-                "Log loss: %lld (wall clock sec) - %d (count), %d (last error), %d (last tag), %d "
-                "(uid), %d (pid)\n",
-                (long long)loss.mWallClockSec, loss.mCount, loss.mLastError, loss.mLastTag,
-                loss.mUid, loss.mPid);
-    }
-
-    dprintf(out, "Event queue overflow: %d; MaxHistoryNs: %lld; MinHistoryNs: %lld\n",
-            mOverflowCount, (long long)mMaxQueueHistoryNs, (long long)mMinQueueHistoryNs);
-
-    if (mActivationBroadcastGuardrailStats.size() > 0) {
-        dprintf(out, "********mActivationBroadcastGuardrail stats***********\n");
-        for (const auto& pair: mActivationBroadcastGuardrailStats) {
-            dprintf(out, "Uid %d: Times: ", pair.first);
-            for (const auto& guardrailHitTime : pair.second) {
-                dprintf(out, "%d ", guardrailHitTime);
-            }
-        }
-        dprintf(out, "\n");
-    }
-}
-
-void addConfigStatsToProto(const ConfigStats& configStats, ProtoOutputStream* proto) {
-    uint64_t token =
-            proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_CONFIG_STATS);
-    proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_UID, configStats.uid);
-    proto->write(FIELD_TYPE_INT64 | FIELD_ID_CONFIG_STATS_ID, (long long)configStats.id);
-    proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_CREATION, configStats.creation_time_sec);
-    if (configStats.reset_time_sec != 0) {
-        proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_RESET, configStats.reset_time_sec);
-    }
-    if (configStats.deletion_time_sec != 0) {
-        proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_DELETION,
-                     configStats.deletion_time_sec);
-    }
-    proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_METRIC_COUNT, configStats.metric_count);
-    proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_CONDITION_COUNT,
-                 configStats.condition_count);
-    proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_MATCHER_COUNT, configStats.matcher_count);
-    proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_ALERT_COUNT, configStats.alert_count);
-    proto->write(FIELD_TYPE_BOOL | FIELD_ID_CONFIG_STATS_VALID, configStats.is_valid);
-
-    for (const auto& broadcast : configStats.broadcast_sent_time_sec) {
-        proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_BROADCAST | FIELD_COUNT_REPEATED,
-                     broadcast);
-    }
-
-    for (const auto& activation : configStats.activation_time_sec) {
-        proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_ACTIVATION | FIELD_COUNT_REPEATED,
-                     activation);
-    }
-
-    for (const auto& deactivation : configStats.deactivation_time_sec) {
-        proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_DEACTIVATION | FIELD_COUNT_REPEATED,
-                     deactivation);
-    }
-
-    for (const auto& drop_time : configStats.data_drop_time_sec) {
-        proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_DATA_DROP_TIME | FIELD_COUNT_REPEATED,
-                     drop_time);
-    }
-
-    for (const auto& drop_bytes : configStats.data_drop_bytes) {
-        proto->write(
-                FIELD_TYPE_INT64 | FIELD_ID_CONFIG_STATS_DATA_DROP_BYTES | FIELD_COUNT_REPEATED,
-                (long long)drop_bytes);
-    }
-
-    for (const auto& dump : configStats.dump_report_stats) {
-        proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_DUMP_REPORT_TIME |
-                     FIELD_COUNT_REPEATED,
-                     dump.first);
-    }
-
-    for (const auto& dump : configStats.dump_report_stats) {
-        proto->write(FIELD_TYPE_INT64 | FIELD_ID_CONFIG_STATS_DUMP_REPORT_BYTES |
-                     FIELD_COUNT_REPEATED,
-                     (long long)dump.second);
-    }
-
-    for (const auto& annotation : configStats.annotations) {
-        uint64_t token = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                      FIELD_ID_CONFIG_STATS_ANNOTATION);
-        proto->write(FIELD_TYPE_INT64 | FIELD_ID_CONFIG_STATS_ANNOTATION_INT64,
-                     (long long)annotation.first);
-        proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_STATS_ANNOTATION_INT32, annotation.second);
-        proto->end(token);
-    }
-
-    for (const auto& pair : configStats.matcher_stats) {
-        uint64_t tmpToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                          FIELD_ID_CONFIG_STATS_MATCHER_STATS);
-        proto->write(FIELD_TYPE_INT64 | FIELD_ID_MATCHER_STATS_ID, (long long)pair.first);
-        proto->write(FIELD_TYPE_INT32 | FIELD_ID_MATCHER_STATS_COUNT, pair.second);
-        proto->end(tmpToken);
-    }
-
-    for (const auto& pair : configStats.condition_stats) {
-        uint64_t tmpToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                          FIELD_ID_CONFIG_STATS_CONDITION_STATS);
-        proto->write(FIELD_TYPE_INT64 | FIELD_ID_CONDITION_STATS_ID, (long long)pair.first);
-        proto->write(FIELD_TYPE_INT32 | FIELD_ID_CONDITION_STATS_COUNT, pair.second);
-        proto->end(tmpToken);
-    }
-
-    for (const auto& pair : configStats.metric_stats) {
-        uint64_t tmpToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                          FIELD_ID_CONFIG_STATS_METRIC_STATS);
-        proto->write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_STATS_ID, (long long)pair.first);
-        proto->write(FIELD_TYPE_INT32 | FIELD_ID_METRIC_STATS_COUNT, pair.second);
-        proto->end(tmpToken);
-    }
-    for (const auto& pair : configStats.metric_dimension_in_condition_stats) {
-        uint64_t tmpToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                         FIELD_ID_CONFIG_STATS_METRIC_DIMENSION_IN_CONDITION_STATS);
-        proto->write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_STATS_ID, (long long)pair.first);
-        proto->write(FIELD_TYPE_INT32 | FIELD_ID_METRIC_STATS_COUNT, pair.second);
-        proto->end(tmpToken);
-    }
-
-    for (const auto& pair : configStats.alert_stats) {
-        uint64_t tmpToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                          FIELD_ID_CONFIG_STATS_ALERT_STATS);
-        proto->write(FIELD_TYPE_INT64 | FIELD_ID_ALERT_STATS_ID, (long long)pair.first);
-        proto->write(FIELD_TYPE_INT32 | FIELD_ID_ALERT_STATS_COUNT, pair.second);
-        proto->end(tmpToken);
-    }
-
-    proto->end(token);
-}
-
-void StatsdStats::dumpStats(std::vector<uint8_t>* output, bool reset) {
-    lock_guard<std::mutex> lock(mLock);
-
-    ProtoOutputStream proto;
-    proto.write(FIELD_TYPE_INT32 | FIELD_ID_BEGIN_TIME, mStartTimeSec);
-    proto.write(FIELD_TYPE_INT32 | FIELD_ID_END_TIME, (int32_t)getWallClockSec());
-
-    for (const auto& configStats : mIceBox) {
-        addConfigStatsToProto(*configStats, &proto);
-    }
-
-    for (auto& pair : mConfigStats) {
-        addConfigStatsToProto(*(pair.second), &proto);
-    }
-
-    const size_t atomCounts = mPushedAtomStats.size();
-    for (size_t i = 2; i < atomCounts; i++) {
-        if (mPushedAtomStats[i] > 0) {
-            uint64_t token =
-                    proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_ATOM_STATS | FIELD_COUNT_REPEATED);
-            proto.write(FIELD_TYPE_INT32 | FIELD_ID_ATOM_STATS_TAG, (int32_t)i);
-            proto.write(FIELD_TYPE_INT32 | FIELD_ID_ATOM_STATS_COUNT, mPushedAtomStats[i]);
-            int errors = getPushedAtomErrors(i);
-            if (errors > 0) {
-                proto.write(FIELD_TYPE_INT32 | FIELD_ID_ATOM_STATS_ERROR_COUNT, errors);
-            }
-            proto.end(token);
-        }
-    }
-
-    for (const auto& pair : mNonPlatformPushedAtomStats) {
-        uint64_t token =
-                proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_ATOM_STATS | FIELD_COUNT_REPEATED);
-        proto.write(FIELD_TYPE_INT32 | FIELD_ID_ATOM_STATS_TAG, pair.first);
-        proto.write(FIELD_TYPE_INT32 | FIELD_ID_ATOM_STATS_COUNT, pair.second);
-        int errors = getPushedAtomErrors(pair.first);
-        if (errors > 0) {
-            proto.write(FIELD_TYPE_INT32 | FIELD_ID_ATOM_STATS_ERROR_COUNT, errors);
-        }
-        proto.end(token);
-    }
-
-    for (const auto& pair : mPulledAtomStats) {
-        android::os::statsd::writePullerStatsToStream(pair, &proto);
-    }
-
-    for (const auto& pair : mAtomMetricStats) {
-        android::os::statsd::writeAtomMetricStatsToStream(pair, &proto);
-    }
-
-    if (mAnomalyAlarmRegisteredStats > 0) {
-        uint64_t token = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_ANOMALY_ALARM_STATS);
-        proto.write(FIELD_TYPE_INT32 | FIELD_ID_ANOMALY_ALARMS_REGISTERED,
-                    mAnomalyAlarmRegisteredStats);
-        proto.end(token);
-    }
-
-    if (mPeriodicAlarmRegisteredStats > 0) {
-        uint64_t token = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_PERIODIC_ALARM_STATS);
-        proto.write(FIELD_TYPE_INT32 | FIELD_ID_PERIODIC_ALARMS_REGISTERED,
-                    mPeriodicAlarmRegisteredStats);
-        proto.end(token);
-    }
-
-    uint64_t uidMapToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_UIDMAP_STATS);
-    proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID_MAP_CHANGES, mUidMapStats.changes);
-    proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID_MAP_BYTES_USED, mUidMapStats.bytes_used);
-    proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID_MAP_DROPPED_CHANGES, mUidMapStats.dropped_changes);
-    proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID_MAP_DELETED_APPS, mUidMapStats.deleted_apps);
-    proto.end(uidMapToken);
-
-    for (const auto& error : mLogLossStats) {
-        uint64_t token = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_LOGGER_ERROR_STATS |
-                                      FIELD_COUNT_REPEATED);
-        proto.write(FIELD_TYPE_INT32 | FIELD_ID_LOG_LOSS_STATS_TIME, error.mWallClockSec);
-        proto.write(FIELD_TYPE_INT32 | FIELD_ID_LOG_LOSS_STATS_COUNT, error.mCount);
-        proto.write(FIELD_TYPE_INT32 | FIELD_ID_LOG_LOSS_STATS_ERROR, error.mLastError);
-        proto.write(FIELD_TYPE_INT32 | FIELD_ID_LOG_LOSS_STATS_TAG, error.mLastTag);
-        proto.write(FIELD_TYPE_INT32 | FIELD_ID_LOG_LOSS_STATS_UID, error.mUid);
-        proto.write(FIELD_TYPE_INT32 | FIELD_ID_LOG_LOSS_STATS_PID, error.mPid);
-        proto.end(token);
-    }
-
-    if (mOverflowCount > 0) {
-        uint64_t token = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_OVERFLOW);
-        proto.write(FIELD_TYPE_INT32 | FIELD_ID_OVERFLOW_COUNT, (int32_t)mOverflowCount);
-        proto.write(FIELD_TYPE_INT64 | FIELD_ID_OVERFLOW_MAX_HISTORY,
-                    (long long)mMaxQueueHistoryNs);
-        proto.write(FIELD_TYPE_INT64 | FIELD_ID_OVERFLOW_MIN_HISTORY,
-                    (long long)mMinQueueHistoryNs);
-        proto.end(token);
-    }
-
-    for (const auto& restart : mSystemServerRestartSec) {
-        proto.write(FIELD_TYPE_INT32 | FIELD_ID_SYSTEM_SERVER_RESTART | FIELD_COUNT_REPEATED,
-                    restart);
-    }
-
-    for (const auto& pair: mActivationBroadcastGuardrailStats) {
-        uint64_t token = proto.start(FIELD_TYPE_MESSAGE |
-                                     FIELD_ID_ACTIVATION_BROADCAST_GUARDRAIL |
-                                     FIELD_COUNT_REPEATED);
-        proto.write(FIELD_TYPE_INT32 | FIELD_ID_ACTIVATION_BROADCAST_GUARDRAIL_UID,
-                    (int32_t) pair.first);
-        for (const auto& guardrailHitTime : pair.second) {
-            proto.write(FIELD_TYPE_INT32 | FIELD_ID_ACTIVATION_BROADCAST_GUARDRAIL_TIME |
-                            FIELD_COUNT_REPEATED,
-                        guardrailHitTime);
-        }
-        proto.end(token);
-    }
-
-    output->clear();
-    size_t bufferSize = proto.size();
-    output->resize(bufferSize);
-
-    size_t pos = 0;
-    sp<android::util::ProtoReader> reader = proto.data();
-    while (reader->readBuffer() != NULL) {
-        size_t toRead = reader->currentToRead();
-        std::memcpy(&((*output)[pos]), reader->readBuffer(), toRead);
-        pos += toRead;
-        reader->move(toRead);
-    }
-
-    if (reset) {
-        resetInternalLocked();
-    }
-
-    VLOG("reset=%d, returned proto size %lu", reset, (unsigned long)bufferSize);
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
deleted file mode 100644
index 0050484..0000000
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ /dev/null
@@ -1,678 +0,0 @@
-/*
- * Copyright 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include "config/ConfigKey.h"
-
-#include <gtest/gtest_prod.h>
-#include <log/log_time.h>
-#include <list>
-#include <mutex>
-#include <string>
-#include <vector>
-#include <unordered_map>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-struct ConfigStats {
-    int32_t uid;
-    int64_t id;
-    int32_t creation_time_sec;
-    int32_t deletion_time_sec = 0;
-    int32_t reset_time_sec = 0;
-    int32_t metric_count;
-    int32_t condition_count;
-    int32_t matcher_count;
-    int32_t alert_count;
-    bool is_valid;
-
-    std::list<int32_t> broadcast_sent_time_sec;
-
-    // Times at which this config is activated.
-    std::list<int32_t> activation_time_sec;
-
-    // Times at which this config is deactivated.
-    std::list<int32_t> deactivation_time_sec;
-
-    std::list<int32_t> data_drop_time_sec;
-    // Number of bytes dropped at corresponding time.
-    std::list<int64_t> data_drop_bytes;
-    std::list<std::pair<int32_t, int64_t>> dump_report_stats;
-
-    // Stores how many times a matcher have been matched. The map size is capped by kMaxConfigCount.
-    std::map<const int64_t, int> matcher_stats;
-
-    // Stores the number of output tuple of condition trackers when it's bigger than
-    // kDimensionKeySizeSoftLimit. When you see the number is kDimensionKeySizeHardLimit +1,
-    // it means some data has been dropped. The map size is capped by kMaxConfigCount.
-    std::map<const int64_t, int> condition_stats;
-
-    // Stores the number of output tuple of metric producers when it's bigger than
-    // kDimensionKeySizeSoftLimit. When you see the number is kDimensionKeySizeHardLimit +1,
-    // it means some data has been dropped. The map size is capped by kMaxConfigCount.
-    std::map<const int64_t, int> metric_stats;
-
-    // Stores the max number of output tuple of dimensions in condition across dimensions in what
-    // when it's bigger than kDimensionKeySizeSoftLimit. When you see the number is
-    // kDimensionKeySizeHardLimit +1, it means some data has been dropped. The map size is capped by
-    // kMaxConfigCount.
-    std::map<const int64_t, int> metric_dimension_in_condition_stats;
-
-    // Stores the number of times an anomaly detection alert has been declared.
-    // The map size is capped by kMaxConfigCount.
-    std::map<const int64_t, int> alert_stats;
-
-    // Stores the config ID for each sub-config used.
-    std::list<std::pair<const int64_t, const int32_t>> annotations;
-};
-
-struct UidMapStats {
-    int32_t changes;
-    int32_t bytes_used;
-    int32_t dropped_changes;
-    int32_t deleted_apps = 0;
-};
-
-// Keeps track of stats of statsd.
-// Single instance shared across the process. All public methods are thread safe.
-class StatsdStats {
-public:
-    static StatsdStats& getInstance();
-    ~StatsdStats(){};
-
-    const static int kDimensionKeySizeSoftLimit = 500;
-    const static int kDimensionKeySizeHardLimit = 800;
-
-    // Per atom dimension key size limit
-    static const std::map<int, std::pair<size_t, size_t>> kAtomDimensionKeySizeLimitMap;
-
-    const static int kMaxConfigCountPerUid = 20;
-    const static int kMaxAlertCountPerConfig = 100;
-    const static int kMaxConditionCountPerConfig = 300;
-    const static int kMaxMetricCountPerConfig = 1000;
-    const static int kMaxMatcherCountPerConfig = 800;
-
-    // The max number of old config stats we keep.
-    const static int kMaxIceBoxSize = 20;
-
-    const static int kMaxLoggerErrors = 20;
-
-    const static int kMaxSystemServerRestarts = 20;
-
-    const static int kMaxTimestampCount = 20;
-
-    const static int kMaxLogSourceCount = 50;
-
-    const static int kMaxPullAtomPackages = 100;
-
-    // Max memory allowed for storing metrics per configuration. If this limit is exceeded, statsd
-    // drops the metrics data in memory.
-    static const size_t kMaxMetricsBytesPerConfig = 2 * 1024 * 1024;
-
-    // Soft memory limit per configuration. Once this limit is exceeded, we begin notifying the
-    // data subscriber that it's time to call getData.
-    static const size_t kBytesPerConfigTriggerGetData = 192 * 1024;
-
-    // Cap the UID map's memory usage to this. This should be fairly high since the UID information
-    // is critical for understanding the metrics.
-    const static size_t kMaxBytesUsedUidMap = 50 * 1024;
-
-    // The number of deleted apps that are stored in the uid map.
-    const static int kMaxDeletedAppsInUidMap = 100;
-
-    /* Minimum period between two broadcasts in nanoseconds. */
-    static const int64_t kMinBroadcastPeriodNs = 60 * NS_PER_SEC;
-
-    /* Min period between two checks of byte size per config key in nanoseconds. */
-    static const int64_t kMinByteSizeCheckPeriodNs = 60 * NS_PER_SEC;
-
-    /* Minimum period between two activation broadcasts in nanoseconds. */
-    static const int64_t kMinActivationBroadcastPeriodNs = 10 * NS_PER_SEC;
-
-    // Maximum age (30 days) that files on disk can exist in seconds.
-    static const int kMaxAgeSecond = 60 * 60 * 24 * 30;
-
-    // Maximum age (2 days) that local history files on disk can exist in seconds.
-    static const int kMaxLocalHistoryAgeSecond = 60 * 60 * 24 * 2;
-
-    // Maximum number of files (1000) that can be in stats directory on disk.
-    static const int kMaxFileNumber = 1000;
-
-    // Maximum size of all files that can be written to stats directory on disk.
-    static const int kMaxFileSize = 50 * 1024 * 1024;
-
-    // How long to try to clear puller cache from last time
-    static const long kPullerCacheClearIntervalSec = 1;
-
-    // Max time to do a pull.
-    static const int64_t kPullMaxDelayNs = 30 * NS_PER_SEC;
-
-    // Maximum number of pushed atoms statsd stats will track above kMaxPushedAtomId.
-    static const int kMaxNonPlatformPushedAtoms = 100;
-
-    // Maximum atom id value that we consider a platform pushed atom.
-    // This should be updated once highest pushed atom id in atoms.proto approaches this value.
-    static const int kMaxPushedAtomId = 500;
-
-    // Atom id that is the start of the pulled atoms.
-    static const int kPullAtomStartTag = 10000;
-
-    // Atom id that is the start of vendor atoms.
-    static const int kVendorAtomStartTag = 100000;
-
-    // Vendor pulled atom start id.
-    static const int32_t kVendorPulledAtomStartTag = 150000;
-
-    // Beginning of range for timestamp truncation.
-    static const int32_t kTimestampTruncationStartTag = 300000;
-
-    // End of range for timestamp truncation.
-    static const int32_t kTimestampTruncationEndTag = 304999;
-
-    // Max accepted atom id.
-    static const int32_t kMaxAtomTag = 200000;
-
-    static const int64_t kInt64Max = 0x7fffffffffffffffLL;
-
-    static const int32_t kMaxLoggedBucketDropEvents = 10;
-
-    /**
-     * Report a new config has been received and report the static stats about the config.
-     *
-     * The static stats include: the count of metrics, conditions, matchers, and alerts.
-     * If the config is not valid, this config stats will be put into icebox immediately.
-     */
-    void noteConfigReceived(const ConfigKey& key, int metricsCount, int conditionsCount,
-                            int matchersCount, int alertCount,
-                            const std::list<std::pair<const int64_t, const int32_t>>& annotations,
-                            bool isValid);
-    /**
-     * Report a config has been removed.
-     */
-    void noteConfigRemoved(const ConfigKey& key);
-    /**
-     * Report a config has been reset when ttl expires.
-     */
-    void noteConfigReset(const ConfigKey& key);
-
-    /**
-     * Report a broadcast has been sent to a config owner to collect the data.
-     */
-    void noteBroadcastSent(const ConfigKey& key);
-
-    /**
-     * Report that a config has become activated or deactivated.
-     * This can be different from whether or not a broadcast is sent if the
-     * guardrail prevented the broadcast from being sent.
-     */
-    void noteActiveStatusChanged(const ConfigKey& key, bool activate);
-
-    /**
-     * Report a config's metrics data has been dropped.
-     */
-    void noteDataDropped(const ConfigKey& key, const size_t totalBytes);
-
-    /**
-     * Report metrics data report has been sent.
-     *
-     * The report may be requested via StatsManager API, or through adb cmd.
-     */
-    void noteMetricsReportSent(const ConfigKey& key, const size_t num_bytes);
-
-    /**
-     * Report the size of output tuple of a condition.
-     *
-     * Note: only report when the condition has an output dimension, and the tuple
-     * count > kDimensionKeySizeSoftLimit.
-     *
-     * [key]: The config key that this condition belongs to.
-     * [id]: The id of the condition.
-     * [size]: The output tuple size.
-     */
-    void noteConditionDimensionSize(const ConfigKey& key, const int64_t& id, int size);
-
-    /**
-     * Report the size of output tuple of a metric.
-     *
-     * Note: only report when the metric has an output dimension, and the tuple
-     * count > kDimensionKeySizeSoftLimit.
-     *
-     * [key]: The config key that this metric belongs to.
-     * [id]: The id of the metric.
-     * [size]: The output tuple size.
-     */
-    void noteMetricDimensionSize(const ConfigKey& key, const int64_t& id, int size);
-
-    /**
-     * Report the max size of output tuple of dimension in condition across dimensions in what.
-     *
-     * Note: only report when the metric has an output dimension in condition, and the max tuple
-     * count > kDimensionKeySizeSoftLimit.
-     *
-     * [key]: The config key that this metric belongs to.
-     * [id]: The id of the metric.
-     * [size]: The output tuple size.
-     */
-    void noteMetricDimensionInConditionSize(const ConfigKey& key, const int64_t& id, int size);
-
-    /**
-     * Report a matcher has been matched.
-     *
-     * [key]: The config key that this matcher belongs to.
-     * [id]: The id of the matcher.
-     */
-    void noteMatcherMatched(const ConfigKey& key, const int64_t& id);
-
-    /**
-     * Report that an anomaly detection alert has been declared.
-     *
-     * [key]: The config key that this alert belongs to.
-     * [id]: The id of the alert.
-     */
-    void noteAnomalyDeclared(const ConfigKey& key, const int64_t& id);
-
-    /**
-     * Report an atom event has been logged.
-     */
-    void noteAtomLogged(int atomId, int32_t timeSec);
-
-    /**
-     * Report that statsd modified the anomaly alarm registered with StatsCompanionService.
-     */
-    void noteRegisteredAnomalyAlarmChanged();
-
-    /**
-     * Report that statsd modified the periodic alarm registered with StatsCompanionService.
-     */
-    void noteRegisteredPeriodicAlarmChanged();
-
-    /**
-     * Records the number of delta entries that are being dropped from the uid map.
-     */
-    void noteUidMapDropped(int deltas);
-
-    /**
-     * Records that an app was deleted (from statsd's map).
-     */
-    void noteUidMapAppDeletionDropped();
-
-    /**
-     * Updates the number of changes currently stored in the uid map.
-     */
-    void setUidMapChanges(int changes);
-    void setCurrentUidMapMemory(int bytes);
-
-    /*
-     * Updates minimum interval between pulls for an pulled atom.
-     */
-    void updateMinPullIntervalSec(int pullAtomId, long intervalSec);
-
-    /*
-     * Notes an atom is pulled.
-     */
-    void notePull(int pullAtomId);
-
-    /*
-     * Notes an atom is served from puller cache.
-     */
-    void notePullFromCache(int pullAtomId);
-
-    /*
-     * Notify data error for pulled atom.
-     */
-    void notePullDataError(int pullAtomId);
-
-    /*
-     * Records time for actual pulling, not including those served from cache and not including
-     * statsd processing delays.
-     */
-    void notePullTime(int pullAtomId, int64_t pullTimeNs);
-
-    /*
-     * Records pull delay for a pulled atom, including those served from cache and including statsd
-     * processing delays.
-     */
-    void notePullDelay(int pullAtomId, int64_t pullDelayNs);
-
-    /*
-     * Records pull exceeds timeout for the puller.
-     */
-    void notePullTimeout(int pullAtomId, int64_t pullUptimeMillis, int64_t pullElapsedMillis);
-
-    /*
-     * Records pull exceeds max delay for a metric.
-     */
-    void notePullExceedMaxDelay(int pullAtomId);
-
-    /*
-     * Records when system server restarts.
-     */
-    void noteSystemServerRestart(int32_t timeSec);
-
-    /**
-     * Records statsd skipped an event.
-     */
-    void noteLogLost(int32_t wallClockTimeSec, int32_t count, int32_t lastError,
-                     int32_t lastAtomTag, int32_t uid, int32_t pid);
-
-    /**
-     * Records that the pull of an atom has failed. Eg, if the client indicated the pull failed, if
-     * the pull timed out, or if the outgoing binder call failed.
-     * This count will only increment if the puller was actually invoked.
-     *
-     * It does not include a pull not occurring due to not finding the appropriate
-     * puller. These cases are covered in other counts.
-     */
-    void notePullFailed(int atomId);
-
-    /**
-     * Records that the pull of an atom has failed due to not having a uid provider.
-     */
-    void notePullUidProviderNotFound(int atomId);
-
-    /**
-     * Records that the pull of an atom has failed due not finding a puller registered by a
-     * trusted uid.
-     */
-    void notePullerNotFound(int atomId);
-
-    /**
-     * Records that the pull has failed due to the outgoing binder call failing.
-     */
-    void notePullBinderCallFailed(int atomId);
-
-    /**
-     * A pull with no data occurred
-     */
-    void noteEmptyData(int atomId);
-
-    /**
-     * Records that a puller callback for the given atomId was registered or unregistered.
-     *
-     * @param registered True if the callback was registered, false if was unregistered.
-     */
-    void notePullerCallbackRegistrationChanged(int atomId, bool registered);
-
-    /**
-     * Hard limit was reached in the cardinality of an atom
-     */
-    void noteHardDimensionLimitReached(int64_t metricId);
-
-    /**
-     * A log event was too late, arrived in the wrong bucket and was skipped
-     */
-    void noteLateLogEventSkipped(int64_t metricId);
-
-    /**
-     * Buckets were skipped as time elapsed without any data for them
-     */
-    void noteSkippedForwardBuckets(int64_t metricId);
-
-    /**
-     * An unsupported value type was received
-     */
-    void noteBadValueType(int64_t metricId);
-
-    /**
-     * Buckets were dropped due to reclaim memory.
-     */
-    void noteBucketDropped(int64_t metricId);
-
-    /**
-     * A condition change was too late, arrived in the wrong bucket and was skipped
-     */
-    void noteConditionChangeInNextBucket(int64_t metricId);
-
-    /**
-     * A bucket has been tagged as invalid.
-     */
-    void noteInvalidatedBucket(int64_t metricId);
-
-    /**
-     * Tracks the total number of buckets (include skipped/invalid buckets).
-     */
-    void noteBucketCount(int64_t metricId);
-
-    /**
-     * For pulls at bucket boundaries, it represents the misalignment between the real timestamp and
-     * the end of the bucket.
-     */
-    void noteBucketBoundaryDelayNs(int64_t metricId, int64_t timeDelayNs);
-
-    /**
-     * Number of buckets with unknown condition.
-     */
-    void noteBucketUnknownCondition(int64_t metricId);
-
-    /* Reports one event has been dropped due to queue overflow, and the oldest event timestamp in
-     * the queue */
-    void noteEventQueueOverflow(int64_t oldestEventTimestampNs);
-
-    /**
-     * Reports that the activation broadcast guardrail was hit for this uid. Namely, the broadcast
-     * should have been sent, but instead was skipped due to hitting the guardrail.
-     */
-     void noteActivationBroadcastGuardrailHit(const int uid);
-
-     /**
-      * Reports that an atom is erroneous or cannot be parsed successfully by
-      * statsd. An atom tag of 0 indicates that the client did not supply the
-      * atom id within the encoding.
-      *
-      * For pushed atoms only, this call should be preceded by a call to
-      * noteAtomLogged.
-      */
-     void noteAtomError(int atomTag, bool pull=false);
-
-    /**
-     * Reset the historical stats. Including all stats in icebox, and the tracked stats about
-     * metrics, matchers, and atoms. The active configs will be kept and StatsdStats will continue
-     * to collect stats after reset() has been called.
-     */
-    void reset();
-
-    /**
-     * Output the stats in protobuf binary format to [buffer].
-     *
-     * [reset]: whether to clear the historical stats after the call.
-     */
-    void dumpStats(std::vector<uint8_t>* buffer, bool reset);
-
-    /**
-     * Output statsd stats in human readable format to [out] file descriptor.
-     */
-    void dumpStats(int outFd) const;
-
-    typedef struct PullTimeoutMetadata {
-        int64_t pullTimeoutUptimeMillis;
-        int64_t pullTimeoutElapsedMillis;
-        PullTimeoutMetadata(int64_t uptimeMillis, int64_t elapsedMillis) :
-            pullTimeoutUptimeMillis(uptimeMillis),
-            pullTimeoutElapsedMillis(elapsedMillis) {/* do nothing */}
-    } PullTimeoutMetadata;
-
-    typedef struct {
-        long totalPull = 0;
-        long totalPullFromCache = 0;
-        long minPullIntervalSec = LONG_MAX;
-        int64_t avgPullTimeNs = 0;
-        int64_t maxPullTimeNs = 0;
-        long numPullTime = 0;
-        int64_t avgPullDelayNs = 0;
-        int64_t maxPullDelayNs = 0;
-        long numPullDelay = 0;
-        long dataError = 0;
-        long pullTimeout = 0;
-        long pullExceedMaxDelay = 0;
-        long pullFailed = 0;
-        long pullUidProviderNotFound = 0;
-        long pullerNotFound = 0;
-        long emptyData = 0;
-        long registeredCount = 0;
-        long unregisteredCount = 0;
-        int32_t atomErrorCount = 0;
-        long binderCallFailCount = 0;
-        std::list<PullTimeoutMetadata> pullTimeoutMetadata;
-    } PulledAtomStats;
-
-    typedef struct {
-        long hardDimensionLimitReached = 0;
-        long lateLogEventSkipped = 0;
-        long skippedForwardBuckets = 0;
-        long badValueType = 0;
-        long conditionChangeInNextBucket = 0;
-        long invalidatedBucket = 0;
-        long bucketDropped = 0;
-        int64_t minBucketBoundaryDelayNs = 0;
-        int64_t maxBucketBoundaryDelayNs = 0;
-        long bucketUnknownCondition = 0;
-        long bucketCount = 0;
-    } AtomMetricStats;
-
-private:
-    StatsdStats();
-
-    mutable std::mutex mLock;
-
-    int32_t mStartTimeSec;
-
-    // Track the number of dropped entries used by the uid map.
-    UidMapStats mUidMapStats;
-
-    // The stats about the configs that are still in use.
-    // The map size is capped by kMaxConfigCount.
-    std::map<const ConfigKey, std::shared_ptr<ConfigStats>> mConfigStats;
-
-    // Stores the stats for the configs that are no longer in use.
-    // The size of the vector is capped by kMaxIceBoxSize.
-    std::list<const std::shared_ptr<ConfigStats>> mIceBox;
-
-    // Stores the number of times a pushed atom is logged.
-    // The size of the vector is the largest pushed atom id in atoms.proto + 1. Atoms
-    // out of that range will be put in mNonPlatformPushedAtomStats.
-    // This is a vector, not a map because it will be accessed A LOT -- for each stats log.
-    std::vector<int> mPushedAtomStats;
-
-    // Stores the number of times a pushed atom is logged for atom ids above kMaxPushedAtomId.
-    // The max size of the map is kMaxNonPlatformPushedAtoms.
-    std::unordered_map<int, int> mNonPlatformPushedAtomStats;
-
-    // Maps PullAtomId to its stats. The size is capped by the puller atom counts.
-    std::map<int, PulledAtomStats> mPulledAtomStats;
-
-    // Stores the number of times a pushed atom was logged erroneously. The
-    // corresponding counts for pulled atoms are stored in PulledAtomStats.
-    // The max size of this map is kMaxAtomErrorsStatsSize.
-    std::map<int, int> mPushedAtomErrorStats;
-    int kMaxPushedAtomErrorStatsSize = 100;
-
-    // Maps metric ID to its stats. The size is capped by the number of metrics.
-    std::map<int64_t, AtomMetricStats> mAtomMetricStats;
-
-    // Maps uids to times when the activation changed broadcast not sent due to hitting the
-    // guardrail. The size is capped by the number of configs, and up to 20 times per uid.
-    std::map<int, std::list<int32_t>> mActivationBroadcastGuardrailStats;
-
-    struct LogLossStats {
-        LogLossStats(int32_t sec, int32_t count, int32_t error, int32_t tag, int32_t uid,
-                     int32_t pid)
-            : mWallClockSec(sec),
-              mCount(count),
-              mLastError(error),
-              mLastTag(tag),
-              mUid(uid),
-              mPid(pid) {
-        }
-        int32_t mWallClockSec;
-        int32_t mCount;
-        // error code defined in linux/errno.h
-        int32_t mLastError;
-        int32_t mLastTag;
-        int32_t mUid;
-        int32_t mPid;
-    };
-
-    // Max of {(now - oldestEventTimestamp) when overflow happens}.
-    // This number is helpful to understand how SLOW statsd can be.
-    int64_t mMaxQueueHistoryNs = 0;
-
-    // Min of {(now - oldestEventTimestamp) when overflow happens}.
-    // This number is helpful to understand how FAST the events floods to statsd.
-    int64_t mMinQueueHistoryNs = kInt64Max;
-
-    // Total number of events that are lost due to queue overflow.
-    int32_t mOverflowCount = 0;
-
-    // Timestamps when we detect log loss, and the number of logs lost.
-    std::list<LogLossStats> mLogLossStats;
-
-    std::list<int32_t> mSystemServerRestartSec;
-
-    // Stores the number of times statsd modified the anomaly alarm registered with
-    // StatsCompanionService.
-    int mAnomalyAlarmRegisteredStats = 0;
-
-    // Stores the number of times statsd registers the periodic alarm changes
-    int mPeriodicAlarmRegisteredStats = 0;
-
-    void noteConfigResetInternalLocked(const ConfigKey& key);
-
-    void noteConfigRemovedInternalLocked(const ConfigKey& key);
-
-    void resetInternalLocked();
-
-    void noteDataDropped(const ConfigKey& key, const size_t totalBytes, int32_t timeSec);
-
-    void noteMetricsReportSent(const ConfigKey& key, const size_t num_bytes, int32_t timeSec);
-
-    void noteBroadcastSent(const ConfigKey& key, int32_t timeSec);
-
-    void noteActiveStatusChanged(const ConfigKey& key, bool activate, int32_t timeSec);
-
-    void noteActivationBroadcastGuardrailHit(const int uid, int32_t timeSec);
-
-    void addToIceBoxLocked(std::shared_ptr<ConfigStats>& stats);
-
-    int getPushedAtomErrors(int atomId) const;
-
-    /**
-     * Get a reference to AtomMetricStats for a metric. If none exists, create it. The reference
-     * will live as long as `this`.
-     */
-    StatsdStats::AtomMetricStats& getAtomMetricStats(int64_t metricId);
-
-    FRIEND_TEST(StatsdStatsTest, TestValidConfigAdd);
-    FRIEND_TEST(StatsdStatsTest, TestInvalidConfigAdd);
-    FRIEND_TEST(StatsdStatsTest, TestConfigRemove);
-    FRIEND_TEST(StatsdStatsTest, TestSubStats);
-    FRIEND_TEST(StatsdStatsTest, TestAtomLog);
-    FRIEND_TEST(StatsdStatsTest, TestNonPlatformAtomLog);
-    FRIEND_TEST(StatsdStatsTest, TestTimestampThreshold);
-    FRIEND_TEST(StatsdStatsTest, TestAnomalyMonitor);
-    FRIEND_TEST(StatsdStatsTest, TestSystemServerCrash);
-    FRIEND_TEST(StatsdStatsTest, TestPullAtomStats);
-    FRIEND_TEST(StatsdStatsTest, TestAtomMetricsStats);
-    FRIEND_TEST(StatsdStatsTest, TestActivationBroadcastGuardrailHit);
-    FRIEND_TEST(StatsdStatsTest, TestAtomErrorStats);
-
-    FRIEND_TEST(StatsLogProcessorTest, InvalidConfigRemoved);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/hash.cpp b/cmds/statsd/src/hash.cpp
deleted file mode 100644
index 543a748..0000000
--- a/cmds/statsd/src/hash.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "hash.h"
-
-#ifndef FALLTHROUGH_INTENDED
-#define FALLTHROUGH_INTENDED [[fallthrough]]
-#endif
-
-namespace android {
-namespace os {
-namespace statsd {
-
-namespace {
-// Lower-level versions of Get... that read directly from a character buffer
-// without any bounds checking.
-inline uint32_t DecodeFixed32(const char *ptr) {
-  return ((static_cast<uint32_t>(static_cast<unsigned char>(ptr[0]))) |
-          (static_cast<uint32_t>(static_cast<unsigned char>(ptr[1])) << 8) |
-          (static_cast<uint32_t>(static_cast<unsigned char>(ptr[2])) << 16) |
-          (static_cast<uint32_t>(static_cast<unsigned char>(ptr[3])) << 24));
-}
-
-inline uint64_t DecodeFixed64(const char* ptr) {
-    uint64_t lo = DecodeFixed32(ptr);
-    uint64_t hi = DecodeFixed32(ptr + 4);
-    return (hi << 32) | lo;
-}
-
-// 0xff is in case char is signed.
-static inline uint32_t ByteAs32(char c) { return static_cast<uint32_t>(c) & 0xff; }
-static inline uint64_t ByteAs64(char c) { return static_cast<uint64_t>(c) & 0xff; }
-
-}  // namespace
-
-uint32_t Hash32(const char *data, size_t n, uint32_t seed) {
-  // 'm' and 'r' are mixing constants generated offline.
-  // They're not really 'magic', they just happen to work well.
-  const uint32_t m = 0x5bd1e995;
-  const int r = 24;
-
-  // Initialize the hash to a 'random' value
-  uint32_t h = static_cast<uint32_t>(seed ^ n);
-
-  // Mix 4 bytes at a time into the hash
-  while (n >= 4) {
-    uint32_t k = DecodeFixed32(data);
-    k *= m;
-    k ^= k >> r;
-    k *= m;
-    h *= m;
-    h ^= k;
-    data += 4;
-    n -= 4;
-  }
-
-  // Handle the last few bytes of the input array
-  switch (n) {
-    case 3:
-      h ^= ByteAs32(data[2]) << 16;
-      FALLTHROUGH_INTENDED;
-    case 2:
-      h ^= ByteAs32(data[1]) << 8;
-      FALLTHROUGH_INTENDED;
-    case 1:
-      h ^= ByteAs32(data[0]);
-      h *= m;
-  }
-
-  // Do a few final mixes of the hash to ensure the last few
-  // bytes are well-incorporated.
-  h ^= h >> 13;
-  h *= m;
-  h ^= h >> 15;
-  return h;
-}
-
-uint64_t Hash64(const char* data, size_t n, uint64_t seed) {
-  const uint64_t m = 0xc6a4a7935bd1e995;
-  const int r = 47;
-
-  uint64_t h = seed ^ (n * m);
-
-  while (n >= 8) {
-    uint64_t k = DecodeFixed64(data);
-    data += 8;
-    n -= 8;
-
-    k *= m;
-    k ^= k >> r;
-    k *= m;
-
-    h ^= k;
-    h *= m;
-  }
-
-  switch (n) {
-    case 7:
-      h ^= ByteAs64(data[6]) << 48;
-      FALLTHROUGH_INTENDED;
-    case 6:
-      h ^= ByteAs64(data[5]) << 40;
-      FALLTHROUGH_INTENDED;
-    case 5:
-      h ^= ByteAs64(data[4]) << 32;
-      FALLTHROUGH_INTENDED;
-    case 4:
-      h ^= ByteAs64(data[3]) << 24;
-      FALLTHROUGH_INTENDED;
-    case 3:
-      h ^= ByteAs64(data[2]) << 16;
-      FALLTHROUGH_INTENDED;
-    case 2:
-      h ^= ByteAs64(data[1]) << 8;
-      FALLTHROUGH_INTENDED;
-    case 1:
-      h ^= ByteAs64(data[0]);
-      h *= m;
-  }
-
-  h ^= h >> r;
-  h *= m;
-  h ^= h >> r;
-
-  return h;
-}
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/hash.h b/cmds/statsd/src/hash.h
deleted file mode 100644
index bd6b0cd..0000000
--- a/cmds/statsd/src/hash.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <string>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// Uses murmur2 hashing algorithm.
-extern uint32_t Hash32(const char *data, size_t n, uint32_t seed);
-extern uint64_t Hash64(const char* data, size_t n, uint64_t seed);
-
-inline uint32_t Hash32(const char *data, size_t n) {
-  return Hash32(data, n, 0xBEEF);
-}
-
-inline uint32_t Hash32(const std::string &input) {
-  return Hash32(input.data(), input.size());
-}
-
-inline uint64_t Hash64(const char* data, size_t n) {
-  return Hash64(data, n, 0xDECAFCAFFE);
-}
-
-inline uint64_t Hash64(const std::string& str) {
-  return Hash64(str.data(), str.size());
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
deleted file mode 100644
index f56fa62..0000000
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ /dev/null
@@ -1,599 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "logd/LogEvent.h"
-
-#include <android-base/stringprintf.h>
-#include <android/binder_ibinder.h>
-#include <private/android_filesystem_config.h>
-
-#include "annotations.h"
-#include "stats_log_util.h"
-#include "statslog_statsd.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// for TrainInfo experiment id serialization
-const int FIELD_ID_EXPERIMENT_ID = 1;
-
-using namespace android::util;
-using android::base::StringPrintf;
-using android::util::ProtoOutputStream;
-using std::string;
-using std::vector;
-
-// stats_event.h socket types. Keep in sync.
-/* ERRORS */
-#define ERROR_NO_TIMESTAMP 0x1
-#define ERROR_NO_ATOM_ID 0x2
-#define ERROR_OVERFLOW 0x4
-#define ERROR_ATTRIBUTION_CHAIN_TOO_LONG 0x8
-#define ERROR_TOO_MANY_KEY_VALUE_PAIRS 0x10
-#define ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD 0x20
-#define ERROR_INVALID_ANNOTATION_ID 0x40
-#define ERROR_ANNOTATION_ID_TOO_LARGE 0x80
-#define ERROR_TOO_MANY_ANNOTATIONS 0x100
-#define ERROR_TOO_MANY_FIELDS 0x200
-#define ERROR_INVALID_VALUE_TYPE 0x400
-#define ERROR_STRING_NOT_NULL_TERMINATED 0x800
-
-/* TYPE IDS */
-#define INT32_TYPE 0x00
-#define INT64_TYPE 0x01
-#define STRING_TYPE 0x02
-#define LIST_TYPE 0x03
-#define FLOAT_TYPE 0x04
-#define BOOL_TYPE 0x05
-#define BYTE_ARRAY_TYPE 0x06
-#define OBJECT_TYPE 0x07
-#define KEY_VALUE_PAIRS_TYPE 0x08
-#define ATTRIBUTION_CHAIN_TYPE 0x09
-#define ERROR_TYPE 0x0F
-
-LogEvent::LogEvent(int32_t uid, int32_t pid)
-    : mLogdTimestampNs(time(nullptr)), mLogUid(uid), mLogPid(pid) {
-}
-
-LogEvent::LogEvent(const string& trainName, int64_t trainVersionCode, bool requiresStaging,
-                   bool rollbackEnabled, bool requiresLowLatencyMonitor, int32_t state,
-                   const std::vector<uint8_t>& experimentIds, int32_t userId) {
-    mLogdTimestampNs = getWallClockNs();
-    mElapsedTimestampNs = getElapsedRealtimeNs();
-    mTagId = util::BINARY_PUSH_STATE_CHANGED;
-    mLogUid = AIBinder_getCallingUid();
-    mLogPid = AIBinder_getCallingPid();
-
-    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(1)), Value(trainName)));
-    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(trainVersionCode)));
-    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(3)), Value((int)requiresStaging)));
-    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(4)), Value((int)rollbackEnabled)));
-    mValues.push_back(
-            FieldValue(Field(mTagId, getSimpleField(5)), Value((int)requiresLowLatencyMonitor)));
-    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(6)), Value(state)));
-    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(7)), Value(experimentIds)));
-    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(8)), Value(userId)));
-}
-
-LogEvent::LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
-                   const InstallTrainInfo& trainInfo) {
-    mLogdTimestampNs = wallClockTimestampNs;
-    mElapsedTimestampNs = elapsedTimestampNs;
-    mTagId = util::TRAIN_INFO;
-
-    mValues.push_back(
-            FieldValue(Field(mTagId, getSimpleField(1)), Value(trainInfo.trainVersionCode)));
-    std::vector<uint8_t> experimentIdsProto;
-    writeExperimentIdsToProto(trainInfo.experimentIds, &experimentIdsProto);
-    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(experimentIdsProto)));
-    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(3)), Value(trainInfo.trainName)));
-    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(4)), Value(trainInfo.status)));
-}
-
-void LogEvent::parseInt32(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
-    int32_t value = readNextValue<int32_t>();
-    addToValues(pos, depth, value, last);
-    parseAnnotations(numAnnotations);
-}
-
-void LogEvent::parseInt64(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
-    int64_t value = readNextValue<int64_t>();
-    addToValues(pos, depth, value, last);
-    parseAnnotations(numAnnotations);
-}
-
-void LogEvent::parseString(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
-    int32_t numBytes = readNextValue<int32_t>();
-    if ((uint32_t)numBytes > mRemainingLen) {
-        mValid = false;
-        return;
-    }
-
-    string value = string((char*)mBuf, numBytes);
-    mBuf += numBytes;
-    mRemainingLen -= numBytes;
-    addToValues(pos, depth, value, last);
-    parseAnnotations(numAnnotations);
-}
-
-void LogEvent::parseFloat(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
-    float value = readNextValue<float>();
-    addToValues(pos, depth, value, last);
-    parseAnnotations(numAnnotations);
-}
-
-void LogEvent::parseBool(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
-    // cast to int32_t because FieldValue does not support bools
-    int32_t value = (int32_t)readNextValue<uint8_t>();
-    addToValues(pos, depth, value, last);
-    parseAnnotations(numAnnotations);
-}
-
-void LogEvent::parseByteArray(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
-    int32_t numBytes = readNextValue<int32_t>();
-    if ((uint32_t)numBytes > mRemainingLen) {
-        mValid = false;
-        return;
-    }
-
-    vector<uint8_t> value(mBuf, mBuf + numBytes);
-    mBuf += numBytes;
-    mRemainingLen -= numBytes;
-    addToValues(pos, depth, value, last);
-    parseAnnotations(numAnnotations);
-}
-
-void LogEvent::parseKeyValuePairs(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations) {
-    int32_t numPairs = readNextValue<uint8_t>();
-
-    for (pos[1] = 1; pos[1] <= numPairs; pos[1]++) {
-        last[1] = (pos[1] == numPairs);
-
-        // parse key
-        pos[2] = 1;
-        parseInt32(pos, /*depth=*/2, last, /*numAnnotations=*/0);
-
-        // parse value
-        last[2] = true;
-
-        uint8_t typeInfo = readNextValue<uint8_t>();
-        switch (getTypeId(typeInfo)) {
-            case INT32_TYPE:
-                pos[2] = 2;  // pos[2] determined by index of type in KeyValuePair in atoms.proto
-                parseInt32(pos, /*depth=*/2, last, /*numAnnotations=*/0);
-                break;
-            case INT64_TYPE:
-                pos[2] = 3;
-                parseInt64(pos, /*depth=*/2, last, /*numAnnotations=*/0);
-                break;
-            case STRING_TYPE:
-                pos[2] = 4;
-                parseString(pos, /*depth=*/2, last, /*numAnnotations=*/0);
-                break;
-            case FLOAT_TYPE:
-                pos[2] = 5;
-                parseFloat(pos, /*depth=*/2, last, /*numAnnotations=*/0);
-                break;
-            default:
-                mValid = false;
-        }
-    }
-
-    parseAnnotations(numAnnotations);
-
-    pos[1] = pos[2] = 1;
-    last[1] = last[2] = false;
-}
-
-void LogEvent::parseAttributionChain(int32_t* pos, int32_t depth, bool* last,
-                                     uint8_t numAnnotations) {
-    const unsigned int firstUidInChainIndex = mValues.size();
-    const int32_t numNodes = readNextValue<uint8_t>();
-    for (pos[1] = 1; pos[1] <= numNodes; pos[1]++) {
-        last[1] = (pos[1] == numNodes);
-
-        // parse uid
-        pos[2] = 1;
-        parseInt32(pos, /*depth=*/2, last, /*numAnnotations=*/0);
-
-        // parse tag
-        pos[2] = 2;
-        last[2] = true;
-        parseString(pos, /*depth=*/2, last, /*numAnnotations=*/0);
-    }
-    // Check if at least one node was successfully parsed.
-    if (mValues.size() - 1 > firstUidInChainIndex) {
-        mAttributionChainStartIndex = static_cast<int8_t>(firstUidInChainIndex);
-        mAttributionChainEndIndex = static_cast<int8_t>(mValues.size() - 1);
-    }
-
-    parseAnnotations(numAnnotations, firstUidInChainIndex);
-
-    pos[1] = pos[2] = 1;
-    last[1] = last[2] = false;
-}
-
-// Assumes that mValues is not empty
-bool LogEvent::checkPreviousValueType(Type expected) {
-    return mValues[mValues.size() - 1].mValue.getType() == expected;
-}
-
-void LogEvent::parseIsUidAnnotation(uint8_t annotationType) {
-    if (mValues.empty() || !checkPreviousValueType(INT) || annotationType != BOOL_TYPE) {
-        mValid = false;
-        return;
-    }
-
-    bool isUid = readNextValue<uint8_t>();
-    if (isUid) mUidFieldIndex = static_cast<int8_t>(mValues.size() - 1);
-    mValues[mValues.size() - 1].mAnnotations.setUidField(isUid);
-}
-
-void LogEvent::parseTruncateTimestampAnnotation(uint8_t annotationType) {
-    if (!mValues.empty() || annotationType != BOOL_TYPE) {
-        mValid = false;
-        return;
-    }
-
-    mTruncateTimestamp = readNextValue<uint8_t>();
-}
-
-void LogEvent::parsePrimaryFieldAnnotation(uint8_t annotationType) {
-    if (mValues.empty() || annotationType != BOOL_TYPE) {
-        mValid = false;
-        return;
-    }
-
-    const bool primaryField = readNextValue<uint8_t>();
-    mValues[mValues.size() - 1].mAnnotations.setPrimaryField(primaryField);
-}
-
-void LogEvent::parsePrimaryFieldFirstUidAnnotation(uint8_t annotationType,
-                                                   int firstUidInChainIndex) {
-    if (mValues.empty() || annotationType != BOOL_TYPE || -1 == firstUidInChainIndex) {
-        mValid = false;
-        return;
-    }
-
-    const bool primaryField = readNextValue<uint8_t>();
-    mValues[firstUidInChainIndex].mAnnotations.setPrimaryField(primaryField);
-}
-
-void LogEvent::parseExclusiveStateAnnotation(uint8_t annotationType) {
-    if (mValues.empty() || annotationType != BOOL_TYPE) {
-        mValid = false;
-        return;
-    }
-
-    const bool exclusiveState = readNextValue<uint8_t>();
-    mExclusiveStateFieldIndex = static_cast<int8_t>(mValues.size() - 1);
-    mValues[getExclusiveStateFieldIndex()].mAnnotations.setExclusiveState(exclusiveState);
-}
-
-void LogEvent::parseTriggerStateResetAnnotation(uint8_t annotationType) {
-    if (mValues.empty() || annotationType != INT32_TYPE) {
-        mValid = false;
-        return;
-    }
-
-    mResetState = readNextValue<int32_t>();
-}
-
-void LogEvent::parseStateNestedAnnotation(uint8_t annotationType) {
-    if (mValues.empty() || annotationType != BOOL_TYPE) {
-        mValid = false;
-        return;
-    }
-
-    bool nested = readNextValue<uint8_t>();
-    mValues[mValues.size() - 1].mAnnotations.setNested(nested);
-}
-
-// firstUidInChainIndex is a default parameter that is only needed when parsing
-// annotations for attribution chains.
-void LogEvent::parseAnnotations(uint8_t numAnnotations, int firstUidInChainIndex) {
-    for (uint8_t i = 0; i < numAnnotations; i++) {
-        uint8_t annotationId = readNextValue<uint8_t>();
-        uint8_t annotationType = readNextValue<uint8_t>();
-
-        switch (annotationId) {
-            case ANNOTATION_ID_IS_UID:
-                parseIsUidAnnotation(annotationType);
-                break;
-            case ANNOTATION_ID_TRUNCATE_TIMESTAMP:
-                parseTruncateTimestampAnnotation(annotationType);
-                break;
-            case ANNOTATION_ID_PRIMARY_FIELD:
-                parsePrimaryFieldAnnotation(annotationType);
-                break;
-            case ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID:
-                parsePrimaryFieldFirstUidAnnotation(annotationType, firstUidInChainIndex);
-                break;
-            case ANNOTATION_ID_EXCLUSIVE_STATE:
-                parseExclusiveStateAnnotation(annotationType);
-                break;
-            case ANNOTATION_ID_TRIGGER_STATE_RESET:
-                parseTriggerStateResetAnnotation(annotationType);
-                break;
-            case ANNOTATION_ID_STATE_NESTED:
-                parseStateNestedAnnotation(annotationType);
-                break;
-            default:
-                mValid = false;
-                return;
-        }
-    }
-}
-
-// This parsing logic is tied to the encoding scheme used in StatsEvent.java and
-// stats_event.c
-bool LogEvent::parseBuffer(uint8_t* buf, size_t len) {
-    mBuf = buf;
-    mRemainingLen = (uint32_t)len;
-
-    int32_t pos[] = {1, 1, 1};
-    bool last[] = {false, false, false};
-
-    // Beginning of buffer is OBJECT_TYPE | NUM_FIELDS | TIMESTAMP | ATOM_ID
-    uint8_t typeInfo = readNextValue<uint8_t>();
-    if (getTypeId(typeInfo) != OBJECT_TYPE) mValid = false;
-
-    uint8_t numElements = readNextValue<uint8_t>();
-    if (numElements < 2 || numElements > 127) mValid = false;
-
-    typeInfo = readNextValue<uint8_t>();
-    if (getTypeId(typeInfo) != INT64_TYPE) mValid = false;
-    mElapsedTimestampNs = readNextValue<int64_t>();
-    numElements--;
-
-    typeInfo = readNextValue<uint8_t>();
-    if (getTypeId(typeInfo) != INT32_TYPE) mValid = false;
-    mTagId = readNextValue<int32_t>();
-    numElements--;
-    parseAnnotations(getNumAnnotations(typeInfo));  // atom-level annotations
-
-    for (pos[0] = 1; pos[0] <= numElements && mValid; pos[0]++) {
-        last[0] = (pos[0] == numElements);
-
-        typeInfo = readNextValue<uint8_t>();
-        uint8_t typeId = getTypeId(typeInfo);
-
-        switch (typeId) {
-            case BOOL_TYPE:
-                parseBool(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
-                break;
-            case INT32_TYPE:
-                parseInt32(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
-                break;
-            case INT64_TYPE:
-                parseInt64(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
-                break;
-            case FLOAT_TYPE:
-                parseFloat(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
-                break;
-            case BYTE_ARRAY_TYPE:
-                parseByteArray(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
-                break;
-            case STRING_TYPE:
-                parseString(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
-                break;
-            case KEY_VALUE_PAIRS_TYPE:
-                parseKeyValuePairs(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
-                break;
-            case ATTRIBUTION_CHAIN_TYPE:
-                parseAttributionChain(pos, /*depth=*/0, last, getNumAnnotations(typeInfo));
-                break;
-            case ERROR_TYPE:
-                /* mErrorBitmask =*/ readNextValue<int32_t>();
-                mValid = false;
-                break;
-            default:
-                mValid = false;
-                break;
-        }
-    }
-
-    if (mRemainingLen != 0) mValid = false;
-    mBuf = nullptr;
-    return mValid;
-}
-
-uint8_t LogEvent::getTypeId(uint8_t typeInfo) {
-    return typeInfo & 0x0F;  // type id in lower 4 bytes
-}
-
-uint8_t LogEvent::getNumAnnotations(uint8_t typeInfo) {
-    return (typeInfo >> 4) & 0x0F;  // num annotations in upper 4 bytes
-}
-
-int64_t LogEvent::GetLong(size_t key, status_t* err) const {
-    // TODO(b/110561208): encapsulate the magical operations in Field struct as static functions
-    int field = getSimpleField(key);
-    for (const auto& value : mValues) {
-        if (value.mField.getField() == field) {
-            if (value.mValue.getType() == LONG) {
-                return value.mValue.long_value;
-            } else if (value.mValue.getType() == INT) {
-                return value.mValue.int_value;
-            } else {
-                *err = BAD_TYPE;
-                return 0;
-            }
-        }
-        if ((size_t)value.mField.getPosAtDepth(0) > key) {
-            break;
-        }
-    }
-
-    *err = BAD_INDEX;
-    return 0;
-}
-
-int LogEvent::GetInt(size_t key, status_t* err) const {
-    int field = getSimpleField(key);
-    for (const auto& value : mValues) {
-        if (value.mField.getField() == field) {
-            if (value.mValue.getType() == INT) {
-                return value.mValue.int_value;
-            } else {
-                *err = BAD_TYPE;
-                return 0;
-            }
-        }
-        if ((size_t)value.mField.getPosAtDepth(0) > key) {
-            break;
-        }
-    }
-
-    *err = BAD_INDEX;
-    return 0;
-}
-
-const char* LogEvent::GetString(size_t key, status_t* err) const {
-    int field = getSimpleField(key);
-    for (const auto& value : mValues) {
-        if (value.mField.getField() == field) {
-            if (value.mValue.getType() == STRING) {
-                return value.mValue.str_value.c_str();
-            } else {
-                *err = BAD_TYPE;
-                return 0;
-            }
-        }
-        if ((size_t)value.mField.getPosAtDepth(0) > key) {
-            break;
-        }
-    }
-
-    *err = BAD_INDEX;
-    return NULL;
-}
-
-bool LogEvent::GetBool(size_t key, status_t* err) const {
-    int field = getSimpleField(key);
-    for (const auto& value : mValues) {
-        if (value.mField.getField() == field) {
-            if (value.mValue.getType() == INT) {
-                return value.mValue.int_value != 0;
-            } else if (value.mValue.getType() == LONG) {
-                return value.mValue.long_value != 0;
-            } else {
-                *err = BAD_TYPE;
-                return false;
-            }
-        }
-        if ((size_t)value.mField.getPosAtDepth(0) > key) {
-            break;
-        }
-    }
-
-    *err = BAD_INDEX;
-    return false;
-}
-
-float LogEvent::GetFloat(size_t key, status_t* err) const {
-    int field = getSimpleField(key);
-    for (const auto& value : mValues) {
-        if (value.mField.getField() == field) {
-            if (value.mValue.getType() == FLOAT) {
-                return value.mValue.float_value;
-            } else {
-                *err = BAD_TYPE;
-                return 0.0;
-            }
-        }
-        if ((size_t)value.mField.getPosAtDepth(0) > key) {
-            break;
-        }
-    }
-
-    *err = BAD_INDEX;
-    return 0.0;
-}
-
-std::vector<uint8_t> LogEvent::GetStorage(size_t key, status_t* err) const {
-    int field = getSimpleField(key);
-    for (const auto& value : mValues) {
-        if (value.mField.getField() == field) {
-            if (value.mValue.getType() == STORAGE) {
-                return value.mValue.storage_value;
-            } else {
-                *err = BAD_TYPE;
-                return vector<uint8_t>();
-            }
-        }
-        if ((size_t)value.mField.getPosAtDepth(0) > key) {
-            break;
-        }
-    }
-
-    *err = BAD_INDEX;
-    return vector<uint8_t>();
-}
-
-string LogEvent::ToString() const {
-    string result;
-    result += StringPrintf("{ uid(%d) %lld %lld (%d)", mLogUid, (long long)mLogdTimestampNs,
-                           (long long)mElapsedTimestampNs, mTagId);
-    for (const auto& value : mValues) {
-        result +=
-                StringPrintf("%#x", value.mField.getField()) + "->" + value.mValue.toString() + " ";
-    }
-    result += " }";
-    return result;
-}
-
-void LogEvent::ToProto(ProtoOutputStream& protoOutput) const {
-    writeFieldValueTreeToStream(mTagId, getValues(), &protoOutput);
-}
-
-bool LogEvent::hasAttributionChain(std::pair<int, int>* indexRange) const {
-    if (mAttributionChainStartIndex == -1 || mAttributionChainEndIndex == -1) {
-        return false;
-    }
-
-    if (nullptr != indexRange) {
-        indexRange->first = static_cast<int>(mAttributionChainStartIndex);
-        indexRange->second = static_cast<int>(mAttributionChainEndIndex);
-    }
-
-    return true;
-}
-
-void writeExperimentIdsToProto(const std::vector<int64_t>& experimentIds,
-                               std::vector<uint8_t>* protoOut) {
-    ProtoOutputStream proto;
-    for (const auto& expId : experimentIds) {
-        proto.write(FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_EXPERIMENT_ID,
-                    (long long)expId);
-    }
-
-    protoOut->resize(proto.size());
-    size_t pos = 0;
-    sp<ProtoReader> reader = proto.data();
-    while (reader->readBuffer() != NULL) {
-        size_t toRead = reader->currentToRead();
-        std::memcpy(protoOut->data() + pos, reader->readBuffer(), toRead);
-        pos += toRead;
-        reader->move(toRead);
-    }
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
deleted file mode 100644
index a5f2460..0000000
--- a/cmds/statsd/src/logd/LogEvent.h
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "FieldValue.h"
-
-#include <android/util/ProtoOutputStream.h>
-#include <private/android_logger.h>
-
-#include <string>
-#include <vector>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-struct InstallTrainInfo {
-    int64_t trainVersionCode;
-    std::string trainName;
-    int32_t status;
-    std::vector<int64_t> experimentIds;
-    bool requiresStaging;
-    bool rollbackEnabled;
-    bool requiresLowLatencyMonitor;
-};
-
-/**
- * This class decodes the structured, serialized encoding of an atom into a
- * vector of FieldValues.
- */
-class LogEvent {
-public:
-    /**
-     * \param uid user id of the logging caller
-     * \param pid process id of the logging caller
-     */
-    explicit LogEvent(int32_t uid, int32_t pid);
-
-    /**
-     * Parses the atomId, timestamp, and vector of values from a buffer
-     * containing the StatsEvent/AStatsEvent encoding of an atom.
-     *
-     * \param buf a buffer that begins at the start of the serialized atom (it
-     * should not include the android_log_header_t or the StatsEventTag)
-     * \param len size of the buffer
-     *
-     * \return success of the initialization
-     */
-    bool parseBuffer(uint8_t* buf, size_t len);
-
-    // Constructs a BinaryPushStateChanged LogEvent from API call.
-    explicit LogEvent(const std::string& trainName, int64_t trainVersionCode, bool requiresStaging,
-                      bool rollbackEnabled, bool requiresLowLatencyMonitor, int32_t state,
-                      const std::vector<uint8_t>& experimentIds, int32_t userId);
-
-    explicit LogEvent(int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
-                      const InstallTrainInfo& installTrainInfo);
-
-    ~LogEvent() {}
-
-    /**
-     * Get the timestamp associated with this event.
-     */
-    inline int64_t GetLogdTimestampNs() const { return mLogdTimestampNs; }
-    inline int64_t GetElapsedTimestampNs() const { return mElapsedTimestampNs; }
-
-    /**
-     * Get the tag for this event.
-     */
-    inline int GetTagId() const { return mTagId; }
-
-    /**
-     * Get the uid of the logging client.
-     * Returns -1 if the uid is unknown/has not been set.
-     */
-    inline int32_t GetUid() const { return mLogUid; }
-
-    /**
-     * Get the pid of the logging client.
-     * Returns -1 if the pid is unknown/has not been set.
-     */
-    inline int32_t GetPid() const { return mLogPid; }
-
-    /**
-     * Get the nth value, starting at 1.
-     *
-     * Returns BAD_INDEX if the index is larger than the number of elements.
-     * Returns BAD_TYPE if the index is available but the data is the wrong type.
-     */
-    int64_t GetLong(size_t key, status_t* err) const;
-    int GetInt(size_t key, status_t* err) const;
-    const char* GetString(size_t key, status_t* err) const;
-    bool GetBool(size_t key, status_t* err) const;
-    float GetFloat(size_t key, status_t* err) const;
-    std::vector<uint8_t> GetStorage(size_t key, status_t* err) const;
-
-    /**
-     * Return a string representation of this event.
-     */
-    std::string ToString() const;
-
-    /**
-     * Write this object to a ProtoOutputStream.
-     */
-    void ToProto(android::util::ProtoOutputStream& out) const;
-
-    /**
-     * Set elapsed timestamp if the original timestamp is missing.
-     */
-    void setElapsedTimestampNs(int64_t timestampNs) {
-        mElapsedTimestampNs = timestampNs;
-    }
-
-    /**
-     * Set the timestamp if the original logd timestamp is missing.
-     */
-    void setLogdWallClockTimestampNs(int64_t timestampNs) {
-        mLogdTimestampNs = timestampNs;
-    }
-
-    inline int size() const {
-        return mValues.size();
-    }
-
-    const std::vector<FieldValue>& getValues() const {
-        return mValues;
-    }
-
-    std::vector<FieldValue>* getMutableValues() {
-        return &mValues;
-    }
-
-    // Default value = false
-    inline bool shouldTruncateTimestamp() const {
-        return mTruncateTimestamp;
-    }
-
-    // Returns the index of the uid field within the FieldValues vector if the
-    // uid exists. If there is no uid field, returns -1.
-    //
-    // If the index within the atom definition is desired, do the following:
-    //    int vectorIndex = LogEvent.getUidFieldIndex();
-    //    if (vectorIndex != -1) {
-    //        FieldValue& v = LogEvent.getValues()[vectorIndex];
-    //        int atomIndex = v.mField.getPosAtDepth(0);
-    //    }
-    // Note that atomIndex is 1-indexed.
-    inline int getUidFieldIndex() {
-        return static_cast<int>(mUidFieldIndex);
-    }
-
-    // Returns whether this LogEvent has an AttributionChain.
-    // If it does and indexRange is not a nullptr, populate indexRange with the start and end index
-    // of the AttributionChain within mValues.
-    bool hasAttributionChain(std::pair<int, int>* indexRange = nullptr) const;
-
-    // Returns the index of the exclusive state field within the FieldValues vector if
-    // an exclusive state exists. If there is no exclusive state field, returns -1.
-    //
-    // If the index within the atom definition is desired, do the following:
-    //    int vectorIndex = LogEvent.getExclusiveStateFieldIndex();
-    //    if (vectorIndex != -1) {
-    //        FieldValue& v = LogEvent.getValues()[vectorIndex];
-    //        int atomIndex = v.mField.getPosAtDepth(0);
-    //    }
-    // Note that atomIndex is 1-indexed.
-    inline int getExclusiveStateFieldIndex() const {
-        return static_cast<int>(mExclusiveStateFieldIndex);
-    }
-
-    // If a reset state is not sent in the StatsEvent, returns -1. Note that a
-    // reset state is sent if and only if a reset should be triggered.
-    inline int getResetState() const {
-        return mResetState;
-    }
-
-    inline LogEvent makeCopy() {
-        return LogEvent(*this);
-    }
-
-    template <class T>
-    status_t updateValue(size_t key, T& value, Type type) {
-        int field = getSimpleField(key);
-        for (auto& fieldValue : mValues) {
-            if (fieldValue.mField.getField() == field) {
-                if (fieldValue.mValue.getType() == type) {
-                    fieldValue.mValue = Value(value);
-                   return OK;
-               } else {
-                   return BAD_TYPE;
-                }
-            }
-        }
-        return BAD_INDEX;
-    }
-
-    bool isValid() const {
-        return mValid;
-    }
-
-private:
-    /**
-     * Only use this if copy is absolutely needed.
-     */
-    LogEvent(const LogEvent&) = default;
-
-    void parseInt32(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
-    void parseInt64(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
-    void parseString(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
-    void parseFloat(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
-    void parseBool(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
-    void parseByteArray(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
-    void parseKeyValuePairs(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
-    void parseAttributionChain(int32_t* pos, int32_t depth, bool* last, uint8_t numAnnotations);
-
-    void parseAnnotations(uint8_t numAnnotations, int firstUidInChainIndex = -1);
-    void parseIsUidAnnotation(uint8_t annotationType);
-    void parseTruncateTimestampAnnotation(uint8_t annotationType);
-    void parsePrimaryFieldAnnotation(uint8_t annotationType);
-    void parsePrimaryFieldFirstUidAnnotation(uint8_t annotationType, int firstUidInChainIndex);
-    void parseExclusiveStateAnnotation(uint8_t annotationType);
-    void parseTriggerStateResetAnnotation(uint8_t annotationType);
-    void parseStateNestedAnnotation(uint8_t annotationType);
-    bool checkPreviousValueType(Type expected);
-
-    /**
-     * The below two variables are only valid during the execution of
-     * parseBuffer. There are no guarantees about the state of these variables
-     * before/after.
-     */
-    uint8_t* mBuf;
-    uint32_t mRemainingLen; // number of valid bytes left in the buffer being parsed
-
-    bool mValid = true; // stores whether the event we received from the socket is valid
-
-    /**
-     * Side-effects:
-     *    If there is enough space in buffer to read value of type T
-     *        - move mBuf past the value that was just read
-     *        - decrement mRemainingLen by size of T
-     *    Else
-     *        - set mValid to false
-     */
-    template <class T>
-    T readNextValue() {
-        T value;
-        if (mRemainingLen < sizeof(T)) {
-            mValid = false;
-            value = 0; // all primitive types can successfully cast 0
-        } else {
-            // When alignof(T) == 1, hopefully the compiler can optimize away
-            // this conditional as always true.
-            if ((reinterpret_cast<uintptr_t>(mBuf) % alignof(T)) == 0) {
-                // We're properly aligned, and can safely make this assignment.
-                value = *((T*)mBuf);
-            } else {
-                // We need to use memcpy.  It's slower, but safe.
-                memcpy(&value, mBuf, sizeof(T));
-            }
-            mBuf += sizeof(T);
-            mRemainingLen -= sizeof(T);
-        }
-        return value;
-    }
-
-    template <class T>
-    void addToValues(int32_t* pos, int32_t depth, T& value, bool* last) {
-        Field f = Field(mTagId, pos, depth);
-        // do not decorate last position at depth 0
-        for (int i = 1; i < depth; i++) {
-            if (last[i]) f.decorateLastPos(i);
-        }
-
-        Value v = Value(value);
-        mValues.push_back(FieldValue(f, v));
-    }
-
-    uint8_t getTypeId(uint8_t typeInfo);
-    uint8_t getNumAnnotations(uint8_t typeInfo);
-
-    // The items are naturally sorted in DFS order as we read them. this allows us to do fast
-    // matching.
-    std::vector<FieldValue> mValues;
-
-    // The timestamp set by the logd.
-    int64_t mLogdTimestampNs;
-
-    // The elapsed timestamp set by statsd log writer.
-    int64_t mElapsedTimestampNs;
-
-    // The atom tag of the event (defaults to 0 if client does not
-    // appropriately set the atom id).
-    int mTagId = 0;
-
-    // The uid of the logging client (defaults to -1).
-    int32_t mLogUid = -1;
-
-    // The pid of the logging client (defaults to -1).
-    int32_t mLogPid = -1;
-
-    // Annotations
-    bool mTruncateTimestamp = false;
-    int mResetState = -1;
-
-    // Indexes within the FieldValue vector can be stored in 7 bits because
-    // that's the assumption enforced by the encoding used in FieldValue.
-    int8_t mUidFieldIndex = -1;
-    int8_t mAttributionChainStartIndex = -1;
-    int8_t mAttributionChainEndIndex = -1;
-    int8_t mExclusiveStateFieldIndex = -1;
-};
-
-void writeExperimentIdsToProto(const std::vector<int64_t>& experimentIds, std::vector<uint8_t>* protoOut);
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/logd/LogEventQueue.cpp b/cmds/statsd/src/logd/LogEventQueue.cpp
deleted file mode 100644
index 146464b..0000000
--- a/cmds/statsd/src/logd/LogEventQueue.cpp
+++ /dev/null
@@ -1,62 +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.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "LogEventQueue.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using std::unique_lock;
-using std::unique_ptr;
-
-unique_ptr<LogEvent> LogEventQueue::waitPop() {
-    std::unique_lock<std::mutex> lock(mMutex);
-
-    if (mQueue.empty()) {
-        mCondition.wait(lock, [this] { return !this->mQueue.empty(); });
-    }
-
-    unique_ptr<LogEvent> item = std::move(mQueue.front());
-    mQueue.pop();
-
-    return item;
-}
-
-bool LogEventQueue::push(unique_ptr<LogEvent> item, int64_t* oldestTimestampNs) {
-    bool success;
-    {
-        std::unique_lock<std::mutex> lock(mMutex);
-        if (mQueue.size() < mQueueLimit) {
-            mQueue.push(std::move(item));
-            success = true;
-        } else {
-            // safe operation as queue must not be empty.
-            *oldestTimestampNs = mQueue.front()->GetElapsedTimestampNs();
-            success = false;
-        }
-    }
-
-    mCondition.notify_one();
-    return success;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/logd/LogEventQueue.h b/cmds/statsd/src/logd/LogEventQueue.h
deleted file mode 100644
index 9dda3d2..0000000
--- a/cmds/statsd/src/logd/LogEventQueue.h
+++ /dev/null
@@ -1,57 +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.
- */
-
-#pragma once
-
-#include "LogEvent.h"
-
-#include <condition_variable>
-#include <mutex>
-#include <queue>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/**
- * A zero copy thread safe queue buffer for producing and consuming LogEvent.
- */
-class LogEventQueue {
-public:
-    explicit LogEventQueue(size_t maxSize) : mQueueLimit(maxSize){};
-
-    /**
-     * Blocking read one event from the queue.
-     */
-    std::unique_ptr<LogEvent> waitPop();
-
-    /**
-     * Puts a LogEvent ptr to the end of the queue.
-     * Returns false on failure when the queue is full, and output the oldest event timestamp
-     * in the queue.
-     */
-    bool push(std::unique_ptr<LogEvent> event, int64_t* oldestTimestampNs);
-
-private:
-    const size_t mQueueLimit;
-    std::condition_variable mCondition;
-    std::mutex mMutex;
-    std::queue<std::unique_ptr<LogEvent>> mQueue;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
deleted file mode 100644
index 03b178a..0000000
--- a/cmds/statsd/src/main.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "StatsService.h"
-#include "socket/StatsSocketListener.h"
-
-#include <android/binder_interface_utils.h>
-#include <android/binder_process.h>
-#include <android/binder_manager.h>
-#include <utils/Looper.h>
-
-#include <stdio.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-using namespace android;
-using namespace android::os::statsd;
-using ::ndk::SharedRefBase;
-using std::shared_ptr;
-using std::make_shared;
-
-shared_ptr<StatsService> gStatsService = nullptr;
-sp<StatsSocketListener> gSocketListener = nullptr;
-
-void signalHandler(int sig) {
-    if (sig == SIGPIPE) {
-        // ShellSubscriber uses SIGPIPE as a signal to detect the end of the
-        // client process. Don't prematurely exit(1) here. Instead, ignore the
-        // signal and allow the write call to return EPIPE.
-        ALOGI("statsd received SIGPIPE. Ignoring signal.");
-        return;
-    }
-
-    if (gSocketListener != nullptr) gSocketListener->stopListener();
-    if (gStatsService != nullptr) gStatsService->Terminate();
-    ALOGW("statsd terminated on receiving signal %d.", sig);
-    exit(1);
-}
-
-void registerSignalHandlers()
-{
-    struct sigaction sa;
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags = 0;
-    sa.sa_handler = signalHandler;
-    sigaction(SIGPIPE, &sa, nullptr);
-    sigaction(SIGHUP, &sa, nullptr);
-    sigaction(SIGINT, &sa, nullptr);
-    sigaction(SIGQUIT, &sa, nullptr);
-    sigaction(SIGTERM, &sa, nullptr);
-}
-
-int main(int /*argc*/, char** /*argv*/) {
-    // Set up the looper
-    sp<Looper> looper(Looper::prepare(0 /* opts */));
-
-    // Set up the binder
-    ABinderProcess_setThreadPoolMaxThreadCount(9);
-    ABinderProcess_startThreadPool();
-
-    std::shared_ptr<LogEventQueue> eventQueue =
-            std::make_shared<LogEventQueue>(4000 /*buffer limit. Buffer is NOT pre-allocated*/);
-
-    // Create the service
-    gStatsService = SharedRefBase::make<StatsService>(looper, eventQueue);
-    // TODO(b/149582373): Set DUMP_FLAG_PROTO once libbinder_ndk supports
-    // setting dumpsys priorities.
-    binder_status_t status = AServiceManager_addService(gStatsService->asBinder().get(), "stats");
-    if (status != STATUS_OK) {
-        ALOGE("Failed to add service as AIDL service");
-        return -1;
-    }
-
-    registerSignalHandlers();
-
-    gStatsService->sayHiToStatsCompanion();
-
-    gStatsService->Startup();
-
-    gSocketListener = new StatsSocketListener(eventQueue);
-
-    ALOGI("Statsd starts to listen to socket.");
-    // Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value
-    if (gSocketListener->startListener(600)) {
-        exit(1);
-    }
-
-    // Loop forever -- the reports run on this thread in a handler, and the
-    // binder calls remain responsive in their pool of one thread.
-    while (true) {
-        looper->pollAll(-1 /* timeoutMillis */);
-    }
-    ALOGW("statsd escaped from its loop.");
-
-    return 1;
-}
diff --git a/cmds/statsd/src/matchers/AtomMatchingTracker.h b/cmds/statsd/src/matchers/AtomMatchingTracker.h
deleted file mode 100644
index c138497..0000000
--- a/cmds/statsd/src/matchers/AtomMatchingTracker.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ATOM_MATCHING_TRACKER_H
-#define ATOM_MATCHING_TRACKER_H
-
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "logd/LogEvent.h"
-#include "matchers/matcher_util.h"
-
-#include <utils/RefBase.h>
-
-#include <set>
-#include <unordered_map>
-#include <vector>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class AtomMatchingTracker : public virtual RefBase {
-public:
-    AtomMatchingTracker(const int64_t& id, const int index, const uint64_t protoHash)
-        : mId(id), mIndex(index), mInitialized(false), mProtoHash(protoHash){};
-
-    virtual ~AtomMatchingTracker(){};
-
-    // Initialize this AtomMatchingTracker.
-    // allAtomMatchers: the list of the AtomMatcher proto config. This is needed because we don't
-    //                  store the proto object in memory. We only need it during initilization.
-    // allAtomMatchingTrackers: the list of the AtomMatchingTracker objects. It's a one-to-one
-    //                          mapping with allAtomMatchers. This is needed because the
-    //                          initialization is done recursively for
-    //                          CombinationAtomMatchingTrackers using DFS.
-    // stack: a bit map to record which matcher has been visited on the stack. This is for detecting
-    //        circle dependency.
-    virtual bool init(const std::vector<AtomMatcher>& allAtomMatchers,
-                      const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-                      const std::unordered_map<int64_t, int>& matcherMap,
-                      std::vector<bool>& stack) = 0;
-
-    // Update appropriate state on config updates. Primarily, all indices need to be updated.
-    // This matcher and all of its children are guaranteed to be preserved across the update.
-    // matcher: the AtomMatcher proto from the config.
-    // index: the index of this matcher in mAllAtomMatchingTrackers.
-    // atomMatchingTrackerMap: map from matcher id to index in mAllAtomMatchingTrackers
-    virtual bool onConfigUpdated(
-            const AtomMatcher& matcher, const int index,
-            const std::unordered_map<int64_t, int>& atomMatchingTrackerMap) = 0;
-
-    // Called when a log event comes.
-    // event: the log event.
-    // allAtomMatchingTrackers: the list of all AtomMatchingTrackers. This is needed because the log
-    //                          processing is done recursively.
-    // matcherResults: The cached results for all matchers for this event. Parent matchers can
-    //                 directly access the children's matching results if they have been evaluated.
-    //                 Otherwise, call children matchers' onLogEvent.
-    virtual void onLogEvent(const LogEvent& event,
-                            const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-                            std::vector<MatchingState>& matcherResults) = 0;
-
-    // Get the tagIds that this matcher cares about. The combined collection is stored
-    // in MetricMananger, so that we can pass any LogEvents that are not interest of us. It uses
-    // some memory but hopefully it can save us much CPU time when there is flood of events.
-    virtual const std::set<int>& getAtomIds() const {
-        return mAtomIds;
-    }
-
-    int64_t getId() const {
-        return mId;
-    }
-
-    uint64_t getProtoHash() const {
-        return mProtoHash;
-    }
-
-protected:
-    // Name of this matching. We don't really need the name, but it makes log message easy to debug.
-    const int64_t mId;
-
-    // Index of this AtomMatchingTracker in MetricsManager's container.
-    int mIndex;
-
-    // Whether this AtomMatchingTracker has been properly initialized.
-    bool mInitialized;
-
-    // The collection of the event tag ids that this AtomMatchingTracker cares. So we can quickly
-    // return kNotMatched when we receive an event with an id not in the list. This is especially
-    // useful when we have a complex CombinationAtomMatchingTracker.
-    std::set<int> mAtomIds;
-
-    // Hash of the AtomMatcher's proto bytes from StatsdConfig.
-    // Used to determine if the definition of this matcher has changed across a config update.
-    const uint64_t mProtoHash;
-
-    FRIEND_TEST(MetricsManagerTest, TestCreateAtomMatchingTrackerSimple);
-    FRIEND_TEST(MetricsManagerTest, TestCreateAtomMatchingTrackerCombination);
-    FRIEND_TEST(ConfigUpdateTest, TestUpdateMatchers);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-#endif  // ATOM_MATCHING_TRACKER_H
diff --git a/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.cpp b/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.cpp
deleted file mode 100644
index 45685ce..0000000
--- a/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.cpp
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Log.h"
-
-#include "CombinationAtomMatchingTracker.h"
-
-#include "matchers/matcher_util.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using std::set;
-using std::unordered_map;
-using std::vector;
-
-CombinationAtomMatchingTracker::CombinationAtomMatchingTracker(const int64_t& id, const int index,
-                                                               const uint64_t protoHash)
-    : AtomMatchingTracker(id, index, protoHash) {
-}
-
-CombinationAtomMatchingTracker::~CombinationAtomMatchingTracker() {
-}
-
-bool CombinationAtomMatchingTracker::init(
-        const vector<AtomMatcher>& allAtomMatchers,
-        const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-        const unordered_map<int64_t, int>& matcherMap, vector<bool>& stack) {
-    if (mInitialized) {
-        return true;
-    }
-
-    // mark this node as visited in the recursion stack.
-    stack[mIndex] = true;
-
-    AtomMatcher_Combination matcher = allAtomMatchers[mIndex].combination();
-
-    // LogicalOperation is missing in the config
-    if (!matcher.has_operation()) {
-        return false;
-    }
-
-    mLogicalOperation = matcher.operation();
-
-    if (mLogicalOperation == LogicalOperation::NOT && matcher.matcher_size() != 1) {
-        return false;
-    }
-
-    for (const auto& child : matcher.matcher()) {
-        auto pair = matcherMap.find(child);
-        if (pair == matcherMap.end()) {
-            ALOGW("Matcher %lld not found in the config", (long long)child);
-            return false;
-        }
-
-        int childIndex = pair->second;
-
-        // if the child is a visited node in the recursion -> circle detected.
-        if (stack[childIndex]) {
-            ALOGE("Circle detected in matcher config");
-            return false;
-        }
-
-        if (!allAtomMatchingTrackers[childIndex]->init(allAtomMatchers, allAtomMatchingTrackers,
-                                                       matcherMap, stack)) {
-            ALOGW("child matcher init failed %lld", (long long)child);
-            return false;
-        }
-
-        mChildren.push_back(childIndex);
-
-        const set<int>& childTagIds = allAtomMatchingTrackers[childIndex]->getAtomIds();
-        mAtomIds.insert(childTagIds.begin(), childTagIds.end());
-    }
-
-    mInitialized = true;
-    // unmark this node in the recursion stack.
-    stack[mIndex] = false;
-    return true;
-}
-
-bool CombinationAtomMatchingTracker::onConfigUpdated(
-        const AtomMatcher& matcher, const int index,
-        const unordered_map<int64_t, int>& atomMatchingTrackerMap) {
-    mIndex = index;
-    mChildren.clear();
-    AtomMatcher_Combination combinationMatcher = matcher.combination();
-    for (const int64_t child : combinationMatcher.matcher()) {
-        const auto& pair = atomMatchingTrackerMap.find(child);
-        if (pair == atomMatchingTrackerMap.end()) {
-            ALOGW("Matcher %lld not found in the config", (long long)child);
-            return false;
-        }
-        mChildren.push_back(pair->second);
-    }
-    return true;
-}
-
-void CombinationAtomMatchingTracker::onLogEvent(
-        const LogEvent& event, const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-        vector<MatchingState>& matcherResults) {
-    // this event has been processed.
-    if (matcherResults[mIndex] != MatchingState::kNotComputed) {
-        return;
-    }
-
-    if (mAtomIds.find(event.GetTagId()) == mAtomIds.end()) {
-        matcherResults[mIndex] = MatchingState::kNotMatched;
-        return;
-    }
-
-    // evaluate children matchers if they haven't been evaluated.
-    for (const int childIndex : mChildren) {
-        if (matcherResults[childIndex] == MatchingState::kNotComputed) {
-            const sp<AtomMatchingTracker>& child = allAtomMatchingTrackers[childIndex];
-            child->onLogEvent(event, allAtomMatchingTrackers, matcherResults);
-        }
-    }
-
-    bool matched = combinationMatch(mChildren, mLogicalOperation, matcherResults);
-    matcherResults[mIndex] = matched ? MatchingState::kMatched : MatchingState::kNotMatched;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.h b/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.h
deleted file mode 100644
index 3160448..0000000
--- a/cmds/statsd/src/matchers/CombinationAtomMatchingTracker.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef COMBINATION_ATOM_MATCHING_TRACKER_H
-#define COMBINATION_ATOM_MATCHING_TRACKER_H
-
-#include <unordered_map>
-#include <vector>
-
-#include "AtomMatchingTracker.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// Represents a AtomMatcher_Combination in the StatsdConfig.
-class CombinationAtomMatchingTracker : public AtomMatchingTracker {
-public:
-    CombinationAtomMatchingTracker(const int64_t& id, const int index, const uint64_t protoHash);
-
-    bool init(const std::vector<AtomMatcher>& allAtomMatchers,
-              const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-              const std::unordered_map<int64_t, int>& matcherMap, std::vector<bool>& stack);
-
-    bool onConfigUpdated(const AtomMatcher& matcher, const int index,
-                         const std::unordered_map<int64_t, int>& atomMatchingTrackerMap) override;
-
-    ~CombinationAtomMatchingTracker();
-
-    void onLogEvent(const LogEvent& event,
-                    const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-                    std::vector<MatchingState>& matcherResults) override;
-
-private:
-    LogicalOperation mLogicalOperation;
-
-    std::vector<int> mChildren;
-
-    FRIEND_TEST(ConfigUpdateTest, TestUpdateMatchers);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#endif  // COMBINATION_ATOM_MATCHING_TRACKER_H
diff --git a/cmds/statsd/src/matchers/EventMatcherWizard.cpp b/cmds/statsd/src/matchers/EventMatcherWizard.cpp
deleted file mode 100644
index 025c9a8..0000000
--- a/cmds/statsd/src/matchers/EventMatcherWizard.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "EventMatcherWizard.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using std::vector;
-
-MatchingState EventMatcherWizard::matchLogEvent(const LogEvent& event, int matcher_index) {
-    if (matcher_index < 0 || matcher_index >= (int)mAllEventMatchers.size()) {
-        return MatchingState::kNotComputed;
-    }
-    vector<MatchingState> matcherCache(mAllEventMatchers.size(), MatchingState::kNotComputed);
-    mAllEventMatchers[matcher_index]->onLogEvent(event, mAllEventMatchers, matcherCache);
-    return matcherCache[matcher_index];
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/matchers/EventMatcherWizard.h b/cmds/statsd/src/matchers/EventMatcherWizard.h
deleted file mode 100644
index 5d780f2..0000000
--- a/cmds/statsd/src/matchers/EventMatcherWizard.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "AtomMatchingTracker.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class EventMatcherWizard : public virtual android::RefBase {
-public:
-    EventMatcherWizard(){};  // for testing
-    EventMatcherWizard(const std::vector<sp<AtomMatchingTracker>>& eventTrackers)
-        : mAllEventMatchers(eventTrackers){};
-
-    virtual ~EventMatcherWizard(){};
-
-    MatchingState matchLogEvent(const LogEvent& event, int matcher_index);
-
-private:
-    std::vector<sp<AtomMatchingTracker>> mAllEventMatchers;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.cpp b/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.cpp
deleted file mode 100644
index 423da5b..0000000
--- a/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "SimpleAtomMatchingTracker.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using std::unordered_map;
-using std::vector;
-
-SimpleAtomMatchingTracker::SimpleAtomMatchingTracker(const int64_t& id, const int index,
-                                                     const uint64_t protoHash,
-                                                     const SimpleAtomMatcher& matcher,
-                                                     const sp<UidMap>& uidMap)
-    : AtomMatchingTracker(id, index, protoHash), mMatcher(matcher), mUidMap(uidMap) {
-    if (!matcher.has_atom_id()) {
-        mInitialized = false;
-    } else {
-        mAtomIds.insert(matcher.atom_id());
-        mInitialized = true;
-    }
-}
-
-SimpleAtomMatchingTracker::~SimpleAtomMatchingTracker() {
-}
-
-bool SimpleAtomMatchingTracker::init(const vector<AtomMatcher>& allAtomMatchers,
-                                     const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-                                     const unordered_map<int64_t, int>& matcherMap,
-                                     vector<bool>& stack) {
-    // no need to do anything.
-    return mInitialized;
-}
-
-bool SimpleAtomMatchingTracker::onConfigUpdated(
-        const AtomMatcher& matcher, const int index,
-        const unordered_map<int64_t, int>& atomMatchingTrackerMap) {
-    mIndex = index;
-    // Do not need to update mMatcher since the matcher must be identical across the update.
-    return mInitialized;
-}
-
-void SimpleAtomMatchingTracker::onLogEvent(
-        const LogEvent& event, const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-        vector<MatchingState>& matcherResults) {
-    if (matcherResults[mIndex] != MatchingState::kNotComputed) {
-        VLOG("Matcher %lld already evaluated ", (long long)mId);
-        return;
-    }
-
-    if (mAtomIds.find(event.GetTagId()) == mAtomIds.end()) {
-        matcherResults[mIndex] = MatchingState::kNotMatched;
-        return;
-    }
-
-    bool matched = matchesSimple(mUidMap, mMatcher, event);
-    matcherResults[mIndex] = matched ? MatchingState::kMatched : MatchingState::kNotMatched;
-    VLOG("Stats SimpleAtomMatcher %lld matched? %d", (long long)mId, matched);
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.h b/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.h
deleted file mode 100644
index b67e6c2..0000000
--- a/cmds/statsd/src/matchers/SimpleAtomMatchingTracker.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SIMPLE_ATOM_MATCHING_TRACKER_H
-#define SIMPLE_ATOM_MATCHING_TRACKER_H
-
-#include <unordered_map>
-#include <vector>
-
-#include "AtomMatchingTracker.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "packages/UidMap.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class SimpleAtomMatchingTracker : public AtomMatchingTracker {
-public:
-    SimpleAtomMatchingTracker(const int64_t& id, const int index, const uint64_t protoHash,
-                              const SimpleAtomMatcher& matcher, const sp<UidMap>& uidMap);
-
-    ~SimpleAtomMatchingTracker();
-
-    bool init(const std::vector<AtomMatcher>& allAtomMatchers,
-              const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-              const std::unordered_map<int64_t, int>& matcherMap,
-              std::vector<bool>& stack) override;
-
-    bool onConfigUpdated(const AtomMatcher& matcher, const int index,
-                         const std::unordered_map<int64_t, int>& atomMatchingTrackerMap) override;
-
-    void onLogEvent(const LogEvent& event,
-                    const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-                    std::vector<MatchingState>& matcherResults) override;
-
-private:
-    const SimpleAtomMatcher mMatcher;
-    const sp<UidMap> mUidMap;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#endif  // SIMPLE_ATOM_MATCHING_TRACKER_H
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
deleted file mode 100644
index a7454c5..0000000
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "matchers/AtomMatchingTracker.h"
-#include "matchers/matcher_util.h"
-#include "stats_util.h"
-
-using std::set;
-using std::string;
-using std::vector;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-bool combinationMatch(const vector<int>& children, const LogicalOperation& operation,
-                      const vector<MatchingState>& matcherResults) {
-    bool matched;
-    switch (operation) {
-        case LogicalOperation::AND: {
-            matched = true;
-            for (const int childIndex : children) {
-                if (matcherResults[childIndex] != MatchingState::kMatched) {
-                    matched = false;
-                    break;
-                }
-            }
-            break;
-        }
-        case LogicalOperation::OR: {
-            matched = false;
-            for (const int childIndex : children) {
-                if (matcherResults[childIndex] == MatchingState::kMatched) {
-                    matched = true;
-                    break;
-                }
-            }
-            break;
-        }
-        case LogicalOperation::NOT:
-            matched = matcherResults[children[0]] == MatchingState::kNotMatched;
-            break;
-        case LogicalOperation::NAND:
-            matched = false;
-            for (const int childIndex : children) {
-                if (matcherResults[childIndex] != MatchingState::kMatched) {
-                    matched = true;
-                    break;
-                }
-            }
-            break;
-        case LogicalOperation::NOR:
-            matched = true;
-            for (const int childIndex : children) {
-                if (matcherResults[childIndex] == MatchingState::kMatched) {
-                    matched = false;
-                    break;
-                }
-            }
-            break;
-        case LogicalOperation::LOGICAL_OPERATION_UNSPECIFIED:
-            matched = false;
-            break;
-    }
-    return matched;
-}
-
-bool tryMatchString(const sp<UidMap>& uidMap, const FieldValue& fieldValue,
-                    const string& str_match) {
-    if (isAttributionUidField(fieldValue) || isUidField(fieldValue)) {
-        int uid = fieldValue.mValue.int_value;
-        auto aidIt = UidMap::sAidToUidMapping.find(str_match);
-        if (aidIt != UidMap::sAidToUidMapping.end()) {
-            return ((int)aidIt->second) == uid;
-        }
-        std::set<string> packageNames = uidMap->getAppNamesFromUid(uid, true /* normalize*/);
-        return packageNames.find(str_match) != packageNames.end();
-    } else if (fieldValue.mValue.getType() == STRING) {
-        return fieldValue.mValue.str_value == str_match;
-    }
-    return false;
-}
-
-bool matchesSimple(const sp<UidMap>& uidMap, const FieldValueMatcher& matcher,
-                   const vector<FieldValue>& values, int start, int end, int depth) {
-    if (depth > 2) {
-        ALOGE("Depth > 3 not supported");
-        return false;
-    }
-
-    if (start >= end) {
-        return false;
-    }
-
-    // Filter by entry field first
-    int newStart = -1;
-    int newEnd = end;
-    // because the fields are naturally sorted in the DFS order. we can safely
-    // break when pos is larger than the one we are searching for.
-    for (int i = start; i < end; i++) {
-        int pos = values[i].mField.getPosAtDepth(depth);
-        if (pos == matcher.field()) {
-            if (newStart == -1) {
-                newStart = i;
-            }
-            newEnd = i + 1;
-        } else if (pos > matcher.field()) {
-            break;
-        }
-    }
-
-    // Now we have zoomed in to a new range
-    start = newStart;
-    end = newEnd;
-
-    if (start == -1) {
-        // No such field found.
-        return false;
-    }
-
-    vector<pair<int, int>> ranges; // the ranges are for matching ANY position
-    if (matcher.has_position()) {
-        // Repeated fields position is stored as a node in the path.
-        depth++;
-        if (depth > 2) {
-            return false;
-        }
-        switch (matcher.position()) {
-            case Position::FIRST: {
-                for (int i = start; i < end; i++) {
-                    int pos = values[i].mField.getPosAtDepth(depth);
-                    if (pos != 1) {
-                        // Again, the log elements are stored in sorted order. so
-                        // once the position is > 1, we break;
-                        end = i;
-                        break;
-                    }
-                }
-                ranges.push_back(std::make_pair(start, end));
-                break;
-            }
-            case Position::LAST: {
-                // move the starting index to the first LAST field at the depth.
-                for (int i = start; i < end; i++) {
-                    if (values[i].mField.isLastPos(depth)) {
-                        start = i;
-                        break;
-                    }
-                }
-                ranges.push_back(std::make_pair(start, end));
-                break;
-            }
-            case Position::ANY: {
-                // ANY means all the children matchers match in any of the sub trees, it's a match
-                newStart = start;
-                newEnd = end;
-                // Here start is guaranteed to be a valid index.
-                int currentPos = values[start].mField.getPosAtDepth(depth);
-                // Now find all sub trees ranges.
-                for (int i = start; i < end; i++) {
-                    int newPos = values[i].mField.getPosAtDepth(depth);
-                    if (newPos != currentPos) {
-                        ranges.push_back(std::make_pair(newStart, i));
-                        newStart = i;
-                        currentPos = newPos;
-                    }
-                }
-                ranges.push_back(std::make_pair(newStart, end));
-                break;
-            }
-            case Position::ALL:
-                ALOGE("Not supported: field matcher with ALL position.");
-                break;
-            case Position::POSITION_UNKNOWN:
-                break;
-        }
-    } else {
-        // No position
-        ranges.push_back(std::make_pair(start, end));
-    }
-    // start and end are still pointing to the matched range.
-    switch (matcher.value_matcher_case()) {
-        case FieldValueMatcher::kMatchesTuple: {
-            ++depth;
-            // If any range matches all matchers, good.
-            for (const auto& range : ranges) {
-                bool matched = true;
-                for (const auto& subMatcher : matcher.matches_tuple().field_value_matcher()) {
-                    if (!matchesSimple(uidMap, subMatcher, values, range.first, range.second,
-                                       depth)) {
-                        matched = false;
-                        break;
-                    }
-                }
-                if (matched) return true;
-            }
-            return false;
-        }
-        // Finally, we get to the point of real value matching.
-        // If the field matcher ends with ANY, then we have [start, end) range > 1.
-        // In the following, we should return true, when ANY of the values matches.
-        case FieldValueMatcher::ValueMatcherCase::kEqBool: {
-            for (int i = start; i < end; i++) {
-                if ((values[i].mValue.getType() == INT &&
-                     (values[i].mValue.int_value != 0) == matcher.eq_bool()) ||
-                    (values[i].mValue.getType() == LONG &&
-                     (values[i].mValue.long_value != 0) == matcher.eq_bool())) {
-                    return true;
-                }
-            }
-            return false;
-        }
-        case FieldValueMatcher::ValueMatcherCase::kEqString: {
-            for (int i = start; i < end; i++) {
-                if (tryMatchString(uidMap, values[i], matcher.eq_string())) {
-                    return true;
-                }
-            }
-            return false;
-        }
-        case FieldValueMatcher::ValueMatcherCase::kNeqAnyString: {
-            const auto& str_list = matcher.neq_any_string();
-            for (int i = start; i < end; i++) {
-                bool notEqAll = true;
-                for (const auto& str : str_list.str_value()) {
-                    if (tryMatchString(uidMap, values[i], str)) {
-                        notEqAll = false;
-                        break;
-                    }
-                }
-                if (notEqAll) {
-                    return true;
-                }
-            }
-            return false;
-        }
-        case FieldValueMatcher::ValueMatcherCase::kEqAnyString: {
-            const auto& str_list = matcher.eq_any_string();
-            for (int i = start; i < end; i++) {
-                for (const auto& str : str_list.str_value()) {
-                    if (tryMatchString(uidMap, values[i], str)) {
-                        return true;
-                    }
-                }
-            }
-            return false;
-        }
-        case FieldValueMatcher::ValueMatcherCase::kEqInt: {
-            for (int i = start; i < end; i++) {
-                if (values[i].mValue.getType() == INT &&
-                    (matcher.eq_int() == values[i].mValue.int_value)) {
-                    return true;
-                }
-                // eq_int covers both int and long.
-                if (values[i].mValue.getType() == LONG &&
-                    (matcher.eq_int() == values[i].mValue.long_value)) {
-                    return true;
-                }
-            }
-            return false;
-        }
-        case FieldValueMatcher::ValueMatcherCase::kLtInt: {
-            for (int i = start; i < end; i++) {
-                if (values[i].mValue.getType() == INT &&
-                    (values[i].mValue.int_value < matcher.lt_int())) {
-                    return true;
-                }
-                // lt_int covers both int and long.
-                if (values[i].mValue.getType() == LONG &&
-                    (values[i].mValue.long_value < matcher.lt_int())) {
-                    return true;
-                }
-            }
-            return false;
-        }
-        case FieldValueMatcher::ValueMatcherCase::kGtInt: {
-            for (int i = start; i < end; i++) {
-                if (values[i].mValue.getType() == INT &&
-                    (values[i].mValue.int_value > matcher.gt_int())) {
-                    return true;
-                }
-                // gt_int covers both int and long.
-                if (values[i].mValue.getType() == LONG &&
-                    (values[i].mValue.long_value > matcher.gt_int())) {
-                    return true;
-                }
-            }
-            return false;
-        }
-        case FieldValueMatcher::ValueMatcherCase::kLtFloat: {
-            for (int i = start; i < end; i++) {
-                if (values[i].mValue.getType() == FLOAT &&
-                    (values[i].mValue.float_value < matcher.lt_float())) {
-                    return true;
-                }
-            }
-            return false;
-        }
-        case FieldValueMatcher::ValueMatcherCase::kGtFloat: {
-            for (int i = start; i < end; i++) {
-                if (values[i].mValue.getType() == FLOAT &&
-                    (values[i].mValue.float_value > matcher.gt_float())) {
-                    return true;
-                }
-            }
-            return false;
-        }
-        case FieldValueMatcher::ValueMatcherCase::kLteInt: {
-            for (int i = start; i < end; i++) {
-                if (values[i].mValue.getType() == INT &&
-                    (values[i].mValue.int_value <= matcher.lte_int())) {
-                    return true;
-                }
-                // lte_int covers both int and long.
-                if (values[i].mValue.getType() == LONG &&
-                    (values[i].mValue.long_value <= matcher.lte_int())) {
-                    return true;
-                }
-            }
-            return false;
-        }
-        case FieldValueMatcher::ValueMatcherCase::kGteInt: {
-            for (int i = start; i < end; i++) {
-                if (values[i].mValue.getType() == INT &&
-                    (values[i].mValue.int_value >= matcher.gte_int())) {
-                    return true;
-                }
-                // gte_int covers both int and long.
-                if (values[i].mValue.getType() == LONG &&
-                    (values[i].mValue.long_value >= matcher.gte_int())) {
-                    return true;
-                }
-            }
-            return false;
-        }
-        default:
-            return false;
-    }
-}
-
-bool matchesSimple(const sp<UidMap>& uidMap, const SimpleAtomMatcher& simpleMatcher,
-                   const LogEvent& event) {
-    if (event.GetTagId() != simpleMatcher.atom_id()) {
-        return false;
-    }
-
-    for (const auto& matcher : simpleMatcher.field_value_matcher()) {
-        if (!matchesSimple(uidMap, matcher, event.getValues(), 0, event.getValues().size(), 0)) {
-            return false;
-        }
-    }
-    return true;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/matchers/matcher_util.h b/cmds/statsd/src/matchers/matcher_util.h
deleted file mode 100644
index 130b606..0000000
--- a/cmds/statsd/src/matchers/matcher_util.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "logd/LogEvent.h"
-
-#include <vector>
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "packages/UidMap.h"
-#include "stats_util.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-enum MatchingState {
-    kNotComputed = -1,
-    kNotMatched = 0,
-    kMatched = 1,
-};
-
-bool combinationMatch(const std::vector<int>& children, const LogicalOperation& operation,
-                      const std::vector<MatchingState>& matcherResults);
-
-bool matchesSimple(const sp<UidMap>& uidMap, const SimpleAtomMatcher& simpleMatcher,
-                   const LogEvent& wrapper);
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/metadata_util.cpp b/cmds/statsd/src/metadata_util.cpp
deleted file mode 100644
index 27ee59b..0000000
--- a/cmds/statsd/src/metadata_util.cpp
+++ /dev/null
@@ -1,122 +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.
- */
-
-#include "FieldValue.h"
-#include "metadata_util.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using google::protobuf::RepeatedPtrField;
-
-void writeValueToProto(metadata::FieldValue* metadataFieldValue, const Value& value) {
-    std::string storage_value;
-    switch (value.getType()) {
-        case INT:
-            metadataFieldValue->set_value_int(value.int_value);
-            break;
-        case LONG:
-            metadataFieldValue->set_value_long(value.long_value);
-            break;
-        case FLOAT:
-            metadataFieldValue->set_value_float(value.float_value);
-            break;
-        case DOUBLE:
-            metadataFieldValue->set_value_double(value.double_value);
-            break;
-        case STRING:
-            metadataFieldValue->set_value_str(value.str_value.c_str());
-            break;
-        case STORAGE: // byte array
-            storage_value = ((char*) value.storage_value.data());
-            metadataFieldValue->set_value_storage(storage_value);
-            break;
-        default:
-            break;
-    }
-}
-
-void writeMetricDimensionKeyToMetadataDimensionKey(
-        const MetricDimensionKey& metricKey,
-        metadata::MetricDimensionKey* metadataMetricKey) {
-    for (const FieldValue& fieldValue : metricKey.getDimensionKeyInWhat().getValues()) {
-        metadata::FieldValue* metadataFieldValue = metadataMetricKey->add_dimension_key_in_what();
-        metadata::Field* metadataField = metadataFieldValue->mutable_field();
-        metadataField->set_tag(fieldValue.mField.getTag());
-        metadataField->set_field(fieldValue.mField.getField());
-        writeValueToProto(metadataFieldValue, fieldValue.mValue);
-    }
-
-    for (const FieldValue& fieldValue : metricKey.getStateValuesKey().getValues()) {
-        metadata::FieldValue* metadataFieldValue = metadataMetricKey->add_state_values_key();
-        metadata::Field* metadataField = metadataFieldValue->mutable_field();
-        metadataField->set_tag(fieldValue.mField.getTag());
-        metadataField->set_field(fieldValue.mField.getField());
-        writeValueToProto(metadataFieldValue, fieldValue.mValue);
-    }
-}
-
-void writeFieldValuesFromMetadata(
-        const RepeatedPtrField<metadata::FieldValue>& repeatedFieldValueList,
-        std::vector<FieldValue>* fieldValues) {
-    for (const metadata::FieldValue& metadataFieldValue : repeatedFieldValueList) {
-        Field field(metadataFieldValue.field().tag(), metadataFieldValue.field().field());
-        Value value;
-        switch (metadataFieldValue.value_case()) {
-            case metadata::FieldValue::ValueCase::kValueInt:
-                value = Value(metadataFieldValue.value_int());
-                break;
-            case metadata::FieldValue::ValueCase::kValueLong:
-                value = Value(metadataFieldValue.value_long());
-                break;
-            case metadata::FieldValue::ValueCase::kValueFloat:
-                value = Value(metadataFieldValue.value_float());
-                break;
-            case metadata::FieldValue::ValueCase::kValueDouble:
-                value = Value(metadataFieldValue.value_double());
-                break;
-            case metadata::FieldValue::ValueCase::kValueStr:
-                value = Value(metadataFieldValue.value_str());
-                break;
-            case metadata::FieldValue::ValueCase::kValueStorage:
-                value = Value(metadataFieldValue.value_storage());
-                break;
-            default:
-                break;
-        }
-        FieldValue fieldValue(field, value);
-        fieldValues->emplace_back(field, value);
-    }
-}
-
-MetricDimensionKey loadMetricDimensionKeyFromProto(
-        const metadata::MetricDimensionKey& metricDimensionKey) {
-    std::vector<FieldValue> dimKeyInWhatFieldValues;
-    writeFieldValuesFromMetadata(metricDimensionKey.dimension_key_in_what(),
-            &dimKeyInWhatFieldValues);
-    std::vector<FieldValue> stateValuesFieldValues;
-    writeFieldValuesFromMetadata(metricDimensionKey.state_values_key(), &stateValuesFieldValues);
-
-    HashableDimensionKey dimKeyInWhat(dimKeyInWhatFieldValues);
-    HashableDimensionKey stateValues(stateValuesFieldValues);
-    MetricDimensionKey metricKey(dimKeyInWhat, stateValues);
-    return metricKey;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/metadata_util.h b/cmds/statsd/src/metadata_util.h
deleted file mode 100644
index 84a39ff..0000000
--- a/cmds/statsd/src/metadata_util.h
+++ /dev/null
@@ -1,32 +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.
- */
-#include "HashableDimensionKey.h"
-
-#include "frameworks/base/cmds/statsd/src/statsd_metadata.pb.h"  // AlertMetadata
-
-namespace android {
-namespace os {
-namespace statsd {
-
-void writeMetricDimensionKeyToMetadataDimensionKey(const MetricDimensionKey& metricKey,
-                                                   metadata::MetricDimensionKey* metadataMetricKey);
-
-MetricDimensionKey loadMetricDimensionKeyFromProto(
-        const metadata::MetricDimensionKey& metricDimensionKey);
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
deleted file mode 100644
index a8ef54a..0000000
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ /dev/null
@@ -1,440 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "CountMetricProducer.h"
-
-#include <inttypes.h>
-#include <limits.h>
-#include <stdlib.h>
-
-#include "guardrail/StatsdStats.h"
-#include "metrics/parsing_utils/metrics_manager_util.h"
-#include "stats_log_util.h"
-#include "stats_util.h"
-
-using android::util::FIELD_COUNT_REPEATED;
-using android::util::FIELD_TYPE_BOOL;
-using android::util::FIELD_TYPE_FLOAT;
-using android::util::FIELD_TYPE_INT32;
-using android::util::FIELD_TYPE_INT64;
-using android::util::FIELD_TYPE_MESSAGE;
-using android::util::FIELD_TYPE_STRING;
-using android::util::ProtoOutputStream;
-using std::map;
-using std::string;
-using std::unordered_map;
-using std::vector;
-using std::shared_ptr;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// for StatsLogReport
-const int FIELD_ID_ID = 1;
-const int FIELD_ID_COUNT_METRICS = 5;
-const int FIELD_ID_TIME_BASE = 9;
-const int FIELD_ID_BUCKET_SIZE = 10;
-const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
-const int FIELD_ID_IS_ACTIVE = 14;
-
-// for CountMetricDataWrapper
-const int FIELD_ID_DATA = 1;
-// for CountMetricData
-const int FIELD_ID_DIMENSION_IN_WHAT = 1;
-const int FIELD_ID_SLICE_BY_STATE = 6;
-const int FIELD_ID_BUCKET_INFO = 3;
-const int FIELD_ID_DIMENSION_LEAF_IN_WHAT = 4;
-// for CountBucketInfo
-const int FIELD_ID_COUNT = 3;
-const int FIELD_ID_BUCKET_NUM = 4;
-const int FIELD_ID_START_BUCKET_ELAPSED_MILLIS = 5;
-const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6;
-
-CountMetricProducer::CountMetricProducer(
-        const ConfigKey& key, const CountMetric& metric, const int conditionIndex,
-        const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
-        const uint64_t protoHash, const int64_t timeBaseNs, const int64_t startTimeNs,
-        const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
-        const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap,
-        const vector<int>& slicedStateAtoms,
-        const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap)
-    : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, initialConditionCache, wizard,
-                     protoHash, eventActivationMap, eventDeactivationMap, slicedStateAtoms,
-                     stateGroupMap) {
-    if (metric.has_bucket()) {
-        mBucketSizeNs =
-                TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket()) * 1000000;
-    } else {
-        mBucketSizeNs = LLONG_MAX;
-    }
-
-    if (metric.has_dimensions_in_what()) {
-        translateFieldMatcher(metric.dimensions_in_what(), &mDimensionsInWhat);
-        mContainANYPositionInDimensionsInWhat = HasPositionANY(metric.dimensions_in_what());
-    }
-
-    mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what());
-
-    if (metric.links().size() > 0) {
-        for (const auto& link : metric.links()) {
-            Metric2Condition mc;
-            mc.conditionId = link.condition();
-            translateFieldMatcher(link.fields_in_what(), &mc.metricFields);
-            translateFieldMatcher(link.fields_in_condition(), &mc.conditionFields);
-            mMetric2ConditionLinks.push_back(mc);
-        }
-        mConditionSliced = true;
-    }
-
-    for (const auto& stateLink : metric.state_link()) {
-        Metric2State ms;
-        ms.stateAtomId = stateLink.state_atom_id();
-        translateFieldMatcher(stateLink.fields_in_what(), &ms.metricFields);
-        translateFieldMatcher(stateLink.fields_in_state(), &ms.stateFields);
-        mMetric2StateLinks.push_back(ms);
-    }
-
-    flushIfNeededLocked(startTimeNs);
-    // Adjust start for partial bucket
-    mCurrentBucketStartTimeNs = startTimeNs;
-
-    VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
-         (long long)mBucketSizeNs, (long long)mTimeBaseNs);
-}
-
-CountMetricProducer::~CountMetricProducer() {
-    VLOG("~CountMetricProducer() called");
-}
-
-bool CountMetricProducer::onConfigUpdatedLocked(
-        const StatsdConfig& config, const int configIndex, const int metricIndex,
-        const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-        const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
-        const unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
-        const sp<EventMatcherWizard>& matcherWizard,
-        const vector<sp<ConditionTracker>>& allConditionTrackers,
-        const unordered_map<int64_t, int>& conditionTrackerMap, const sp<ConditionWizard>& wizard,
-        const unordered_map<int64_t, int>& metricToActivationMap,
-        unordered_map<int, vector<int>>& trackerToMetricMap,
-        unordered_map<int, vector<int>>& conditionToMetricMap,
-        unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
-        unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
-        vector<int>& metricsWithActivation) {
-    if (!MetricProducer::onConfigUpdatedLocked(
-                config, configIndex, metricIndex, allAtomMatchingTrackers,
-                oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, matcherWizard,
-                allConditionTrackers, conditionTrackerMap, wizard, metricToActivationMap,
-                trackerToMetricMap, conditionToMetricMap, activationAtomTrackerToMetricMap,
-                deactivationAtomTrackerToMetricMap, metricsWithActivation)) {
-        return false;
-    }
-
-    const CountMetric& metric = config.count_metric(configIndex);
-    int trackerIndex;
-    // Update appropriate indices, specifically mConditionIndex and MetricsManager maps.
-    if (!handleMetricWithAtomMatchingTrackers(metric.what(), metricIndex, false,
-                                              allAtomMatchingTrackers, newAtomMatchingTrackerMap,
-                                              trackerToMetricMap, trackerIndex)) {
-        return false;
-    }
-
-    if (metric.has_condition() &&
-        !handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
-                                    metric.links(), allConditionTrackers, mConditionTrackerIndex,
-                                    conditionToMetricMap)) {
-        return false;
-    }
-    return true;
-}
-
-void CountMetricProducer::onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
-                                         const HashableDimensionKey& primaryKey,
-                                         const FieldValue& oldState, const FieldValue& newState) {
-    VLOG("CountMetric %lld onStateChanged time %lld, State%d, key %s, %d -> %d",
-         (long long)mMetricId, (long long)eventTimeNs, atomId, primaryKey.toString().c_str(),
-         oldState.mValue.int_value, newState.mValue.int_value);
-}
-
-void CountMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
-    if (mCurrentSlicedCounter == nullptr ||
-        mCurrentSlicedCounter->size() == 0) {
-        return;
-    }
-
-    fprintf(out, "CountMetric %lld dimension size %lu\n", (long long)mMetricId,
-            (unsigned long)mCurrentSlicedCounter->size());
-    if (verbose) {
-        for (const auto& it : *mCurrentSlicedCounter) {
-            fprintf(out, "\t(what)%s\t(state)%s  %lld\n",
-                    it.first.getDimensionKeyInWhat().toString().c_str(),
-                    it.first.getStateValuesKey().toString().c_str(), (unsigned long long)it.second);
-        }
-    }
-}
-
-void CountMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition,
-                                                           const int64_t eventTime) {
-    VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
-}
-
-
-void CountMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) {
-    mPastBuckets.clear();
-}
-
-void CountMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
-                                             const bool include_current_partial_bucket,
-                                             const bool erase_data,
-                                             const DumpLatency dumpLatency,
-                                             std::set<string> *str_set,
-                                             ProtoOutputStream* protoOutput) {
-    if (include_current_partial_bucket) {
-        flushLocked(dumpTimeNs);
-    } else {
-        flushIfNeededLocked(dumpTimeNs);
-    }
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
-    protoOutput->write(FIELD_TYPE_BOOL | FIELD_ID_IS_ACTIVE, isActiveLocked());
-
-
-    if (mPastBuckets.empty()) {
-        return;
-    }
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TIME_BASE, (long long)mTimeBaseNs);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_SIZE, (long long)mBucketSizeNs);
-
-    // Fills the dimension path if not slicing by ALL.
-    if (!mSliceByPositionALL) {
-        if (!mDimensionsInWhat.empty()) {
-            uint64_t dimenPathToken = protoOutput->start(
-                    FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_WHAT);
-            writeDimensionPathToProto(mDimensionsInWhat, protoOutput);
-            protoOutput->end(dimenPathToken);
-        }
-    }
-
-    uint64_t protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_COUNT_METRICS);
-
-    for (const auto& counter : mPastBuckets) {
-        const MetricDimensionKey& dimensionKey = counter.first;
-        VLOG("  dimension key %s", dimensionKey.toString().c_str());
-
-        uint64_t wrapperToken =
-                protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
-
-        // First fill dimension.
-        if (mSliceByPositionALL) {
-            uint64_t dimensionToken = protoOutput->start(
-                    FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
-            writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput);
-            protoOutput->end(dimensionToken);
-        } else {
-            writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInWhat(),
-                                           FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput);
-        }
-        // Then fill slice_by_state.
-        for (auto state : dimensionKey.getStateValuesKey().getValues()) {
-            uint64_t stateToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                                     FIELD_ID_SLICE_BY_STATE);
-            writeStateToProto(state, protoOutput);
-            protoOutput->end(stateToken);
-        }
-        // Then fill bucket_info (CountBucketInfo).
-        for (const auto& bucket : counter.second) {
-            uint64_t bucketInfoToken = protoOutput->start(
-                    FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
-            // Partial bucket.
-            if (bucket.mBucketEndNs - bucket.mBucketStartNs != mBucketSizeNs) {
-                protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_ELAPSED_MILLIS,
-                                   (long long)NanoToMillis(bucket.mBucketStartNs));
-                protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_ELAPSED_MILLIS,
-                                   (long long)NanoToMillis(bucket.mBucketEndNs));
-            } else {
-                protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_NUM,
-                                   (long long)(getBucketNumFromEndTimeNs(bucket.mBucketEndNs)));
-            }
-            protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_COUNT, (long long)bucket.mCount);
-            protoOutput->end(bucketInfoToken);
-            VLOG("\t bucket [%lld - %lld] count: %lld", (long long)bucket.mBucketStartNs,
-                 (long long)bucket.mBucketEndNs, (long long)bucket.mCount);
-        }
-        protoOutput->end(wrapperToken);
-    }
-
-    protoOutput->end(protoToken);
-
-    if (erase_data) {
-        mPastBuckets.clear();
-    }
-}
-
-void CountMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
-    flushIfNeededLocked(dropTimeNs);
-    StatsdStats::getInstance().noteBucketDropped(mMetricId);
-    mPastBuckets.clear();
-}
-
-void CountMetricProducer::onConditionChangedLocked(const bool conditionMet,
-                                                   const int64_t eventTime) {
-    VLOG("Metric %lld onConditionChanged", (long long)mMetricId);
-    mCondition = conditionMet ? ConditionState::kTrue : ConditionState::kFalse;
-}
-
-bool CountMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
-    if (mCurrentSlicedCounter->find(newKey) != mCurrentSlicedCounter->end()) {
-        return false;
-    }
-    // ===========GuardRail==============
-    // 1. Report the tuple count if the tuple count > soft limit
-    if (mCurrentSlicedCounter->size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
-        size_t newTupleCount = mCurrentSlicedCounter->size() + 1;
-        StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount);
-        // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
-        if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
-            ALOGE("CountMetric %lld dropping data for dimension key %s",
-                (long long)mMetricId, newKey.toString().c_str());
-            StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId);
-            return true;
-        }
-    }
-
-    return false;
-}
-
-void CountMetricProducer::onMatchedLogEventInternalLocked(
-        const size_t matcherIndex, const MetricDimensionKey& eventKey,
-        const ConditionKey& conditionKey, bool condition, const LogEvent& event,
-        const map<int, HashableDimensionKey>& statePrimaryKeys) {
-    int64_t eventTimeNs = event.GetElapsedTimestampNs();
-    flushIfNeededLocked(eventTimeNs);
-
-    if (!condition) {
-        return;
-    }
-
-    auto it = mCurrentSlicedCounter->find(eventKey);
-    if (it == mCurrentSlicedCounter->end()) {
-        // ===========GuardRail==============
-        if (hitGuardRailLocked(eventKey)) {
-            return;
-        }
-        // create a counter for the new key
-        (*mCurrentSlicedCounter)[eventKey] = 1;
-    } else {
-        // increment the existing value
-        auto& count = it->second;
-        count++;
-    }
-    for (auto& tracker : mAnomalyTrackers) {
-        int64_t countWholeBucket = mCurrentSlicedCounter->find(eventKey)->second;
-        auto prev = mCurrentFullCounters->find(eventKey);
-        if (prev != mCurrentFullCounters->end()) {
-            countWholeBucket += prev->second;
-        }
-        tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, mMetricId, eventKey,
-                                         countWholeBucket);
-    }
-
-    VLOG("metric %lld %s->%lld", (long long)mMetricId, eventKey.toString().c_str(),
-         (long long)(*mCurrentSlicedCounter)[eventKey]);
-}
-
-// When a new matched event comes in, we check if event falls into the current
-// bucket. If not, flush the old counter to past buckets and initialize the new bucket.
-void CountMetricProducer::flushIfNeededLocked(const int64_t& eventTimeNs) {
-    int64_t currentBucketEndTimeNs = getCurrentBucketEndTimeNs();
-    if (eventTimeNs < currentBucketEndTimeNs) {
-        return;
-    }
-
-    // Setup the bucket start time and number.
-    int64_t numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
-    int64_t nextBucketNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
-    flushCurrentBucketLocked(eventTimeNs, nextBucketNs);
-
-    mCurrentBucketNum += numBucketsForward;
-    VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
-         (long long)mCurrentBucketStartTimeNs);
-}
-
-void CountMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
-                                                   const int64_t& nextBucketStartTimeNs) {
-    int64_t fullBucketEndTimeNs = getCurrentBucketEndTimeNs();
-    CountBucket info;
-    info.mBucketStartNs = mCurrentBucketStartTimeNs;
-    if (eventTimeNs < fullBucketEndTimeNs) {
-        info.mBucketEndNs = eventTimeNs;
-    } else {
-        info.mBucketEndNs = fullBucketEndTimeNs;
-    }
-    for (const auto& counter : *mCurrentSlicedCounter) {
-        info.mCount = counter.second;
-        auto& bucketList = mPastBuckets[counter.first];
-        bucketList.push_back(info);
-        VLOG("metric %lld, dump key value: %s -> %lld", (long long)mMetricId,
-             counter.first.toString().c_str(),
-             (long long)counter.second);
-    }
-
-    // If we have finished a full bucket, then send this to anomaly tracker.
-    if (eventTimeNs > fullBucketEndTimeNs) {
-        // Accumulate partial buckets with current value and then send to anomaly tracker.
-        if (mCurrentFullCounters->size() > 0) {
-            for (const auto& keyValuePair : *mCurrentSlicedCounter) {
-                (*mCurrentFullCounters)[keyValuePair.first] += keyValuePair.second;
-            }
-            for (auto& tracker : mAnomalyTrackers) {
-                tracker->addPastBucket(mCurrentFullCounters, mCurrentBucketNum);
-            }
-            mCurrentFullCounters = std::make_shared<DimToValMap>();
-        } else {
-            // Skip aggregating the partial buckets since there's no previous partial bucket.
-            for (auto& tracker : mAnomalyTrackers) {
-                tracker->addPastBucket(mCurrentSlicedCounter, mCurrentBucketNum);
-            }
-        }
-    } else {
-        // Accumulate partial bucket.
-        for (const auto& keyValuePair : *mCurrentSlicedCounter) {
-            (*mCurrentFullCounters)[keyValuePair.first] += keyValuePair.second;
-        }
-    }
-
-    StatsdStats::getInstance().noteBucketCount(mMetricId);
-    // Only resets the counters, but doesn't setup the times nor numbers.
-    // (Do not clear since the old one is still referenced in mAnomalyTrackers).
-    mCurrentSlicedCounter = std::make_shared<DimToValMap>();
-    mCurrentBucketStartTimeNs = nextBucketStartTimeNs;
-}
-
-// Rough estimate of CountMetricProducer buffer stored. This number will be
-// greater than actual data size as it contains each dimension of
-// CountMetricData is  duplicated.
-size_t CountMetricProducer::byteSizeLocked() const {
-    size_t totalSize = 0;
-    for (const auto& pair : mPastBuckets) {
-        totalSize += pair.second.size() * kBucketSize;
-    }
-    return totalSize;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
deleted file mode 100644
index 0769ac4..0000000
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef COUNT_METRIC_PRODUCER_H
-#define COUNT_METRIC_PRODUCER_H
-
-#include <android/util/ProtoOutputStream.h>
-#include <gtest/gtest_prod.h>
-
-#include <unordered_map>
-
-#include "MetricProducer.h"
-#include "anomaly/AnomalyTracker.h"
-#include "condition/ConditionTracker.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "matchers/matcher_util.h"
-#include "stats_util.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-struct CountBucket {
-    int64_t mBucketStartNs;
-    int64_t mBucketEndNs;
-    int64_t mCount;
-};
-
-class CountMetricProducer : public MetricProducer {
-public:
-    CountMetricProducer(
-            const ConfigKey& key, const CountMetric& countMetric, const int conditionIndex,
-            const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
-            const uint64_t protoHash, const int64_t timeBaseNs, const int64_t startTimeNs,
-            const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap = {},
-            const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
-                    eventDeactivationMap = {},
-            const vector<int>& slicedStateAtoms = {},
-            const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap = {});
-
-    virtual ~CountMetricProducer();
-
-    void onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
-                        const HashableDimensionKey& primaryKey, const FieldValue& oldState,
-                        const FieldValue& newState) override;
-
-    MetricType getMetricType() const override {
-        return METRIC_TYPE_COUNT;
-    }
-
-protected:
-    void onMatchedLogEventInternalLocked(
-            const size_t matcherIndex, const MetricDimensionKey& eventKey,
-            const ConditionKey& conditionKey, bool condition, const LogEvent& event,
-            const std::map<int, HashableDimensionKey>& statePrimaryKeys) override;
-
-private:
-
-    void onDumpReportLocked(const int64_t dumpTimeNs,
-                            const bool include_current_partial_bucket,
-                            const bool erase_data,
-                            const DumpLatency dumpLatency,
-                            std::set<string> *str_set,
-                            android::util::ProtoOutputStream* protoOutput) override;
-
-    void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
-
-    // Internal interface to handle condition change.
-    void onConditionChangedLocked(const bool conditionMet, const int64_t eventTime) override;
-
-    // Internal interface to handle sliced condition change.
-    void onSlicedConditionMayChangeLocked(bool overallCondition, const int64_t eventTime) override;
-
-    // Internal function to calculate the current used bytes.
-    size_t byteSizeLocked() const override;
-
-    void dumpStatesLocked(FILE* out, bool verbose) const override;
-
-    void dropDataLocked(const int64_t dropTimeNs) override;
-
-    // Util function to flush the old packet.
-    void flushIfNeededLocked(const int64_t& newEventTime) override;
-
-    void flushCurrentBucketLocked(const int64_t& eventTimeNs,
-                                  const int64_t& nextBucketStartTimeNs) override;
-
-    bool onConfigUpdatedLocked(
-            const StatsdConfig& config, const int configIndex, const int metricIndex,
-            const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-            const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
-            const std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
-            const sp<EventMatcherWizard>& matcherWizard,
-            const std::vector<sp<ConditionTracker>>& allConditionTrackers,
-            const std::unordered_map<int64_t, int>& conditionTrackerMap,
-            const sp<ConditionWizard>& wizard,
-            const std::unordered_map<int64_t, int>& metricToActivationMap,
-            std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
-            std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
-            std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
-            std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
-            std::vector<int>& metricsWithActivation) override;
-
-    std::unordered_map<MetricDimensionKey, std::vector<CountBucket>> mPastBuckets;
-
-    // The current bucket (may be a partial bucket).
-    std::shared_ptr<DimToValMap> mCurrentSlicedCounter = std::make_shared<DimToValMap>();
-
-    // The sum of previous partial buckets in the current full bucket (excluding the current
-    // partial bucket). This is only updated while flushing the current bucket.
-    std::shared_ptr<DimToValMap> mCurrentFullCounters = std::make_shared<DimToValMap>();
-
-    static const size_t kBucketSize = sizeof(CountBucket{});
-
-    bool hitGuardRailLocked(const MetricDimensionKey& newKey);
-
-    FRIEND_TEST(CountMetricProducerTest, TestNonDimensionalEvents);
-    FRIEND_TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition);
-    FRIEND_TEST(CountMetricProducerTest, TestEventsWithSlicedCondition);
-    FRIEND_TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced);
-    FRIEND_TEST(CountMetricProducerTest, TestFirstBucket);
-    FRIEND_TEST(CountMetricProducerTest, TestOneWeekTimeUnit);
-
-    FRIEND_TEST(CountMetricProducerTest_PartialBucket, TestSplitInCurrentBucket);
-    FRIEND_TEST(CountMetricProducerTest_PartialBucket, TestSplitInNextBucket);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#endif  // COUNT_METRIC_PRODUCER_H
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
deleted file mode 100644
index 001ad36..0000000
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ /dev/null
@@ -1,783 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false
-
-#include "Log.h"
-
-#include "DurationMetricProducer.h"
-
-#include <limits.h>
-#include <stdlib.h>
-
-#include "guardrail/StatsdStats.h"
-#include "metrics/parsing_utils/metrics_manager_util.h"
-#include "stats_log_util.h"
-#include "stats_util.h"
-
-using android::util::FIELD_COUNT_REPEATED;
-using android::util::FIELD_TYPE_BOOL;
-using android::util::FIELD_TYPE_FLOAT;
-using android::util::FIELD_TYPE_INT32;
-using android::util::FIELD_TYPE_INT64;
-using android::util::FIELD_TYPE_MESSAGE;
-using android::util::FIELD_TYPE_STRING;
-using android::util::ProtoOutputStream;
-using std::string;
-using std::unordered_map;
-using std::vector;
-using std::shared_ptr;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// for StatsLogReport
-const int FIELD_ID_ID = 1;
-const int FIELD_ID_DURATION_METRICS = 6;
-const int FIELD_ID_TIME_BASE = 9;
-const int FIELD_ID_BUCKET_SIZE = 10;
-const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
-const int FIELD_ID_IS_ACTIVE = 14;
-// for DurationMetricDataWrapper
-const int FIELD_ID_DATA = 1;
-// for DurationMetricData
-const int FIELD_ID_DIMENSION_IN_WHAT = 1;
-const int FIELD_ID_BUCKET_INFO = 3;
-const int FIELD_ID_DIMENSION_LEAF_IN_WHAT = 4;
-const int FIELD_ID_SLICE_BY_STATE = 6;
-// for DurationBucketInfo
-const int FIELD_ID_DURATION = 3;
-const int FIELD_ID_BUCKET_NUM = 4;
-const int FIELD_ID_START_BUCKET_ELAPSED_MILLIS = 5;
-const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6;
-
-DurationMetricProducer::DurationMetricProducer(
-        const ConfigKey& key, const DurationMetric& metric, const int conditionIndex,
-        const vector<ConditionState>& initialConditionCache, const int whatIndex,
-        const int startIndex, const int stopIndex, const int stopAllIndex, const bool nesting,
-        const sp<ConditionWizard>& wizard, const uint64_t protoHash,
-        const FieldMatcher& internalDimensions, const int64_t timeBaseNs, const int64_t startTimeNs,
-        const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
-        const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap,
-        const vector<int>& slicedStateAtoms,
-        const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap)
-    : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, initialConditionCache, wizard,
-                     protoHash, eventActivationMap, eventDeactivationMap, slicedStateAtoms,
-                     stateGroupMap),
-      mAggregationType(metric.aggregation_type()),
-      mStartIndex(startIndex),
-      mStopIndex(stopIndex),
-      mStopAllIndex(stopAllIndex),
-      mNested(nesting),
-      mContainANYPositionInInternalDimensions(false) {
-    if (metric.has_bucket()) {
-        mBucketSizeNs =
-                TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket()) * 1000000;
-    } else {
-        mBucketSizeNs = LLONG_MAX;
-    }
-
-    if (metric.has_dimensions_in_what()) {
-        translateFieldMatcher(metric.dimensions_in_what(), &mDimensionsInWhat);
-        mContainANYPositionInDimensionsInWhat = HasPositionANY(metric.dimensions_in_what());
-    }
-
-    if (internalDimensions.has_field()) {
-        translateFieldMatcher(internalDimensions, &mInternalDimensions);
-        mContainANYPositionInInternalDimensions = HasPositionANY(internalDimensions);
-    }
-    if (mContainANYPositionInInternalDimensions) {
-        ALOGE("Position ANY in internal dimension not supported.");
-    }
-    if (mContainANYPositionInDimensionsInWhat) {
-        ALOGE("Position ANY in dimension_in_what not supported.");
-    }
-
-    // Dimensions in what must be subset of internal dimensions
-    if (!subsetDimensions(mDimensionsInWhat, mInternalDimensions)) {
-        ALOGE("Dimensions in what must be a subset of the internal dimensions");
-        mValid = false;
-    }
-
-    mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what());
-
-    if (metric.links().size() > 0) {
-        for (const auto& link : metric.links()) {
-            Metric2Condition mc;
-            mc.conditionId = link.condition();
-            translateFieldMatcher(link.fields_in_what(), &mc.metricFields);
-            translateFieldMatcher(link.fields_in_condition(), &mc.conditionFields);
-            if (!subsetDimensions(mc.metricFields, mInternalDimensions)) {
-                ALOGE(("Condition links must be a subset of the internal dimensions"));
-                mValid = false;
-            }
-            mMetric2ConditionLinks.push_back(mc);
-        }
-        mConditionSliced = true;
-    }
-    mUnSlicedPartCondition = ConditionState::kUnknown;
-
-    for (const auto& stateLink : metric.state_link()) {
-        Metric2State ms;
-        ms.stateAtomId = stateLink.state_atom_id();
-        translateFieldMatcher(stateLink.fields_in_what(), &ms.metricFields);
-        translateFieldMatcher(stateLink.fields_in_state(), &ms.stateFields);
-        if (!subsetDimensions(ms.metricFields, mInternalDimensions)) {
-            ALOGE(("State links must be a subset of the dimensions in what  internal dimensions"));
-            mValid = false;
-        }
-        mMetric2StateLinks.push_back(ms);
-    }
-
-    mUseWhatDimensionAsInternalDimension = equalDimensions(mDimensionsInWhat, mInternalDimensions);
-    if (mWizard != nullptr && mConditionTrackerIndex >= 0 &&
-            mMetric2ConditionLinks.size() == 1) {
-        mHasLinksToAllConditionDimensionsInTracker = mWizard->equalOutputDimensions(
-                mConditionTrackerIndex, mMetric2ConditionLinks.begin()->conditionFields);
-    }
-    flushIfNeededLocked(startTimeNs);
-    // Adjust start for partial bucket
-    mCurrentBucketStartTimeNs = startTimeNs;
-    VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
-         (long long)mBucketSizeNs, (long long)mTimeBaseNs);
-
-    initTrueDimensions(whatIndex, startTimeNs);
-}
-
-DurationMetricProducer::~DurationMetricProducer() {
-    VLOG("~DurationMetric() called");
-}
-
-bool DurationMetricProducer::onConfigUpdatedLocked(
-        const StatsdConfig& config, const int configIndex, const int metricIndex,
-        const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-        const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
-        const unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
-        const sp<EventMatcherWizard>& matcherWizard,
-        const vector<sp<ConditionTracker>>& allConditionTrackers,
-        const unordered_map<int64_t, int>& conditionTrackerMap, const sp<ConditionWizard>& wizard,
-        const unordered_map<int64_t, int>& metricToActivationMap,
-        unordered_map<int, vector<int>>& trackerToMetricMap,
-        unordered_map<int, vector<int>>& conditionToMetricMap,
-        unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
-        unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
-        vector<int>& metricsWithActivation) {
-    if (!MetricProducer::onConfigUpdatedLocked(
-                config, configIndex, metricIndex, allAtomMatchingTrackers,
-                oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, matcherWizard,
-                allConditionTrackers, conditionTrackerMap, wizard, metricToActivationMap,
-                trackerToMetricMap, conditionToMetricMap, activationAtomTrackerToMetricMap,
-                deactivationAtomTrackerToMetricMap, metricsWithActivation)) {
-        return false;
-    }
-
-    const DurationMetric& metric = config.duration_metric(configIndex);
-    const auto& what_it = conditionTrackerMap.find(metric.what());
-    if (what_it == conditionTrackerMap.end()) {
-        ALOGE("DurationMetric's \"what\" is not present in the config");
-        return false;
-    }
-
-    const Predicate& durationWhat = config.predicate(what_it->second);
-    if (durationWhat.contents_case() != Predicate::ContentsCase::kSimplePredicate) {
-        ALOGE("DurationMetric's \"what\" must be a simple condition");
-        return false;
-    }
-
-    const SimplePredicate& simplePredicate = durationWhat.simple_predicate();
-
-    // Update indices: mStartIndex, mStopIndex, mStopAllIndex, mConditionIndex and MetricsManager
-    // maps.
-    if (!handleMetricWithAtomMatchingTrackers(simplePredicate.start(), metricIndex,
-                                              metric.has_dimensions_in_what(),
-                                              allAtomMatchingTrackers, newAtomMatchingTrackerMap,
-                                              trackerToMetricMap, mStartIndex)) {
-        ALOGE("Duration metrics must specify a valid start event matcher");
-        return false;
-    }
-
-    if (simplePredicate.has_stop() &&
-        !handleMetricWithAtomMatchingTrackers(simplePredicate.stop(), metricIndex,
-                                              metric.has_dimensions_in_what(),
-                                              allAtomMatchingTrackers, newAtomMatchingTrackerMap,
-                                              trackerToMetricMap, mStopIndex)) {
-        return false;
-    }
-
-    if (simplePredicate.has_stop_all() &&
-        !handleMetricWithAtomMatchingTrackers(simplePredicate.stop_all(), metricIndex,
-                                              metric.has_dimensions_in_what(),
-                                              allAtomMatchingTrackers, newAtomMatchingTrackerMap,
-                                              trackerToMetricMap, mStopAllIndex)) {
-        return false;
-    }
-
-    if (metric.has_condition() &&
-        !handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
-                                    metric.links(), allConditionTrackers, mConditionTrackerIndex,
-                                    conditionToMetricMap)) {
-        return false;
-    }
-
-    for (const auto& it : mCurrentSlicedDurationTrackerMap) {
-        it.second->onConfigUpdated(wizard, mConditionTrackerIndex);
-    }
-
-    return true;
-}
-
-void DurationMetricProducer::initTrueDimensions(const int whatIndex, const int64_t startTimeNs) {
-    std::lock_guard<std::mutex> lock(mMutex);
-    // Currently whatIndex will only be -1 in tests. In the future, we might want to avoid creating
-    // a ConditionTracker if the condition is only used in the "what" of a duration metric. In that
-    // scenario, -1 can also be passed.
-    if (whatIndex == -1) {
-        return;
-    }
-    const map<HashableDimensionKey, int>* slicedWhatMap = mWizard->getSlicedDimensionMap(whatIndex);
-    for (const auto& [internalDimKey, count] : *slicedWhatMap) {
-        for (int i = 0; i < count; i++) {
-            // Fake start events.
-            handleMatchedLogEventValuesLocked(mStartIndex, internalDimKey.getValues(), startTimeNs);
-        }
-    }
-}
-
-sp<AnomalyTracker> DurationMetricProducer::addAnomalyTracker(
-        const Alert &alert, const sp<AlarmMonitor>& anomalyAlarmMonitor) {
-    std::lock_guard<std::mutex> lock(mMutex);
-    if (mAggregationType == DurationMetric_AggregationType_SUM) {
-        if (alert.trigger_if_sum_gt() > alert.num_buckets() * mBucketSizeNs) {
-            ALOGW("invalid alert for SUM: threshold (%f) > possible recordable value (%d x %lld)",
-                  alert.trigger_if_sum_gt(), alert.num_buckets(), (long long)mBucketSizeNs);
-            return nullptr;
-        }
-    }
-    sp<AnomalyTracker> anomalyTracker =
-            new DurationAnomalyTracker(alert, mConfigKey, anomalyAlarmMonitor);
-    addAnomalyTrackerLocked(anomalyTracker);
-    return anomalyTracker;
-}
-
-// Adds an AnomalyTracker that has already been created.
-// Note: this gets called on config updates, and will only get called if the metric and the
-// associated alert are preserved, which means the AnomalyTracker must be a DurationAnomalyTracker.
-void DurationMetricProducer::addAnomalyTracker(sp<AnomalyTracker>& anomalyTracker) {
-    std::lock_guard<std::mutex> lock(mMutex);
-    addAnomalyTrackerLocked(anomalyTracker);
-}
-
-void DurationMetricProducer::addAnomalyTrackerLocked(sp<AnomalyTracker>& anomalyTracker) {
-    mAnomalyTrackers.push_back(anomalyTracker);
-    for (const auto& [_, durationTracker] : mCurrentSlicedDurationTrackerMap) {
-        durationTracker->addAnomalyTracker(anomalyTracker);
-    }
-}
-void DurationMetricProducer::onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
-                                            const HashableDimensionKey& primaryKey,
-                                            const FieldValue& oldState,
-                                            const FieldValue& newState) {
-    // Check if this metric has a StateMap. If so, map the new state value to
-    // the correct state group id.
-    FieldValue newStateCopy = newState;
-    mapStateValue(atomId, &newStateCopy);
-
-    flushIfNeededLocked(eventTimeNs);
-
-    // Each duration tracker is mapped to a different whatKey (a set of values from the
-    // dimensionsInWhat fields). We notify all trackers iff the primaryKey field values from the
-    // state change event are a subset of the tracker's whatKey field values.
-    //
-    // Ex. For a duration metric dimensioned on uid and tag:
-    // DurationTracker1 whatKey = uid: 1001, tag: 1
-    // DurationTracker2 whatKey = uid: 1002, tag 1
-    //
-    // If the state change primaryKey = uid: 1001, we only notify DurationTracker1 of a state
-    // change.
-    for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
-        if (!containsLinkedStateValues(whatIt.first, primaryKey, mMetric2StateLinks, atomId)) {
-            continue;
-        }
-        whatIt.second->onStateChanged(eventTimeNs, atomId, newStateCopy);
-    }
-}
-
-unique_ptr<DurationTracker> DurationMetricProducer::createDurationTracker(
-        const MetricDimensionKey& eventKey) const {
-    switch (mAggregationType) {
-        case DurationMetric_AggregationType_SUM:
-            return make_unique<OringDurationTracker>(
-                    mConfigKey, mMetricId, eventKey, mWizard, mConditionTrackerIndex, mNested,
-                    mCurrentBucketStartTimeNs, mCurrentBucketNum, mTimeBaseNs, mBucketSizeNs,
-                    mConditionSliced, mHasLinksToAllConditionDimensionsInTracker, mAnomalyTrackers);
-        case DurationMetric_AggregationType_MAX_SPARSE:
-            return make_unique<MaxDurationTracker>(
-                    mConfigKey, mMetricId, eventKey, mWizard, mConditionTrackerIndex, mNested,
-                    mCurrentBucketStartTimeNs, mCurrentBucketNum, mTimeBaseNs, mBucketSizeNs,
-                    mConditionSliced, mHasLinksToAllConditionDimensionsInTracker, mAnomalyTrackers);
-    }
-}
-
-// SlicedConditionChange optimization case 1:
-// 1. If combination condition, logical operation is AND, only one sliced child predicate.
-// 2. The links covers all dimension fields in the sliced child condition predicate.
-void DurationMetricProducer::onSlicedConditionMayChangeLocked_opt1(bool condition,
-                                                                   const int64_t eventTime) {
-    if (mMetric2ConditionLinks.size() != 1 ||
-        !mHasLinksToAllConditionDimensionsInTracker) {
-        return;
-    }
-
-    bool  currentUnSlicedPartCondition = true;
-    if (!mWizard->IsSimpleCondition(mConditionTrackerIndex)) {
-        ConditionState unslicedPartState =
-            mWizard->getUnSlicedPartConditionState(mConditionTrackerIndex);
-        // When the unsliced part is still false, return directly.
-        if (mUnSlicedPartCondition == ConditionState::kFalse &&
-            unslicedPartState == ConditionState::kFalse) {
-            return;
-        }
-        mUnSlicedPartCondition = unslicedPartState;
-        currentUnSlicedPartCondition = mUnSlicedPartCondition > 0;
-    }
-
-    auto dimensionsChangedToTrue = mWizard->getChangedToTrueDimensions(mConditionTrackerIndex);
-    auto dimensionsChangedToFalse = mWizard->getChangedToFalseDimensions(mConditionTrackerIndex);
-
-    // The condition change is from the unsliced predicates.
-    // We need to find out the true dimensions from the sliced predicate and flip their condition
-    // state based on the new unsliced condition state.
-    if (dimensionsChangedToTrue == nullptr || dimensionsChangedToFalse == nullptr ||
-        (dimensionsChangedToTrue->empty() && dimensionsChangedToFalse->empty())) {
-        const map<HashableDimensionKey, int>* slicedConditionMap =
-                mWizard->getSlicedDimensionMap(mConditionTrackerIndex);
-        for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
-            HashableDimensionKey linkedConditionDimensionKey;
-            getDimensionForCondition(whatIt.first.getValues(), mMetric2ConditionLinks[0],
-                                     &linkedConditionDimensionKey);
-            const auto& slicedConditionIt = slicedConditionMap->find(linkedConditionDimensionKey);
-            if (slicedConditionIt != slicedConditionMap->end() && slicedConditionIt->second > 0) {
-                whatIt.second->onConditionChanged(currentUnSlicedPartCondition, eventTime);
-            }
-        }
-    } else {
-        // Handle the condition change from the sliced predicate.
-        if (currentUnSlicedPartCondition) {
-            for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
-                HashableDimensionKey linkedConditionDimensionKey;
-                getDimensionForCondition(whatIt.first.getValues(), mMetric2ConditionLinks[0],
-                                         &linkedConditionDimensionKey);
-                if (dimensionsChangedToTrue->find(linkedConditionDimensionKey) !=
-                        dimensionsChangedToTrue->end()) {
-                    whatIt.second->onConditionChanged(true, eventTime);
-                }
-                if (dimensionsChangedToFalse->find(linkedConditionDimensionKey) !=
-                        dimensionsChangedToFalse->end()) {
-                    whatIt.second->onConditionChanged(false, eventTime);
-                }
-            }
-        }
-    }
-}
-
-void DurationMetricProducer::onSlicedConditionMayChangeInternalLocked(bool overallCondition,
-        const int64_t eventTimeNs) {
-    bool changeDimTrackable = mWizard->IsChangedDimensionTrackable(mConditionTrackerIndex);
-    if (changeDimTrackable && mHasLinksToAllConditionDimensionsInTracker) {
-        onSlicedConditionMayChangeLocked_opt1(overallCondition, eventTimeNs);
-        return;
-    }
-
-    // Now for each of the on-going event, check if the condition has changed for them.
-    for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
-        whatIt.second->onSlicedConditionMayChange(overallCondition, eventTimeNs);
-    }
-}
-
-void DurationMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition,
-                                                              const int64_t eventTime) {
-    VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
-
-    if (!mIsActive) {
-        return;
-    }
-
-    flushIfNeededLocked(eventTime);
-
-    if (!mConditionSliced) {
-        return;
-    }
-
-    onSlicedConditionMayChangeInternalLocked(overallCondition, eventTime);
-}
-
-void DurationMetricProducer::onActiveStateChangedLocked(const int64_t& eventTimeNs) {
-    MetricProducer::onActiveStateChangedLocked(eventTimeNs);
-
-    if (!mConditionSliced) {
-        if (ConditionState::kTrue != mCondition) {
-            return;
-        }
-
-        if (mIsActive) {
-            flushIfNeededLocked(eventTimeNs);
-        }
-
-        for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
-            whatIt.second->onConditionChanged(mIsActive, eventTimeNs);
-        }
-    } else if (mIsActive) {
-        flushIfNeededLocked(eventTimeNs);
-        onSlicedConditionMayChangeInternalLocked(mIsActive, eventTimeNs);
-    } else { // mConditionSliced == true && !mIsActive
-        for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
-            whatIt.second->onConditionChanged(mIsActive, eventTimeNs);
-        }
-    }
-}
-
-void DurationMetricProducer::onConditionChangedLocked(const bool conditionMet,
-                                                      const int64_t eventTime) {
-    VLOG("Metric %lld onConditionChanged", (long long)mMetricId);
-    mCondition = conditionMet ? ConditionState::kTrue : ConditionState::kFalse;
-
-    if (!mIsActive) {
-        return;
-    }
-
-    flushIfNeededLocked(eventTime);
-    for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
-        whatIt.second->onConditionChanged(conditionMet, eventTime);
-    }
-}
-
-void DurationMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
-    flushIfNeededLocked(dropTimeNs);
-    StatsdStats::getInstance().noteBucketDropped(mMetricId);
-    mPastBuckets.clear();
-}
-
-void DurationMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) {
-    flushIfNeededLocked(dumpTimeNs);
-    mPastBuckets.clear();
-}
-
-void DurationMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
-                                                const bool include_current_partial_bucket,
-                                                const bool erase_data,
-                                                const DumpLatency dumpLatency,
-                                                std::set<string> *str_set,
-                                                ProtoOutputStream* protoOutput) {
-    if (include_current_partial_bucket) {
-        flushLocked(dumpTimeNs);
-    } else {
-        flushIfNeededLocked(dumpTimeNs);
-    }
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
-    protoOutput->write(FIELD_TYPE_BOOL | FIELD_ID_IS_ACTIVE, isActiveLocked());
-
-    if (mPastBuckets.empty()) {
-        VLOG(" Duration metric, empty return");
-        return;
-    }
-
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TIME_BASE, (long long)mTimeBaseNs);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_SIZE, (long long)mBucketSizeNs);
-
-    if (!mSliceByPositionALL) {
-        if (!mDimensionsInWhat.empty()) {
-            uint64_t dimenPathToken = protoOutput->start(
-                    FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_WHAT);
-            writeDimensionPathToProto(mDimensionsInWhat, protoOutput);
-            protoOutput->end(dimenPathToken);
-        }
-    }
-
-    uint64_t protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DURATION_METRICS);
-
-    VLOG("Duration metric %lld dump report now...", (long long)mMetricId);
-
-    for (const auto& pair : mPastBuckets) {
-        const MetricDimensionKey& dimensionKey = pair.first;
-        VLOG("  dimension key %s", dimensionKey.toString().c_str());
-
-        uint64_t wrapperToken =
-                protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
-
-        // First fill dimension.
-        if (mSliceByPositionALL) {
-            uint64_t dimensionToken = protoOutput->start(
-                    FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
-            writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput);
-            protoOutput->end(dimensionToken);
-        } else {
-            writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInWhat(),
-                                           FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput);
-        }
-        // Then fill slice_by_state.
-        for (auto state : dimensionKey.getStateValuesKey().getValues()) {
-            uint64_t stateToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                                     FIELD_ID_SLICE_BY_STATE);
-            writeStateToProto(state, protoOutput);
-            protoOutput->end(stateToken);
-        }
-        // Then fill bucket_info (DurationBucketInfo).
-        for (const auto& bucket : pair.second) {
-            uint64_t bucketInfoToken = protoOutput->start(
-                    FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
-            if (bucket.mBucketEndNs - bucket.mBucketStartNs != mBucketSizeNs) {
-                protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_ELAPSED_MILLIS,
-                                   (long long)NanoToMillis(bucket.mBucketStartNs));
-                protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_ELAPSED_MILLIS,
-                                   (long long)NanoToMillis(bucket.mBucketEndNs));
-            } else {
-                protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_NUM,
-                                   (long long)(getBucketNumFromEndTimeNs(bucket.mBucketEndNs)));
-            }
-            protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_DURATION, (long long)bucket.mDuration);
-            protoOutput->end(bucketInfoToken);
-            VLOG("\t bucket [%lld - %lld] duration: %lld", (long long)bucket.mBucketStartNs,
-                 (long long)bucket.mBucketEndNs, (long long)bucket.mDuration);
-        }
-
-        protoOutput->end(wrapperToken);
-    }
-
-    protoOutput->end(protoToken);
-    if (erase_data) {
-        mPastBuckets.clear();
-    }
-}
-
-void DurationMetricProducer::flushIfNeededLocked(const int64_t& eventTimeNs) {
-    int64_t currentBucketEndTimeNs = getCurrentBucketEndTimeNs();
-
-    if (currentBucketEndTimeNs > eventTimeNs) {
-        return;
-    }
-    VLOG("flushing...........");
-    int numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
-    int64_t nextBucketNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
-    flushCurrentBucketLocked(eventTimeNs, nextBucketNs);
-
-    mCurrentBucketNum += numBucketsForward;
-}
-
-void DurationMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
-                                                      const int64_t& nextBucketStartTimeNs) {
-    for (auto whatIt = mCurrentSlicedDurationTrackerMap.begin();
-            whatIt != mCurrentSlicedDurationTrackerMap.end();) {
-        if (whatIt->second->flushCurrentBucket(eventTimeNs, &mPastBuckets)) {
-            VLOG("erase bucket for key %s", whatIt->first.toString().c_str());
-            whatIt = mCurrentSlicedDurationTrackerMap.erase(whatIt);
-        } else {
-            ++whatIt;
-        }
-    }
-    StatsdStats::getInstance().noteBucketCount(mMetricId);
-    mCurrentBucketStartTimeNs = nextBucketStartTimeNs;
-}
-
-void DurationMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
-    if (mCurrentSlicedDurationTrackerMap.size() == 0) {
-        return;
-    }
-
-    fprintf(out, "DurationMetric %lld dimension size %lu\n", (long long)mMetricId,
-            (unsigned long)mCurrentSlicedDurationTrackerMap.size());
-    if (verbose) {
-        for (const auto& whatIt : mCurrentSlicedDurationTrackerMap) {
-            fprintf(out, "\t(what)%s\n", whatIt.first.toString().c_str());
-            whatIt.second->dumpStates(out, verbose);
-        }
-    }
-}
-
-bool DurationMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
-    auto whatIt = mCurrentSlicedDurationTrackerMap.find(newKey.getDimensionKeyInWhat());
-    if (whatIt == mCurrentSlicedDurationTrackerMap.end()) {
-        // 1. Report the tuple count if the tuple count > soft limit
-        if (mCurrentSlicedDurationTrackerMap.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
-            size_t newTupleCount = mCurrentSlicedDurationTrackerMap.size() + 1;
-            StatsdStats::getInstance().noteMetricDimensionSize(
-                    mConfigKey, mMetricId, newTupleCount);
-            // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
-            if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
-                ALOGE("DurationMetric %lld dropping data for what dimension key %s",
-                    (long long)mMetricId, newKey.getDimensionKeyInWhat().toString().c_str());
-                StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId);
-                return true;
-            }
-        }
-    }
-    return false;
-}
-
-void DurationMetricProducer::handleStartEvent(const MetricDimensionKey& eventKey,
-                                              const ConditionKey& conditionKeys, bool condition,
-                                              const int64_t eventTimeNs,
-                                              const vector<FieldValue>& eventValues) {
-    const auto& whatKey = eventKey.getDimensionKeyInWhat();
-    auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatKey);
-    if (whatIt == mCurrentSlicedDurationTrackerMap.end()) {
-        if (hitGuardRailLocked(eventKey)) {
-            return;
-        }
-        mCurrentSlicedDurationTrackerMap[whatKey] = createDurationTracker(eventKey);
-    }
-
-    auto it = mCurrentSlicedDurationTrackerMap.find(whatKey);
-    if (mUseWhatDimensionAsInternalDimension) {
-        it->second->noteStart(whatKey, condition, eventTimeNs, conditionKeys);
-        return;
-    }
-
-    if (mInternalDimensions.empty()) {
-        it->second->noteStart(DEFAULT_DIMENSION_KEY, condition, eventTimeNs, conditionKeys);
-    } else {
-        HashableDimensionKey dimensionKey = DEFAULT_DIMENSION_KEY;
-        filterValues(mInternalDimensions, eventValues, &dimensionKey);
-        it->second->noteStart(dimensionKey, condition, eventTimeNs, conditionKeys);
-    }
-}
-
-void DurationMetricProducer::onMatchedLogEventInternalLocked(
-        const size_t matcherIndex, const MetricDimensionKey& eventKey,
-        const ConditionKey& conditionKeys, bool condition, const LogEvent& event,
-        const map<int, HashableDimensionKey>& statePrimaryKeys) {
-    ALOGW("Not used in duration tracker.");
-}
-
-void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
-                                                     const LogEvent& event) {
-    handleMatchedLogEventValuesLocked(matcherIndex, event.getValues(),
-                                      event.GetElapsedTimestampNs());
-}
-
-void DurationMetricProducer::handleMatchedLogEventValuesLocked(const size_t matcherIndex,
-                                                               const vector<FieldValue>& values,
-                                                               const int64_t eventTimeNs) {
-    if (eventTimeNs < mTimeBaseNs) {
-        return;
-    }
-
-    if (mIsActive) {
-        flushIfNeededLocked(eventTimeNs);
-    }
-
-    // Handles Stopall events.
-    if ((int)matcherIndex == mStopAllIndex) {
-        for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
-            whatIt.second->noteStopAll(eventTimeNs);
-        }
-        return;
-    }
-
-    HashableDimensionKey dimensionInWhat = DEFAULT_DIMENSION_KEY;
-    if (!mDimensionsInWhat.empty()) {
-        filterValues(mDimensionsInWhat, values, &dimensionInWhat);
-    }
-
-    // Stores atom id to primary key pairs for each state atom that the metric is
-    // sliced by.
-    std::map<int, HashableDimensionKey> statePrimaryKeys;
-
-    // For states with primary fields, use MetricStateLinks to get the primary
-    // field values from the log event. These values will form a primary key
-    // that will be used to query StateTracker for the correct state value.
-    for (const auto& stateLink : mMetric2StateLinks) {
-        getDimensionForState(values, stateLink, &statePrimaryKeys[stateLink.stateAtomId]);
-    }
-
-    // For each sliced state, query StateTracker for the state value using
-    // either the primary key from the previous step or the DEFAULT_DIMENSION_KEY.
-    //
-    // Expected functionality: for any case where the MetricStateLinks are
-    // initialized incorrectly (ex. # of state links != # of primary fields, no
-    // links are provided for a state with primary fields, links are provided
-    // in the wrong order, etc.), StateTracker will simply return kStateUnknown
-    // when queried using an incorrect key.
-    HashableDimensionKey stateValuesKey = DEFAULT_DIMENSION_KEY;
-    for (auto atomId : mSlicedStateAtoms) {
-        FieldValue value;
-        if (statePrimaryKeys.find(atomId) != statePrimaryKeys.end()) {
-            // found a primary key for this state, query using the key
-            queryStateValue(atomId, statePrimaryKeys[atomId], &value);
-        } else {
-            // if no MetricStateLinks exist for this state atom,
-            // query using the default dimension key (empty HashableDimensionKey)
-            queryStateValue(atomId, DEFAULT_DIMENSION_KEY, &value);
-        }
-        mapStateValue(atomId, &value);
-        stateValuesKey.addValue(value);
-    }
-
-    // Handles Stop events.
-    if ((int)matcherIndex == mStopIndex) {
-        if (mUseWhatDimensionAsInternalDimension) {
-            auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
-            if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
-                whatIt->second->noteStop(dimensionInWhat, eventTimeNs, false);
-            }
-            return;
-        }
-
-        HashableDimensionKey internalDimensionKey = DEFAULT_DIMENSION_KEY;
-        if (!mInternalDimensions.empty()) {
-            filterValues(mInternalDimensions, values, &internalDimensionKey);
-        }
-
-        auto whatIt = mCurrentSlicedDurationTrackerMap.find(dimensionInWhat);
-        if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
-            whatIt->second->noteStop(internalDimensionKey, eventTimeNs, false);
-        }
-        return;
-    }
-
-    bool condition;
-    ConditionKey conditionKey;
-    if (mConditionSliced) {
-        for (const auto& link : mMetric2ConditionLinks) {
-            getDimensionForCondition(values, link, &conditionKey[link.conditionId]);
-        }
-
-        auto conditionState =
-            mWizard->query(mConditionTrackerIndex, conditionKey,
-                           !mHasLinksToAllConditionDimensionsInTracker);
-        condition = conditionState == ConditionState::kTrue;
-    } else {
-        // TODO: The unknown condition state is not handled here, we should fix it.
-        condition = mCondition == ConditionState::kTrue;
-    }
-
-    condition = condition && mIsActive;
-
-    handleStartEvent(MetricDimensionKey(dimensionInWhat, stateValuesKey), conditionKey, condition,
-                     eventTimeNs, values);
-}
-
-size_t DurationMetricProducer::byteSizeLocked() const {
-    size_t totalSize = 0;
-    for (const auto& pair : mPastBuckets) {
-        totalSize += pair.second.size() * kBucketSize;
-    }
-    return totalSize;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
deleted file mode 100644
index 9fb586f..0000000
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-
-#include <unordered_map>
-
-#include <android/util/ProtoOutputStream.h>
-#include "../anomaly/DurationAnomalyTracker.h"
-#include "../condition/ConditionTracker.h"
-#include "../matchers/matcher_util.h"
-#include "MetricProducer.h"
-#include "duration_helper/DurationTracker.h"
-#include "duration_helper/MaxDurationTracker.h"
-#include "duration_helper/OringDurationTracker.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "stats_util.h"
-
-using namespace std;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class DurationMetricProducer : public MetricProducer {
-public:
-    DurationMetricProducer(
-            const ConfigKey& key, const DurationMetric& durationMetric, const int conditionIndex,
-            const vector<ConditionState>& initialConditionCache, const int whatIndex,
-            const int startIndex, const int stopIndex, const int stopAllIndex, const bool nesting,
-            const sp<ConditionWizard>& wizard, const uint64_t protoHash,
-            const FieldMatcher& internalDimensions, const int64_t timeBaseNs,
-            const int64_t startTimeNs,
-            const unordered_map<int, shared_ptr<Activation>>& eventActivationMap = {},
-            const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap = {},
-            const vector<int>& slicedStateAtoms = {},
-            const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap = {});
-
-    virtual ~DurationMetricProducer();
-
-    sp<AnomalyTracker> addAnomalyTracker(const Alert &alert,
-                                         const sp<AlarmMonitor>& anomalyAlarmMonitor) override;
-
-    void addAnomalyTracker(sp<AnomalyTracker>& anomalyTracker) override;
-
-    void onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
-                        const HashableDimensionKey& primaryKey, const FieldValue& oldState,
-                        const FieldValue& newState) override;
-
-    MetricType getMetricType() const override {
-        return METRIC_TYPE_DURATION;
-    }
-
-protected:
-    void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) override;
-
-    void onMatchedLogEventInternalLocked(
-            const size_t matcherIndex, const MetricDimensionKey& eventKey,
-            const ConditionKey& conditionKeys, bool condition, const LogEvent& event,
-            const std::map<int, HashableDimensionKey>& statePrimaryKeys) override;
-
-private:
-    // Initializes true dimensions of the 'what' predicate. Only to be called during initialization.
-    void initTrueDimensions(const int whatIndex, const int64_t startTimeNs);
-
-    void handleMatchedLogEventValuesLocked(const size_t matcherIndex,
-                                           const std::vector<FieldValue>& values,
-                                           const int64_t eventTimeNs);
-    void handleStartEvent(const MetricDimensionKey& eventKey, const ConditionKey& conditionKeys,
-                          bool condition, const int64_t eventTimeNs,
-                          const vector<FieldValue>& eventValues);
-
-    void onDumpReportLocked(const int64_t dumpTimeNs,
-                            const bool include_current_partial_bucket,
-                            const bool erase_data,
-                            const DumpLatency dumpLatency,
-                            std::set<string> *str_set,
-                            android::util::ProtoOutputStream* protoOutput) override;
-
-    void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
-
-    // Internal interface to handle condition change.
-    void onConditionChangedLocked(const bool conditionMet, const int64_t eventTime) override;
-
-    // Internal interface to handle active state change.
-    void onActiveStateChangedLocked(const int64_t& eventTimeNs) override;
-
-    // Internal interface to handle sliced condition change.
-    void onSlicedConditionMayChangeLocked(bool overallCondition, const int64_t eventTime) override;
-
-    void onSlicedConditionMayChangeInternalLocked(bool overallCondition,
-                                                  const int64_t eventTimeNs);
-
-    void onSlicedConditionMayChangeLocked_opt1(bool overallCondition, const int64_t eventTime);
-    void onSlicedConditionMayChangeLocked_opt2(bool overallCondition, const int64_t eventTime);
-
-    // Internal function to calculate the current used bytes.
-    size_t byteSizeLocked() const override;
-
-    void dumpStatesLocked(FILE* out, bool verbose) const override;
-
-    void dropDataLocked(const int64_t dropTimeNs) override;
-
-    // Util function to flush the old packet.
-    void flushIfNeededLocked(const int64_t& eventTime);
-
-    void flushCurrentBucketLocked(const int64_t& eventTimeNs,
-                                  const int64_t& nextBucketStartTimeNs) override;
-
-    bool onConfigUpdatedLocked(
-            const StatsdConfig& config, const int configIndex, const int metricIndex,
-            const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-            const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
-            const std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
-            const sp<EventMatcherWizard>& matcherWizard,
-            const std::vector<sp<ConditionTracker>>& allConditionTrackers,
-            const std::unordered_map<int64_t, int>& conditionTrackerMap,
-            const sp<ConditionWizard>& wizard,
-            const std::unordered_map<int64_t, int>& metricToActivationMap,
-            std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
-            std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
-            std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
-            std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
-            std::vector<int>& metricsWithActivation) override;
-
-    void addAnomalyTrackerLocked(sp<AnomalyTracker>& anomalyTracker);
-
-    const DurationMetric_AggregationType mAggregationType;
-
-    // Index of the SimpleAtomMatcher which defines the start.
-    int mStartIndex;
-
-    // Index of the SimpleAtomMatcher which defines the stop.
-    int mStopIndex;
-
-    // Index of the SimpleAtomMatcher which defines the stop all for all dimensions.
-    int mStopAllIndex;
-
-    // nest counting -- for the same key, stops must match the number of starts to make real stop
-    const bool mNested;
-
-    // The dimension from the atom predicate. e.g., uid, wakelock name.
-    vector<Matcher> mInternalDimensions;
-
-    bool mContainANYPositionInInternalDimensions;
-
-    // This boolean is true iff When mInternalDimensions == mDimensionsInWhat
-    bool mUseWhatDimensionAsInternalDimension;
-
-    // Caches the current unsliced part condition.
-    ConditionState mUnSlicedPartCondition;
-
-    // Save the past buckets and we can clear when the StatsLogReport is dumped.
-    std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>> mPastBuckets;
-
-    // The duration trackers in the current bucket.
-    std::unordered_map<HashableDimensionKey, std::unique_ptr<DurationTracker>>
-            mCurrentSlicedDurationTrackerMap;
-
-    // Helper function to create a duration tracker given the metric aggregation type.
-    std::unique_ptr<DurationTracker> createDurationTracker(
-            const MetricDimensionKey& eventKey) const;
-
-    // Util function to check whether the specified dimension hits the guardrail.
-    bool hitGuardRailLocked(const MetricDimensionKey& newKey);
-
-    static const size_t kBucketSize = sizeof(DurationBucket{});
-
-    FRIEND_TEST(DurationMetricTrackerTest, TestNoCondition);
-    FRIEND_TEST(DurationMetricTrackerTest, TestNonSlicedCondition);
-    FRIEND_TEST(DurationMetricTrackerTest, TestNonSlicedConditionUnknownState);
-    FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicates);
-    FRIEND_TEST(DurationMetricTrackerTest, TestFirstBucket);
-
-    FRIEND_TEST(DurationMetricProducerTest_PartialBucket, TestSumDuration);
-    FRIEND_TEST(DurationMetricProducerTest_PartialBucket,
-                TestSumDurationWithSplitInFollowingBucket);
-    FRIEND_TEST(DurationMetricProducerTest_PartialBucket, TestMaxDuration);
-    FRIEND_TEST(DurationMetricProducerTest_PartialBucket, TestMaxDurationWithSplitInNextBucket);
-
-    FRIEND_TEST(ConfigUpdateTest, TestUpdateDurationMetrics);
-    FRIEND_TEST(ConfigUpdateTest, TestUpdateAlerts);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
deleted file mode 100644
index ca302c0..0000000
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "EventMetricProducer.h"
-
-#include <limits.h>
-#include <stdlib.h>
-
-#include "metrics/parsing_utils/metrics_manager_util.h"
-#include "stats_log_util.h"
-#include "stats_util.h"
-
-using android::util::FIELD_COUNT_REPEATED;
-using android::util::FIELD_TYPE_BOOL;
-using android::util::FIELD_TYPE_FLOAT;
-using android::util::FIELD_TYPE_INT32;
-using android::util::FIELD_TYPE_INT64;
-using android::util::FIELD_TYPE_STRING;
-using android::util::FIELD_TYPE_MESSAGE;
-using android::util::ProtoOutputStream;
-using std::map;
-using std::string;
-using std::unordered_map;
-using std::vector;
-using std::shared_ptr;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// for StatsLogReport
-const int FIELD_ID_ID = 1;
-const int FIELD_ID_EVENT_METRICS = 4;
-const int FIELD_ID_IS_ACTIVE = 14;
-// for EventMetricDataWrapper
-const int FIELD_ID_DATA = 1;
-// for EventMetricData
-const int FIELD_ID_ELAPSED_TIMESTAMP_NANOS = 1;
-const int FIELD_ID_ATOMS = 2;
-
-EventMetricProducer::EventMetricProducer(
-        const ConfigKey& key, const EventMetric& metric, const int conditionIndex,
-        const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
-        const uint64_t protoHash, const int64_t startTimeNs,
-        const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
-        const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap,
-        const vector<int>& slicedStateAtoms,
-        const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap)
-    : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, initialConditionCache, wizard,
-                     protoHash, eventActivationMap, eventDeactivationMap, slicedStateAtoms,
-                     stateGroupMap) {
-    if (metric.links().size() > 0) {
-        for (const auto& link : metric.links()) {
-            Metric2Condition mc;
-            mc.conditionId = link.condition();
-            translateFieldMatcher(link.fields_in_what(), &mc.metricFields);
-            translateFieldMatcher(link.fields_in_condition(), &mc.conditionFields);
-            mMetric2ConditionLinks.push_back(mc);
-        }
-        mConditionSliced = true;
-    }
-    mProto = std::make_unique<ProtoOutputStream>();
-    VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
-         (long long)mBucketSizeNs, (long long)mTimeBaseNs);
-}
-
-EventMetricProducer::~EventMetricProducer() {
-    VLOG("~EventMetricProducer() called");
-}
-
-bool EventMetricProducer::onConfigUpdatedLocked(
-        const StatsdConfig& config, const int configIndex, const int metricIndex,
-        const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-        const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
-        const unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
-        const sp<EventMatcherWizard>& matcherWizard,
-        const vector<sp<ConditionTracker>>& allConditionTrackers,
-        const unordered_map<int64_t, int>& conditionTrackerMap, const sp<ConditionWizard>& wizard,
-        const unordered_map<int64_t, int>& metricToActivationMap,
-        unordered_map<int, vector<int>>& trackerToMetricMap,
-        unordered_map<int, vector<int>>& conditionToMetricMap,
-        unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
-        unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
-        vector<int>& metricsWithActivation) {
-    if (!MetricProducer::onConfigUpdatedLocked(
-                config, configIndex, metricIndex, allAtomMatchingTrackers,
-                oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, matcherWizard,
-                allConditionTrackers, conditionTrackerMap, wizard, metricToActivationMap,
-                trackerToMetricMap, conditionToMetricMap, activationAtomTrackerToMetricMap,
-                deactivationAtomTrackerToMetricMap, metricsWithActivation)) {
-        return false;
-    }
-
-    const EventMetric& metric = config.event_metric(configIndex);
-    int trackerIndex;
-    // Update appropriate indices, specifically mConditionIndex and MetricsManager maps.
-    if (!handleMetricWithAtomMatchingTrackers(metric.what(), metricIndex, false,
-                                              allAtomMatchingTrackers, newAtomMatchingTrackerMap,
-                                              trackerToMetricMap, trackerIndex)) {
-        return false;
-    }
-
-    if (metric.has_condition() &&
-        !handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
-                                    metric.links(), allConditionTrackers, mConditionTrackerIndex,
-                                    conditionToMetricMap)) {
-        return false;
-    }
-    return true;
-}
-
-void EventMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
-    mProto->clear();
-    StatsdStats::getInstance().noteBucketDropped(mMetricId);
-}
-
-void EventMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition,
-                                                           const int64_t eventTime) {
-}
-
-std::unique_ptr<std::vector<uint8_t>> serializeProtoLocked(ProtoOutputStream& protoOutput) {
-    size_t bufferSize = protoOutput.size();
-
-    std::unique_ptr<std::vector<uint8_t>> buffer(new std::vector<uint8_t>(bufferSize));
-
-    size_t pos = 0;
-    sp<android::util::ProtoReader> reader = protoOutput.data();
-    while (reader->readBuffer() != NULL) {
-        size_t toRead = reader->currentToRead();
-        std::memcpy(&((*buffer)[pos]), reader->readBuffer(), toRead);
-        pos += toRead;
-        reader->move(toRead);
-    }
-
-    return buffer;
-}
-
-void EventMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) {
-    mProto->clear();
-}
-
-void EventMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
-                                             const bool include_current_partial_bucket,
-                                             const bool erase_data,
-                                             const DumpLatency dumpLatency,
-                                             std::set<string> *str_set,
-                                             ProtoOutputStream* protoOutput) {
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
-    protoOutput->write(FIELD_TYPE_BOOL | FIELD_ID_IS_ACTIVE, isActiveLocked());
-    if (mProto->size() <= 0) {
-        return;
-    }
-
-    size_t bufferSize = mProto->size();
-    VLOG("metric %lld dump report now... proto size: %zu ",
-        (long long)mMetricId, bufferSize);
-    std::unique_ptr<std::vector<uint8_t>> buffer = serializeProtoLocked(*mProto);
-
-    protoOutput->write(FIELD_TYPE_MESSAGE | FIELD_ID_EVENT_METRICS,
-                       reinterpret_cast<char*>(buffer.get()->data()), buffer.get()->size());
-
-    if (erase_data) {
-        mProto->clear();
-    }
-}
-
-void EventMetricProducer::onConditionChangedLocked(const bool conditionMet,
-                                                   const int64_t eventTime) {
-    VLOG("Metric %lld onConditionChanged", (long long)mMetricId);
-    mCondition = conditionMet ? ConditionState::kTrue : ConditionState::kFalse;
-}
-
-void EventMetricProducer::onMatchedLogEventInternalLocked(
-        const size_t matcherIndex, const MetricDimensionKey& eventKey,
-        const ConditionKey& conditionKey, bool condition, const LogEvent& event,
-        const map<int, HashableDimensionKey>& statePrimaryKeys) {
-    if (!condition) {
-        return;
-    }
-
-    uint64_t wrapperToken =
-            mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
-    const int64_t elapsedTimeNs = truncateTimestampIfNecessary(event);
-    mProto->write(FIELD_TYPE_INT64 | FIELD_ID_ELAPSED_TIMESTAMP_NANOS, (long long) elapsedTimeNs);
-
-    uint64_t eventToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_ATOMS);
-    event.ToProto(*mProto);
-    mProto->end(eventToken);
-    mProto->end(wrapperToken);
-}
-
-size_t EventMetricProducer::byteSizeLocked() const {
-    return mProto->bytesWritten();
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
deleted file mode 100644
index 3347d7b..0000000
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef EVENT_METRIC_PRODUCER_H
-#define EVENT_METRIC_PRODUCER_H
-
-#include <unordered_map>
-
-#include <android/util/ProtoOutputStream.h>
-
-#include "../condition/ConditionTracker.h"
-#include "../matchers/matcher_util.h"
-#include "MetricProducer.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "stats_util.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class EventMetricProducer : public MetricProducer {
-public:
-    EventMetricProducer(
-            const ConfigKey& key, const EventMetric& eventMetric, const int conditionIndex,
-            const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
-            const uint64_t protoHash, const int64_t startTimeNs,
-            const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap = {},
-            const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
-                    eventDeactivationMap = {},
-            const vector<int>& slicedStateAtoms = {},
-            const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap = {});
-
-    virtual ~EventMetricProducer();
-
-    MetricType getMetricType() const override {
-        return METRIC_TYPE_EVENT;
-    }
-
-private:
-    void onMatchedLogEventInternalLocked(
-            const size_t matcherIndex, const MetricDimensionKey& eventKey,
-            const ConditionKey& conditionKey, bool condition, const LogEvent& event,
-            const std::map<int, HashableDimensionKey>& statePrimaryKeys) override;
-
-    void onDumpReportLocked(const int64_t dumpTimeNs,
-                            const bool include_current_partial_bucket,
-                            const bool erase_data,
-                            const DumpLatency dumpLatency,
-                            std::set<string> *str_set,
-                            android::util::ProtoOutputStream* protoOutput) override;
-    void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
-
-    // Internal interface to handle condition change.
-    void onConditionChangedLocked(const bool conditionMet, const int64_t eventTime) override;
-
-    // Internal interface to handle sliced condition change.
-    void onSlicedConditionMayChangeLocked(bool overallCondition, const int64_t eventTime) override;
-
-    bool onConfigUpdatedLocked(
-            const StatsdConfig& config, const int configIndex, const int metricIndex,
-            const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-            const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
-            const std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
-            const sp<EventMatcherWizard>& matcherWizard,
-            const std::vector<sp<ConditionTracker>>& allConditionTrackers,
-            const std::unordered_map<int64_t, int>& conditionTrackerMap,
-            const sp<ConditionWizard>& wizard,
-            const std::unordered_map<int64_t, int>& metricToActivationMap,
-            std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
-            std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
-            std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
-            std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
-            std::vector<int>& metricsWithActivation) override;
-
-    void dropDataLocked(const int64_t dropTimeNs) override;
-
-    // Internal function to calculate the current used bytes.
-    size_t byteSizeLocked() const override;
-
-    void dumpStatesLocked(FILE* out, bool verbose) const override{};
-
-    // Maps to a EventMetricDataWrapper. Storing atom events in ProtoOutputStream
-    // is more space efficient than storing LogEvent.
-    std::unique_ptr<android::util::ProtoOutputStream> mProto;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#endif  // EVENT_METRIC_PRODUCER_H
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
deleted file mode 100644
index 2a37b58..0000000
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ /dev/null
@@ -1,675 +0,0 @@
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*      http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "GaugeMetricProducer.h"
-
-#include "guardrail/StatsdStats.h"
-#include "metrics/parsing_utils/metrics_manager_util.h"
-#include "stats_log_util.h"
-
-using android::util::FIELD_COUNT_REPEATED;
-using android::util::FIELD_TYPE_BOOL;
-using android::util::FIELD_TYPE_FLOAT;
-using android::util::FIELD_TYPE_INT32;
-using android::util::FIELD_TYPE_INT64;
-using android::util::FIELD_TYPE_MESSAGE;
-using android::util::FIELD_TYPE_STRING;
-using android::util::ProtoOutputStream;
-using std::map;
-using std::string;
-using std::unordered_map;
-using std::vector;
-using std::make_shared;
-using std::shared_ptr;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// for StatsLogReport
-const int FIELD_ID_ID = 1;
-const int FIELD_ID_GAUGE_METRICS = 8;
-const int FIELD_ID_TIME_BASE = 9;
-const int FIELD_ID_BUCKET_SIZE = 10;
-const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
-const int FIELD_ID_IS_ACTIVE = 14;
-// for GaugeMetricDataWrapper
-const int FIELD_ID_DATA = 1;
-const int FIELD_ID_SKIPPED = 2;
-// for SkippedBuckets
-const int FIELD_ID_SKIPPED_START_MILLIS = 3;
-const int FIELD_ID_SKIPPED_END_MILLIS = 4;
-const int FIELD_ID_SKIPPED_DROP_EVENT = 5;
-// for DumpEvent Proto
-const int FIELD_ID_BUCKET_DROP_REASON = 1;
-const int FIELD_ID_DROP_TIME = 2;
-// for GaugeMetricData
-const int FIELD_ID_DIMENSION_IN_WHAT = 1;
-const int FIELD_ID_BUCKET_INFO = 3;
-const int FIELD_ID_DIMENSION_LEAF_IN_WHAT = 4;
-// for GaugeBucketInfo
-const int FIELD_ID_ATOM = 3;
-const int FIELD_ID_ELAPSED_ATOM_TIMESTAMP = 4;
-const int FIELD_ID_BUCKET_NUM = 6;
-const int FIELD_ID_START_BUCKET_ELAPSED_MILLIS = 7;
-const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 8;
-
-GaugeMetricProducer::GaugeMetricProducer(
-        const ConfigKey& key, const GaugeMetric& metric, const int conditionIndex,
-        const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
-        const uint64_t protoHash, const int whatMatcherIndex,
-        const sp<EventMatcherWizard>& matcherWizard, const int pullTagId, const int triggerAtomId,
-        const int atomId, const int64_t timeBaseNs, const int64_t startTimeNs,
-        const sp<StatsPullerManager>& pullerManager,
-        const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
-        const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap)
-    : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, initialConditionCache, wizard,
-                     protoHash, eventActivationMap, eventDeactivationMap, /*slicedStateAtoms=*/{},
-                     /*stateGroupMap=*/{}),
-      mWhatMatcherIndex(whatMatcherIndex),
-      mEventMatcherWizard(matcherWizard),
-      mPullerManager(pullerManager),
-      mPullTagId(pullTagId),
-      mTriggerAtomId(triggerAtomId),
-      mAtomId(atomId),
-      mIsPulled(pullTagId != -1),
-      mMinBucketSizeNs(metric.min_bucket_size_nanos()),
-      mMaxPullDelayNs(metric.max_pull_delay_sec() > 0 ? metric.max_pull_delay_sec() * NS_PER_SEC
-                                                      : StatsdStats::kPullMaxDelayNs),
-      mDimensionSoftLimit(StatsdStats::kAtomDimensionKeySizeLimitMap.find(pullTagId) !=
-                                          StatsdStats::kAtomDimensionKeySizeLimitMap.end()
-                                  ? StatsdStats::kAtomDimensionKeySizeLimitMap.at(pullTagId).first
-                                  : StatsdStats::kDimensionKeySizeSoftLimit),
-      mDimensionHardLimit(StatsdStats::kAtomDimensionKeySizeLimitMap.find(pullTagId) !=
-                                          StatsdStats::kAtomDimensionKeySizeLimitMap.end()
-                                  ? StatsdStats::kAtomDimensionKeySizeLimitMap.at(pullTagId).second
-                                  : StatsdStats::kDimensionKeySizeHardLimit),
-      mGaugeAtomsPerDimensionLimit(metric.max_num_gauge_atoms_per_bucket()),
-      mSplitBucketForAppUpgrade(metric.split_bucket_for_app_upgrade()) {
-    mCurrentSlicedBucket = std::make_shared<DimToGaugeAtomsMap>();
-    mCurrentSlicedBucketForAnomaly = std::make_shared<DimToValMap>();
-    int64_t bucketSizeMills = 0;
-    if (metric.has_bucket()) {
-        bucketSizeMills = TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket());
-    } else {
-        bucketSizeMills = TimeUnitToBucketSizeInMillis(ONE_HOUR);
-    }
-    mBucketSizeNs = bucketSizeMills * 1000000;
-
-    mSamplingType = metric.sampling_type();
-    if (!metric.gauge_fields_filter().include_all()) {
-        translateFieldMatcher(metric.gauge_fields_filter().fields(), &mFieldMatchers);
-    }
-
-    if (metric.has_dimensions_in_what()) {
-        translateFieldMatcher(metric.dimensions_in_what(), &mDimensionsInWhat);
-        mContainANYPositionInDimensionsInWhat = HasPositionANY(metric.dimensions_in_what());
-    }
-
-    if (metric.links().size() > 0) {
-        for (const auto& link : metric.links()) {
-            Metric2Condition mc;
-            mc.conditionId = link.condition();
-            translateFieldMatcher(link.fields_in_what(), &mc.metricFields);
-            translateFieldMatcher(link.fields_in_condition(), &mc.conditionFields);
-            mMetric2ConditionLinks.push_back(mc);
-        }
-        mConditionSliced = true;
-    }
-    mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what());
-
-    flushIfNeededLocked(startTimeNs);
-    // Kicks off the puller immediately.
-    if (mIsPulled && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
-        mPullerManager->RegisterReceiver(mPullTagId, mConfigKey, this, getCurrentBucketEndTimeNs(),
-                                         mBucketSizeNs);
-    }
-
-    // Adjust start for partial first bucket and then pull if needed
-    mCurrentBucketStartTimeNs = startTimeNs;
-
-    VLOG("Gauge metric %lld created. bucket size %lld start_time: %lld sliced %d",
-         (long long)metric.id(), (long long)mBucketSizeNs, (long long)mTimeBaseNs,
-         mConditionSliced);
-}
-
-GaugeMetricProducer::~GaugeMetricProducer() {
-    VLOG("~GaugeMetricProducer() called");
-    if (mIsPulled && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
-        mPullerManager->UnRegisterReceiver(mPullTagId, mConfigKey, this);
-    }
-}
-
-bool GaugeMetricProducer::onConfigUpdatedLocked(
-        const StatsdConfig& config, const int configIndex, const int metricIndex,
-        const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-        const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
-        const unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
-        const sp<EventMatcherWizard>& matcherWizard,
-        const vector<sp<ConditionTracker>>& allConditionTrackers,
-        const unordered_map<int64_t, int>& conditionTrackerMap, const sp<ConditionWizard>& wizard,
-        const unordered_map<int64_t, int>& metricToActivationMap,
-        unordered_map<int, vector<int>>& trackerToMetricMap,
-        unordered_map<int, vector<int>>& conditionToMetricMap,
-        unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
-        unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
-        vector<int>& metricsWithActivation) {
-    if (!MetricProducer::onConfigUpdatedLocked(
-                config, configIndex, metricIndex, allAtomMatchingTrackers,
-                oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, matcherWizard,
-                allConditionTrackers, conditionTrackerMap, wizard, metricToActivationMap,
-                trackerToMetricMap, conditionToMetricMap, activationAtomTrackerToMetricMap,
-                deactivationAtomTrackerToMetricMap, metricsWithActivation)) {
-        return false;
-    }
-
-    const GaugeMetric& metric = config.gauge_metric(configIndex);
-    // Update appropriate indices: mWhatMatcherIndex, mConditionIndex and MetricsManager maps.
-    if (!handleMetricWithAtomMatchingTrackers(metric.what(), metricIndex, /*enforceOneAtom=*/false,
-                                              allAtomMatchingTrackers, newAtomMatchingTrackerMap,
-                                              trackerToMetricMap, mWhatMatcherIndex)) {
-        return false;
-    }
-
-    // Need to update maps since the index changed, but mTriggerAtomId will not change.
-    int triggerTrackerIndex;
-    if (metric.has_trigger_event() &&
-        !handleMetricWithAtomMatchingTrackers(metric.trigger_event(), metricIndex,
-                                              /*enforceOneAtom=*/true, allAtomMatchingTrackers,
-                                              newAtomMatchingTrackerMap, trackerToMetricMap,
-                                              triggerTrackerIndex)) {
-        return false;
-    }
-
-    if (metric.has_condition() &&
-        !handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
-                                    metric.links(), allConditionTrackers, mConditionTrackerIndex,
-                                    conditionToMetricMap)) {
-        return false;
-    }
-    sp<EventMatcherWizard> tmpEventWizard = mEventMatcherWizard;
-    mEventMatcherWizard = matcherWizard;
-    return true;
-}
-
-void GaugeMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
-    if (mCurrentSlicedBucket == nullptr ||
-        mCurrentSlicedBucket->size() == 0) {
-        return;
-    }
-
-    fprintf(out, "GaugeMetric %lld dimension size %lu\n", (long long)mMetricId,
-            (unsigned long)mCurrentSlicedBucket->size());
-    if (verbose) {
-        for (const auto& it : *mCurrentSlicedBucket) {
-            fprintf(out, "\t(what)%s\t(states)%s  %d atoms\n",
-                    it.first.getDimensionKeyInWhat().toString().c_str(),
-                    it.first.getStateValuesKey().toString().c_str(), (int)it.second.size());
-        }
-    }
-}
-
-void GaugeMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) {
-    flushIfNeededLocked(dumpTimeNs);
-    mPastBuckets.clear();
-    mSkippedBuckets.clear();
-}
-
-void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
-                                             const bool include_current_partial_bucket,
-                                             const bool erase_data,
-                                             const DumpLatency dumpLatency,
-                                             std::set<string> *str_set,
-                                             ProtoOutputStream* protoOutput) {
-    VLOG("Gauge metric %lld report now...", (long long)mMetricId);
-    if (include_current_partial_bucket) {
-        flushLocked(dumpTimeNs);
-    } else {
-        flushIfNeededLocked(dumpTimeNs);
-    }
-
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
-    protoOutput->write(FIELD_TYPE_BOOL | FIELD_ID_IS_ACTIVE, isActiveLocked());
-
-    if (mPastBuckets.empty() && mSkippedBuckets.empty()) {
-        return;
-    }
-
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TIME_BASE, (long long)mTimeBaseNs);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_SIZE, (long long)mBucketSizeNs);
-
-    // Fills the dimension path if not slicing by ALL.
-    if (!mSliceByPositionALL) {
-        if (!mDimensionsInWhat.empty()) {
-            uint64_t dimenPathToken = protoOutput->start(
-                    FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_WHAT);
-            writeDimensionPathToProto(mDimensionsInWhat, protoOutput);
-            protoOutput->end(dimenPathToken);
-        }
-    }
-
-    uint64_t protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_GAUGE_METRICS);
-
-    for (const auto& skippedBucket : mSkippedBuckets) {
-        uint64_t wrapperToken =
-                protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_SKIPPED);
-        protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_SKIPPED_START_MILLIS,
-                           (long long)(NanoToMillis(skippedBucket.bucketStartTimeNs)));
-        protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_SKIPPED_END_MILLIS,
-                           (long long)(NanoToMillis(skippedBucket.bucketEndTimeNs)));
-
-        for (const auto& dropEvent : skippedBucket.dropEvents) {
-            uint64_t dropEventToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                                         FIELD_ID_SKIPPED_DROP_EVENT);
-            protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_BUCKET_DROP_REASON, dropEvent.reason);
-            protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_DROP_TIME, (long long) (NanoToMillis(dropEvent.dropTimeNs)));
-            protoOutput->end(dropEventToken);
-        }
-        protoOutput->end(wrapperToken);
-    }
-
-    for (const auto& pair : mPastBuckets) {
-        const MetricDimensionKey& dimensionKey = pair.first;
-
-        VLOG("Gauge dimension key %s", dimensionKey.toString().c_str());
-        uint64_t wrapperToken =
-                protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
-
-        // First fill dimension.
-        if (mSliceByPositionALL) {
-            uint64_t dimensionToken = protoOutput->start(
-                    FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
-            writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput);
-            protoOutput->end(dimensionToken);
-        } else {
-            writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInWhat(),
-                                           FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput);
-        }
-
-        // Then fill bucket_info (GaugeBucketInfo).
-        for (const auto& bucket : pair.second) {
-            uint64_t bucketInfoToken = protoOutput->start(
-                    FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
-
-            if (bucket.mBucketEndNs - bucket.mBucketStartNs != mBucketSizeNs) {
-                protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_ELAPSED_MILLIS,
-                                   (long long)NanoToMillis(bucket.mBucketStartNs));
-                protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_ELAPSED_MILLIS,
-                                   (long long)NanoToMillis(bucket.mBucketEndNs));
-            } else {
-                protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_NUM,
-                                   (long long)(getBucketNumFromEndTimeNs(bucket.mBucketEndNs)));
-            }
-
-            if (!bucket.mGaugeAtoms.empty()) {
-                for (const auto& atom : bucket.mGaugeAtoms) {
-                    uint64_t atomsToken =
-                        protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                           FIELD_ID_ATOM);
-                    writeFieldValueTreeToStream(mAtomId, *(atom.mFields), protoOutput);
-                    protoOutput->end(atomsToken);
-                }
-                for (const auto& atom : bucket.mGaugeAtoms) {
-                    protoOutput->write(FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED |
-                                               FIELD_ID_ELAPSED_ATOM_TIMESTAMP,
-                                       (long long)atom.mElapsedTimestampNs);
-                }
-            }
-            protoOutput->end(bucketInfoToken);
-            VLOG("Gauge \t bucket [%lld - %lld] includes %d atoms.",
-                 (long long)bucket.mBucketStartNs, (long long)bucket.mBucketEndNs,
-                 (int)bucket.mGaugeAtoms.size());
-        }
-        protoOutput->end(wrapperToken);
-    }
-    protoOutput->end(protoToken);
-
-
-    if (erase_data) {
-        mPastBuckets.clear();
-        mSkippedBuckets.clear();
-    }
-}
-
-void GaugeMetricProducer::prepareFirstBucketLocked() {
-    if (mIsActive && mIsPulled && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
-        pullAndMatchEventsLocked(mCurrentBucketStartTimeNs);
-    }
-}
-
-void GaugeMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) {
-    bool triggerPuller = false;
-    switch(mSamplingType) {
-        // When the metric wants to do random sampling and there is already one gauge atom for the
-        // current bucket, do not do it again.
-        case GaugeMetric::RANDOM_ONE_SAMPLE: {
-            triggerPuller = mCondition == ConditionState::kTrue && mCurrentSlicedBucket->empty();
-            break;
-        }
-        case GaugeMetric::CONDITION_CHANGE_TO_TRUE: {
-            triggerPuller = mCondition == ConditionState::kTrue;
-            break;
-        }
-        case GaugeMetric::FIRST_N_SAMPLES: {
-            triggerPuller = mCondition == ConditionState::kTrue;
-            break;
-        }
-        default:
-            break;
-    }
-    if (!triggerPuller) {
-        return;
-    }
-    vector<std::shared_ptr<LogEvent>> allData;
-    if (!mPullerManager->Pull(mPullTagId, mConfigKey, timestampNs, &allData)) {
-        ALOGE("Gauge Stats puller failed for tag: %d at %lld", mPullTagId, (long long)timestampNs);
-        return;
-    }
-    const int64_t pullDelayNs = getElapsedRealtimeNs() - timestampNs;
-    StatsdStats::getInstance().notePullDelay(mPullTagId, pullDelayNs);
-    if (pullDelayNs > mMaxPullDelayNs) {
-        ALOGE("Pull finish too late for atom %d", mPullTagId);
-        StatsdStats::getInstance().notePullExceedMaxDelay(mPullTagId);
-        return;
-    }
-    for (const auto& data : allData) {
-        LogEvent localCopy = data->makeCopy();
-        localCopy.setElapsedTimestampNs(timestampNs);
-        if (mEventMatcherWizard->matchLogEvent(localCopy, mWhatMatcherIndex) ==
-            MatchingState::kMatched) {
-            onMatchedLogEventLocked(mWhatMatcherIndex, localCopy);
-        }
-    }
-}
-
-void GaugeMetricProducer::onActiveStateChangedLocked(const int64_t& eventTimeNs) {
-    MetricProducer::onActiveStateChangedLocked(eventTimeNs);
-    if (ConditionState::kTrue != mCondition || !mIsPulled) {
-        return;
-    }
-    if (mTriggerAtomId == -1 || (mIsActive && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE)) {
-        pullAndMatchEventsLocked(eventTimeNs);
-    }
-
-}
-
-void GaugeMetricProducer::onConditionChangedLocked(const bool conditionMet,
-                                                   const int64_t eventTimeNs) {
-    VLOG("GaugeMetric %lld onConditionChanged", (long long)mMetricId);
-
-    mCondition = conditionMet ? ConditionState::kTrue : ConditionState::kFalse;
-    if (!mIsActive) {
-        return;
-    }
-
-    flushIfNeededLocked(eventTimeNs);
-    if (mIsPulled && mTriggerAtomId == -1) {
-        pullAndMatchEventsLocked(eventTimeNs);
-    }  // else: Push mode. No need to proactively pull the gauge data.
-}
-
-void GaugeMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition,
-                                                           const int64_t eventTimeNs) {
-    VLOG("GaugeMetric %lld onSlicedConditionMayChange overall condition %d", (long long)mMetricId,
-         overallCondition);
-    mCondition = overallCondition ? ConditionState::kTrue : ConditionState::kFalse;
-    if (!mIsActive) {
-        return;
-    }
-
-    flushIfNeededLocked(eventTimeNs);
-    // If the condition is sliced, mCondition is true if any of the dimensions is true. And we will
-    // pull for every dimension.
-    if (mIsPulled && mTriggerAtomId == -1) {
-        pullAndMatchEventsLocked(eventTimeNs);
-    }  // else: Push mode. No need to proactively pull the gauge data.
-}
-
-std::shared_ptr<vector<FieldValue>> GaugeMetricProducer::getGaugeFields(const LogEvent& event) {
-    std::shared_ptr<vector<FieldValue>> gaugeFields;
-    if (mFieldMatchers.size() > 0) {
-        gaugeFields = std::make_shared<vector<FieldValue>>();
-        filterGaugeValues(mFieldMatchers, event.getValues(), gaugeFields.get());
-    } else {
-        gaugeFields = std::make_shared<vector<FieldValue>>(event.getValues());
-    }
-    // Trim all dimension fields from output. Dimensions will appear in output report and will
-    // benefit from dictionary encoding. For large pulled atoms, this can give the benefit of
-    // optional repeated field.
-    for (const auto& field : mDimensionsInWhat) {
-        for (auto it = gaugeFields->begin(); it != gaugeFields->end();) {
-            if (it->mField.matches(field)) {
-                it = gaugeFields->erase(it);
-            } else {
-                it++;
-            }
-        }
-    }
-    return gaugeFields;
-}
-
-void GaugeMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData,
-                                       bool pullSuccess, int64_t originalPullTimeNs) {
-    std::lock_guard<std::mutex> lock(mMutex);
-    if (!pullSuccess || allData.size() == 0) {
-        return;
-    }
-    const int64_t pullDelayNs = getElapsedRealtimeNs() - originalPullTimeNs;
-    StatsdStats::getInstance().notePullDelay(mPullTagId, pullDelayNs);
-    if (pullDelayNs > mMaxPullDelayNs) {
-        ALOGE("Pull finish too late for atom %d", mPullTagId);
-        StatsdStats::getInstance().notePullExceedMaxDelay(mPullTagId);
-        return;
-    }
-    for (const auto& data : allData) {
-        if (mEventMatcherWizard->matchLogEvent(
-                *data, mWhatMatcherIndex) == MatchingState::kMatched) {
-            onMatchedLogEventLocked(mWhatMatcherIndex, *data);
-        }
-    }
-}
-
-bool GaugeMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
-    if (mCurrentSlicedBucket->find(newKey) != mCurrentSlicedBucket->end()) {
-        return false;
-    }
-    // 1. Report the tuple count if the tuple count > soft limit
-    if (mCurrentSlicedBucket->size() > mDimensionSoftLimit - 1) {
-        size_t newTupleCount = mCurrentSlicedBucket->size() + 1;
-        StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount);
-        // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
-        if (newTupleCount > mDimensionHardLimit) {
-            ALOGE("GaugeMetric %lld dropping data for dimension key %s",
-                (long long)mMetricId, newKey.toString().c_str());
-            StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId);
-            return true;
-        }
-    }
-
-    return false;
-}
-
-void GaugeMetricProducer::onMatchedLogEventInternalLocked(
-        const size_t matcherIndex, const MetricDimensionKey& eventKey,
-        const ConditionKey& conditionKey, bool condition, const LogEvent& event,
-        const map<int, HashableDimensionKey>& statePrimaryKeys) {
-    if (condition == false) {
-        return;
-    }
-    int64_t eventTimeNs = event.GetElapsedTimestampNs();
-    if (eventTimeNs < mCurrentBucketStartTimeNs) {
-        VLOG("Gauge Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
-             (long long)mCurrentBucketStartTimeNs);
-        return;
-    }
-    flushIfNeededLocked(eventTimeNs);
-
-    if (mTriggerAtomId == event.GetTagId()) {
-        pullAndMatchEventsLocked(eventTimeNs);
-        return;
-    }
-
-    // When gauge metric wants to randomly sample the output atom, we just simply use the first
-    // gauge in the given bucket.
-    if (mCurrentSlicedBucket->find(eventKey) != mCurrentSlicedBucket->end() &&
-        mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
-        return;
-    }
-    if (hitGuardRailLocked(eventKey)) {
-        return;
-    }
-    if ((*mCurrentSlicedBucket)[eventKey].size() >= mGaugeAtomsPerDimensionLimit) {
-        return;
-    }
-
-    const int64_t truncatedElapsedTimestampNs = truncateTimestampIfNecessary(event);
-    GaugeAtom gaugeAtom(getGaugeFields(event), truncatedElapsedTimestampNs);
-    (*mCurrentSlicedBucket)[eventKey].push_back(gaugeAtom);
-    // Anomaly detection on gauge metric only works when there is one numeric
-    // field specified.
-    if (mAnomalyTrackers.size() > 0) {
-        if (gaugeAtom.mFields->size() == 1) {
-            const Value& value = gaugeAtom.mFields->begin()->mValue;
-            long gaugeVal = 0;
-            if (value.getType() == INT) {
-                gaugeVal = (long)value.int_value;
-            } else if (value.getType() == LONG) {
-                gaugeVal = value.long_value;
-            }
-            for (auto& tracker : mAnomalyTrackers) {
-                tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, mMetricId,
-                                                 eventKey, gaugeVal);
-            }
-        }
-    }
-}
-
-void GaugeMetricProducer::updateCurrentSlicedBucketForAnomaly() {
-    for (const auto& slice : *mCurrentSlicedBucket) {
-        if (slice.second.empty()) {
-            continue;
-        }
-        const Value& value = slice.second.front().mFields->front().mValue;
-        long gaugeVal = 0;
-        if (value.getType() == INT) {
-            gaugeVal = (long)value.int_value;
-        } else if (value.getType() == LONG) {
-            gaugeVal = value.long_value;
-        }
-        (*mCurrentSlicedBucketForAnomaly)[slice.first] = gaugeVal;
-    }
-}
-
-void GaugeMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
-    flushIfNeededLocked(dropTimeNs);
-    StatsdStats::getInstance().noteBucketDropped(mMetricId);
-    mPastBuckets.clear();
-}
-
-// When a new matched event comes in, we check if event falls into the current
-// bucket. If not, flush the old counter to past buckets and initialize the new
-// bucket.
-// if data is pushed, onMatchedLogEvent will only be called through onConditionChanged() inside
-// the GaugeMetricProducer while holding the lock.
-void GaugeMetricProducer::flushIfNeededLocked(const int64_t& eventTimeNs) {
-    int64_t currentBucketEndTimeNs = getCurrentBucketEndTimeNs();
-
-    if (eventTimeNs < currentBucketEndTimeNs) {
-        VLOG("Gauge eventTime is %lld, less than next bucket start time %lld",
-             (long long)eventTimeNs, (long long)(mCurrentBucketStartTimeNs + mBucketSizeNs));
-        return;
-    }
-
-    // Adjusts the bucket start and end times.
-    int64_t numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
-    int64_t nextBucketNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
-    flushCurrentBucketLocked(eventTimeNs, nextBucketNs);
-
-    mCurrentBucketNum += numBucketsForward;
-    VLOG("Gauge metric %lld: new bucket start time: %lld", (long long)mMetricId,
-         (long long)mCurrentBucketStartTimeNs);
-}
-
-void GaugeMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
-                                                   const int64_t& nextBucketStartTimeNs) {
-    int64_t fullBucketEndTimeNs = getCurrentBucketEndTimeNs();
-    int64_t bucketEndTime = eventTimeNs < fullBucketEndTimeNs ? eventTimeNs : fullBucketEndTimeNs;
-
-    GaugeBucket info;
-    info.mBucketStartNs = mCurrentBucketStartTimeNs;
-    info.mBucketEndNs = bucketEndTime;
-
-    // Add bucket to mPastBuckets if bucket is large enough.
-    // Otherwise, drop the bucket data and add bucket metadata to mSkippedBuckets.
-    bool isBucketLargeEnough = info.mBucketEndNs - mCurrentBucketStartTimeNs >= mMinBucketSizeNs;
-    if (isBucketLargeEnough) {
-        for (const auto& slice : *mCurrentSlicedBucket) {
-            info.mGaugeAtoms = slice.second;
-            auto& bucketList = mPastBuckets[slice.first];
-            bucketList.push_back(info);
-            VLOG("Gauge gauge metric %lld, dump key value: %s", (long long)mMetricId,
-                 slice.first.toString().c_str());
-        }
-    } else {
-        mCurrentSkippedBucket.bucketStartTimeNs = mCurrentBucketStartTimeNs;
-        mCurrentSkippedBucket.bucketEndTimeNs = bucketEndTime;
-        if (!maxDropEventsReached()) {
-            mCurrentSkippedBucket.dropEvents.emplace_back(
-                    buildDropEvent(eventTimeNs, BucketDropReason::BUCKET_TOO_SMALL));
-        }
-        mSkippedBuckets.emplace_back(mCurrentSkippedBucket);
-    }
-
-    // If we have anomaly trackers, we need to update the partial bucket values.
-    if (mAnomalyTrackers.size() > 0) {
-        updateCurrentSlicedBucketForAnomaly();
-
-        if (eventTimeNs > fullBucketEndTimeNs) {
-            // This is known to be a full bucket, so send this data to the anomaly tracker.
-            for (auto& tracker : mAnomalyTrackers) {
-                tracker->addPastBucket(mCurrentSlicedBucketForAnomaly, mCurrentBucketNum);
-            }
-            mCurrentSlicedBucketForAnomaly = std::make_shared<DimToValMap>();
-        }
-    }
-
-    StatsdStats::getInstance().noteBucketCount(mMetricId);
-    mCurrentSlicedBucket = std::make_shared<DimToGaugeAtomsMap>();
-    mCurrentBucketStartTimeNs = nextBucketStartTimeNs;
-    mCurrentSkippedBucket.reset();
-}
-
-size_t GaugeMetricProducer::byteSizeLocked() const {
-    size_t totalSize = 0;
-    for (const auto& pair : mPastBuckets) {
-        for (const auto& bucket : pair.second) {
-            totalSize += bucket.mGaugeAtoms.size() * sizeof(GaugeAtom);
-            for (const auto& atom : bucket.mGaugeAtoms) {
-                if (atom.mFields != nullptr) {
-                    totalSize += atom.mFields->size() * sizeof(FieldValue);
-                }
-            }
-        }
-    }
-    return totalSize;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
deleted file mode 100644
index 9bdaac9..0000000
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <unordered_map>
-
-#include <android/util/ProtoOutputStream.h>
-#include <gtest/gtest_prod.h>
-#include "../condition/ConditionTracker.h"
-#include "../external/PullDataReceiver.h"
-#include "../external/StatsPullerManager.h"
-#include "../matchers/matcher_util.h"
-#include "../matchers/EventMatcherWizard.h"
-#include "MetricProducer.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "../stats_util.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-struct GaugeAtom {
-    GaugeAtom(std::shared_ptr<vector<FieldValue>> fields, int64_t elapsedTimeNs)
-        : mFields(fields), mElapsedTimestampNs(elapsedTimeNs) {
-    }
-    std::shared_ptr<vector<FieldValue>> mFields;
-    int64_t mElapsedTimestampNs;
-};
-
-struct GaugeBucket {
-    int64_t mBucketStartNs;
-    int64_t mBucketEndNs;
-    std::vector<GaugeAtom> mGaugeAtoms;
-};
-
-typedef std::unordered_map<MetricDimensionKey, std::vector<GaugeAtom>>
-    DimToGaugeAtomsMap;
-
-// This gauge metric producer first register the puller to automatically pull the gauge at the
-// beginning of each bucket. If the condition is met, insert it to the bucket info. Otherwise
-// proactively pull the gauge when the condition is changed to be true. Therefore, the gauge metric
-// producer always reports the gauge at the earliest time of the bucket when the condition is met.
-class GaugeMetricProducer : public MetricProducer, public virtual PullDataReceiver {
-public:
-    GaugeMetricProducer(
-            const ConfigKey& key, const GaugeMetric& gaugeMetric, const int conditionIndex,
-            const vector<ConditionState>& initialConditionCache,
-            const sp<ConditionWizard>& conditionWizard, const uint64_t protoHash,
-            const int whatMatcherIndex, const sp<EventMatcherWizard>& matcherWizard,
-            const int pullTagId, const int triggerAtomId, const int atomId,
-            const int64_t timeBaseNs, const int64_t startTimeNs,
-            const sp<StatsPullerManager>& pullerManager,
-            const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap = {},
-            const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
-                    eventDeactivationMap = {});
-
-    virtual ~GaugeMetricProducer();
-
-    // Handles when the pulled data arrives.
-    void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data,
-                      bool pullSuccess, int64_t originalPullTimeNs) override;
-
-    // GaugeMetric needs to immediately trigger another pull when we create the partial bucket.
-    void notifyAppUpgrade(const int64_t& eventTimeNs) override {
-        std::lock_guard<std::mutex> lock(mMutex);
-
-        if (!mSplitBucketForAppUpgrade) {
-            return;
-        }
-        flushLocked(eventTimeNs);
-        if (mIsPulled && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
-            pullAndMatchEventsLocked(eventTimeNs);
-        }
-    };
-
-    // GaugeMetric needs to immediately trigger another pull when we create the partial bucket.
-    void onStatsdInitCompleted(const int64_t& eventTimeNs) override {
-        std::lock_guard<std::mutex> lock(mMutex);
-
-        flushLocked(eventTimeNs);
-        if (mIsPulled && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
-            pullAndMatchEventsLocked(eventTimeNs);
-        }
-    };
-
-    MetricType getMetricType() const override {
-        return METRIC_TYPE_GAUGE;
-    }
-
-protected:
-    void onMatchedLogEventInternalLocked(
-            const size_t matcherIndex, const MetricDimensionKey& eventKey,
-            const ConditionKey& conditionKey, bool condition, const LogEvent& event,
-            const std::map<int, HashableDimensionKey>& statePrimaryKeys) override;
-
-private:
-    void onDumpReportLocked(const int64_t dumpTimeNs,
-                            const bool include_current_partial_bucket,
-                            const bool erase_data,
-                            const DumpLatency dumpLatency,
-                            std::set<string> *str_set,
-                            android::util::ProtoOutputStream* protoOutput) override;
-    void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
-
-    // Internal interface to handle condition change.
-    void onConditionChangedLocked(const bool conditionMet, const int64_t eventTime) override;
-
-    // Internal interface to handle active state change.
-    void onActiveStateChangedLocked(const int64_t& eventTimeNs) override;
-
-    // Internal interface to handle sliced condition change.
-    void onSlicedConditionMayChangeLocked(bool overallCondition, const int64_t eventTime) override;
-
-    // Internal function to calculate the current used bytes.
-    size_t byteSizeLocked() const override;
-
-    void dumpStatesLocked(FILE* out, bool verbose) const override;
-
-    void dropDataLocked(const int64_t dropTimeNs) override;
-
-    // Util function to flush the old packet.
-    void flushIfNeededLocked(const int64_t& eventTime) override;
-
-    void flushCurrentBucketLocked(const int64_t& eventTimeNs,
-                                  const int64_t& nextBucketStartTimeNs) override;
-
-    void prepareFirstBucketLocked() override;
-
-    void pullAndMatchEventsLocked(const int64_t timestampNs);
-
-    bool onConfigUpdatedLocked(
-            const StatsdConfig& config, const int configIndex, const int metricIndex,
-            const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-            const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
-            const std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
-            const sp<EventMatcherWizard>& matcherWizard,
-            const std::vector<sp<ConditionTracker>>& allConditionTrackers,
-            const std::unordered_map<int64_t, int>& conditionTrackerMap,
-            const sp<ConditionWizard>& wizard,
-            const std::unordered_map<int64_t, int>& metricToActivationMap,
-            std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
-            std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
-            std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
-            std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
-            std::vector<int>& metricsWithActivation) override;
-
-    int mWhatMatcherIndex;
-
-    sp<EventMatcherWizard> mEventMatcherWizard;
-
-    sp<StatsPullerManager> mPullerManager;
-    // tagId for pulled data. -1 if this is not pulled
-    const int mPullTagId;
-
-    // tagId for atoms that trigger the pulling, if any
-    const int mTriggerAtomId;
-
-    // tagId for output atom
-    const int mAtomId;
-
-    // if this is pulled metric
-    const bool mIsPulled;
-
-    // Save the past buckets and we can clear when the StatsLogReport is dumped.
-    std::unordered_map<MetricDimensionKey, std::vector<GaugeBucket>> mPastBuckets;
-
-    // The current partial bucket.
-    std::shared_ptr<DimToGaugeAtomsMap> mCurrentSlicedBucket;
-
-    // The current full bucket for anomaly detection. This is updated to the latest value seen for
-    // this slice (ie, for partial buckets, we use the last partial bucket in this full bucket).
-    std::shared_ptr<DimToValMap> mCurrentSlicedBucketForAnomaly;
-
-    const int64_t mMinBucketSizeNs;
-
-    // Translate Atom based bucket to single numeric value bucket for anomaly and updates the map
-    // for each slice with the latest value.
-    void updateCurrentSlicedBucketForAnomaly();
-
-    // Allowlist of fields to report. Empty means all are reported.
-    std::vector<Matcher> mFieldMatchers;
-
-    GaugeMetric::SamplingType mSamplingType;
-
-    const int64_t mMaxPullDelayNs;
-
-    // apply an allowlist on the original input
-    std::shared_ptr<vector<FieldValue>> getGaugeFields(const LogEvent& event);
-
-    // Util function to check whether the specified dimension hits the guardrail.
-    bool hitGuardRailLocked(const MetricDimensionKey& newKey);
-
-    static const size_t kBucketSize = sizeof(GaugeBucket{});
-
-    const size_t mDimensionSoftLimit;
-
-    const size_t mDimensionHardLimit;
-
-    const size_t mGaugeAtomsPerDimensionLimit;
-
-    const bool mSplitBucketForAppUpgrade;
-
-    FRIEND_TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition);
-    FRIEND_TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition);
-    FRIEND_TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition);
-    FRIEND_TEST(GaugeMetricProducerTest, TestPulledWithAppUpgradeDisabled);
-    FRIEND_TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection);
-    FRIEND_TEST(GaugeMetricProducerTest, TestFirstBucket);
-    FRIEND_TEST(GaugeMetricProducerTest, TestPullOnTrigger);
-    FRIEND_TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput);
-
-    FRIEND_TEST(GaugeMetricProducerTest_PartialBucket, TestPushedEvents);
-    FRIEND_TEST(GaugeMetricProducerTest_PartialBucket, TestPulled);
-
-    FRIEND_TEST(ConfigUpdateTest, TestUpdateGaugeMetrics);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
deleted file mode 100644
index c68e61e..0000000
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "MetricProducer.h"
-
-#include "../guardrail/StatsdStats.h"
-#include "metrics/parsing_utils/metrics_manager_util.h"
-#include "state/StateTracker.h"
-
-using android::util::FIELD_COUNT_REPEATED;
-using android::util::FIELD_TYPE_ENUM;
-using android::util::FIELD_TYPE_INT32;
-using android::util::FIELD_TYPE_INT64;
-using android::util::FIELD_TYPE_MESSAGE;
-using android::util::ProtoOutputStream;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-
-// for ActiveMetric
-const int FIELD_ID_ACTIVE_METRIC_ID = 1;
-const int FIELD_ID_ACTIVE_METRIC_ACTIVATION = 2;
-
-// for ActiveEventActivation
-const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_ATOM_MATCHER_INDEX = 1;
-const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS = 2;
-const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE = 3;
-
-MetricProducer::MetricProducer(
-        const int64_t& metricId, const ConfigKey& key, const int64_t timeBaseNs,
-        const int conditionIndex, const vector<ConditionState>& initialConditionCache,
-        const sp<ConditionWizard>& wizard, const uint64_t protoHash,
-        const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap,
-        const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
-                eventDeactivationMap,
-        const vector<int>& slicedStateAtoms,
-        const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap)
-    : mMetricId(metricId),
-      mProtoHash(protoHash),
-      mConfigKey(key),
-      mValid(true),
-      mTimeBaseNs(timeBaseNs),
-      mCurrentBucketStartTimeNs(timeBaseNs),
-      mCurrentBucketNum(0),
-      mCondition(initialCondition(conditionIndex, initialConditionCache)),
-      mConditionTrackerIndex(conditionIndex),
-      mConditionSliced(false),
-      mWizard(wizard),
-      mContainANYPositionInDimensionsInWhat(false),
-      mSliceByPositionALL(false),
-      mHasLinksToAllConditionDimensionsInTracker(false),
-      mEventActivationMap(eventActivationMap),
-      mEventDeactivationMap(eventDeactivationMap),
-      mIsActive(mEventActivationMap.empty()),
-      mSlicedStateAtoms(slicedStateAtoms),
-      mStateGroupMap(stateGroupMap) {
-}
-
-bool MetricProducer::onConfigUpdatedLocked(
-        const StatsdConfig& config, const int configIndex, const int metricIndex,
-        const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-        const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
-        const unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
-        const sp<EventMatcherWizard>& matcherWizard,
-        const vector<sp<ConditionTracker>>& allConditionTrackers,
-        const unordered_map<int64_t, int>& conditionTrackerMap, const sp<ConditionWizard>& wizard,
-        const unordered_map<int64_t, int>& metricToActivationMap,
-        unordered_map<int, vector<int>>& trackerToMetricMap,
-        unordered_map<int, vector<int>>& conditionToMetricMap,
-        unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
-        unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
-        vector<int>& metricsWithActivation) {
-    sp<ConditionWizard> tmpWizard = mWizard;
-    mWizard = wizard;
-
-    unordered_map<int, shared_ptr<Activation>> newEventActivationMap;
-    unordered_map<int, vector<shared_ptr<Activation>>> newEventDeactivationMap;
-    if (!handleMetricActivationOnConfigUpdate(
-                config, mMetricId, metricIndex, metricToActivationMap, oldAtomMatchingTrackerMap,
-                newAtomMatchingTrackerMap, mEventActivationMap, activationAtomTrackerToMetricMap,
-                deactivationAtomTrackerToMetricMap, metricsWithActivation, newEventActivationMap,
-                newEventDeactivationMap)) {
-        return false;
-    }
-    mEventActivationMap = newEventActivationMap;
-    mEventDeactivationMap = newEventDeactivationMap;
-    mAnomalyTrackers.clear();
-    return true;
-}
-
-void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) {
-    if (!mIsActive) {
-        return;
-    }
-    int64_t eventTimeNs = event.GetElapsedTimestampNs();
-    // this is old event, maybe statsd restarted?
-    if (eventTimeNs < mTimeBaseNs) {
-        return;
-    }
-
-    bool condition;
-    ConditionKey conditionKey;
-    if (mConditionSliced) {
-        for (const auto& link : mMetric2ConditionLinks) {
-            getDimensionForCondition(event.getValues(), link, &conditionKey[link.conditionId]);
-        }
-        auto conditionState =
-            mWizard->query(mConditionTrackerIndex, conditionKey,
-                           !mHasLinksToAllConditionDimensionsInTracker);
-        condition = (conditionState == ConditionState::kTrue);
-    } else {
-        // TODO: The unknown condition state is not handled here, we should fix it.
-        condition = mCondition == ConditionState::kTrue;
-    }
-
-    // Stores atom id to primary key pairs for each state atom that the metric is
-    // sliced by.
-    std::map<int32_t, HashableDimensionKey> statePrimaryKeys;
-
-    // For states with primary fields, use MetricStateLinks to get the primary
-    // field values from the log event. These values will form a primary key
-    // that will be used to query StateTracker for the correct state value.
-    for (const auto& stateLink : mMetric2StateLinks) {
-        getDimensionForState(event.getValues(), stateLink,
-                             &statePrimaryKeys[stateLink.stateAtomId]);
-    }
-
-    // For each sliced state, query StateTracker for the state value using
-    // either the primary key from the previous step or the DEFAULT_DIMENSION_KEY.
-    //
-    // Expected functionality: for any case where the MetricStateLinks are
-    // initialized incorrectly (ex. # of state links != # of primary fields, no
-    // links are provided for a state with primary fields, links are provided
-    // in the wrong order, etc.), StateTracker will simply return kStateUnknown
-    // when queried using an incorrect key.
-    HashableDimensionKey stateValuesKey;
-    for (auto atomId : mSlicedStateAtoms) {
-        FieldValue value;
-        if (statePrimaryKeys.find(atomId) != statePrimaryKeys.end()) {
-            // found a primary key for this state, query using the key
-            queryStateValue(atomId, statePrimaryKeys[atomId], &value);
-        } else {
-            // if no MetricStateLinks exist for this state atom,
-            // query using the default dimension key (empty HashableDimensionKey)
-            queryStateValue(atomId, DEFAULT_DIMENSION_KEY, &value);
-        }
-        mapStateValue(atomId, &value);
-        stateValuesKey.addValue(value);
-    }
-
-    HashableDimensionKey dimensionInWhat;
-    filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat);
-    MetricDimensionKey metricKey(dimensionInWhat, stateValuesKey);
-    onMatchedLogEventInternalLocked(matcherIndex, metricKey, conditionKey, condition, event,
-                                    statePrimaryKeys);
-}
-
-bool MetricProducer::evaluateActiveStateLocked(int64_t elapsedTimestampNs) {
-    bool isActive = mEventActivationMap.empty();
-    for (auto& it : mEventActivationMap) {
-        if (it.second->state == ActivationState::kActive &&
-            elapsedTimestampNs > it.second->ttl_ns + it.second->start_ns) {
-            it.second->state = ActivationState::kNotActive;
-        }
-        if (it.second->state == ActivationState::kActive) {
-            isActive = true;
-        }
-    }
-    return isActive;
-}
-
-void MetricProducer::flushIfExpire(int64_t elapsedTimestampNs) {
-    std::lock_guard<std::mutex> lock(mMutex);
-    if (!mIsActive) {
-        return;
-    }
-    mIsActive = evaluateActiveStateLocked(elapsedTimestampNs);
-    if (!mIsActive) {
-        onActiveStateChangedLocked(elapsedTimestampNs);
-    }
-}
-
-void MetricProducer::activateLocked(int activationTrackerIndex, int64_t elapsedTimestampNs) {
-    auto it = mEventActivationMap.find(activationTrackerIndex);
-    if (it == mEventActivationMap.end()) {
-        return;
-    }
-    auto& activation = it->second;
-    if (ACTIVATE_ON_BOOT == activation->activationType) {
-        if (ActivationState::kNotActive == activation->state) {
-            activation->state = ActivationState::kActiveOnBoot;
-        }
-        // If the Activation is already active or set to kActiveOnBoot, do nothing.
-        return;
-    }
-    activation->start_ns = elapsedTimestampNs;
-    activation->state = ActivationState::kActive;
-    bool oldActiveState = mIsActive;
-    mIsActive = true;
-    if (!oldActiveState) { // Metric went from not active to active.
-        onActiveStateChangedLocked(elapsedTimestampNs);
-    }
-}
-
-void MetricProducer::cancelEventActivationLocked(int deactivationTrackerIndex) {
-    auto it = mEventDeactivationMap.find(deactivationTrackerIndex);
-    if (it == mEventDeactivationMap.end()) {
-        return;
-    }
-    for (auto activationToCancelIt : it->second)  {
-        activationToCancelIt->state = ActivationState::kNotActive;
-    }
-}
-
-void MetricProducer::loadActiveMetricLocked(const ActiveMetric& activeMetric,
-                                            int64_t currentTimeNs) {
-    if (mEventActivationMap.size() == 0) {
-        return;
-    }
-    for (int i = 0; i < activeMetric.activation_size(); i++) {
-        const auto& activeEventActivation = activeMetric.activation(i);
-        auto it = mEventActivationMap.find(activeEventActivation.atom_matcher_index());
-        if (it == mEventActivationMap.end()) {
-            ALOGE("Saved event activation not found");
-            continue;
-        }
-        auto& activation = it->second;
-        // If the event activation does not have a state, assume it is active.
-        if (!activeEventActivation.has_state() ||
-                activeEventActivation.state() == ActiveEventActivation::ACTIVE) {
-            // We don't want to change the ttl for future activations, so we set the start_ns
-            // such that start_ns + ttl_ns == currentTimeNs + remaining_ttl_nanos
-            activation->start_ns =
-                currentTimeNs + activeEventActivation.remaining_ttl_nanos() - activation->ttl_ns;
-            activation->state = ActivationState::kActive;
-            mIsActive = true;
-        } else if (activeEventActivation.state() == ActiveEventActivation::ACTIVATE_ON_BOOT) {
-            activation->state = ActivationState::kActiveOnBoot;
-        }
-    }
-}
-
-void MetricProducer::writeActiveMetricToProtoOutputStream(
-        int64_t currentTimeNs, const DumpReportReason reason, ProtoOutputStream* proto) {
-    proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_METRIC_ID, (long long)mMetricId);
-    for (auto& it : mEventActivationMap) {
-        const int atom_matcher_index = it.first;
-        const std::shared_ptr<Activation>& activation = it.second;
-
-        if (ActivationState::kNotActive == activation->state ||
-                (ActivationState::kActive == activation->state &&
-                 activation->start_ns + activation->ttl_ns < currentTimeNs)) {
-            continue;
-        }
-
-        const uint64_t activationToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                FIELD_ID_ACTIVE_METRIC_ACTIVATION);
-        proto->write(FIELD_TYPE_INT32 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_ATOM_MATCHER_INDEX,
-                atom_matcher_index);
-        if (ActivationState::kActive == activation->state) {
-            const int64_t remainingTtlNs =
-                    activation->start_ns + activation->ttl_ns - currentTimeNs;
-            proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS,
-                    (long long)remainingTtlNs);
-            proto->write(FIELD_TYPE_ENUM | FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE,
-                    ActiveEventActivation::ACTIVE);
-
-        } else if (ActivationState::kActiveOnBoot == activation->state) {
-            if (reason == DEVICE_SHUTDOWN || reason == TERMINATION_SIGNAL_RECEIVED) {
-                proto->write(
-                        FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_EVENT_ACTIVATION_REMAINING_TTL_NANOS,
-                        (long long)activation->ttl_ns);
-                proto->write(FIELD_TYPE_ENUM | FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE,
-                                    ActiveEventActivation::ACTIVE);
-            } else if (reason == STATSCOMPANION_DIED) {
-                // We are saving because of system server death, not due to a device shutdown.
-                // Next time we load, we do not want to activate metrics that activate on boot.
-                proto->write(FIELD_TYPE_ENUM | FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE,
-                                                    ActiveEventActivation::ACTIVATE_ON_BOOT);
-            }
-        }
-        proto->end(activationToken);
-    }
-}
-
-void MetricProducer::queryStateValue(const int32_t atomId, const HashableDimensionKey& queryKey,
-                                     FieldValue* value) {
-    if (!StateManager::getInstance().getStateValue(atomId, queryKey, value)) {
-        value->mValue = Value(StateTracker::kStateUnknown);
-        value->mField.setTag(atomId);
-        ALOGW("StateTracker not found for state atom %d", atomId);
-        return;
-    }
-}
-
-void MetricProducer::mapStateValue(const int32_t atomId, FieldValue* value) {
-    // check if there is a state map for this atom
-    auto atomIt = mStateGroupMap.find(atomId);
-    if (atomIt == mStateGroupMap.end()) {
-        return;
-    }
-    auto valueIt = atomIt->second.find(value->mValue.int_value);
-    if (valueIt == atomIt->second.end()) {
-        // state map exists, but value was not put in a state group
-        // so set mValue to kStateUnknown
-        // TODO(tsaichristine): handle incomplete state maps
-        value->mValue.setInt(StateTracker::kStateUnknown);
-    } else {
-        // set mValue to group_id
-        value->mValue.setLong(valueIt->second);
-    }
-}
-
-HashableDimensionKey MetricProducer::getUnknownStateKey() {
-    HashableDimensionKey stateKey;
-    for (auto atom : mSlicedStateAtoms) {
-        FieldValue fieldValue;
-        fieldValue.mField.setTag(atom);
-        fieldValue.mValue.setInt(StateTracker::kStateUnknown);
-        stateKey.addValue(fieldValue);
-    }
-    return stateKey;
-}
-
-DropEvent MetricProducer::buildDropEvent(const int64_t dropTimeNs, const BucketDropReason reason) {
-    DropEvent event;
-    event.reason = reason;
-    event.dropTimeNs = dropTimeNs;
-    return event;
-}
-
-bool MetricProducer::maxDropEventsReached() {
-    return mCurrentSkippedBucket.dropEvents.size() >= StatsdStats::kMaxLoggedBucketDropEvents;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
deleted file mode 100644
index 7a1c008..0000000
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ /dev/null
@@ -1,588 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef METRIC_PRODUCER_H
-#define METRIC_PRODUCER_H
-
-#include <frameworks/base/cmds/statsd/src/active_config_list.pb.h>
-#include <utils/RefBase.h>
-
-#include <unordered_map>
-
-#include "HashableDimensionKey.h"
-#include "anomaly/AnomalyTracker.h"
-#include "condition/ConditionWizard.h"
-#include "config/ConfigKey.h"
-#include "matchers/EventMatcherWizard.h"
-#include "matchers/matcher_util.h"
-#include "packages/PackageInfoListener.h"
-#include "state/StateListener.h"
-#include "state/StateManager.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// Keep this in sync with DumpReportReason enum in stats_log.proto
-enum DumpReportReason {
-    DEVICE_SHUTDOWN = 1,
-    CONFIG_UPDATED = 2,
-    CONFIG_REMOVED = 3,
-    GET_DATA_CALLED = 4,
-    ADB_DUMP = 5,
-    CONFIG_RESET = 6,
-    STATSCOMPANION_DIED = 7,
-    TERMINATION_SIGNAL_RECEIVED = 8
-};
-
-// If the metric has no activation requirement, it will be active once the metric producer is
-// created.
-// If the metric needs to be activated by atoms, the metric producer will start
-// with kNotActive state, turn to kActive or kActiveOnBoot when the activation event arrives, become
-// kNotActive when it reaches the duration limit (timebomb). If the activation event arrives again
-// before or after it expires, the event producer will be re-activated and ttl will be reset.
-enum ActivationState {
-    kNotActive = 0,
-    kActive = 1,
-    kActiveOnBoot = 2,
-};
-
-enum DumpLatency {
-    // In some cases, we only have a short time range to do the dump, e.g. statsd is being killed.
-    // We might be able to return all the data in this mode. For instance, pull metrics might need
-    // to be pulled when the current bucket is requested.
-    FAST = 1,
-    // In other cases, it is fine for a dump to take more than a few milliseconds, e.g. config
-    // updates.
-    NO_TIME_CONSTRAINTS = 2
-};
-
-// Keep this in sync with BucketDropReason enum in stats_log.proto
-enum BucketDropReason {
-    // For ValueMetric, a bucket is dropped during a dump report request iff
-    // current bucket should be included, a pull is needed (pulled metric and
-    // condition is true), and we are under fast time constraints.
-    DUMP_REPORT_REQUESTED = 1,
-    EVENT_IN_WRONG_BUCKET = 2,
-    CONDITION_UNKNOWN = 3,
-    PULL_FAILED = 4,
-    PULL_DELAYED = 5,
-    DIMENSION_GUARDRAIL_REACHED = 6,
-    MULTIPLE_BUCKETS_SKIPPED = 7,
-    // Not an invalid bucket case, but the bucket is dropped.
-    BUCKET_TOO_SMALL = 8,
-    // Not an invalid bucket case, but the bucket is skipped.
-    NO_DATA = 9
-};
-
-enum MetricType {
-    METRIC_TYPE_EVENT = 1,
-    METRIC_TYPE_COUNT = 2,
-    METRIC_TYPE_DURATION = 3,
-    METRIC_TYPE_GAUGE = 4,
-    METRIC_TYPE_VALUE = 5,
-};
-struct Activation {
-    Activation(const ActivationType& activationType, const int64_t ttlNs)
-        : ttl_ns(ttlNs),
-          start_ns(0),
-          state(ActivationState::kNotActive),
-          activationType(activationType) {}
-
-    const int64_t ttl_ns;
-    int64_t start_ns;
-    ActivationState state;
-    const ActivationType activationType;
-};
-
-struct DropEvent {
-    // Reason for dropping the bucket and/or marking the bucket invalid.
-    BucketDropReason reason;
-    // The timestamp of the drop event.
-    int64_t dropTimeNs;
-};
-
-struct SkippedBucket {
-    // Start time of the dropped bucket.
-    int64_t bucketStartTimeNs;
-    // End time of the dropped bucket.
-    int64_t bucketEndTimeNs;
-    // List of events that invalidated this bucket.
-    std::vector<DropEvent> dropEvents;
-
-    void reset() {
-        bucketStartTimeNs = 0;
-        bucketEndTimeNs = 0;
-        dropEvents.clear();
-    }
-};
-
-// A MetricProducer is responsible for compute one single metrics, creating stats log report, and
-// writing the report to dropbox. MetricProducers should respond to package changes as required in
-// PackageInfoListener, but if none of the metrics are slicing by package name, then the update can
-// be a no-op.
-class MetricProducer : public virtual android::RefBase, public virtual StateListener {
-public:
-    MetricProducer(const int64_t& metricId, const ConfigKey& key, const int64_t timeBaseNs,
-                   const int conditionIndex, const vector<ConditionState>& initialConditionCache,
-                   const sp<ConditionWizard>& wizard, const uint64_t protoHash,
-                   const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap,
-                   const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
-                           eventDeactivationMap,
-                   const vector<int>& slicedStateAtoms,
-                   const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap);
-
-    virtual ~MetricProducer(){};
-
-    ConditionState initialCondition(const int conditionIndex,
-                                    const vector<ConditionState>& initialConditionCache) const {
-        return conditionIndex >= 0 ? initialConditionCache[conditionIndex] : ConditionState::kTrue;
-    }
-
-    // Update appropriate state on config updates. Primarily, all indices need to be updated.
-    // This metric and all of its dependencies are guaranteed to be preserved across the update.
-    // This function also updates several maps used by metricsManager.
-    // This function clears all anomaly trackers. All anomaly trackers need to be added again.
-    bool onConfigUpdated(
-            const StatsdConfig& config, const int configIndex, const int metricIndex,
-            const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-            const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
-            const std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
-            const sp<EventMatcherWizard>& matcherWizard,
-            const std::vector<sp<ConditionTracker>>& allConditionTrackers,
-            const std::unordered_map<int64_t, int>& conditionTrackerMap,
-            const sp<ConditionWizard>& wizard,
-            const std::unordered_map<int64_t, int>& metricToActivationMap,
-            std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
-            std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
-            std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
-            std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
-            std::vector<int>& metricsWithActivation) {
-        std::lock_guard<std::mutex> lock(mMutex);
-        return onConfigUpdatedLocked(config, configIndex, metricIndex, allAtomMatchingTrackers,
-                                     oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap,
-                                     matcherWizard, allConditionTrackers, conditionTrackerMap,
-                                     wizard, metricToActivationMap, trackerToMetricMap,
-                                     conditionToMetricMap, activationAtomTrackerToMetricMap,
-                                     deactivationAtomTrackerToMetricMap, metricsWithActivation);
-    };
-
-    /**
-     * Force a partial bucket split on app upgrade
-     */
-    virtual void notifyAppUpgrade(const int64_t& eventTimeNs) {
-        std::lock_guard<std::mutex> lock(mMutex);
-        flushLocked(eventTimeNs);
-    };
-
-    void notifyAppRemoved(const int64_t& eventTimeNs) {
-        // Force buckets to split on removal also.
-        notifyAppUpgrade(eventTimeNs);
-    };
-
-    /**
-     * Force a partial bucket split on boot complete.
-     */
-    virtual void onStatsdInitCompleted(const int64_t& eventTimeNs) {
-        std::lock_guard<std::mutex> lock(mMutex);
-        flushLocked(eventTimeNs);
-    }
-    // Consume the parsed stats log entry that already matched the "what" of the metric.
-    void onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event) {
-        std::lock_guard<std::mutex> lock(mMutex);
-        onMatchedLogEventLocked(matcherIndex, event);
-    }
-
-    void onConditionChanged(const bool condition, const int64_t eventTime) {
-        std::lock_guard<std::mutex> lock(mMutex);
-        onConditionChangedLocked(condition, eventTime);
-    }
-
-    void onSlicedConditionMayChange(bool overallCondition, const int64_t eventTime) {
-        std::lock_guard<std::mutex> lock(mMutex);
-        onSlicedConditionMayChangeLocked(overallCondition, eventTime);
-    }
-
-    bool isConditionSliced() const {
-        std::lock_guard<std::mutex> lock(mMutex);
-        return mConditionSliced;
-    };
-
-    void onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
-                        const HashableDimensionKey& primaryKey, const FieldValue& oldState,
-                        const FieldValue& newState){};
-
-    // Output the metrics data to [protoOutput]. All metrics reports end with the same timestamp.
-    // This method clears all the past buckets.
-    void onDumpReport(const int64_t dumpTimeNs,
-                      const bool include_current_partial_bucket,
-                      const bool erase_data,
-                      const DumpLatency dumpLatency,
-                      std::set<string> *str_set,
-                      android::util::ProtoOutputStream* protoOutput) {
-        std::lock_guard<std::mutex> lock(mMutex);
-        return onDumpReportLocked(dumpTimeNs, include_current_partial_bucket, erase_data,
-                dumpLatency, str_set, protoOutput);
-    }
-
-    virtual bool onConfigUpdatedLocked(
-            const StatsdConfig& config, const int configIndex, const int metricIndex,
-            const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-            const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
-            const std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
-            const sp<EventMatcherWizard>& matcherWizard,
-            const std::vector<sp<ConditionTracker>>& allConditionTrackers,
-            const std::unordered_map<int64_t, int>& conditionTrackerMap,
-            const sp<ConditionWizard>& wizard,
-            const std::unordered_map<int64_t, int>& metricToActivationMap,
-            std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
-            std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
-            std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
-            std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
-            std::vector<int>& metricsWithActivation);
-
-    void clearPastBuckets(const int64_t dumpTimeNs) {
-        std::lock_guard<std::mutex> lock(mMutex);
-        return clearPastBucketsLocked(dumpTimeNs);
-    }
-
-    void prepareFirstBucket() {
-        std::lock_guard<std::mutex> lock(mMutex);
-        prepareFirstBucketLocked();
-    }
-
-    // Returns the memory in bytes currently used to store this metric's data. Does not change
-    // state.
-    size_t byteSize() const {
-        std::lock_guard<std::mutex> lock(mMutex);
-        return byteSizeLocked();
-    }
-
-    void dumpStates(FILE* out, bool verbose) const {
-        std::lock_guard<std::mutex> lock(mMutex);
-        dumpStatesLocked(out, verbose);
-    }
-
-    // Let MetricProducer drop in-memory data to save memory.
-    // We still need to keep future data valid and anomaly tracking work, which means we will
-    // have to flush old data, informing anomaly trackers then safely drop old data.
-    // We still keep current bucket data for future metrics' validity.
-    void dropData(const int64_t dropTimeNs) {
-        std::lock_guard<std::mutex> lock(mMutex);
-        dropDataLocked(dropTimeNs);
-    }
-
-    void loadActiveMetric(const ActiveMetric& activeMetric, int64_t currentTimeNs) {
-        std::lock_guard<std::mutex> lock(mMutex);
-        loadActiveMetricLocked(activeMetric, currentTimeNs);
-    }
-
-    void activate(int activationTrackerIndex, int64_t elapsedTimestampNs) {
-        std::lock_guard<std::mutex> lock(mMutex);
-        activateLocked(activationTrackerIndex, elapsedTimestampNs);
-    }
-
-    void cancelEventActivation(int deactivationTrackerIndex) {
-        std::lock_guard<std::mutex> lock(mMutex);
-        cancelEventActivationLocked(deactivationTrackerIndex);
-    }
-
-    bool isActive() const {
-        std::lock_guard<std::mutex> lock(mMutex);
-        return isActiveLocked();
-    }
-
-    void flushIfExpire(int64_t elapsedTimestampNs);
-
-    void writeActiveMetricToProtoOutputStream(
-            int64_t currentTimeNs, const DumpReportReason reason, ProtoOutputStream* proto);
-
-    // Start: getters/setters
-    inline int64_t getMetricId() const {
-        return mMetricId;
-    }
-
-    inline uint64_t getProtoHash() const {
-        return mProtoHash;
-    }
-
-    virtual MetricType getMetricType() const = 0;
-
-    // For test only.
-    inline int64_t getCurrentBucketNum() const {
-        return mCurrentBucketNum;
-    }
-
-    int64_t getBucketSizeInNs() const {
-        std::lock_guard<std::mutex> lock(mMutex);
-        return mBucketSizeNs;
-    }
-
-    inline const std::vector<int> getSlicedStateAtoms() {
-        std::lock_guard<std::mutex> lock(mMutex);
-        return mSlicedStateAtoms;
-    }
-
-    inline bool isValid() const {
-        return mValid;
-    }
-
-    /* Adds an AnomalyTracker and returns it. */
-    virtual sp<AnomalyTracker> addAnomalyTracker(const Alert &alert,
-                                                 const sp<AlarmMonitor>& anomalyAlarmMonitor) {
-        std::lock_guard<std::mutex> lock(mMutex);
-        sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, mConfigKey);
-        mAnomalyTrackers.push_back(anomalyTracker);
-        return anomalyTracker;
-    }
-
-    /* Adds an AnomalyTracker that has already been created */
-    virtual void addAnomalyTracker(sp<AnomalyTracker>& anomalyTracker) {
-        std::lock_guard<std::mutex> lock(mMutex);
-        mAnomalyTrackers.push_back(anomalyTracker);
-    }
-    // End: getters/setters
-protected:
-    /**
-     * Flushes the current bucket if the eventTime is after the current bucket's end time.
-     */
-    virtual void flushIfNeededLocked(const int64_t& eventTime){};
-
-    /**
-     * For metrics that aggregate (ie, every metric producer except for EventMetricProducer),
-     * we need to be able to flush the current buckets on demand (ie, end the current bucket and
-     * start new bucket). If this function is called when eventTimeNs is greater than the current
-     * bucket's end timestamp, than we flush up to the end of the latest full bucket; otherwise,
-     * we assume that we want to flush a partial bucket. The bucket start timestamp and bucket
-     * number are not changed by this function. This method should only be called by
-     * flushIfNeededLocked or flushLocked or the app upgrade handler; the caller MUST update the
-     * bucket timestamp and bucket number as needed.
-     */
-    virtual void flushCurrentBucketLocked(const int64_t& eventTimeNs,
-                                          const int64_t& nextBucketStartTimeNs) {};
-
-    /**
-     * Flushes all the data including the current partial bucket.
-     */
-    virtual void flushLocked(const int64_t& eventTimeNs) {
-        flushIfNeededLocked(eventTimeNs);
-        flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
-    };
-
-    /*
-     * Individual metrics can implement their own business logic here. All pre-processing is done.
-     *
-     * [matcherIndex]: the index of the matcher which matched this event. This is interesting to
-     *                 DurationMetric, because it has start/stop/stop_all 3 matchers.
-     * [eventKey]: the extracted dimension key for the final output. if the metric doesn't have
-     *             dimensions, it will be DEFAULT_DIMENSION_KEY
-     * [conditionKey]: the keys of conditions which should be used to query the condition for this
-     *                 target event (from MetricConditionLink). This is passed to individual metrics
-     *                 because DurationMetric needs it to be cached.
-     * [condition]: whether condition is met. If condition is sliced, this is the result coming from
-     *              query with ConditionWizard; If condition is not sliced, this is the
-     *              nonSlicedCondition.
-     * [event]: the log event, just in case the metric needs its data, e.g., EventMetric.
-     */
-    virtual void onMatchedLogEventInternalLocked(
-            const size_t matcherIndex, const MetricDimensionKey& eventKey,
-            const ConditionKey& conditionKey, bool condition, const LogEvent& event,
-            const map<int, HashableDimensionKey>& statePrimaryKeys) = 0;
-
-    // Consume the parsed stats log entry that already matched the "what" of the metric.
-    virtual void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event);
-    virtual void onConditionChangedLocked(const bool condition, const int64_t eventTime) = 0;
-    virtual void onSlicedConditionMayChangeLocked(bool overallCondition,
-                                                  const int64_t eventTime) = 0;
-    virtual void onDumpReportLocked(const int64_t dumpTimeNs,
-                                    const bool include_current_partial_bucket,
-                                    const bool erase_data,
-                                    const DumpLatency dumpLatency,
-                                    std::set<string> *str_set,
-                                    android::util::ProtoOutputStream* protoOutput) = 0;
-    virtual void clearPastBucketsLocked(const int64_t dumpTimeNs) = 0;
-    virtual void prepareFirstBucketLocked(){};
-    virtual size_t byteSizeLocked() const = 0;
-    virtual void dumpStatesLocked(FILE* out, bool verbose) const = 0;
-    virtual void dropDataLocked(const int64_t dropTimeNs) = 0;
-    void loadActiveMetricLocked(const ActiveMetric& activeMetric, int64_t currentTimeNs);
-    void activateLocked(int activationTrackerIndex, int64_t elapsedTimestampNs);
-    void cancelEventActivationLocked(int deactivationTrackerIndex);
-
-    bool evaluateActiveStateLocked(int64_t elapsedTimestampNs);
-
-    virtual void onActiveStateChangedLocked(const int64_t& eventTimeNs) {
-        if (!mIsActive) {
-            flushLocked(eventTimeNs);
-        }
-    }
-
-    inline bool isActiveLocked() const {
-        return mIsActive;
-    }
-
-    // Convenience to compute the current bucket's end time, which is always aligned with the
-    // start time of the metric.
-    int64_t getCurrentBucketEndTimeNs() const {
-        return mTimeBaseNs + (mCurrentBucketNum + 1) * mBucketSizeNs;
-    }
-
-    int64_t getBucketNumFromEndTimeNs(const int64_t endNs) {
-        return (endNs - mTimeBaseNs) / mBucketSizeNs - 1;
-    }
-
-    // Query StateManager for original state value using the queryKey.
-    // The field and value are output.
-    void queryStateValue(const int32_t atomId, const HashableDimensionKey& queryKey,
-                         FieldValue* value);
-
-    // If a state map exists for the given atom, replace the original state
-    // value with the group id mapped to the value.
-    // If no state map exists, keep the original state value.
-    void mapStateValue(const int32_t atomId, FieldValue* value);
-
-    // Returns a HashableDimensionKey with unknown state value for each state
-    // atom.
-    HashableDimensionKey getUnknownStateKey();
-
-    DropEvent buildDropEvent(const int64_t dropTimeNs, const BucketDropReason reason);
-
-    // Returns true if the number of drop events in the current bucket has
-    // exceeded the maximum number allowed, which is currently capped at 10.
-    bool maxDropEventsReached();
-
-    const int64_t mMetricId;
-
-    // Hash of the Metric's proto bytes from StatsdConfig, including any activations.
-    // Used to determine if the definition of this metric has changed across a config update.
-    const uint64_t mProtoHash;
-
-    const ConfigKey mConfigKey;
-
-    bool mValid;
-
-    // The time when this metric producer was first created. The end time for the current bucket
-    // can be computed from this based on mCurrentBucketNum.
-    int64_t mTimeBaseNs;
-
-    // Start time may not be aligned with the start of statsd if there is an app upgrade in the
-    // middle of a bucket.
-    int64_t mCurrentBucketStartTimeNs;
-
-    // Used by anomaly detector to track which bucket we are in. This is not sent with the produced
-    // report.
-    int64_t mCurrentBucketNum;
-
-    int64_t mBucketSizeNs;
-
-    ConditionState mCondition;
-
-    int mConditionTrackerIndex;
-
-    bool mConditionSliced;
-
-    sp<ConditionWizard> mWizard;
-
-    bool mContainANYPositionInDimensionsInWhat;
-
-    bool mSliceByPositionALL;
-
-    vector<Matcher> mDimensionsInWhat;  // The dimensions_in_what defined in statsd_config
-
-    // True iff the metric to condition links cover all dimension fields in the condition tracker.
-    // This field is always false for combinational condition trackers.
-    bool mHasLinksToAllConditionDimensionsInTracker;
-
-    std::vector<Metric2Condition> mMetric2ConditionLinks;
-
-    std::vector<sp<AnomalyTracker>> mAnomalyTrackers;
-
-    mutable std::mutex mMutex;
-
-    // When the metric producer has multiple activations, these activations are ORed to determine
-    // whether the metric producer is ready to generate metrics.
-    std::unordered_map<int, std::shared_ptr<Activation>> mEventActivationMap;
-
-    // Maps index of atom matcher for deactivation to a list of Activation structs.
-    std::unordered_map<int, std::vector<std::shared_ptr<Activation>>> mEventDeactivationMap;
-
-    bool mIsActive;
-
-    // The slice_by_state atom ids defined in statsd_config.
-    const std::vector<int32_t> mSlicedStateAtoms;
-
-    // Maps atom ids and state values to group_ids (<atom_id, <value, group_id>>).
-    const std::unordered_map<int32_t, std::unordered_map<int, int64_t>> mStateGroupMap;
-
-    // MetricStateLinks defined in statsd_config that link fields in the state
-    // atom to fields in the "what" atom.
-    std::vector<Metric2State> mMetric2StateLinks;
-
-    SkippedBucket mCurrentSkippedBucket;
-    // Buckets that were invalidated and had their data dropped.
-    std::vector<SkippedBucket> mSkippedBuckets;
-
-    FRIEND_TEST(CountMetricE2eTest, TestSlicedState);
-    FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithMap);
-    FRIEND_TEST(CountMetricE2eTest, TestMultipleSlicedStates);
-    FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields);
-    FRIEND_TEST(CountMetricE2eTest, TestInitialConditionChanges);
-
-    FRIEND_TEST(DurationMetricE2eTest, TestOneBucket);
-    FRIEND_TEST(DurationMetricE2eTest, TestTwoBuckets);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithActivation);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithCondition);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithSlicedCondition);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithActivationAndSlicedCondition);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithSlicedState);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithConditionAndSlicedState);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithSlicedStateMapped);
-    FRIEND_TEST(DurationMetricE2eTest, TestSlicedStatePrimaryFieldsNotSubsetDimInWhat);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithSlicedStatePrimaryFieldsSubset);
-
-    FRIEND_TEST(MetricActivationE2eTest, TestCountMetric);
-    FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation);
-    FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations);
-    FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithSameDeactivation);
-    FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations);
-
-    FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
-    FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot);
-    FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations);
-    FRIEND_TEST(StatsLogProcessorTest,
-            TestActivationOnBootMultipleActivationsDifferentActivationTypes);
-    FRIEND_TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart);
-
-    FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState);
-    FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithDimensions);
-    FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithIncorrectDimensions);
-    FRIEND_TEST(ValueMetricE2eTest, TestInitialConditionChanges);
-
-    FRIEND_TEST(MetricsManagerTest, TestInitialConditions);
-
-    FRIEND_TEST(ConfigUpdateTest, TestUpdateMetricActivations);
-    FRIEND_TEST(ConfigUpdateTest, TestUpdateCountMetrics);
-    FRIEND_TEST(ConfigUpdateTest, TestUpdateEventMetrics);
-    FRIEND_TEST(ConfigUpdateTest, TestUpdateGaugeMetrics);
-    FRIEND_TEST(ConfigUpdateTest, TestUpdateDurationMetrics);
-    FRIEND_TEST(ConfigUpdateTest, TestUpdateMetricsMultipleTypes);
-    FRIEND_TEST(ConfigUpdateTest, TestUpdateAlerts);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#endif  // METRIC_PRODUCER_H
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
deleted file mode 100644
index f9b0a10..0000000
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ /dev/null
@@ -1,773 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "MetricsManager.h"
-
-#include <private/android_filesystem_config.h>
-
-#include "CountMetricProducer.h"
-#include "condition/CombinationConditionTracker.h"
-#include "condition/SimpleConditionTracker.h"
-#include "guardrail/StatsdStats.h"
-#include "matchers/CombinationAtomMatchingTracker.h"
-#include "matchers/SimpleAtomMatchingTracker.h"
-#include "parsing_utils/config_update_utils.h"
-#include "parsing_utils/metrics_manager_util.h"
-#include "state/StateManager.h"
-#include "stats_log_util.h"
-#include "stats_util.h"
-#include "statslog_statsd.h"
-
-using android::util::FIELD_COUNT_REPEATED;
-using android::util::FIELD_TYPE_INT32;
-using android::util::FIELD_TYPE_INT64;
-using android::util::FIELD_TYPE_MESSAGE;
-using android::util::FIELD_TYPE_STRING;
-using android::util::ProtoOutputStream;
-
-using std::set;
-using std::string;
-using std::vector;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-const int FIELD_ID_METRICS = 1;
-const int FIELD_ID_ANNOTATIONS = 7;
-const int FIELD_ID_ANNOTATIONS_INT64 = 1;
-const int FIELD_ID_ANNOTATIONS_INT32 = 2;
-
-// for ActiveConfig
-const int FIELD_ID_ACTIVE_CONFIG_ID = 1;
-const int FIELD_ID_ACTIVE_CONFIG_UID = 2;
-const int FIELD_ID_ACTIVE_CONFIG_METRIC = 3;
-
-MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
-                               const int64_t timeBaseNs, const int64_t currentTimeNs,
-                               const sp<UidMap>& uidMap,
-                               const sp<StatsPullerManager>& pullerManager,
-                               const sp<AlarmMonitor>& anomalyAlarmMonitor,
-                               const sp<AlarmMonitor>& periodicAlarmMonitor)
-    : mConfigKey(key),
-      mUidMap(uidMap),
-      mTtlNs(config.has_ttl_in_seconds() ? config.ttl_in_seconds() * NS_PER_SEC : -1),
-      mTtlEndNs(-1),
-      mLastReportTimeNs(currentTimeNs),
-      mLastReportWallClockNs(getWallClockNs()),
-      mPullerManager(pullerManager),
-      mWhitelistedAtomIds(config.whitelisted_atom_ids().begin(),
-                          config.whitelisted_atom_ids().end()),
-      mShouldPersistHistory(config.persist_locally()) {
-    // Init the ttl end timestamp.
-    refreshTtl(timeBaseNs);
-
-    mConfigValid = initStatsdConfig(
-            key, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
-            timeBaseNs, currentTimeNs, mTagIds, mAllAtomMatchingTrackers, mAtomMatchingTrackerMap,
-            mAllConditionTrackers, mConditionTrackerMap, mAllMetricProducers, mMetricProducerMap,
-            mAllAnomalyTrackers, mAllPeriodicAlarmTrackers, mConditionToMetricMap,
-            mTrackerToMetricMap, mTrackerToConditionMap, mActivationAtomTrackerToMetricMap,
-            mDeactivationAtomTrackerToMetricMap, mAlertTrackerMap, mMetricIndexesWithActivation,
-            mStateProtoHashes, mNoReportMetricIds);
-
-    mHashStringsInReport = config.hash_strings_in_metric_report();
-    mVersionStringsInReport = config.version_strings_in_metric_report();
-    mInstallerInReport = config.installer_in_metric_report();
-
-    createAllLogSourcesFromConfig(config);
-    mPullerManager->RegisterPullUidProvider(mConfigKey, this);
-
-    // Store the sub-configs used.
-    for (const auto& annotation : config.annotation()) {
-        mAnnotations.emplace_back(annotation.field_int64(), annotation.field_int32());
-    }
-    verifyGuardrailsAndUpdateStatsdStats();
-    initializeConfigActiveStatus();
-}
-
-MetricsManager::~MetricsManager() {
-    for (auto it : mAllMetricProducers) {
-        for (int atomId : it->getSlicedStateAtoms()) {
-            StateManager::getInstance().unregisterListener(atomId, it);
-        }
-    }
-    mPullerManager->UnregisterPullUidProvider(mConfigKey, this);
-
-    VLOG("~MetricsManager()");
-}
-
-bool MetricsManager::updateConfig(const StatsdConfig& config, const int64_t timeBaseNs,
-                                  const int64_t currentTimeNs,
-                                  const sp<AlarmMonitor>& anomalyAlarmMonitor,
-                                  const sp<AlarmMonitor>& periodicAlarmMonitor) {
-    vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers;
-    unordered_map<int64_t, int> newAtomMatchingTrackerMap;
-    vector<sp<ConditionTracker>> newConditionTrackers;
-    unordered_map<int64_t, int> newConditionTrackerMap;
-    map<int64_t, uint64_t> newStateProtoHashes;
-    vector<sp<MetricProducer>> newMetricProducers;
-    unordered_map<int64_t, int> newMetricProducerMap;
-    vector<sp<AnomalyTracker>> newAnomalyTrackers;
-    unordered_map<int64_t, int> newAlertTrackerMap;
-    vector<sp<AlarmTracker>> newPeriodicAlarmTrackers;
-    mTagIds.clear();
-    mConditionToMetricMap.clear();
-    mTrackerToMetricMap.clear();
-    mTrackerToConditionMap.clear();
-    mActivationAtomTrackerToMetricMap.clear();
-    mDeactivationAtomTrackerToMetricMap.clear();
-    mMetricIndexesWithActivation.clear();
-    mNoReportMetricIds.clear();
-    mConfigValid = updateStatsdConfig(
-            mConfigKey, config, mUidMap, mPullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
-            timeBaseNs, currentTimeNs, mAllAtomMatchingTrackers, mAtomMatchingTrackerMap,
-            mAllConditionTrackers, mConditionTrackerMap, mAllMetricProducers, mMetricProducerMap,
-            mAllAnomalyTrackers, mAlertTrackerMap, mStateProtoHashes, mTagIds,
-            newAtomMatchingTrackers, newAtomMatchingTrackerMap, newConditionTrackers,
-            newConditionTrackerMap, newMetricProducers, newMetricProducerMap, newAnomalyTrackers,
-            newAlertTrackerMap, newPeriodicAlarmTrackers, mConditionToMetricMap,
-            mTrackerToMetricMap, mTrackerToConditionMap, mActivationAtomTrackerToMetricMap,
-            mDeactivationAtomTrackerToMetricMap, mMetricIndexesWithActivation, newStateProtoHashes,
-            mNoReportMetricIds);
-    mAllAtomMatchingTrackers = newAtomMatchingTrackers;
-    mAtomMatchingTrackerMap = newAtomMatchingTrackerMap;
-    mAllConditionTrackers = newConditionTrackers;
-    mConditionTrackerMap = newConditionTrackerMap;
-    mAllMetricProducers = newMetricProducers;
-    mMetricProducerMap = newMetricProducerMap;
-    mStateProtoHashes = newStateProtoHashes;
-    mAllAnomalyTrackers = newAnomalyTrackers;
-    mAlertTrackerMap = newAlertTrackerMap;
-    mAllPeriodicAlarmTrackers = newPeriodicAlarmTrackers;
-
-    mTtlNs = config.has_ttl_in_seconds() ? config.ttl_in_seconds() * NS_PER_SEC : -1;
-    refreshTtl(currentTimeNs);
-
-    mHashStringsInReport = config.hash_strings_in_metric_report();
-    mVersionStringsInReport = config.version_strings_in_metric_report();
-    mInstallerInReport = config.installer_in_metric_report();
-    mWhitelistedAtomIds.clear();
-    mWhitelistedAtomIds.insert(config.whitelisted_atom_ids().begin(),
-                               config.whitelisted_atom_ids().end());
-    mShouldPersistHistory = config.persist_locally();
-
-    // Store the sub-configs used.
-    mAnnotations.clear();
-    for (const auto& annotation : config.annotation()) {
-        mAnnotations.emplace_back(annotation.field_int64(), annotation.field_int32());
-    }
-
-    mAllowedUid.clear();
-    mAllowedPkg.clear();
-    mDefaultPullUids.clear();
-    mPullAtomUids.clear();
-    mPullAtomPackages.clear();
-    createAllLogSourcesFromConfig(config);
-
-    verifyGuardrailsAndUpdateStatsdStats();
-    initializeConfigActiveStatus();
-    return mConfigValid;
-}
-
-void MetricsManager::createAllLogSourcesFromConfig(const StatsdConfig& config) {
-    // Init allowed pushed atom uids.
-    if (config.allowed_log_source_size() == 0) {
-        mConfigValid = false;
-        ALOGE("Log source allowlist is empty! This config won't get any data. Suggest adding at "
-              "least AID_SYSTEM and AID_STATSD to the allowed_log_source field.");
-    } else {
-        for (const auto& source : config.allowed_log_source()) {
-            auto it = UidMap::sAidToUidMapping.find(source);
-            if (it != UidMap::sAidToUidMapping.end()) {
-                mAllowedUid.push_back(it->second);
-            } else {
-                mAllowedPkg.push_back(source);
-            }
-        }
-
-        if (mAllowedUid.size() + mAllowedPkg.size() > StatsdStats::kMaxLogSourceCount) {
-            ALOGE("Too many log sources. This is likely to be an error in the config.");
-            mConfigValid = false;
-        } else {
-            initAllowedLogSources();
-        }
-    }
-
-    // Init default allowed pull atom uids.
-    int numPullPackages = 0;
-    for (const string& pullSource : config.default_pull_packages()) {
-        auto it = UidMap::sAidToUidMapping.find(pullSource);
-        if (it != UidMap::sAidToUidMapping.end()) {
-            numPullPackages++;
-            mDefaultPullUids.insert(it->second);
-        } else {
-            ALOGE("Default pull atom packages must be in sAidToUidMapping");
-            mConfigValid = false;
-        }
-    }
-    // Init per-atom pull atom packages.
-    for (const PullAtomPackages& pullAtomPackages : config.pull_atom_packages()) {
-        int32_t atomId = pullAtomPackages.atom_id();
-        for (const string& pullPackage : pullAtomPackages.packages()) {
-            numPullPackages++;
-            auto it = UidMap::sAidToUidMapping.find(pullPackage);
-            if (it != UidMap::sAidToUidMapping.end()) {
-                mPullAtomUids[atomId].insert(it->second);
-            } else {
-                mPullAtomPackages[atomId].insert(pullPackage);
-            }
-        }
-    }
-    if (numPullPackages > StatsdStats::kMaxPullAtomPackages) {
-        ALOGE("Too many sources in default_pull_packages and pull_atom_packages. This is likely to "
-              "be an error in the config");
-        mConfigValid = false;
-    } else {
-        initPullAtomSources();
-    }
-}
-
-void MetricsManager::verifyGuardrailsAndUpdateStatsdStats() {
-    // Guardrail. Reject the config if it's too big.
-    if (mAllMetricProducers.size() > StatsdStats::kMaxMetricCountPerConfig ||
-        mAllConditionTrackers.size() > StatsdStats::kMaxConditionCountPerConfig ||
-        mAllAtomMatchingTrackers.size() > StatsdStats::kMaxMatcherCountPerConfig) {
-        ALOGE("This config is too big! Reject!");
-        mConfigValid = false;
-    }
-    if (mAllAnomalyTrackers.size() > StatsdStats::kMaxAlertCountPerConfig) {
-        ALOGE("This config has too many alerts! Reject!");
-        mConfigValid = false;
-    }
-    // no matter whether this config is valid, log it in the stats.
-    StatsdStats::getInstance().noteConfigReceived(
-            mConfigKey, mAllMetricProducers.size(), mAllConditionTrackers.size(),
-            mAllAtomMatchingTrackers.size(), mAllAnomalyTrackers.size(), mAnnotations,
-            mConfigValid);
-}
-
-void MetricsManager::initializeConfigActiveStatus() {
-    mIsAlwaysActive = (mMetricIndexesWithActivation.size() != mAllMetricProducers.size()) ||
-                      (mAllMetricProducers.size() == 0);
-    mIsActive = mIsAlwaysActive;
-    for (int metric : mMetricIndexesWithActivation) {
-        mIsActive |= mAllMetricProducers[metric]->isActive();
-    }
-    VLOG("mIsActive is initialized to %d", mIsActive);
-}
-
-void MetricsManager::initAllowedLogSources() {
-    std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
-    mAllowedLogSources.clear();
-    mAllowedLogSources.insert(mAllowedUid.begin(), mAllowedUid.end());
-
-    for (const auto& pkg : mAllowedPkg) {
-        auto uids = mUidMap->getAppUid(pkg);
-        mAllowedLogSources.insert(uids.begin(), uids.end());
-    }
-    if (DEBUG) {
-        for (const auto& uid : mAllowedLogSources) {
-            VLOG("Allowed uid %d", uid);
-        }
-    }
-}
-
-void MetricsManager::initPullAtomSources() {
-    std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
-    mCombinedPullAtomUids.clear();
-    for (const auto& [atomId, uids] : mPullAtomUids) {
-        mCombinedPullAtomUids[atomId].insert(uids.begin(), uids.end());
-    }
-    for (const auto& [atomId, packages] : mPullAtomPackages) {
-        for (const string& pkg : packages) {
-            set<int32_t> uids = mUidMap->getAppUid(pkg);
-            mCombinedPullAtomUids[atomId].insert(uids.begin(), uids.end());
-        }
-    }
-}
-
-bool MetricsManager::isConfigValid() const {
-    return mConfigValid;
-}
-
-void MetricsManager::notifyAppUpgrade(const int64_t& eventTimeNs, const string& apk, const int uid,
-                                      const int64_t version) {
-    // Inform all metric producers.
-    for (const auto& it : mAllMetricProducers) {
-        it->notifyAppUpgrade(eventTimeNs);
-    }
-    // check if we care this package
-    if (std::find(mAllowedPkg.begin(), mAllowedPkg.end(), apk) != mAllowedPkg.end()) {
-        // We will re-initialize the whole list because we don't want to keep the multi mapping of
-        // UID<->pkg inside MetricsManager to reduce the memory usage.
-        initAllowedLogSources();
-    }
-
-    for (const auto& it : mPullAtomPackages) {
-        if (it.second.find(apk) != it.second.end()) {
-            initPullAtomSources();
-            return;
-        }
-    }
-}
-
-void MetricsManager::notifyAppRemoved(const int64_t& eventTimeNs, const string& apk,
-                                      const int uid) {
-    // Inform all metric producers.
-    for (const auto& it : mAllMetricProducers) {
-        it->notifyAppRemoved(eventTimeNs);
-    }
-    // check if we care this package
-    if (std::find(mAllowedPkg.begin(), mAllowedPkg.end(), apk) != mAllowedPkg.end()) {
-        // We will re-initialize the whole list because we don't want to keep the multi mapping of
-        // UID<->pkg inside MetricsManager to reduce the memory usage.
-        initAllowedLogSources();
-    }
-
-    for (const auto& it : mPullAtomPackages) {
-        if (it.second.find(apk) != it.second.end()) {
-            initPullAtomSources();
-            return;
-        }
-    }
-}
-
-void MetricsManager::onUidMapReceived(const int64_t& eventTimeNs) {
-    // Purposefully don't inform metric producers on a new snapshot
-    // because we don't need to flush partial buckets.
-    // This occurs if a new user is added/removed or statsd crashes.
-    initPullAtomSources();
-
-    if (mAllowedPkg.size() == 0) {
-        return;
-    }
-    initAllowedLogSources();
-}
-
-void MetricsManager::onStatsdInitCompleted(const int64_t& eventTimeNs) {
-    // Inform all metric producers.
-    for (const auto& it : mAllMetricProducers) {
-        it->onStatsdInitCompleted(eventTimeNs);
-    }
-}
-
-void MetricsManager::init() {
-    for (const auto& producer : mAllMetricProducers) {
-        producer->prepareFirstBucket();
-    }
-}
-
-vector<int32_t> MetricsManager::getPullAtomUids(int32_t atomId) {
-    std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
-    vector<int32_t> uids;
-    const auto& it = mCombinedPullAtomUids.find(atomId);
-    if (it != mCombinedPullAtomUids.end()) {
-        uids.insert(uids.end(), it->second.begin(), it->second.end());
-    }
-    uids.insert(uids.end(), mDefaultPullUids.begin(), mDefaultPullUids.end());
-    return uids;
-}
-
-void MetricsManager::dumpStates(FILE* out, bool verbose) {
-    fprintf(out, "ConfigKey %s, allowed source:", mConfigKey.ToString().c_str());
-    {
-        std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
-        for (const auto& source : mAllowedLogSources) {
-            fprintf(out, "%d ", source);
-        }
-    }
-    fprintf(out, "\n");
-    for (const auto& producer : mAllMetricProducers) {
-        producer->dumpStates(out, verbose);
-    }
-}
-
-void MetricsManager::dropData(const int64_t dropTimeNs) {
-    for (const auto& producer : mAllMetricProducers) {
-        producer->dropData(dropTimeNs);
-    }
-}
-
-void MetricsManager::onDumpReport(const int64_t dumpTimeStampNs,
-                                  const bool include_current_partial_bucket,
-                                  const bool erase_data,
-                                  const DumpLatency dumpLatency,
-                                  std::set<string> *str_set,
-                                  ProtoOutputStream* protoOutput) {
-    VLOG("=========================Metric Reports Start==========================");
-    // one StatsLogReport per MetricProduer
-    for (const auto& producer : mAllMetricProducers) {
-        if (mNoReportMetricIds.find(producer->getMetricId()) == mNoReportMetricIds.end()) {
-            uint64_t token = protoOutput->start(
-                    FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_METRICS);
-            if (mHashStringsInReport) {
-                producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, erase_data,
-                                       dumpLatency, str_set, protoOutput);
-            } else {
-                producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, erase_data,
-                                       dumpLatency, nullptr, protoOutput);
-            }
-            protoOutput->end(token);
-        } else {
-            producer->clearPastBuckets(dumpTimeStampNs);
-        }
-    }
-    for (const auto& annotation : mAnnotations) {
-        uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                            FIELD_ID_ANNOTATIONS);
-        protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ANNOTATIONS_INT64,
-                           (long long)annotation.first);
-        protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_ANNOTATIONS_INT32, annotation.second);
-        protoOutput->end(token);
-    }
-
-    // Do not update the timestamps when data is not cleared to avoid timestamps from being
-    // misaligned.
-    if (erase_data) {
-        mLastReportTimeNs = dumpTimeStampNs;
-        mLastReportWallClockNs = getWallClockNs();
-    }
-    VLOG("=========================Metric Reports End==========================");
-}
-
-
-bool MetricsManager::checkLogCredentials(const LogEvent& event) {
-    if (mWhitelistedAtomIds.find(event.GetTagId()) != mWhitelistedAtomIds.end()) {
-        return true;
-    }
-    std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
-    if (mAllowedLogSources.find(event.GetUid()) == mAllowedLogSources.end()) {
-        VLOG("log source %d not on the whitelist", event.GetUid());
-        return false;
-    }
-    return true;
-}
-
-bool MetricsManager::eventSanityCheck(const LogEvent& event) {
-    if (event.GetTagId() == util::APP_BREADCRUMB_REPORTED) {
-        // Check that app breadcrumb reported fields are valid.
-        status_t err = NO_ERROR;
-
-        // Uid is 3rd from last field and must match the caller's uid,
-        // unless that caller is statsd itself (statsd is allowed to spoof uids).
-        long appHookUid = event.GetLong(event.size()-2, &err);
-        if (err != NO_ERROR) {
-            VLOG("APP_BREADCRUMB_REPORTED had error when parsing the uid");
-            return false;
-        }
-
-        // Because the uid within the LogEvent may have been mapped from
-        // isolated to host, map the loggerUid similarly before comparing.
-        int32_t loggerUid = mUidMap->getHostUidOrSelf(event.GetUid());
-        if (loggerUid != appHookUid && loggerUid != AID_STATSD) {
-            VLOG("APP_BREADCRUMB_REPORTED has invalid uid: claimed %ld but caller is %d",
-                 appHookUid, loggerUid);
-            return false;
-        }
-
-        // The state must be from 0,3. This part of code must be manually updated.
-        long appHookState = event.GetLong(event.size(), &err);
-        if (err != NO_ERROR) {
-            VLOG("APP_BREADCRUMB_REPORTED had error when parsing the state field");
-            return false;
-        } else if (appHookState < 0 || appHookState > 3) {
-            VLOG("APP_BREADCRUMB_REPORTED does not have valid state %ld", appHookState);
-            return false;
-        }
-    } else if (event.GetTagId() == util::DAVEY_OCCURRED) {
-        // Daveys can be logged from any app since they are logged in libs/hwui/JankTracker.cpp.
-        // Check that the davey duration is reasonable. Max length check is for privacy.
-        status_t err = NO_ERROR;
-
-        // Uid is the first field provided.
-        long jankUid = event.GetLong(1, &err);
-        if (err != NO_ERROR) {
-            VLOG("Davey occurred had error when parsing the uid");
-            return false;
-        }
-        int32_t loggerUid = event.GetUid();
-        if (loggerUid != jankUid && loggerUid != AID_STATSD) {
-            VLOG("DAVEY_OCCURRED has invalid uid: claimed %ld but caller is %d", jankUid,
-                 loggerUid);
-            return false;
-        }
-
-        long duration = event.GetLong(event.size(), &err);
-        if (err != NO_ERROR) {
-            VLOG("Davey occurred had error when parsing the duration");
-            return false;
-        } else if (duration > 100000) {
-            VLOG("Davey duration is unreasonably long: %ld", duration);
-            return false;
-        }
-    }
-
-    return true;
-}
-
-// Consume the stats log if it's interesting to this metric.
-void MetricsManager::onLogEvent(const LogEvent& event) {
-    if (!mConfigValid) {
-        return;
-    }
-
-    if (!checkLogCredentials(event)) {
-        return;
-    }
-
-    if (!eventSanityCheck(event)) {
-        return;
-    }
-
-    int tagId = event.GetTagId();
-    int64_t eventTimeNs = event.GetElapsedTimestampNs();
-
-    bool isActive = mIsAlwaysActive;
-
-    // Set of metrics that are still active after flushing.
-    unordered_set<int> activeMetricsIndices;
-
-    // Update state of all metrics w/ activation conditions as of eventTimeNs.
-    for (int metricIndex : mMetricIndexesWithActivation) {
-        const sp<MetricProducer>& metric = mAllMetricProducers[metricIndex];
-        metric->flushIfExpire(eventTimeNs);
-        if (metric->isActive()) {
-            // If this metric w/ activation condition is still active after
-            // flushing, remember it.
-            activeMetricsIndices.insert(metricIndex);
-        }
-    }
-
-    mIsActive = isActive || !activeMetricsIndices.empty();
-
-    if (mTagIds.find(tagId) == mTagIds.end()) {
-        // Not interesting...
-        return;
-    }
-
-    vector<MatchingState> matcherCache(mAllAtomMatchingTrackers.size(),
-                                       MatchingState::kNotComputed);
-
-    // Evaluate all atom matchers.
-    for (auto& matcher : mAllAtomMatchingTrackers) {
-        matcher->onLogEvent(event, mAllAtomMatchingTrackers, matcherCache);
-    }
-
-    // Set of metrics that received an activation cancellation.
-    unordered_set<int> metricIndicesWithCanceledActivations;
-
-    // Determine which metric activations received a cancellation and cancel them.
-    for (const auto& it : mDeactivationAtomTrackerToMetricMap) {
-        if (matcherCache[it.first] == MatchingState::kMatched) {
-            for (int metricIndex : it.second) {
-                mAllMetricProducers[metricIndex]->cancelEventActivation(it.first);
-                metricIndicesWithCanceledActivations.insert(metricIndex);
-            }
-        }
-    }
-
-    // Determine whether any metrics are no longer active after cancelling metric activations.
-    for (const int metricIndex : metricIndicesWithCanceledActivations) {
-        const sp<MetricProducer>& metric = mAllMetricProducers[metricIndex];
-        metric->flushIfExpire(eventTimeNs);
-        if (!metric->isActive()) {
-            activeMetricsIndices.erase(metricIndex);
-        }
-    }
-
-    isActive |= !activeMetricsIndices.empty();
-
-
-    // Determine which metric activations should be turned on and turn them on
-    for (const auto& it : mActivationAtomTrackerToMetricMap) {
-        if (matcherCache[it.first] == MatchingState::kMatched) {
-            for (int metricIndex : it.second) {
-                mAllMetricProducers[metricIndex]->activate(it.first, eventTimeNs);
-                isActive |= mAllMetricProducers[metricIndex]->isActive();
-            }
-        }
-    }
-
-    mIsActive = isActive;
-
-    // A bitmap to see which ConditionTracker needs to be re-evaluated.
-    vector<bool> conditionToBeEvaluated(mAllConditionTrackers.size(), false);
-
-    for (const auto& pair : mTrackerToConditionMap) {
-        if (matcherCache[pair.first] == MatchingState::kMatched) {
-            const auto& conditionList = pair.second;
-            for (const int conditionIndex : conditionList) {
-                conditionToBeEvaluated[conditionIndex] = true;
-            }
-        }
-    }
-
-    vector<ConditionState> conditionCache(mAllConditionTrackers.size(),
-                                          ConditionState::kNotEvaluated);
-    // A bitmap to track if a condition has changed value.
-    vector<bool> changedCache(mAllConditionTrackers.size(), false);
-    for (size_t i = 0; i < mAllConditionTrackers.size(); i++) {
-        if (conditionToBeEvaluated[i] == false) {
-            continue;
-        }
-        sp<ConditionTracker>& condition = mAllConditionTrackers[i];
-        condition->evaluateCondition(event, matcherCache, mAllConditionTrackers, conditionCache,
-                                     changedCache);
-    }
-
-    for (size_t i = 0; i < mAllConditionTrackers.size(); i++) {
-        if (changedCache[i] == false) {
-            continue;
-        }
-        auto pair = mConditionToMetricMap.find(i);
-        if (pair != mConditionToMetricMap.end()) {
-            auto& metricList = pair->second;
-            for (auto metricIndex : metricList) {
-                // Metric cares about non sliced condition, and it's changed.
-                // Push the new condition to it directly.
-                if (!mAllMetricProducers[metricIndex]->isConditionSliced()) {
-                    mAllMetricProducers[metricIndex]->onConditionChanged(conditionCache[i],
-                                                                         eventTimeNs);
-                    // Metric cares about sliced conditions, and it may have changed. Send
-                    // notification, and the metric can query the sliced conditions that are
-                    // interesting to it.
-                } else {
-                    mAllMetricProducers[metricIndex]->onSlicedConditionMayChange(conditionCache[i],
-                                                                                 eventTimeNs);
-                }
-            }
-        }
-    }
-
-    // For matched AtomMatchers, tell relevant metrics that a matched event has come.
-    for (size_t i = 0; i < mAllAtomMatchingTrackers.size(); i++) {
-        if (matcherCache[i] == MatchingState::kMatched) {
-            StatsdStats::getInstance().noteMatcherMatched(mConfigKey,
-                                                          mAllAtomMatchingTrackers[i]->getId());
-            auto pair = mTrackerToMetricMap.find(i);
-            if (pair != mTrackerToMetricMap.end()) {
-                auto& metricList = pair->second;
-                for (const int metricIndex : metricList) {
-                    // pushed metrics are never scheduled pulls
-                    mAllMetricProducers[metricIndex]->onMatchedLogEvent(i, event);
-                }
-            }
-        }
-    }
-}
-
-void MetricsManager::onAnomalyAlarmFired(
-        const int64_t& timestampNs,
-        unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& alarmSet) {
-    for (const auto& itr : mAllAnomalyTrackers) {
-        itr->informAlarmsFired(timestampNs, alarmSet);
-    }
-}
-
-void MetricsManager::onPeriodicAlarmFired(
-        const int64_t& timestampNs,
-        unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& alarmSet) {
-    for (const auto& itr : mAllPeriodicAlarmTrackers) {
-        itr->informAlarmsFired(timestampNs, alarmSet);
-    }
-}
-
-// Returns the total byte size of all metrics managed by a single config source.
-size_t MetricsManager::byteSize() {
-    size_t totalSize = 0;
-    for (const auto& metricProducer : mAllMetricProducers) {
-        totalSize += metricProducer->byteSize();
-    }
-    return totalSize;
-}
-
-void MetricsManager::loadActiveConfig(const ActiveConfig& config, int64_t currentTimeNs) {
-    if (config.metric_size() == 0) {
-        ALOGW("No active metric for config %s", mConfigKey.ToString().c_str());
-        return;
-    }
-
-    for (int i = 0; i < config.metric_size(); i++) {
-        const auto& activeMetric = config.metric(i);
-        for (int metricIndex : mMetricIndexesWithActivation) {
-            const auto& metric = mAllMetricProducers[metricIndex];
-            if (metric->getMetricId() == activeMetric.id()) {
-                VLOG("Setting active metric: %lld", (long long)metric->getMetricId());
-                metric->loadActiveMetric(activeMetric, currentTimeNs);
-                if (!mIsActive && metric->isActive()) {
-                    StatsdStats::getInstance().noteActiveStatusChanged(mConfigKey,
-                                                                       /*activate=*/ true);
-                }
-                mIsActive |= metric->isActive();
-            }
-        }
-    }
-}
-
-void MetricsManager::writeActiveConfigToProtoOutputStream(
-        int64_t currentTimeNs, const DumpReportReason reason, ProtoOutputStream* proto) {
-    proto->write(FIELD_TYPE_INT64 | FIELD_ID_ACTIVE_CONFIG_ID, (long long)mConfigKey.GetId());
-    proto->write(FIELD_TYPE_INT32 | FIELD_ID_ACTIVE_CONFIG_UID, mConfigKey.GetUid());
-    for (int metricIndex : mMetricIndexesWithActivation) {
-        const auto& metric = mAllMetricProducers[metricIndex];
-        const uint64_t metricToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                FIELD_ID_ACTIVE_CONFIG_METRIC);
-        metric->writeActiveMetricToProtoOutputStream(currentTimeNs, reason, proto);
-        proto->end(metricToken);
-    }
-}
-
-bool MetricsManager::writeMetadataToProto(int64_t currentWallClockTimeNs,
-                                          int64_t systemElapsedTimeNs,
-                                          metadata::StatsMetadata* statsMetadata) {
-    bool metadataWritten = false;
-    metadata::ConfigKey* configKey = statsMetadata->mutable_config_key();
-    configKey->set_config_id(mConfigKey.GetId());
-    configKey->set_uid(mConfigKey.GetUid());
-    for (const auto& anomalyTracker : mAllAnomalyTrackers) {
-        metadata::AlertMetadata* alertMetadata = statsMetadata->add_alert_metadata();
-        bool alertWritten = anomalyTracker->writeAlertMetadataToProto(currentWallClockTimeNs,
-                systemElapsedTimeNs, alertMetadata);
-        if (!alertWritten) {
-            statsMetadata->mutable_alert_metadata()->RemoveLast();
-        }
-        metadataWritten |= alertWritten;
-    }
-    return metadataWritten;
-}
-
-void MetricsManager::loadMetadata(const metadata::StatsMetadata& metadata,
-                                  int64_t currentWallClockTimeNs,
-                                  int64_t systemElapsedTimeNs) {
-    for (const metadata::AlertMetadata& alertMetadata : metadata.alert_metadata()) {
-        int64_t alertId = alertMetadata.alert_id();
-        auto it = mAlertTrackerMap.find(alertId);
-        if (it == mAlertTrackerMap.end()) {
-            ALOGE("No anomalyTracker found for alertId %lld", (long long) alertId);
-            continue;
-        }
-        mAllAnomalyTrackers[it->second]->loadAlertMetadata(alertMetadata,
-                                                           currentWallClockTimeNs,
-                                                           systemElapsedTimeNs);
-    }
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
deleted file mode 100644
index 0e56371..0000000
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "anomaly/AlarmMonitor.h"
-#include "anomaly/AlarmTracker.h"
-#include "anomaly/AnomalyTracker.h"
-#include "condition/ConditionTracker.h"
-#include "config/ConfigKey.h"
-#include "external/StatsPullerManager.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "frameworks/base/cmds/statsd/src/statsd_metadata.pb.h"
-#include "logd/LogEvent.h"
-#include "matchers/AtomMatchingTracker.h"
-#include "metrics/MetricProducer.h"
-#include "packages/UidMap.h"
-
-#include <unordered_map>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// A MetricsManager is responsible for managing metrics from one single config source.
-class MetricsManager : public virtual android::RefBase, public virtual PullUidProvider {
-public:
-    MetricsManager(const ConfigKey& configKey, const StatsdConfig& config, const int64_t timeBaseNs,
-                   const int64_t currentTimeNs, const sp<UidMap>& uidMap,
-                   const sp<StatsPullerManager>& pullerManager,
-                   const sp<AlarmMonitor>& anomalyAlarmMonitor,
-                   const sp<AlarmMonitor>& periodicAlarmMonitor);
-
-    virtual ~MetricsManager();
-
-    bool updateConfig(const StatsdConfig& config, const int64_t timeBaseNs,
-                      const int64_t currentTimeNs, const sp<AlarmMonitor>& anomalyAlarmMonitor,
-                      const sp<AlarmMonitor>& periodicAlarmMonitor);
-
-    // Return whether the configuration is valid.
-    bool isConfigValid() const;
-
-    bool checkLogCredentials(const LogEvent& event);
-
-    bool eventSanityCheck(const LogEvent& event);
-
-    void onLogEvent(const LogEvent& event);
-
-    void onAnomalyAlarmFired(
-        const int64_t& timestampNs,
-        unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& alarmSet);
-
-    void onPeriodicAlarmFired(
-        const int64_t& timestampNs,
-        unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>>& alarmSet);
-
-    void notifyAppUpgrade(const int64_t& eventTimeNs, const string& apk, const int uid,
-                          const int64_t version);
-
-    void notifyAppRemoved(const int64_t& eventTimeNs, const string& apk, const int uid);
-
-    void onUidMapReceived(const int64_t& eventTimeNs);
-
-    void onStatsdInitCompleted(const int64_t& elapsedTimeNs);
-
-    void init();
-
-    vector<int32_t> getPullAtomUids(int32_t atomId) override;
-
-    bool shouldWriteToDisk() const {
-        return mNoReportMetricIds.size() != mAllMetricProducers.size();
-    }
-
-    bool shouldPersistLocalHistory() const {
-        return mShouldPersistHistory;
-    }
-
-    void dumpStates(FILE* out, bool verbose);
-
-    inline bool isInTtl(const int64_t timestampNs) const {
-        return mTtlNs <= 0 || timestampNs < mTtlEndNs;
-    };
-
-    inline bool hashStringInReport() const {
-        return mHashStringsInReport;
-    };
-
-    inline bool versionStringsInReport() const {
-        return mVersionStringsInReport;
-    };
-
-    inline bool installerInReport() const {
-        return mInstallerInReport;
-    };
-
-    void refreshTtl(const int64_t currentTimestampNs) {
-        if (mTtlNs > 0) {
-            mTtlEndNs = currentTimestampNs + mTtlNs;
-        }
-    };
-
-    // Returns the elapsed realtime when this metric manager last reported metrics. If this config
-    // has not yet dumped any reports, this is the time the metricsmanager was initialized.
-    inline int64_t getLastReportTimeNs() const {
-        return mLastReportTimeNs;
-    };
-
-    inline int64_t getLastReportWallClockNs() const {
-        return mLastReportWallClockNs;
-    };
-
-    inline size_t getNumMetrics() const {
-        return mAllMetricProducers.size();
-    }
-
-    virtual void dropData(const int64_t dropTimeNs);
-
-    virtual void onDumpReport(const int64_t dumpTimeNs,
-                              const bool include_current_partial_bucket,
-                              const bool erase_data,
-                              const DumpLatency dumpLatency,
-                              std::set<string> *str_set,
-                              android::util::ProtoOutputStream* protoOutput);
-
-    // Computes the total byte size of all metrics managed by a single config source.
-    // Does not change the state.
-    virtual size_t byteSize();
-
-    // Returns whether or not this config is active.
-    // The config is active if any metric in the config is active.
-    inline bool isActive() const {
-        return mIsActive;
-    }
-
-    void loadActiveConfig(const ActiveConfig& config, int64_t currentTimeNs);
-
-    void writeActiveConfigToProtoOutputStream(
-            int64_t currentTimeNs, const DumpReportReason reason, ProtoOutputStream* proto);
-
-    // Returns true if at least one piece of metadata is written.
-    bool writeMetadataToProto(int64_t currentWallClockTimeNs,
-                              int64_t systemElapsedTimeNs,
-                              metadata::StatsMetadata* statsMetadata);
-
-    void loadMetadata(const metadata::StatsMetadata& metadata,
-                      int64_t currentWallClockTimeNs,
-                      int64_t systemElapsedTimeNs);
-private:
-    // For test only.
-    inline int64_t getTtlEndNs() const { return mTtlEndNs; }
-
-    const ConfigKey mConfigKey;
-
-    sp<UidMap> mUidMap;
-
-    bool mConfigValid = false;
-
-    bool mHashStringsInReport = false;
-    bool mVersionStringsInReport = false;
-    bool mInstallerInReport = false;
-
-    int64_t mTtlNs;
-    int64_t mTtlEndNs;
-
-    int64_t mLastReportTimeNs;
-    int64_t mLastReportWallClockNs;
-
-    sp<StatsPullerManager> mPullerManager;
-
-    // The uid log sources from StatsdConfig.
-    std::vector<int32_t> mAllowedUid;
-
-    // The pkg log sources from StatsdConfig.
-    std::vector<std::string> mAllowedPkg;
-
-    // The combined uid sources (after translating pkg name to uid).
-    // Logs from uids that are not in the list will be ignored to avoid spamming.
-    std::set<int32_t> mAllowedLogSources;
-
-    // To guard access to mAllowedLogSources
-    mutable std::mutex mAllowedLogSourcesMutex;
-
-    std::set<int32_t> mWhitelistedAtomIds;
-
-    // We can pull any atom from these uids.
-    std::set<int32_t> mDefaultPullUids;
-
-    // Uids that specific atoms can pull from.
-    // This is a map<atom id, set<uids>>
-    std::map<int32_t, std::set<int32_t>> mPullAtomUids;
-
-    // Packages that specific atoms can be pulled from.
-    std::map<int32_t, std::set<std::string>> mPullAtomPackages;
-
-    // All uids to pull for this atom. NOTE: Does not include the default uids for memory.
-    std::map<int32_t, std::set<int32_t>> mCombinedPullAtomUids;
-
-    // Contains the annotations passed in with StatsdConfig.
-    std::list<std::pair<const int64_t, const int32_t>> mAnnotations;
-
-    bool mShouldPersistHistory;
-
-    // All event tags that are interesting to my metrics.
-    std::set<int> mTagIds;
-
-    // We only store the sp of AtomMatchingTracker, MetricProducer, and ConditionTracker in
-    // MetricsManager. There are relationships between them, and the relationships are denoted by
-    // index instead of pointers. The reasons for this are: (1) the relationship between them are
-    // complicated, so storing index instead of pointers reduces the risk that A holds B's sp, and B
-    // holds A's sp. (2) When we evaluate matcher results, or condition results, we can quickly get
-    // the related results from a cache using the index.
-
-    // Hold all the atom matchers from the config.
-    std::vector<sp<AtomMatchingTracker>> mAllAtomMatchingTrackers;
-
-    // Hold all the conditions from the config.
-    std::vector<sp<ConditionTracker>> mAllConditionTrackers;
-
-    // Hold all metrics from the config.
-    std::vector<sp<MetricProducer>> mAllMetricProducers;
-
-    // Hold all alert trackers.
-    std::vector<sp<AnomalyTracker>> mAllAnomalyTrackers;
-
-    // Hold all periodic alarm trackers.
-    std::vector<sp<AlarmTracker>> mAllPeriodicAlarmTrackers;
-
-    // To make updating configs faster, we map the id of a AtomMatchingTracker, MetricProducer, and
-    // ConditionTracker to its index in the corresponding vector.
-
-    // Maps the id of an atom matching tracker to its index in mAllAtomMatchingTrackers.
-    std::unordered_map<int64_t, int> mAtomMatchingTrackerMap;
-
-    // Maps the id of a condition tracker to its index in mAllConditionTrackers.
-    std::unordered_map<int64_t, int> mConditionTrackerMap;
-
-    // Maps the id of a metric producer to its index in mAllMetricProducers.
-    std::unordered_map<int64_t, int> mMetricProducerMap;
-
-    // To make the log processing more efficient, we want to do as much filtering as possible
-    // before we go into individual trackers and conditions to match.
-
-    // 1st filter: check if the event tag id is in mTagIds.
-    // 2nd filter: if it is, we parse the event because there is at least one member is interested.
-    //             then pass to all AtomMatchingTrackers (itself also filter events by ids).
-    // 3nd filter: for AtomMatchingTrackers that matched this event, we pass this event to the
-    //             ConditionTrackers and MetricProducers that use this matcher.
-    // 4th filter: for ConditionTrackers that changed value due to this event, we pass
-    //             new conditions to  metrics that use this condition.
-
-    // The following map is initialized from the statsd_config.
-
-    // Maps from the index of the AtomMatchingTracker to index of MetricProducer.
-    std::unordered_map<int, std::vector<int>> mTrackerToMetricMap;
-
-    // Maps from AtomMatchingTracker to ConditionTracker
-    std::unordered_map<int, std::vector<int>> mTrackerToConditionMap;
-
-    // Maps from ConditionTracker to MetricProducer
-    std::unordered_map<int, std::vector<int>> mConditionToMetricMap;
-
-    // Maps from life span triggering event to MetricProducers.
-    std::unordered_map<int, std::vector<int>> mActivationAtomTrackerToMetricMap;
-
-    // Maps deactivation triggering event to MetricProducers.
-    std::unordered_map<int, std::vector<int>> mDeactivationAtomTrackerToMetricMap;
-
-    // Maps AlertIds to the index of the corresponding AnomalyTracker stored in mAllAnomalyTrackers.
-    // The map is used in LoadMetadata to more efficiently lookup AnomalyTrackers from an AlertId.
-    std::unordered_map<int64_t, int> mAlertTrackerMap;
-
-    std::vector<int> mMetricIndexesWithActivation;
-
-    void initAllowedLogSources();
-
-    void initPullAtomSources();
-
-    // Only called on config creation/update to initialize log sources from the config.
-    // Calls initAllowedLogSources and initPullAtomSources. Sets mConfigValid to false on error.
-    void createAllLogSourcesFromConfig(const StatsdConfig& config);
-
-    // Verifies the config meets guardrails and updates statsdStats.
-    // Sets mConfigValid to false on error. Should be called on config creation/update
-    void verifyGuardrailsAndUpdateStatsdStats();
-
-    // Initializes mIsAlwaysActive and mIsActive.
-    // Should be called on config creation/update.
-    void initializeConfigActiveStatus();
-
-    // The metrics that don't need to be uploaded or even reported.
-    std::set<int64_t> mNoReportMetricIds;
-
-   // The config is active if any metric in the config is active.
-    bool mIsActive;
-
-    // The config is always active if any metric in the config does not have an activation signal.
-    bool mIsAlwaysActive;
-
-    // Hashes of the States used in this config, keyed by the state id, used in config updates.
-    std::map<int64_t, uint64_t> mStateProtoHashes;
-
-    FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensions);
-    FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks);
-    FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid);
-    FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain);
-    FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent);
-    FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents);
-    FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm);
-    FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsWithActivation);
-    FRIEND_TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsNoCondition);
-    FRIEND_TEST(GaugeMetricE2eTest, TestConditionChangeToTrueSamplePulledEvents);
-
-    FRIEND_TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_single_bucket);
-    FRIEND_TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_multiple_buckets);
-    FRIEND_TEST(AnomalyDetectionE2eTest, TestCountMetric_save_refractory_to_disk_no_data_written);
-    FRIEND_TEST(AnomalyDetectionE2eTest, TestCountMetric_save_refractory_to_disk);
-    FRIEND_TEST(AnomalyDetectionE2eTest, TestCountMetric_load_refractory_from_disk);
-    FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket);
-    FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets);
-    FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period);
-
-    FRIEND_TEST(AlarmE2eTest, TestMultipleAlarms);
-    FRIEND_TEST(ConfigTtlE2eTest, TestCountMetric);
-    FRIEND_TEST(ConfigUpdateE2eAbTest, TestConfigTtl);
-    FRIEND_TEST(MetricActivationE2eTest, TestCountMetric);
-    FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation);
-    FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations);
-    FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithSameDeactivation);
-    FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations);
-
-    FRIEND_TEST(MetricsManagerTest, TestLogSources);
-    FRIEND_TEST(MetricsManagerTest, TestLogSourcesOnConfigUpdate);
-
-    FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
-    FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot);
-    FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations);
-    FRIEND_TEST(StatsLogProcessorTest,
-            TestActivationOnBootMultipleActivationsDifferentActivationTypes);
-    FRIEND_TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart);
-
-    FRIEND_TEST(CountMetricE2eTest, TestInitialConditionChanges);
-    FRIEND_TEST(CountMetricE2eTest, TestSlicedState);
-    FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithMap);
-    FRIEND_TEST(CountMetricE2eTest, TestMultipleSlicedStates);
-    FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields);
-
-    FRIEND_TEST(DurationMetricE2eTest, TestOneBucket);
-    FRIEND_TEST(DurationMetricE2eTest, TestTwoBuckets);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithActivation);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithCondition);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithSlicedCondition);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithActivationAndSlicedCondition);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithSlicedState);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithConditionAndSlicedState);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithSlicedStateMapped);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithSlicedStatePrimaryFieldsSuperset);
-    FRIEND_TEST(DurationMetricE2eTest, TestWithSlicedStatePrimaryFieldsSubset);
-
-    FRIEND_TEST(ValueMetricE2eTest, TestInitialConditionChanges);
-    FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents);
-    FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm);
-    FRIEND_TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation);
-    FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState);
-    FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithDimensions);
-    FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithIncorrectDimensions);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
deleted file mode 100644
index 22fdf16..0000000
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ /dev/null
@@ -1,1282 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "ValueMetricProducer.h"
-
-#include <limits.h>
-#include <stdlib.h>
-
-#include "../guardrail/StatsdStats.h"
-#include "../stats_log_util.h"
-#include "metrics/parsing_utils/metrics_manager_util.h"
-
-using android::util::FIELD_COUNT_REPEATED;
-using android::util::FIELD_TYPE_BOOL;
-using android::util::FIELD_TYPE_DOUBLE;
-using android::util::FIELD_TYPE_INT32;
-using android::util::FIELD_TYPE_INT64;
-using android::util::FIELD_TYPE_MESSAGE;
-using android::util::FIELD_TYPE_STRING;
-using android::util::ProtoOutputStream;
-using std::map;
-using std::shared_ptr;
-using std::unordered_map;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// for StatsLogReport
-const int FIELD_ID_ID = 1;
-const int FIELD_ID_VALUE_METRICS = 7;
-const int FIELD_ID_TIME_BASE = 9;
-const int FIELD_ID_BUCKET_SIZE = 10;
-const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
-const int FIELD_ID_IS_ACTIVE = 14;
-// for ValueMetricDataWrapper
-const int FIELD_ID_DATA = 1;
-const int FIELD_ID_SKIPPED = 2;
-// for SkippedBuckets
-const int FIELD_ID_SKIPPED_START_MILLIS = 3;
-const int FIELD_ID_SKIPPED_END_MILLIS = 4;
-const int FIELD_ID_SKIPPED_DROP_EVENT = 5;
-// for DumpEvent Proto
-const int FIELD_ID_BUCKET_DROP_REASON = 1;
-const int FIELD_ID_DROP_TIME = 2;
-// for ValueMetricData
-const int FIELD_ID_DIMENSION_IN_WHAT = 1;
-const int FIELD_ID_BUCKET_INFO = 3;
-const int FIELD_ID_DIMENSION_LEAF_IN_WHAT = 4;
-const int FIELD_ID_SLICE_BY_STATE = 6;
-// for ValueBucketInfo
-const int FIELD_ID_VALUE_INDEX = 1;
-const int FIELD_ID_VALUE_LONG = 2;
-const int FIELD_ID_VALUE_DOUBLE = 3;
-const int FIELD_ID_VALUES = 9;
-const int FIELD_ID_BUCKET_NUM = 4;
-const int FIELD_ID_START_BUCKET_ELAPSED_MILLIS = 5;
-const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6;
-const int FIELD_ID_CONDITION_TRUE_NS = 10;
-
-const Value ZERO_LONG((int64_t)0);
-const Value ZERO_DOUBLE((int64_t)0);
-
-// ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently
-ValueMetricProducer::ValueMetricProducer(
-        const ConfigKey& key, const ValueMetric& metric, const int conditionIndex,
-        const vector<ConditionState>& initialConditionCache,
-        const sp<ConditionWizard>& conditionWizard, const uint64_t protoHash,
-        const int whatMatcherIndex, const sp<EventMatcherWizard>& matcherWizard,
-        const int pullTagId, const int64_t timeBaseNs, const int64_t startTimeNs,
-        const sp<StatsPullerManager>& pullerManager,
-        const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
-        const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap,
-        const vector<int>& slicedStateAtoms,
-        const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap)
-    : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, initialConditionCache,
-                     conditionWizard, protoHash, eventActivationMap, eventDeactivationMap,
-                     slicedStateAtoms, stateGroupMap),
-      mWhatMatcherIndex(whatMatcherIndex),
-      mEventMatcherWizard(matcherWizard),
-      mPullerManager(pullerManager),
-      mPullTagId(pullTagId),
-      mIsPulled(pullTagId != -1),
-      mMinBucketSizeNs(metric.min_bucket_size_nanos()),
-      mDimensionSoftLimit(StatsdStats::kAtomDimensionKeySizeLimitMap.find(pullTagId) !=
-                                          StatsdStats::kAtomDimensionKeySizeLimitMap.end()
-                                  ? StatsdStats::kAtomDimensionKeySizeLimitMap.at(pullTagId).first
-                                  : StatsdStats::kDimensionKeySizeSoftLimit),
-      mDimensionHardLimit(StatsdStats::kAtomDimensionKeySizeLimitMap.find(pullTagId) !=
-                                          StatsdStats::kAtomDimensionKeySizeLimitMap.end()
-                                  ? StatsdStats::kAtomDimensionKeySizeLimitMap.at(pullTagId).second
-                                  : StatsdStats::kDimensionKeySizeHardLimit),
-      mUseAbsoluteValueOnReset(metric.use_absolute_value_on_reset()),
-      mAggregationType(metric.aggregation_type()),
-      mUseDiff(metric.has_use_diff() ? metric.use_diff() : (mIsPulled ? true : false)),
-      mValueDirection(metric.value_direction()),
-      mSkipZeroDiffOutput(metric.skip_zero_diff_output()),
-      mUseZeroDefaultBase(metric.use_zero_default_base()),
-      mHasGlobalBase(false),
-      mCurrentBucketIsSkipped(false),
-      mMaxPullDelayNs(metric.max_pull_delay_sec() > 0 ? metric.max_pull_delay_sec() * NS_PER_SEC
-                                                      : StatsdStats::kPullMaxDelayNs),
-      mSplitBucketForAppUpgrade(metric.split_bucket_for_app_upgrade()),
-      // Condition timer will be set later within the constructor after pulling events
-      mConditionTimer(false, timeBaseNs) {
-    int64_t bucketSizeMills = 0;
-    if (metric.has_bucket()) {
-        bucketSizeMills = TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket());
-    } else {
-        bucketSizeMills = TimeUnitToBucketSizeInMillis(ONE_HOUR);
-    }
-
-    mBucketSizeNs = bucketSizeMills * 1000000;
-
-    translateFieldMatcher(metric.value_field(), &mFieldMatchers);
-
-    if (metric.has_dimensions_in_what()) {
-        translateFieldMatcher(metric.dimensions_in_what(), &mDimensionsInWhat);
-        mContainANYPositionInDimensionsInWhat = HasPositionANY(metric.dimensions_in_what());
-        mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what());
-    }
-
-    if (metric.links().size() > 0) {
-        for (const auto& link : metric.links()) {
-            Metric2Condition mc;
-            mc.conditionId = link.condition();
-            translateFieldMatcher(link.fields_in_what(), &mc.metricFields);
-            translateFieldMatcher(link.fields_in_condition(), &mc.conditionFields);
-            mMetric2ConditionLinks.push_back(mc);
-        }
-        mConditionSliced = true;
-    }
-
-    for (const auto& stateLink : metric.state_link()) {
-        Metric2State ms;
-        ms.stateAtomId = stateLink.state_atom_id();
-        translateFieldMatcher(stateLink.fields_in_what(), &ms.metricFields);
-        translateFieldMatcher(stateLink.fields_in_state(), &ms.stateFields);
-        mMetric2StateLinks.push_back(ms);
-    }
-
-    int64_t numBucketsForward = calcBucketsForwardCount(startTimeNs);
-    mCurrentBucketNum += numBucketsForward;
-
-    flushIfNeededLocked(startTimeNs);
-
-    if (mIsPulled) {
-        mPullerManager->RegisterReceiver(mPullTagId, mConfigKey, this, getCurrentBucketEndTimeNs(),
-                                         mBucketSizeNs);
-    }
-
-    // Only do this for partial buckets like first bucket. All other buckets should use
-    // flushIfNeeded to adjust start and end to bucket boundaries.
-    // Adjust start for partial bucket
-    mCurrentBucketStartTimeNs = startTimeNs;
-    mConditionTimer.newBucketStart(mCurrentBucketStartTimeNs);
-
-    // Now that activations are processed, start the condition timer if needed.
-    mConditionTimer.onConditionChanged(mIsActive && mCondition == ConditionState::kTrue,
-                                       mCurrentBucketStartTimeNs);
-
-    VLOG("value metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
-         (long long)mBucketSizeNs, (long long)mTimeBaseNs);
-}
-
-ValueMetricProducer::~ValueMetricProducer() {
-    VLOG("~ValueMetricProducer() called");
-    if (mIsPulled) {
-        mPullerManager->UnRegisterReceiver(mPullTagId, mConfigKey, this);
-    }
-}
-
-bool ValueMetricProducer::onConfigUpdatedLocked(
-        const StatsdConfig& config, const int configIndex, const int metricIndex,
-        const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-        const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
-        const unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
-        const sp<EventMatcherWizard>& matcherWizard,
-        const vector<sp<ConditionTracker>>& allConditionTrackers,
-        const unordered_map<int64_t, int>& conditionTrackerMap, const sp<ConditionWizard>& wizard,
-        const unordered_map<int64_t, int>& metricToActivationMap,
-        unordered_map<int, vector<int>>& trackerToMetricMap,
-        unordered_map<int, vector<int>>& conditionToMetricMap,
-        unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
-        unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
-        vector<int>& metricsWithActivation) {
-    if (!MetricProducer::onConfigUpdatedLocked(
-                config, configIndex, metricIndex, allAtomMatchingTrackers,
-                oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, matcherWizard,
-                allConditionTrackers, conditionTrackerMap, wizard, metricToActivationMap,
-                trackerToMetricMap, conditionToMetricMap, activationAtomTrackerToMetricMap,
-                deactivationAtomTrackerToMetricMap, metricsWithActivation)) {
-        return false;
-    }
-
-    const ValueMetric& metric = config.value_metric(configIndex);
-    // Update appropriate indices: mWhatMatcherIndex, mConditionIndex and MetricsManager maps.
-    if (!handleMetricWithAtomMatchingTrackers(metric.what(), metricIndex, /*enforceOneAtom=*/false,
-                                              allAtomMatchingTrackers, newAtomMatchingTrackerMap,
-                                              trackerToMetricMap, mWhatMatcherIndex)) {
-        return false;
-    }
-
-    if (metric.has_condition() &&
-        !handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
-                                    metric.links(), allConditionTrackers, mConditionTrackerIndex,
-                                    conditionToMetricMap)) {
-        return false;
-    }
-    sp<EventMatcherWizard> tmpEventWizard = mEventMatcherWizard;
-    mEventMatcherWizard = matcherWizard;
-    return true;
-}
-
-void ValueMetricProducer::onStateChanged(int64_t eventTimeNs, int32_t atomId,
-                                         const HashableDimensionKey& primaryKey,
-                                         const FieldValue& oldState, const FieldValue& newState) {
-    VLOG("ValueMetric %lld onStateChanged time %lld, State %d, key %s, %d -> %d",
-         (long long)mMetricId, (long long)eventTimeNs, atomId, primaryKey.toString().c_str(),
-         oldState.mValue.int_value, newState.mValue.int_value);
-
-    // If old and new states are in the same StateGroup, then we do not need to
-    // pull for this state change.
-    FieldValue oldStateCopy = oldState;
-    FieldValue newStateCopy = newState;
-    mapStateValue(atomId, &oldStateCopy);
-    mapStateValue(atomId, &newStateCopy);
-    if (oldStateCopy == newStateCopy) {
-        return;
-    }
-
-    // If condition is not true or metric is not active, we do not need to pull
-    // for this state change.
-    if (mCondition != ConditionState::kTrue || !mIsActive) {
-        return;
-    }
-
-    bool isEventLate = eventTimeNs < mCurrentBucketStartTimeNs;
-    if (isEventLate) {
-        VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
-             (long long)mCurrentBucketStartTimeNs);
-        invalidateCurrentBucket(eventTimeNs, BucketDropReason::EVENT_IN_WRONG_BUCKET);
-        return;
-    }
-    mStateChangePrimaryKey.first = atomId;
-    mStateChangePrimaryKey.second = primaryKey;
-    if (mIsPulled) {
-        pullAndMatchEventsLocked(eventTimeNs);
-    }
-    mStateChangePrimaryKey.first = 0;
-    mStateChangePrimaryKey.second = DEFAULT_DIMENSION_KEY;
-    flushIfNeededLocked(eventTimeNs);
-}
-
-void ValueMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition,
-                                                           const int64_t eventTime) {
-    VLOG("Metric %lld onSlicedConditionMayChange", (long long)mMetricId);
-}
-
-void ValueMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
-    StatsdStats::getInstance().noteBucketDropped(mMetricId);
-
-    // The current partial bucket is not flushed and does not require a pull,
-    // so the data is still valid.
-    flushIfNeededLocked(dropTimeNs);
-    clearPastBucketsLocked(dropTimeNs);
-}
-
-void ValueMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) {
-    mPastBuckets.clear();
-    mSkippedBuckets.clear();
-}
-
-void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
-                                             const bool include_current_partial_bucket,
-                                             const bool erase_data,
-                                             const DumpLatency dumpLatency,
-                                             std::set<string> *str_set,
-                                             ProtoOutputStream* protoOutput) {
-    VLOG("metric %lld dump report now...", (long long)mMetricId);
-    if (include_current_partial_bucket) {
-        // For pull metrics, we need to do a pull at bucket boundaries. If we do not do that the
-        // current bucket will have incomplete data and the next will have the wrong snapshot to do
-        // a diff against. If the condition is false, we are fine since the base data is reset and
-        // we are not tracking anything.
-        bool pullNeeded = mIsPulled && mCondition == ConditionState::kTrue;
-        if (pullNeeded) {
-            switch (dumpLatency) {
-                case FAST:
-                    invalidateCurrentBucket(dumpTimeNs, BucketDropReason::DUMP_REPORT_REQUESTED);
-                    break;
-                case NO_TIME_CONSTRAINTS:
-                    pullAndMatchEventsLocked(dumpTimeNs);
-                    break;
-            }
-        }
-        flushCurrentBucketLocked(dumpTimeNs, dumpTimeNs);
-    }
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
-    protoOutput->write(FIELD_TYPE_BOOL | FIELD_ID_IS_ACTIVE, isActiveLocked());
-
-    if (mPastBuckets.empty() && mSkippedBuckets.empty()) {
-        return;
-    }
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TIME_BASE, (long long)mTimeBaseNs);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_SIZE, (long long)mBucketSizeNs);
-    // Fills the dimension path if not slicing by ALL.
-    if (!mSliceByPositionALL) {
-        if (!mDimensionsInWhat.empty()) {
-            uint64_t dimenPathToken =
-                    protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_PATH_IN_WHAT);
-            writeDimensionPathToProto(mDimensionsInWhat, protoOutput);
-            protoOutput->end(dimenPathToken);
-        }
-    }
-
-    uint64_t protoToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_VALUE_METRICS);
-
-    for (const auto& skippedBucket : mSkippedBuckets) {
-        uint64_t wrapperToken =
-                protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_SKIPPED);
-        protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_SKIPPED_START_MILLIS,
-                           (long long)(NanoToMillis(skippedBucket.bucketStartTimeNs)));
-        protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_SKIPPED_END_MILLIS,
-                           (long long)(NanoToMillis(skippedBucket.bucketEndTimeNs)));
-        for (const auto& dropEvent : skippedBucket.dropEvents) {
-            uint64_t dropEventToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                                         FIELD_ID_SKIPPED_DROP_EVENT);
-            protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_BUCKET_DROP_REASON, dropEvent.reason);
-            protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_DROP_TIME,
-                               (long long)(NanoToMillis(dropEvent.dropTimeNs)));
-            protoOutput->end(dropEventToken);
-        }
-        protoOutput->end(wrapperToken);
-    }
-
-    for (const auto& pair : mPastBuckets) {
-        const MetricDimensionKey& dimensionKey = pair.first;
-        VLOG("  dimension key %s", dimensionKey.toString().c_str());
-        uint64_t wrapperToken =
-                protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
-
-        // First fill dimension.
-        if (mSliceByPositionALL) {
-            uint64_t dimensionToken =
-                    protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION_IN_WHAT);
-            writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), str_set, protoOutput);
-            protoOutput->end(dimensionToken);
-        } else {
-            writeDimensionLeafNodesToProto(dimensionKey.getDimensionKeyInWhat(),
-                                           FIELD_ID_DIMENSION_LEAF_IN_WHAT, str_set, protoOutput);
-        }
-
-        // Then fill slice_by_state.
-        for (auto state : dimensionKey.getStateValuesKey().getValues()) {
-            uint64_t stateToken = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                                     FIELD_ID_SLICE_BY_STATE);
-            writeStateToProto(state, protoOutput);
-            protoOutput->end(stateToken);
-        }
-
-        // Then fill bucket_info (ValueBucketInfo).
-        for (const auto& bucket : pair.second) {
-            uint64_t bucketInfoToken = protoOutput->start(
-                    FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_BUCKET_INFO);
-
-            if (bucket.mBucketEndNs - bucket.mBucketStartNs != mBucketSizeNs) {
-                protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_ELAPSED_MILLIS,
-                                   (long long)NanoToMillis(bucket.mBucketStartNs));
-                protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_ELAPSED_MILLIS,
-                                   (long long)NanoToMillis(bucket.mBucketEndNs));
-            } else {
-                protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_NUM,
-                                   (long long)(getBucketNumFromEndTimeNs(bucket.mBucketEndNs)));
-            }
-            // We only write the condition timer value if the metric has a
-            // condition and/or is sliced by state.
-            // If the metric is sliced by state, the condition timer value is
-            // also sliced by state to reflect time spent in that state.
-            if (mConditionTrackerIndex >= 0 || !mSlicedStateAtoms.empty()) {
-                protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_CONDITION_TRUE_NS,
-                                   (long long)bucket.mConditionTrueNs);
-            }
-            for (int i = 0; i < (int)bucket.valueIndex.size(); i++) {
-                int index = bucket.valueIndex[i];
-                const Value& value = bucket.values[i];
-                uint64_t valueToken = protoOutput->start(
-                        FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_VALUES);
-                protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_VALUE_INDEX,
-                                   index);
-                if (value.getType() == LONG) {
-                    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE_LONG,
-                                       (long long)value.long_value);
-                    VLOG("\t bucket [%lld - %lld] value %d: %lld", (long long)bucket.mBucketStartNs,
-                         (long long)bucket.mBucketEndNs, index, (long long)value.long_value);
-                } else if (value.getType() == DOUBLE) {
-                    protoOutput->write(FIELD_TYPE_DOUBLE | FIELD_ID_VALUE_DOUBLE,
-                                       value.double_value);
-                    VLOG("\t bucket [%lld - %lld] value %d: %.2f", (long long)bucket.mBucketStartNs,
-                         (long long)bucket.mBucketEndNs, index, value.double_value);
-                } else {
-                    VLOG("Wrong value type for ValueMetric output: %d", value.getType());
-                }
-                protoOutput->end(valueToken);
-            }
-            protoOutput->end(bucketInfoToken);
-        }
-        protoOutput->end(wrapperToken);
-    }
-    protoOutput->end(protoToken);
-
-    VLOG("metric %lld dump report now...", (long long)mMetricId);
-    if (erase_data) {
-        mPastBuckets.clear();
-        mSkippedBuckets.clear();
-    }
-}
-
-void ValueMetricProducer::invalidateCurrentBucketWithoutResetBase(const int64_t dropTimeNs,
-                                                                  const BucketDropReason reason) {
-    if (!mCurrentBucketIsSkipped) {
-        // Only report to StatsdStats once per invalid bucket.
-        StatsdStats::getInstance().noteInvalidatedBucket(mMetricId);
-    }
-
-    skipCurrentBucket(dropTimeNs, reason);
-}
-
-void ValueMetricProducer::invalidateCurrentBucket(const int64_t dropTimeNs,
-                                                  const BucketDropReason reason) {
-    invalidateCurrentBucketWithoutResetBase(dropTimeNs, reason);
-    resetBase();
-}
-
-void ValueMetricProducer::skipCurrentBucket(const int64_t dropTimeNs,
-                                            const BucketDropReason reason) {
-    if (!maxDropEventsReached()) {
-        mCurrentSkippedBucket.dropEvents.emplace_back(buildDropEvent(dropTimeNs, reason));
-    }
-    mCurrentBucketIsSkipped = true;
-}
-
-void ValueMetricProducer::resetBase() {
-    for (auto& slice : mCurrentBaseInfo) {
-        for (auto& baseInfo : slice.second.baseInfos) {
-            baseInfo.hasBase = false;
-        }
-    }
-    mHasGlobalBase = false;
-}
-
-// Handle active state change. Active state change is treated like a condition change:
-// - drop bucket if active state change event arrives too late
-// - if condition is true, pull data on active state changes
-// - ConditionTimer tracks changes based on AND of condition and active state.
-void ValueMetricProducer::onActiveStateChangedLocked(const int64_t& eventTimeNs) {
-    bool isEventTooLate  = eventTimeNs < mCurrentBucketStartTimeNs;
-    if (isEventTooLate) {
-        // Drop bucket because event arrived too late, ie. we are missing data for this bucket.
-        StatsdStats::getInstance().noteLateLogEventSkipped(mMetricId);
-        invalidateCurrentBucket(eventTimeNs, BucketDropReason::EVENT_IN_WRONG_BUCKET);
-    }
-
-    // Call parent method once we've verified the validity of current bucket.
-    MetricProducer::onActiveStateChangedLocked(eventTimeNs);
-
-    if (ConditionState::kTrue != mCondition) {
-        return;
-    }
-
-    // Pull on active state changes.
-    if (!isEventTooLate) {
-        if (mIsPulled) {
-            pullAndMatchEventsLocked(eventTimeNs);
-        }
-        // When active state changes from true to false, clear diff base but don't
-        // reset other counters as we may accumulate more value in the bucket.
-        if (mUseDiff && !mIsActive) {
-            resetBase();
-        }
-    }
-
-    flushIfNeededLocked(eventTimeNs);
-
-    // Let condition timer know of new active state.
-    mConditionTimer.onConditionChanged(mIsActive, eventTimeNs);
-
-    updateCurrentSlicedBucketConditionTimers(mIsActive, eventTimeNs);
-}
-
-void ValueMetricProducer::onConditionChangedLocked(const bool condition,
-                                                   const int64_t eventTimeNs) {
-    ConditionState newCondition = condition ? ConditionState::kTrue : ConditionState::kFalse;
-    bool isEventTooLate  = eventTimeNs < mCurrentBucketStartTimeNs;
-
-    // If the config is not active, skip the event.
-    if (!mIsActive) {
-        mCondition = isEventTooLate ? ConditionState::kUnknown : newCondition;
-        return;
-    }
-
-    // If the event arrived late, mark the bucket as invalid and skip the event.
-    if (isEventTooLate) {
-        VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
-             (long long)mCurrentBucketStartTimeNs);
-        StatsdStats::getInstance().noteLateLogEventSkipped(mMetricId);
-        StatsdStats::getInstance().noteConditionChangeInNextBucket(mMetricId);
-        invalidateCurrentBucket(eventTimeNs, BucketDropReason::EVENT_IN_WRONG_BUCKET);
-        mCondition = ConditionState::kUnknown;
-        mConditionTimer.onConditionChanged(mCondition, eventTimeNs);
-
-        updateCurrentSlicedBucketConditionTimers(mCondition, eventTimeNs);
-        return;
-    }
-
-    // If the previous condition was unknown, mark the bucket as invalid
-    // because the bucket will contain partial data. For example, the condition
-    // change might happen close to the end of the bucket and we might miss a
-    // lot of data.
-    //
-    // We still want to pull to set the base.
-    if (mCondition == ConditionState::kUnknown) {
-        invalidateCurrentBucket(eventTimeNs, BucketDropReason::CONDITION_UNKNOWN);
-    }
-
-    // Pull and match for the following condition change cases:
-    // unknown/false -> true - condition changed
-    // true -> false - condition changed
-    // true -> true - old condition was true so we can flush the bucket at the
-    // end if needed.
-    //
-    // We don’t need to pull for unknown -> false or false -> false.
-    //
-    // onConditionChangedLocked might happen on bucket boundaries if this is
-    // called before #onDataPulled.
-    if (mIsPulled &&
-        (newCondition == ConditionState::kTrue || mCondition == ConditionState::kTrue)) {
-        pullAndMatchEventsLocked(eventTimeNs);
-    }
-
-    // For metrics that use diff, when condition changes from true to false,
-    // clear diff base but don't reset other counts because we may accumulate
-    // more value in the bucket.
-    if (mUseDiff &&
-        (mCondition == ConditionState::kTrue && newCondition == ConditionState::kFalse)) {
-        resetBase();
-    }
-
-    // Update condition state after pulling.
-    mCondition = newCondition;
-
-    flushIfNeededLocked(eventTimeNs);
-    mConditionTimer.onConditionChanged(mCondition, eventTimeNs);
-
-    updateCurrentSlicedBucketConditionTimers(mCondition, eventTimeNs);
-}
-
-void ValueMetricProducer::updateCurrentSlicedBucketConditionTimers(bool newCondition,
-                                                                   int64_t eventTimeNs) {
-    if (mSlicedStateAtoms.empty()) {
-        return;
-    }
-
-    // Utilize the current state key of each DimensionsInWhat key to determine
-    // which condition timers to update.
-    //
-    // Assumes that the MetricDimensionKey exists in `mCurrentSlicedBucket`.
-    bool inPulledData;
-    for (const auto& [dimensionInWhatKey, dimensionInWhatInfo] : mCurrentBaseInfo) {
-        // If the new condition is true, turn ON the condition timer only if
-        // the DimensionInWhat key was present in the pulled data.
-        inPulledData = dimensionInWhatInfo.hasCurrentState;
-        mCurrentSlicedBucket[MetricDimensionKey(dimensionInWhatKey,
-                                                dimensionInWhatInfo.currentState)]
-                .conditionTimer.onConditionChanged(newCondition && inPulledData, eventTimeNs);
-    }
-}
-
-void ValueMetricProducer::prepareFirstBucketLocked() {
-    // Kicks off the puller immediately if condition is true and diff based.
-    if (mIsActive && mIsPulled && mCondition == ConditionState::kTrue && mUseDiff) {
-        pullAndMatchEventsLocked(mCurrentBucketStartTimeNs);
-    }
-}
-
-void ValueMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) {
-    vector<std::shared_ptr<LogEvent>> allData;
-    if (!mPullerManager->Pull(mPullTagId, mConfigKey, timestampNs, &allData)) {
-        ALOGE("Stats puller failed for tag: %d at %lld", mPullTagId, (long long)timestampNs);
-        invalidateCurrentBucket(timestampNs, BucketDropReason::PULL_FAILED);
-        return;
-    }
-
-    accumulateEvents(allData, timestampNs, timestampNs);
-}
-
-int64_t ValueMetricProducer::calcPreviousBucketEndTime(const int64_t currentTimeNs) {
-    return mTimeBaseNs + ((currentTimeNs - mTimeBaseNs) / mBucketSizeNs) * mBucketSizeNs;
-}
-
-// By design, statsd pulls data at bucket boundaries using AlarmManager. These pulls are likely
-// to be delayed. Other events like condition changes or app upgrade which are not based on
-// AlarmManager might have arrived earlier and close the bucket.
-void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData,
-                                       bool pullSuccess, int64_t originalPullTimeNs) {
-    std::lock_guard<std::mutex> lock(mMutex);
-    if (mCondition == ConditionState::kTrue) {
-        // If the pull failed, we won't be able to compute a diff.
-        if (!pullSuccess) {
-            invalidateCurrentBucket(originalPullTimeNs, BucketDropReason::PULL_FAILED);
-        } else {
-            bool isEventLate = originalPullTimeNs < getCurrentBucketEndTimeNs();
-            if (isEventLate) {
-                // If the event is late, we are in the middle of a bucket. Just
-                // process the data without trying to snap the data to the nearest bucket.
-                accumulateEvents(allData, originalPullTimeNs, originalPullTimeNs);
-            } else {
-                // For scheduled pulled data, the effective event time is snap to the nearest
-                // bucket end. In the case of waking up from a deep sleep state, we will
-                // attribute to the previous bucket end. If the sleep was long but not very
-                // long, we will be in the immediate next bucket. Previous bucket may get a
-                // larger number as we pull at a later time than real bucket end.
-                //
-                // If the sleep was very long, we skip more than one bucket before sleep. In
-                // this case, if the diff base will be cleared and this new data will serve as
-                // new diff base.
-                int64_t bucketEndTime = calcPreviousBucketEndTime(originalPullTimeNs) - 1;
-                StatsdStats::getInstance().noteBucketBoundaryDelayNs(
-                        mMetricId, originalPullTimeNs - bucketEndTime);
-                accumulateEvents(allData, originalPullTimeNs, bucketEndTime);
-            }
-        }
-    }
-
-    // We can probably flush the bucket. Since we used bucketEndTime when calling
-    // #onMatchedLogEventInternalLocked, the current bucket will not have been flushed.
-    flushIfNeededLocked(originalPullTimeNs);
-}
-
-void ValueMetricProducer::accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData,
-                                           int64_t originalPullTimeNs, int64_t eventElapsedTimeNs) {
-    bool isEventLate = eventElapsedTimeNs < mCurrentBucketStartTimeNs;
-    if (isEventLate) {
-        VLOG("Skip bucket end pull due to late arrival: %lld vs %lld",
-             (long long)eventElapsedTimeNs, (long long)mCurrentBucketStartTimeNs);
-        StatsdStats::getInstance().noteLateLogEventSkipped(mMetricId);
-        invalidateCurrentBucket(eventElapsedTimeNs, BucketDropReason::EVENT_IN_WRONG_BUCKET);
-        return;
-    }
-
-    const int64_t elapsedRealtimeNs = getElapsedRealtimeNs();
-    const int64_t pullDelayNs = elapsedRealtimeNs - originalPullTimeNs;
-    StatsdStats::getInstance().notePullDelay(mPullTagId, pullDelayNs);
-    if (pullDelayNs > mMaxPullDelayNs) {
-        ALOGE("Pull finish too late for atom %d, longer than %lld", mPullTagId,
-              (long long)mMaxPullDelayNs);
-        StatsdStats::getInstance().notePullExceedMaxDelay(mPullTagId);
-        // We are missing one pull from the bucket which means we will not have a complete view of
-        // what's going on.
-        invalidateCurrentBucket(eventElapsedTimeNs, BucketDropReason::PULL_DELAYED);
-        return;
-    }
-
-    mMatchedMetricDimensionKeys.clear();
-    for (const auto& data : allData) {
-        LogEvent localCopy = data->makeCopy();
-        if (mEventMatcherWizard->matchLogEvent(localCopy, mWhatMatcherIndex) ==
-            MatchingState::kMatched) {
-            localCopy.setElapsedTimestampNs(eventElapsedTimeNs);
-            onMatchedLogEventLocked(mWhatMatcherIndex, localCopy);
-        }
-    }
-    // If a key that is:
-    // 1. Tracked in mCurrentSlicedBucket and
-    // 2. A superset of the current mStateChangePrimaryKey
-    // was not found in the new pulled data (i.e. not in mMatchedDimensionInWhatKeys)
-    // then we need to reset the base.
-    for (auto& [metricDimensionKey, currentValueBucket] : mCurrentSlicedBucket) {
-        const auto& whatKey = metricDimensionKey.getDimensionKeyInWhat();
-        bool presentInPulledData =
-                mMatchedMetricDimensionKeys.find(whatKey) != mMatchedMetricDimensionKeys.end();
-        if (!presentInPulledData && whatKey.contains(mStateChangePrimaryKey.second)) {
-            auto it = mCurrentBaseInfo.find(whatKey);
-            for (auto& baseInfo : it->second.baseInfos) {
-                baseInfo.hasBase = false;
-            }
-            // Set to false when DimensionInWhat key is not present in a pull.
-            // Used in onMatchedLogEventInternalLocked() to ensure the condition
-            // timer is turned on the next pull when data is present.
-            it->second.hasCurrentState = false;
-            // Turn OFF condition timer for keys not present in pulled data.
-            currentValueBucket.conditionTimer.onConditionChanged(false, eventElapsedTimeNs);
-        }
-    }
-    mMatchedMetricDimensionKeys.clear();
-    mHasGlobalBase = true;
-
-    // If we reach the guardrail, we might have dropped some data which means the bucket is
-    // incomplete.
-    //
-    // The base also needs to be reset. If we do not have the full data, we might
-    // incorrectly compute the diff when mUseZeroDefaultBase is true since an existing key
-    // might be missing from mCurrentSlicedBucket.
-    if (hasReachedGuardRailLimit()) {
-        invalidateCurrentBucket(eventElapsedTimeNs, BucketDropReason::DIMENSION_GUARDRAIL_REACHED);
-        mCurrentSlicedBucket.clear();
-    }
-}
-
-void ValueMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
-    if (mCurrentSlicedBucket.size() == 0) {
-        return;
-    }
-
-    fprintf(out, "ValueMetric %lld dimension size %lu\n", (long long)mMetricId,
-            (unsigned long)mCurrentSlicedBucket.size());
-    if (verbose) {
-        for (const auto& it : mCurrentSlicedBucket) {
-          for (const auto& interval : it.second.intervals) {
-              fprintf(out, "\t(what)%s\t(states)%s  (value)%s\n",
-                      it.first.getDimensionKeyInWhat().toString().c_str(),
-                      it.first.getStateValuesKey().toString().c_str(),
-                      interval.value.toString().c_str());
-          }
-        }
-    }
-}
-
-bool ValueMetricProducer::hasReachedGuardRailLimit() const {
-    return mCurrentSlicedBucket.size() >= mDimensionHardLimit;
-}
-
-bool ValueMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
-    // ===========GuardRail==============
-    // 1. Report the tuple count if the tuple count > soft limit
-    if (mCurrentSlicedBucket.find(newKey) != mCurrentSlicedBucket.end()) {
-        return false;
-    }
-    if (mCurrentSlicedBucket.size() > mDimensionSoftLimit - 1) {
-        size_t newTupleCount = mCurrentSlicedBucket.size() + 1;
-        StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount);
-        // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
-        if (hasReachedGuardRailLimit()) {
-            ALOGE("ValueMetric %lld dropping data for dimension key %s", (long long)mMetricId,
-                  newKey.toString().c_str());
-            StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId);
-            return true;
-        }
-    }
-
-    return false;
-}
-
-bool ValueMetricProducer::hitFullBucketGuardRailLocked(const MetricDimensionKey& newKey) {
-    // ===========GuardRail==============
-    // 1. Report the tuple count if the tuple count > soft limit
-    if (mCurrentFullBucket.find(newKey) != mCurrentFullBucket.end()) {
-        return false;
-    }
-    if (mCurrentFullBucket.size() > mDimensionSoftLimit - 1) {
-        size_t newTupleCount = mCurrentFullBucket.size() + 1;
-        // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
-        if (newTupleCount > mDimensionHardLimit) {
-            ALOGE("ValueMetric %lld dropping data for full bucket dimension key %s",
-                  (long long)mMetricId,
-                  newKey.toString().c_str());
-            return true;
-        }
-    }
-
-    return false;
-}
-
-bool getDoubleOrLong(const LogEvent& event, const Matcher& matcher, Value& ret) {
-    for (const FieldValue& value : event.getValues()) {
-        if (value.mField.matches(matcher)) {
-            switch (value.mValue.type) {
-                case INT:
-                    ret.setLong(value.mValue.int_value);
-                    break;
-                case LONG:
-                    ret.setLong(value.mValue.long_value);
-                    break;
-                case FLOAT:
-                    ret.setDouble(value.mValue.float_value);
-                    break;
-                case DOUBLE:
-                    ret.setDouble(value.mValue.double_value);
-                    break;
-                default:
-                    return false;
-                    break;
-            }
-            return true;
-        }
-    }
-    return false;
-}
-
-bool ValueMetricProducer::multipleBucketsSkipped(const int64_t numBucketsForward) {
-    // Skip buckets if this is a pulled metric or a pushed metric that is diffed.
-    return numBucketsForward > 1 && (mIsPulled || mUseDiff);
-}
-
-void ValueMetricProducer::onMatchedLogEventInternalLocked(
-        const size_t matcherIndex, const MetricDimensionKey& eventKey,
-        const ConditionKey& conditionKey, bool condition, const LogEvent& event,
-        const map<int, HashableDimensionKey>& statePrimaryKeys) {
-    auto whatKey = eventKey.getDimensionKeyInWhat();
-    auto stateKey = eventKey.getStateValuesKey();
-
-    // Skip this event if a state changed occurred for a different primary key.
-    auto it = statePrimaryKeys.find(mStateChangePrimaryKey.first);
-    // Check that both the atom id and the primary key are equal.
-    if (it != statePrimaryKeys.end() && it->second != mStateChangePrimaryKey.second) {
-        VLOG("ValueMetric skip event with primary key %s because state change primary key "
-             "is %s",
-             it->second.toString().c_str(), mStateChangePrimaryKey.second.toString().c_str());
-        return;
-    }
-
-    int64_t eventTimeNs = event.GetElapsedTimestampNs();
-    if (eventTimeNs < mCurrentBucketStartTimeNs) {
-        VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
-             (long long)mCurrentBucketStartTimeNs);
-        return;
-    }
-    mMatchedMetricDimensionKeys.insert(whatKey);
-
-    if (!mIsPulled) {
-        // We cannot flush without doing a pull first.
-        flushIfNeededLocked(eventTimeNs);
-    }
-
-    // We should not accumulate the data for pushed metrics when the condition is false.
-    bool shouldSkipForPushMetric = !mIsPulled && !condition;
-    // For pulled metrics, there are two cases:
-    // - to compute diffs, we need to process all the state changes
-    // - for non-diffs metrics, we should ignore the data if the condition wasn't true. If we have a
-    // state change from
-    //     + True -> True: we should process the data, it might be a bucket boundary
-    //     + True -> False: we als need to process the data.
-    bool shouldSkipForPulledMetric = mIsPulled && !mUseDiff
-            && mCondition != ConditionState::kTrue;
-    if (shouldSkipForPushMetric || shouldSkipForPulledMetric) {
-        VLOG("ValueMetric skip event because condition is false and we are not using diff (for "
-             "pulled metric)");
-        return;
-    }
-
-    if (hitGuardRailLocked(eventKey)) {
-        return;
-    }
-
-    const auto& returnVal =
-            mCurrentBaseInfo.emplace(whatKey, DimensionsInWhatInfo(getUnknownStateKey()));
-    DimensionsInWhatInfo& dimensionsInWhatInfo = returnVal.first->second;
-    const HashableDimensionKey oldStateKey = dimensionsInWhatInfo.currentState;
-    vector<BaseInfo>& baseInfos = dimensionsInWhatInfo.baseInfos;
-    if (baseInfos.size() < mFieldMatchers.size()) {
-        VLOG("Resizing number of intervals to %d", (int)mFieldMatchers.size());
-        baseInfos.resize(mFieldMatchers.size());
-    }
-
-    // Ensure we turn on the condition timer in the case where dimensions
-    // were missing on a previous pull due to a state change.
-    bool stateChange = oldStateKey != stateKey;
-    if (!dimensionsInWhatInfo.hasCurrentState) {
-        stateChange = true;
-        dimensionsInWhatInfo.hasCurrentState = true;
-    }
-
-    // We need to get the intervals stored with the previous state key so we can
-    // close these value intervals.
-    vector<Interval>& intervals =
-            mCurrentSlicedBucket[MetricDimensionKey(whatKey, oldStateKey)].intervals;
-    if (intervals.size() < mFieldMatchers.size()) {
-        VLOG("Resizing number of intervals to %d", (int)mFieldMatchers.size());
-        intervals.resize(mFieldMatchers.size());
-    }
-
-    // We only use anomaly detection under certain cases.
-    // N.B.: The anomaly detection cases were modified in order to fix an issue with value metrics
-    // containing multiple values. We tried to retain all previous behaviour, but we are unsure the
-    // previous behaviour was correct. At the time of the fix, anomaly detection had no owner.
-    // Whoever next works on it should look into the cases where it is triggered in this function.
-    // Discussion here: http://ag/6124370.
-    bool useAnomalyDetection = true;
-
-    dimensionsInWhatInfo.hasCurrentState = true;
-    dimensionsInWhatInfo.currentState = stateKey;
-    for (int i = 0; i < (int)mFieldMatchers.size(); i++) {
-        const Matcher& matcher = mFieldMatchers[i];
-        BaseInfo& baseInfo = baseInfos[i];
-        Interval& interval = intervals[i];
-        interval.valueIndex = i;
-        Value value;
-        if (!getDoubleOrLong(event, matcher, value)) {
-            VLOG("Failed to get value %d from event %s", i, event.ToString().c_str());
-            StatsdStats::getInstance().noteBadValueType(mMetricId);
-            return;
-        }
-        interval.seenNewData = true;
-
-        if (mUseDiff) {
-            if (!baseInfo.hasBase) {
-                if (mHasGlobalBase && mUseZeroDefaultBase) {
-                    // The bucket has global base. This key does not.
-                    // Optionally use zero as base.
-                    baseInfo.base = (value.type == LONG ? ZERO_LONG : ZERO_DOUBLE);
-                    baseInfo.hasBase = true;
-                } else {
-                    // no base. just update base and return.
-                    baseInfo.base = value;
-                    baseInfo.hasBase = true;
-                    // If we're missing a base, do not use anomaly detection on incomplete data
-                    useAnomalyDetection = false;
-                    // Continue (instead of return) here in order to set baseInfo.base and
-                    // baseInfo.hasBase for other baseInfos
-                    continue;
-                }
-            }
-
-            Value diff;
-            switch (mValueDirection) {
-                case ValueMetric::INCREASING:
-                    if (value >= baseInfo.base) {
-                        diff = value - baseInfo.base;
-                    } else if (mUseAbsoluteValueOnReset) {
-                        diff = value;
-                    } else {
-                        VLOG("Unexpected decreasing value");
-                        StatsdStats::getInstance().notePullDataError(mPullTagId);
-                        baseInfo.base = value;
-                        // If we've got bad data, do not use anomaly detection
-                        useAnomalyDetection = false;
-                        continue;
-                    }
-                    break;
-                case ValueMetric::DECREASING:
-                    if (baseInfo.base >= value) {
-                        diff = baseInfo.base - value;
-                    } else if (mUseAbsoluteValueOnReset) {
-                        diff = value;
-                    } else {
-                        VLOG("Unexpected increasing value");
-                        StatsdStats::getInstance().notePullDataError(mPullTagId);
-                        baseInfo.base = value;
-                        // If we've got bad data, do not use anomaly detection
-                        useAnomalyDetection = false;
-                        continue;
-                    }
-                    break;
-                case ValueMetric::ANY:
-                    diff = value - baseInfo.base;
-                    break;
-                default:
-                    break;
-            }
-            baseInfo.base = value;
-            value = diff;
-        }
-
-        if (interval.hasValue) {
-            switch (mAggregationType) {
-                case ValueMetric::SUM:
-                    // for AVG, we add up and take average when flushing the bucket
-                case ValueMetric::AVG:
-                    interval.value += value;
-                    break;
-                case ValueMetric::MIN:
-                    interval.value = std::min(value, interval.value);
-                    break;
-                case ValueMetric::MAX:
-                    interval.value = std::max(value, interval.value);
-                    break;
-                default:
-                    break;
-            }
-        } else {
-            interval.value = value;
-            interval.hasValue = true;
-        }
-        interval.sampleSize += 1;
-    }
-
-    // State change.
-    if (!mSlicedStateAtoms.empty() && stateChange) {
-        // Turn OFF the condition timer for the previous state key.
-        mCurrentSlicedBucket[MetricDimensionKey(whatKey, oldStateKey)]
-                .conditionTimer.onConditionChanged(false, eventTimeNs);
-
-        // Turn ON the condition timer for the new state key.
-        mCurrentSlicedBucket[MetricDimensionKey(whatKey, stateKey)]
-                .conditionTimer.onConditionChanged(true, eventTimeNs);
-    }
-
-    // Only trigger the tracker if all intervals are correct and we have not skipped the bucket due
-    // to MULTIPLE_BUCKETS_SKIPPED.
-    if (useAnomalyDetection && !multipleBucketsSkipped(calcBucketsForwardCount(eventTimeNs))) {
-        // TODO: propgate proper values down stream when anomaly support doubles
-        long wholeBucketVal = intervals[0].value.long_value;
-        auto prev = mCurrentFullBucket.find(eventKey);
-        if (prev != mCurrentFullBucket.end()) {
-            wholeBucketVal += prev->second;
-        }
-        for (auto& tracker : mAnomalyTrackers) {
-            tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, mMetricId, eventKey,
-                                             wholeBucketVal);
-        }
-    }
-}
-
-// For pulled metrics, we always need to make sure we do a pull before flushing the bucket
-// if mCondition is true!
-void ValueMetricProducer::flushIfNeededLocked(const int64_t& eventTimeNs) {
-    int64_t currentBucketEndTimeNs = getCurrentBucketEndTimeNs();
-    if (eventTimeNs < currentBucketEndTimeNs) {
-        VLOG("eventTime is %lld, less than current bucket end time %lld", (long long)eventTimeNs,
-             (long long)(currentBucketEndTimeNs));
-        return;
-    }
-    int64_t numBucketsForward = calcBucketsForwardCount(eventTimeNs);
-    int64_t nextBucketStartTimeNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
-    flushCurrentBucketLocked(eventTimeNs, nextBucketStartTimeNs);
-}
-
-int64_t ValueMetricProducer::calcBucketsForwardCount(const int64_t& eventTimeNs) const {
-    int64_t currentBucketEndTimeNs = getCurrentBucketEndTimeNs();
-    if (eventTimeNs < currentBucketEndTimeNs) {
-        return 0;
-    }
-    return 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
-}
-
-void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
-                                                   const int64_t& nextBucketStartTimeNs) {
-    if (mCondition == ConditionState::kUnknown) {
-        StatsdStats::getInstance().noteBucketUnknownCondition(mMetricId);
-        invalidateCurrentBucketWithoutResetBase(eventTimeNs, BucketDropReason::CONDITION_UNKNOWN);
-    }
-
-    VLOG("finalizing bucket for %ld, dumping %d slices", (long)mCurrentBucketStartTimeNs,
-         (int)mCurrentSlicedBucket.size());
-
-    int64_t fullBucketEndTimeNs = getCurrentBucketEndTimeNs();
-    int64_t bucketEndTime = fullBucketEndTimeNs;
-    int64_t numBucketsForward = calcBucketsForwardCount(eventTimeNs);
-
-    if (multipleBucketsSkipped(numBucketsForward)) {
-        VLOG("Skipping forward %lld buckets", (long long)numBucketsForward);
-        StatsdStats::getInstance().noteSkippedForwardBuckets(mMetricId);
-        // Something went wrong. Maybe the device was sleeping for a long time. It is better
-        // to mark the current bucket as invalid. The last pull might have been successful through.
-        invalidateCurrentBucketWithoutResetBase(eventTimeNs,
-                                                BucketDropReason::MULTIPLE_BUCKETS_SKIPPED);
-        // End the bucket at the next bucket start time so the entire interval is skipped.
-        bucketEndTime = nextBucketStartTimeNs;
-    } else if (eventTimeNs < fullBucketEndTimeNs) {
-        bucketEndTime = eventTimeNs;
-    }
-
-    // Close the current bucket.
-    int64_t conditionTrueDuration = mConditionTimer.newBucketStart(bucketEndTime);
-    bool isBucketLargeEnough = bucketEndTime - mCurrentBucketStartTimeNs >= mMinBucketSizeNs;
-    if (!isBucketLargeEnough) {
-        skipCurrentBucket(eventTimeNs, BucketDropReason::BUCKET_TOO_SMALL);
-    }
-    if (!mCurrentBucketIsSkipped) {
-        bool bucketHasData = false;
-        // The current bucket is large enough to keep.
-        for (auto& [metricDimensionKey, currentValueBucket] : mCurrentSlicedBucket) {
-            PastValueBucket bucket =
-                    buildPartialBucket(bucketEndTime, currentValueBucket.intervals);
-            if (!mSlicedStateAtoms.empty()) {
-                bucket.mConditionTrueNs =
-                        currentValueBucket.conditionTimer.newBucketStart(bucketEndTime);
-            } else {
-                bucket.mConditionTrueNs = conditionTrueDuration;
-            }
-            // it will auto create new vector of ValuebucketInfo if the key is not found.
-            if (bucket.valueIndex.size() > 0) {
-                auto& bucketList = mPastBuckets[metricDimensionKey];
-                bucketList.push_back(bucket);
-                bucketHasData = true;
-            }
-        }
-        if (!bucketHasData) {
-            skipCurrentBucket(eventTimeNs, BucketDropReason::NO_DATA);
-        }
-    }
-
-    if (mCurrentBucketIsSkipped) {
-        mCurrentSkippedBucket.bucketStartTimeNs = mCurrentBucketStartTimeNs;
-        mCurrentSkippedBucket.bucketEndTimeNs = bucketEndTime;
-        mSkippedBuckets.emplace_back(mCurrentSkippedBucket);
-    }
-
-    // This means that the current bucket was not flushed before a forced bucket split.
-    // This can happen if an app update or a dump report with include_current_partial_bucket is
-    // requested before we get a chance to flush the bucket due to receiving new data, either from
-    // the statsd socket or the StatsPullerManager.
-    if (bucketEndTime < nextBucketStartTimeNs) {
-        SkippedBucket bucketInGap;
-        bucketInGap.bucketStartTimeNs = bucketEndTime;
-        bucketInGap.bucketEndTimeNs = nextBucketStartTimeNs;
-        bucketInGap.dropEvents.emplace_back(
-                buildDropEvent(eventTimeNs, BucketDropReason::NO_DATA));
-        mSkippedBuckets.emplace_back(bucketInGap);
-    }
-    appendToFullBucket(eventTimeNs > fullBucketEndTimeNs);
-    initCurrentSlicedBucket(nextBucketStartTimeNs);
-    // Update the condition timer again, in case we skipped buckets.
-    mConditionTimer.newBucketStart(nextBucketStartTimeNs);
-
-    // NOTE: Update the condition timers in `mCurrentSlicedBucket` only when slicing
-    // by state. Otherwise, the "global" condition timer will be used.
-    if (!mSlicedStateAtoms.empty()) {
-        for (auto& [metricDimensionKey, currentValueBucket] : mCurrentSlicedBucket) {
-            currentValueBucket.conditionTimer.newBucketStart(nextBucketStartTimeNs);
-        }
-    }
-    mCurrentBucketNum += numBucketsForward;
-}
-
-PastValueBucket ValueMetricProducer::buildPartialBucket(int64_t bucketEndTime,
-                                                        const std::vector<Interval>& intervals) {
-    PastValueBucket bucket;
-    bucket.mBucketStartNs = mCurrentBucketStartTimeNs;
-    bucket.mBucketEndNs = bucketEndTime;
-    for (const auto& interval : intervals) {
-        if (interval.hasValue) {
-            // skip the output if the diff is zero
-            if (mSkipZeroDiffOutput && mUseDiff && interval.value.isZero()) {
-                continue;
-            }
-            bucket.valueIndex.push_back(interval.valueIndex);
-            if (mAggregationType != ValueMetric::AVG) {
-                bucket.values.push_back(interval.value);
-            } else {
-                double sum = interval.value.type == LONG ? (double)interval.value.long_value
-                                                         : interval.value.double_value;
-                bucket.values.push_back(Value((double)sum / interval.sampleSize));
-            }
-        }
-    }
-    return bucket;
-}
-
-void ValueMetricProducer::initCurrentSlicedBucket(int64_t nextBucketStartTimeNs) {
-    StatsdStats::getInstance().noteBucketCount(mMetricId);
-    // Cleanup data structure to aggregate values.
-    for (auto it = mCurrentSlicedBucket.begin(); it != mCurrentSlicedBucket.end();) {
-        bool obsolete = true;
-        for (auto& interval : it->second.intervals) {
-            interval.hasValue = false;
-            interval.sampleSize = 0;
-            if (interval.seenNewData) {
-                obsolete = false;
-            }
-            interval.seenNewData = false;
-        }
-
-        if (obsolete && !mSlicedStateAtoms.empty()) {
-            // When slicing by state, only delete the MetricDimensionKey when the
-            // state key in the MetricDimensionKey is not the current state key.
-            const HashableDimensionKey& dimensionInWhatKey = it->first.getDimensionKeyInWhat();
-            const auto& currentBaseInfoItr = mCurrentBaseInfo.find(dimensionInWhatKey);
-
-            if ((currentBaseInfoItr != mCurrentBaseInfo.end()) &&
-                (it->first.getStateValuesKey() == currentBaseInfoItr->second.currentState)) {
-                obsolete = false;
-            }
-        }
-        if (obsolete) {
-            it = mCurrentSlicedBucket.erase(it);
-        } else {
-            it++;
-        }
-        // TODO(b/157655103): remove mCurrentBaseInfo entries when obsolete
-    }
-
-    mCurrentBucketIsSkipped = false;
-    mCurrentSkippedBucket.reset();
-
-    // If we do not have a global base when the condition is true,
-    // we will have incomplete bucket for the next bucket.
-    if (mUseDiff && !mHasGlobalBase && mCondition) {
-        mCurrentBucketIsSkipped = false;
-    }
-    mCurrentBucketStartTimeNs = nextBucketStartTimeNs;
-    VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
-         (long long)mCurrentBucketStartTimeNs);
-}
-
-void ValueMetricProducer::appendToFullBucket(const bool isFullBucketReached) {
-    if (mCurrentBucketIsSkipped) {
-        if (isFullBucketReached) {
-            // If the bucket is invalid, we ignore the full bucket since it contains invalid data.
-            mCurrentFullBucket.clear();
-        }
-        // Current bucket is invalid, we do not add it to the full bucket.
-        return;
-    }
-
-    if (isFullBucketReached) {  // If full bucket, send to anomaly tracker.
-        // Accumulate partial buckets with current value and then send to anomaly tracker.
-        if (mCurrentFullBucket.size() > 0) {
-            for (const auto& slice : mCurrentSlicedBucket) {
-                if (hitFullBucketGuardRailLocked(slice.first) || slice.second.intervals.empty()) {
-                    continue;
-                }
-                // TODO: fix this when anomaly can accept double values
-                auto& interval = slice.second.intervals[0];
-                if (interval.hasValue) {
-                    mCurrentFullBucket[slice.first] += interval.value.long_value;
-                }
-            }
-            for (const auto& slice : mCurrentFullBucket) {
-                for (auto& tracker : mAnomalyTrackers) {
-                    if (tracker != nullptr) {
-                        tracker->addPastBucket(slice.first, slice.second, mCurrentBucketNum);
-                    }
-                }
-            }
-            mCurrentFullBucket.clear();
-        } else {
-            // Skip aggregating the partial buckets since there's no previous partial bucket.
-            for (const auto& slice : mCurrentSlicedBucket) {
-                for (auto& tracker : mAnomalyTrackers) {
-                    if (tracker != nullptr && !slice.second.intervals.empty()) {
-                        // TODO: fix this when anomaly can accept double values
-                        auto& interval = slice.second.intervals[0];
-                        if (interval.hasValue) {
-                            tracker->addPastBucket(slice.first, interval.value.long_value,
-                                                   mCurrentBucketNum);
-                        }
-                    }
-                }
-            }
-        }
-    } else {
-        // Accumulate partial bucket.
-        for (const auto& slice : mCurrentSlicedBucket) {
-            if (!slice.second.intervals.empty()) {
-                // TODO: fix this when anomaly can accept double values
-                auto& interval = slice.second.intervals[0];
-                if (interval.hasValue) {
-                    mCurrentFullBucket[slice.first] += interval.value.long_value;
-                }
-            }
-        }
-    }
-}
-
-size_t ValueMetricProducer::byteSizeLocked() const {
-    size_t totalSize = 0;
-    for (const auto& pair : mPastBuckets) {
-        totalSize += pair.second.size() * kBucketSize;
-    }
-    return totalSize;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
deleted file mode 100644
index ebd8fec..0000000
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <gtest/gtest_prod.h>
-#include "anomaly/AnomalyTracker.h"
-#include "condition/ConditionTimer.h"
-#include "condition/ConditionTracker.h"
-#include "external/PullDataReceiver.h"
-#include "external/StatsPullerManager.h"
-#include "matchers/EventMatcherWizard.h"
-#include "stats_log_util.h"
-#include "MetricProducer.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-struct PastValueBucket {
-    int64_t mBucketStartNs;
-    int64_t mBucketEndNs;
-    std::vector<int> valueIndex;
-    std::vector<Value> values;
-    // If the metric has no condition, then this field is just wasted.
-    // When we tune statsd memory usage in the future, this is a candidate to optimize.
-    int64_t mConditionTrueNs;
-};
-
-// Aggregates values within buckets.
-//
-// There are different events that might complete a bucket
-// - a condition change
-// - an app upgrade
-// - an alarm set to the end of the bucket
-class ValueMetricProducer : public MetricProducer, public virtual PullDataReceiver {
-public:
-    ValueMetricProducer(
-            const ConfigKey& key, const ValueMetric& valueMetric, const int conditionIndex,
-            const vector<ConditionState>& initialConditionCache,
-            const sp<ConditionWizard>& conditionWizard, const uint64_t protoHash,
-            const int whatMatcherIndex, const sp<EventMatcherWizard>& matcherWizard,
-            const int pullTagId, const int64_t timeBaseNs, const int64_t startTimeNs,
-            const sp<StatsPullerManager>& pullerManager,
-            const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap = {},
-            const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
-                    eventDeactivationMap = {},
-            const vector<int>& slicedStateAtoms = {},
-            const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap = {});
-
-    virtual ~ValueMetricProducer();
-
-    // Process data pulled on bucket boundary.
-    void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data,
-                      bool pullSuccess, int64_t originalPullTimeNs) override;
-
-    // ValueMetric needs special logic if it's a pulled atom.
-    void notifyAppUpgrade(const int64_t& eventTimeNs) override {
-        std::lock_guard<std::mutex> lock(mMutex);
-        if (!mSplitBucketForAppUpgrade) {
-            return;
-        }
-        if (mIsPulled && mCondition == ConditionState::kTrue) {
-            pullAndMatchEventsLocked(eventTimeNs);
-        }
-        flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
-    };
-
-    // ValueMetric needs special logic if it's a pulled atom.
-    void onStatsdInitCompleted(const int64_t& eventTimeNs) override {
-        std::lock_guard<std::mutex> lock(mMutex);
-        if (mIsPulled && mCondition == ConditionState::kTrue) {
-            pullAndMatchEventsLocked(eventTimeNs);
-        }
-        flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
-    };
-
-    void onStateChanged(int64_t eventTimeNs, int32_t atomId, const HashableDimensionKey& primaryKey,
-                        const FieldValue& oldState, const FieldValue& newState) override;
-
-    MetricType getMetricType() const override {
-        return METRIC_TYPE_VALUE;
-    }
-
-protected:
-    void onMatchedLogEventInternalLocked(
-            const size_t matcherIndex, const MetricDimensionKey& eventKey,
-            const ConditionKey& conditionKey, bool condition, const LogEvent& event,
-            const std::map<int, HashableDimensionKey>& statePrimaryKeys) override;
-
-private:
-    void onDumpReportLocked(const int64_t dumpTimeNs,
-                            const bool include_current_partial_bucket,
-                            const bool erase_data,
-                            const DumpLatency dumpLatency,
-                            std::set<string> *str_set,
-                            android::util::ProtoOutputStream* protoOutput) override;
-    void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
-
-    // Internal interface to handle active state change.
-    void onActiveStateChangedLocked(const int64_t& eventTimeNs) override;
-
-    // Internal interface to handle condition change.
-    void onConditionChangedLocked(const bool conditionMet, const int64_t eventTime) override;
-
-    // Internal interface to handle sliced condition change.
-    void onSlicedConditionMayChangeLocked(bool overallCondition, const int64_t eventTime) override;
-
-    // Internal function to calculate the current used bytes.
-    size_t byteSizeLocked() const override;
-
-    void dumpStatesLocked(FILE* out, bool verbose) const override;
-
-    // For pulled metrics, this method should only be called if a pull has be done. Else we will
-    // not have complete data for the bucket.
-    void flushIfNeededLocked(const int64_t& eventTime) override;
-
-    // For pulled metrics, this method should only be called if a pulled have be done. Else we will
-    // not have complete data for the bucket.
-    void flushCurrentBucketLocked(const int64_t& eventTimeNs,
-                                  const int64_t& nextBucketStartTimeNs) override;
-
-    void prepareFirstBucketLocked() override;
-
-    void dropDataLocked(const int64_t dropTimeNs) override;
-
-    // Calculate previous bucket end time based on current time.
-    int64_t calcPreviousBucketEndTime(const int64_t currentTimeNs);
-
-    // Calculate how many buckets are present between the current bucket and eventTimeNs.
-    int64_t calcBucketsForwardCount(const int64_t& eventTimeNs) const;
-
-    // Mark the data as invalid.
-    void invalidateCurrentBucket(const int64_t dropTimeNs, const BucketDropReason reason);
-
-    void invalidateCurrentBucketWithoutResetBase(const int64_t dropTimeNs,
-                                                 const BucketDropReason reason);
-
-    // Skips the current bucket without notifying StatsdStats of the skipped bucket.
-    // This should only be called from #flushCurrentBucketLocked. Otherwise, a future event that
-    // causes the bucket to be invalidated will not notify StatsdStats.
-    void skipCurrentBucket(const int64_t dropTimeNs, const BucketDropReason reason);
-
-    bool onConfigUpdatedLocked(
-            const StatsdConfig& config, const int configIndex, const int metricIndex,
-            const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-            const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
-            const std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
-            const sp<EventMatcherWizard>& matcherWizard,
-            const std::vector<sp<ConditionTracker>>& allConditionTrackers,
-            const std::unordered_map<int64_t, int>& conditionTrackerMap,
-            const sp<ConditionWizard>& wizard,
-            const std::unordered_map<int64_t, int>& metricToActivationMap,
-            std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
-            std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
-            std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
-            std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
-            std::vector<int>& metricsWithActivation) override;
-
-    int mWhatMatcherIndex;
-
-    sp<EventMatcherWizard> mEventMatcherWizard;
-
-    sp<StatsPullerManager> mPullerManager;
-
-    // Value fields for matching.
-    std::vector<Matcher> mFieldMatchers;
-
-    // Value fields for matching.
-    std::set<HashableDimensionKey> mMatchedMetricDimensionKeys;
-
-    // Holds the atom id, primary key pair from a state change.
-    pair<int32_t, HashableDimensionKey> mStateChangePrimaryKey;
-
-    // tagId for pulled data. -1 if this is not pulled
-    const int mPullTagId;
-
-    // if this is pulled metric
-    const bool mIsPulled;
-
-    // Tracks the value information of one value field.
-    typedef struct {
-        // Index in multi value aggregation.
-        int valueIndex;
-        // Current value, depending on the aggregation type.
-        Value value;
-        // Number of samples collected.
-        int sampleSize;
-        // If this dimension has any non-tainted value. If not, don't report the
-        // dimension.
-        bool hasValue = false;
-        // Whether new data is seen in the bucket.
-        bool seenNewData = false;
-    } Interval;
-
-    // Internal state of an ongoing aggregation bucket.
-    typedef struct CurrentValueBucket {
-        // If the `MetricDimensionKey` state key is the current state key, then
-        // the condition timer will be updated later (e.g. condition/state/active
-        // state change) with the correct condition and time.
-        CurrentValueBucket() : intervals(), conditionTimer(ConditionTimer(false, 0)) {}
-        // Value information for each value field of the metric.
-        std::vector<Interval> intervals;
-        // Tracks how long the condition is true.
-        ConditionTimer conditionTimer;
-    } CurrentValueBucket;
-
-    // Holds base information for diffing values from one value field.
-    typedef struct {
-        // Holds current base value of the dimension. Take diff and update if necessary.
-        Value base;
-        // Whether there is a base to diff to.
-        bool hasBase;
-    } BaseInfo;
-
-    // State key and base information for a specific DimensionsInWhat key.
-    typedef struct DimensionsInWhatInfo {
-        DimensionsInWhatInfo(const HashableDimensionKey& stateKey)
-            : baseInfos(), currentState(stateKey), hasCurrentState(false) {
-        }
-        std::vector<BaseInfo> baseInfos;
-        // Last seen state value(s).
-        HashableDimensionKey currentState;
-        // Whether this dimensions in what key has a current state key.
-        bool hasCurrentState;
-    } DimensionsInWhatInfo;
-
-    // Tracks the internal state in the ongoing aggregation bucket for each DimensionsInWhat
-    // key and StateValuesKey pair.
-    std::unordered_map<MetricDimensionKey, CurrentValueBucket> mCurrentSlicedBucket;
-
-    // Tracks current state key and base information for each DimensionsInWhat key.
-    std::unordered_map<HashableDimensionKey, DimensionsInWhatInfo> mCurrentBaseInfo;
-
-    std::unordered_map<MetricDimensionKey, int64_t> mCurrentFullBucket;
-
-    // Save the past buckets and we can clear when the StatsLogReport is dumped.
-    std::unordered_map<MetricDimensionKey, std::vector<PastValueBucket>> mPastBuckets;
-
-    const int64_t mMinBucketSizeNs;
-
-    // Util function to check whether the specified dimension hits the guardrail.
-    bool hitGuardRailLocked(const MetricDimensionKey& newKey);
-
-    bool hasReachedGuardRailLimit() const;
-
-    bool hitFullBucketGuardRailLocked(const MetricDimensionKey& newKey);
-
-    void pullAndMatchEventsLocked(const int64_t timestampNs);
-
-    bool multipleBucketsSkipped(const int64_t numBucketsForward);
-
-    void accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData,
-                          int64_t originalPullTimeNs, int64_t eventElapsedTimeNs);
-
-    PastValueBucket buildPartialBucket(int64_t bucketEndTime,
-                                       const std::vector<Interval>& intervals);
-
-    void initCurrentSlicedBucket(int64_t nextBucketStartTimeNs);
-
-    void appendToFullBucket(const bool isFullBucketReached);
-
-    // Reset diff base and mHasGlobalBase
-    void resetBase();
-
-    // Updates the condition timers in the current sliced bucket when there is a
-    // condition change or an active state change.
-    void updateCurrentSlicedBucketConditionTimers(bool newCondition, int64_t eventTimeNs);
-
-    static const size_t kBucketSize = sizeof(PastValueBucket{});
-
-    const size_t mDimensionSoftLimit;
-
-    const size_t mDimensionHardLimit;
-
-    const bool mUseAbsoluteValueOnReset;
-
-    const ValueMetric::AggregationType mAggregationType;
-
-    const bool mUseDiff;
-
-    const ValueMetric::ValueDirection mValueDirection;
-
-    const bool mSkipZeroDiffOutput;
-
-    // If true, use a zero value as base to compute the diff.
-    // This is used for new keys which are present in the new data but was not
-    // present in the base data.
-    // The default base will only be used if we have a global base.
-    const bool mUseZeroDefaultBase;
-
-    // For pulled metrics, this is always set to true whenever a pull succeeds.
-    // It is set to false when a pull fails, or upon condition change to false.
-    // This is used to decide if we have the right base data to compute the
-    // diff against.
-    bool mHasGlobalBase;
-
-    // This is to track whether or not the bucket is skipped for any of the reasons listed in
-    // BucketDropReason, many of which make the bucket potentially invalid.
-    bool mCurrentBucketIsSkipped;
-
-    const int64_t mMaxPullDelayNs;
-
-    const bool mSplitBucketForAppUpgrade;
-
-    ConditionTimer mConditionTimer;
-
-    FRIEND_TEST(ValueMetricProducerTest, TestAnomalyDetection);
-    FRIEND_TEST(ValueMetricProducerTest, TestBaseSetOnConditionChange);
-    FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundariesOnConditionChange);
-    FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition);
-    FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition);
-    FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2);
-    FRIEND_TEST(ValueMetricProducerTest, TestBucketInvalidIfGlobalBaseIsNotSet);
-    FRIEND_TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime);
-    FRIEND_TEST(ValueMetricProducerTest, TestDataIsNotUpdatedWhenNoConditionChanged);
-    FRIEND_TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onBucketBoundary);
-    FRIEND_TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onConditionChanged);
-    FRIEND_TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onDataPulled);
-    FRIEND_TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition);
-    FRIEND_TEST(ValueMetricProducerTest, TestFirstBucket);
-    FRIEND_TEST(ValueMetricProducerTest, TestLateOnDataPulledWithDiff);
-    FRIEND_TEST(ValueMetricProducerTest, TestLateOnDataPulledWithoutDiff);
-    FRIEND_TEST(ValueMetricProducerTest, TestPartialResetOnBucketBoundaries);
-    FRIEND_TEST(ValueMetricProducerTest, TestPulledData_noDiff_bucketBoundaryFalse);
-    FRIEND_TEST(ValueMetricProducerTest, TestPulledData_noDiff_bucketBoundaryTrue);
-    FRIEND_TEST(ValueMetricProducerTest, TestPulledData_noDiff_withFailure);
-    FRIEND_TEST(ValueMetricProducerTest, TestPulledData_noDiff_withMultipleConditionChanges);
-    FRIEND_TEST(ValueMetricProducerTest, TestPulledData_noDiff_withoutCondition);
-    FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsNoCondition);
-    FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset);
-    FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset);
-    FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering);
-    FRIEND_TEST(ValueMetricProducerTest, TestPulledWithAppUpgradeDisabled);
-    FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateAvg);
-    FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateMax);
-    FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateMin);
-    FRIEND_TEST(ValueMetricProducerTest, TestPushedAggregateSum);
-    FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithCondition);
-    FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition);
-    FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullDelayExceeded);
-    FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange);
-    FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange_EndOfBucket);
-    FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullFailBeforeConditionChange);
-    FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate);
-    FRIEND_TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput);
-    FRIEND_TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue);
-    FRIEND_TEST(ValueMetricProducerTest, TestSlicedState);
-    FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithMap);
-    FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions);
-    FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithCondition);
-    FRIEND_TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey);
-    FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBase);
-    FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures);
-    FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithMultipleDimensions);
-    FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithMissingDataInStateChange);
-    FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithDataMissingInConditionChange);
-    FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithMissingDataThenFlushBucket);
-    FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithNoPullOnBucketBoundary);
-
-    FRIEND_TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenOneConditionFailed);
-    FRIEND_TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenInitialPullFailed);
-    FRIEND_TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenLastPullFailed);
-    FRIEND_TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenGuardRailHit);
-    FRIEND_TEST(ValueMetricProducerTest_BucketDrop,
-                TestInvalidBucketWhenAccumulateEventWrongBucket);
-
-    FRIEND_TEST(ValueMetricProducerTest_PartialBucket, TestBucketBoundariesOnPartialBucket);
-    FRIEND_TEST(ValueMetricProducerTest_PartialBucket, TestFullBucketResetWhenLastBucketInvalid);
-    FRIEND_TEST(ValueMetricProducerTest_PartialBucket, TestPartialBucketCreated);
-    FRIEND_TEST(ValueMetricProducerTest_PartialBucket, TestPushedEvents);
-    FRIEND_TEST(ValueMetricProducerTest_PartialBucket, TestPulledValue);
-    FRIEND_TEST(ValueMetricProducerTest_PartialBucket, TestPulledValueWhileConditionFalse);
-
-    FRIEND_TEST(ConfigUpdateTest, TestUpdateValueMetrics);
-
-    friend class ValueMetricProducerTestHelper;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
deleted file mode 100644
index cf1f437..0000000
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef DURATION_TRACKER_H
-#define DURATION_TRACKER_H
-
-#include "anomaly/DurationAnomalyTracker.h"
-#include "condition/ConditionWizard.h"
-#include "config/ConfigKey.h"
-#include "stats_util.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-enum DurationState {
-    kStopped = 0,  // The event is stopped.
-    kStarted = 1,  // The event is on going.
-    kPaused = 2,   // The event is started, but condition is false, clock is paused. When condition
-                   // turns to true, kPaused will become kStarted.
-};
-
-// Hold duration information for one atom level duration in current on-going bucket.
-struct DurationInfo {
-    DurationState state;
-
-    // the number of starts seen.
-    int32_t startCount;
-
-    // most recent start time.
-    int64_t lastStartTime;
-    // existing duration in current bucket.
-    int64_t lastDuration;
-    // cache the HashableDimensionKeys we need to query the condition for this duration event.
-    ConditionKey conditionKeys;
-
-    DurationInfo() : state(kStopped), startCount(0), lastStartTime(0), lastDuration(0){};
-};
-
-struct DurationBucket {
-    int64_t mBucketStartNs;
-    int64_t mBucketEndNs;
-    int64_t mDuration;
-};
-
-struct DurationValues {
-    // Recorded duration for current partial bucket.
-    int64_t mDuration;
-
-    // Sum of past partial bucket durations in current full bucket.
-    // Used for anomaly detection.
-    int64_t mDurationFullBucket;
-};
-
-class DurationTracker {
-public:
-    DurationTracker(const ConfigKey& key, const int64_t& id, const MetricDimensionKey& eventKey,
-                    sp<ConditionWizard> wizard, int conditionIndex, bool nesting,
-                    int64_t currentBucketStartNs, int64_t currentBucketNum, int64_t startTimeNs,
-                    int64_t bucketSizeNs, bool conditionSliced, bool fullLink,
-                    const std::vector<sp<AnomalyTracker>>& anomalyTrackers)
-        : mConfigKey(key),
-          mTrackerId(id),
-          mEventKey(eventKey),
-          mWizard(wizard),
-          mConditionTrackerIndex(conditionIndex),
-          mBucketSizeNs(bucketSizeNs),
-          mNested(nesting),
-          mCurrentBucketStartTimeNs(currentBucketStartNs),
-          mDuration(0),
-          mCurrentBucketNum(currentBucketNum),
-          mStartTimeNs(startTimeNs),
-          mConditionSliced(conditionSliced),
-          mHasLinksToAllConditionDimensionsInTracker(fullLink),
-          mAnomalyTrackers(anomalyTrackers){};
-
-    virtual ~DurationTracker(){};
-
-    void onConfigUpdated(const sp<ConditionWizard>& wizard, const int conditionTrackerIndex) {
-        sp<ConditionWizard> tmpWizard = mWizard;
-        mWizard = wizard;
-        mConditionTrackerIndex = conditionTrackerIndex;
-        mAnomalyTrackers.clear();
-    };
-
-    virtual void noteStart(const HashableDimensionKey& key, bool condition, const int64_t eventTime,
-                           const ConditionKey& conditionKey) = 0;
-    virtual void noteStop(const HashableDimensionKey& key, const int64_t eventTime,
-                          const bool stopAll) = 0;
-    virtual void noteStopAll(const int64_t eventTime) = 0;
-
-    virtual void onSlicedConditionMayChange(bool overallCondition, const int64_t timestamp) = 0;
-    virtual void onConditionChanged(bool condition, const int64_t timestamp) = 0;
-
-    virtual void onStateChanged(const int64_t timestamp, const int32_t atomId,
-                                const FieldValue& newState) = 0;
-
-    // Flush stale buckets if needed, and return true if the tracker has no on-going duration
-    // events, so that the owner can safely remove the tracker.
-    virtual bool flushIfNeeded(
-            int64_t timestampNs,
-            std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) = 0;
-
-    // Should only be called during an app upgrade or from this tracker's flushIfNeeded. If from
-    // an app upgrade, we assume that we're trying to form a partial bucket.
-    virtual bool flushCurrentBucket(
-            const int64_t& eventTimeNs,
-            std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) = 0;
-
-    // Predict the anomaly timestamp given the current status.
-    virtual int64_t predictAnomalyTimestampNs(const AnomalyTracker& anomalyTracker,
-                                              const int64_t currentTimestamp) const = 0;
-    // Dump internal states for debugging
-    virtual void dumpStates(FILE* out, bool verbose) const = 0;
-
-    virtual int64_t getCurrentStateKeyDuration() const = 0;
-
-    virtual int64_t getCurrentStateKeyFullBucketDuration() const = 0;
-
-    // Replace old value with new value for the given state atom.
-    virtual void updateCurrentStateKey(const int32_t atomId, const FieldValue& newState) = 0;
-
-    void addAnomalyTracker(sp<AnomalyTracker>& anomalyTracker) {
-        mAnomalyTrackers.push_back(anomalyTracker);
-    }
-
-protected:
-    int64_t getCurrentBucketEndTimeNs() const {
-        return mStartTimeNs + (mCurrentBucketNum + 1) * mBucketSizeNs;
-    }
-
-    // Starts the anomaly alarm.
-    void startAnomalyAlarm(const int64_t eventTime) {
-        for (auto& anomalyTracker : mAnomalyTrackers) {
-            if (anomalyTracker != nullptr) {
-                const int64_t alarmTimestampNs =
-                    predictAnomalyTimestampNs(*anomalyTracker, eventTime);
-                if (alarmTimestampNs > 0) {
-                    anomalyTracker->startAlarm(mEventKey, alarmTimestampNs);
-                }
-            }
-        }
-    }
-
-    // Stops the anomaly alarm. If it should have already fired, declare the anomaly now.
-    void stopAnomalyAlarm(const int64_t timestamp) {
-        for (auto& anomalyTracker : mAnomalyTrackers) {
-            if (anomalyTracker != nullptr) {
-                anomalyTracker->stopAlarm(mEventKey, timestamp);
-            }
-        }
-    }
-
-    void addPastBucketToAnomalyTrackers(const MetricDimensionKey eventKey,
-                                        const int64_t& bucketValue, const int64_t& bucketNum) {
-        for (auto& anomalyTracker : mAnomalyTrackers) {
-            if (anomalyTracker != nullptr) {
-                anomalyTracker->addPastBucket(eventKey, bucketValue, bucketNum);
-            }
-        }
-    }
-
-    void detectAndDeclareAnomaly(const int64_t& timestamp, const int64_t& currBucketNum,
-                                 const int64_t& currentBucketValue) {
-        for (auto& anomalyTracker : mAnomalyTrackers) {
-            if (anomalyTracker != nullptr) {
-                anomalyTracker->detectAndDeclareAnomaly(timestamp, currBucketNum, mTrackerId,
-                                                        mEventKey, currentBucketValue);
-            }
-        }
-    }
-
-    // Convenience to compute the current bucket's end time, which is always aligned with the
-    // start time of the metric.
-    int64_t getCurrentBucketEndTimeNs() {
-        return mStartTimeNs + (mCurrentBucketNum + 1) * mBucketSizeNs;
-    }
-
-    void setEventKey(const MetricDimensionKey& eventKey) {
-        mEventKey = eventKey;
-    }
-
-    // A reference to the DurationMetricProducer's config key.
-    const ConfigKey& mConfigKey;
-
-    const int64_t mTrackerId;
-
-    MetricDimensionKey mEventKey;
-
-    sp<ConditionWizard> mWizard;
-
-    int mConditionTrackerIndex;
-
-    const int64_t mBucketSizeNs;
-
-    const bool mNested;
-
-    int64_t mCurrentBucketStartTimeNs;
-
-    int64_t mDuration;  // current recorded duration result (for partial bucket)
-
-    // Recorded duration results for each state key in the current partial bucket.
-    std::unordered_map<HashableDimensionKey, DurationValues> mStateKeyDurationMap;
-
-    int64_t mCurrentBucketNum;
-
-    const int64_t mStartTimeNs;
-
-    const bool mConditionSliced;
-
-    bool mHasLinksToAllConditionDimensionsInTracker;
-
-    std::vector<sp<AnomalyTracker>> mAnomalyTrackers;
-
-    FRIEND_TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp);
-    FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm);
-    FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm);
-
-    FRIEND_TEST(ConfigUpdateTest, TestUpdateDurationMetrics);
-    FRIEND_TEST(ConfigUpdateTest, TestUpdateAlerts);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-#endif  // DURATION_TRACKER_H
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
deleted file mode 100644
index 62f4982..0000000
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false
-
-#include "Log.h"
-#include "MaxDurationTracker.h"
-#include "guardrail/StatsdStats.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-MaxDurationTracker::MaxDurationTracker(const ConfigKey& key, const int64_t& id,
-                                       const MetricDimensionKey& eventKey,
-                                       sp<ConditionWizard> wizard, int conditionIndex, bool nesting,
-                                       int64_t currentBucketStartNs, int64_t currentBucketNum,
-                                       int64_t startTimeNs, int64_t bucketSizeNs,
-                                       bool conditionSliced, bool fullLink,
-                                       const vector<sp<AnomalyTracker>>& anomalyTrackers)
-    : DurationTracker(key, id, eventKey, wizard, conditionIndex, nesting, currentBucketStartNs,
-                      currentBucketNum, startTimeNs, bucketSizeNs, conditionSliced, fullLink,
-                      anomalyTrackers) {
-}
-
-bool MaxDurationTracker::hitGuardRail(const HashableDimensionKey& newKey) {
-    // ===========GuardRail==============
-    if (mInfos.find(newKey) != mInfos.end()) {
-        // if the key existed, we are good!
-        return false;
-    }
-    // 1. Report the tuple count if the tuple count > soft limit
-    if (mInfos.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
-        size_t newTupleCount = mInfos.size() + 1;
-        StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mTrackerId, newTupleCount);
-        // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
-        if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
-            ALOGE("MaxDurTracker %lld dropping data for dimension key %s",
-                (long long)mTrackerId, newKey.toString().c_str());
-            return true;
-        }
-    }
-    return false;
-}
-
-void MaxDurationTracker::noteStart(const HashableDimensionKey& key, bool condition,
-                                   const int64_t eventTime, const ConditionKey& conditionKey) {
-    // this will construct a new DurationInfo if this key didn't exist.
-    if (hitGuardRail(key)) {
-        return;
-    }
-
-    DurationInfo& duration = mInfos[key];
-    if (mConditionSliced) {
-        duration.conditionKeys = conditionKey;
-    }
-    VLOG("MaxDuration: key %s start condition %d", key.toString().c_str(), condition);
-
-    switch (duration.state) {
-        case kStarted:
-            duration.startCount++;
-            break;
-        case kPaused:
-            duration.startCount++;
-            break;
-        case kStopped:
-            if (!condition) {
-                // event started, but we need to wait for the condition to become true.
-                duration.state = DurationState::kPaused;
-            } else {
-                duration.state = DurationState::kStarted;
-                duration.lastStartTime = eventTime;
-                startAnomalyAlarm(eventTime);
-            }
-            duration.startCount = 1;
-            break;
-    }
-}
-
-void MaxDurationTracker::noteStop(const HashableDimensionKey& key, const int64_t eventTime,
-                                  bool forceStop) {
-    VLOG("MaxDuration: key %s stop", key.toString().c_str());
-    if (mInfos.find(key) == mInfos.end()) {
-        // we didn't see a start event before. do nothing.
-        return;
-    }
-    DurationInfo& duration = mInfos[key];
-
-    switch (duration.state) {
-        case DurationState::kStopped:
-            // already stopped, do nothing.
-            break;
-        case DurationState::kStarted: {
-            duration.startCount--;
-            if (forceStop || !mNested || duration.startCount <= 0) {
-                stopAnomalyAlarm(eventTime);
-                duration.state = DurationState::kStopped;
-                int64_t durationTime = eventTime - duration.lastStartTime;
-                VLOG("Max, key %s, Stop %lld %lld %lld", key.toString().c_str(),
-                     (long long)duration.lastStartTime, (long long)eventTime,
-                     (long long)durationTime);
-                duration.lastDuration += durationTime;
-                if (anyStarted()) {
-                    // In case any other dimensions are still started, we need to keep the alarm
-                    // set.
-                    startAnomalyAlarm(eventTime);
-                }
-                VLOG("  record duration: %lld ", (long long)duration.lastDuration);
-            }
-            break;
-        }
-        case DurationState::kPaused: {
-            duration.startCount--;
-            if (forceStop || !mNested || duration.startCount <= 0) {
-                duration.state = DurationState::kStopped;
-            }
-            break;
-        }
-    }
-
-    if (duration.lastDuration > mDuration) {
-        mDuration = duration.lastDuration;
-        VLOG("Max: new max duration: %lld", (long long)mDuration);
-    }
-    // Once an atom duration ends, we erase it. Next time, if we see another atom event with the
-    // same name, they are still considered as different atom durations.
-    if (duration.state == DurationState::kStopped) {
-        mInfos.erase(key);
-    }
-}
-
-bool MaxDurationTracker::anyStarted() {
-    for (auto& pair : mInfos) {
-        if (pair.second.state == kStarted) {
-            return true;
-        }
-    }
-    return false;
-}
-
-void MaxDurationTracker::noteStopAll(const int64_t eventTime) {
-    std::set<HashableDimensionKey> keys;
-    for (const auto& pair : mInfos) {
-        keys.insert(pair.first);
-    }
-    for (auto& key : keys) {
-        noteStop(key, eventTime, true);
-    }
-}
-
-bool MaxDurationTracker::flushCurrentBucket(
-        const int64_t& eventTimeNs,
-        std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) {
-    VLOG("MaxDurationTracker flushing.....");
-
-    // adjust the bucket start time
-    int numBucketsForward = 0;
-    int64_t fullBucketEnd = getCurrentBucketEndTimeNs();
-    int64_t currentBucketEndTimeNs;
-    if (eventTimeNs >= fullBucketEnd) {
-        numBucketsForward = 1 + (eventTimeNs - fullBucketEnd) / mBucketSizeNs;
-        currentBucketEndTimeNs = fullBucketEnd;
-    } else {
-        // This must be a partial bucket.
-        currentBucketEndTimeNs = eventTimeNs;
-    }
-
-    bool hasPendingEvent =
-            false;  // has either a kStarted or kPaused event across bucket boundaries
-    // meaning we need to carry them over to the new bucket.
-    for (auto it = mInfos.begin(); it != mInfos.end();) {
-        if (it->second.state == DurationState::kStopped) {
-            // No need to keep buckets for events that were stopped before.
-            it = mInfos.erase(it);
-        } else {
-            ++it;
-            hasPendingEvent = true;
-        }
-    }
-
-    // mDuration is updated in noteStop to the maximum duration that ended in the current bucket.
-    if (mDuration != 0) {
-        DurationBucket info;
-        info.mBucketStartNs = mCurrentBucketStartTimeNs;
-        info.mBucketEndNs = currentBucketEndTimeNs;
-        info.mDuration = mDuration;
-        (*output)[mEventKey].push_back(info);
-        VLOG("  final duration for last bucket: %lld", (long long)mDuration);
-    }
-
-    if (numBucketsForward > 0) {
-        mCurrentBucketStartTimeNs = fullBucketEnd + (numBucketsForward - 1) * mBucketSizeNs;
-        mCurrentBucketNum += numBucketsForward;
-    } else {  // We must be forming a partial bucket.
-        mCurrentBucketStartTimeNs = eventTimeNs;
-    }
-
-    mDuration = 0;
-    // If this tracker has no pending events, tell owner to remove.
-    return !hasPendingEvent;
-}
-
-bool MaxDurationTracker::flushIfNeeded(
-        int64_t eventTimeNs, unordered_map<MetricDimensionKey, vector<DurationBucket>>* output) {
-    if (eventTimeNs < getCurrentBucketEndTimeNs()) {
-        return false;
-    }
-    return flushCurrentBucket(eventTimeNs, output);
-}
-
-void MaxDurationTracker::onSlicedConditionMayChange(bool overallCondition,
-                                                    const int64_t timestamp) {
-    // Now for each of the on-going event, check if the condition has changed for them.
-    for (auto& pair : mInfos) {
-        if (pair.second.state == kStopped) {
-            continue;
-        }
-        ConditionState conditionState = mWizard->query(
-            mConditionTrackerIndex, pair.second.conditionKeys,
-            !mHasLinksToAllConditionDimensionsInTracker);
-        bool conditionMet = (conditionState == ConditionState::kTrue);
-
-        VLOG("key: %s, condition: %d", pair.first.toString().c_str(), conditionMet);
-        noteConditionChanged(pair.first, conditionMet, timestamp);
-    }
-}
-
-void MaxDurationTracker::onStateChanged(const int64_t timestamp, const int32_t atomId,
-                                        const FieldValue& newState) {
-    ALOGE("MaxDurationTracker does not handle sliced state changes.");
-}
-
-void MaxDurationTracker::onConditionChanged(bool condition, const int64_t timestamp) {
-    for (auto& pair : mInfos) {
-        noteConditionChanged(pair.first, condition, timestamp);
-    }
-}
-
-void MaxDurationTracker::noteConditionChanged(const HashableDimensionKey& key, bool conditionMet,
-                                              const int64_t timestamp) {
-    auto it = mInfos.find(key);
-    if (it == mInfos.end()) {
-        return;
-    }
-
-    switch (it->second.state) {
-        case kStarted:
-            // If condition becomes false, kStarted -> kPaused. Record the current duration and
-            // stop anomaly alarm.
-            if (!conditionMet) {
-                stopAnomalyAlarm(timestamp);
-                it->second.state = DurationState::kPaused;
-                it->second.lastDuration += (timestamp - it->second.lastStartTime);
-                if (anyStarted()) {
-                    // In case any other dimensions are still started, we need to set the alarm.
-                    startAnomalyAlarm(timestamp);
-                }
-                VLOG("MaxDurationTracker Key: %s Started->Paused ", key.toString().c_str());
-            }
-            break;
-        case kStopped:
-            // Nothing to do if it's stopped.
-            break;
-        case kPaused:
-            // If condition becomes true, kPaused -> kStarted. and the start time is the condition
-            // change time.
-            if (conditionMet) {
-                it->second.state = DurationState::kStarted;
-                it->second.lastStartTime = timestamp;
-                startAnomalyAlarm(timestamp);
-                VLOG("MaxDurationTracker Key: %s Paused->Started", key.toString().c_str());
-            }
-            break;
-    }
-    // Note that we don't update mDuration here since it's only updated during noteStop.
-}
-
-int64_t MaxDurationTracker::predictAnomalyTimestampNs(const AnomalyTracker& anomalyTracker,
-                                                      const int64_t currentTimestamp) const {
-    // The allowed time we can continue in the current state is the
-    // (anomaly threshold) - max(elapsed time of the started mInfos).
-    int64_t maxElapsed = 0;
-    for (auto it = mInfos.begin(); it != mInfos.end(); ++it) {
-        if (it->second.state == DurationState::kStarted) {
-            int64_t duration =
-                    it->second.lastDuration + (currentTimestamp - it->second.lastStartTime);
-            if (duration > maxElapsed) {
-                maxElapsed = duration;
-            }
-        }
-    }
-    int64_t anomalyTimeNs = currentTimestamp + anomalyTracker.getAnomalyThreshold() - maxElapsed;
-    int64_t refractoryEndNs = anomalyTracker.getRefractoryPeriodEndsSec(mEventKey) * NS_PER_SEC;
-    return std::max(anomalyTimeNs, refractoryEndNs);
-}
-
-void MaxDurationTracker::dumpStates(FILE* out, bool verbose) const {
-    fprintf(out, "\t\t sub-durations %lu\n", (unsigned long)mInfos.size());
-    fprintf(out, "\t\t current duration %lld\n", (long long)mDuration);
-}
-
-int64_t MaxDurationTracker::getCurrentStateKeyDuration() const {
-    ALOGE("MaxDurationTracker does not handle sliced state changes.");
-    return -1;
-}
-
-int64_t MaxDurationTracker::getCurrentStateKeyFullBucketDuration() const {
-    ALOGE("MaxDurationTracker does not handle sliced state changes.");
-    return -1;
-}
-
-void MaxDurationTracker::updateCurrentStateKey(const int32_t atomId, const FieldValue& newState) {
-    ALOGE("MaxDurationTracker does not handle sliced state changes.");
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
deleted file mode 100644
index be2707c..0000000
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MAX_DURATION_TRACKER_H
-#define MAX_DURATION_TRACKER_H
-
-#include "DurationTracker.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// Tracks a pool of atom durations, and output the max duration for each bucket.
-// To get max duration, we need to keep track of each individual durations, and compare them when
-// they stop or bucket expires.
-class MaxDurationTracker : public DurationTracker {
-public:
-    MaxDurationTracker(const ConfigKey& key, const int64_t& id, const MetricDimensionKey& eventKey,
-                       sp<ConditionWizard> wizard, int conditionIndex, bool nesting,
-                       int64_t currentBucketStartNs, int64_t currentBucketNum, int64_t startTimeNs,
-                       int64_t bucketSizeNs, bool conditionSliced, bool fullLink,
-                       const std::vector<sp<AnomalyTracker>>& anomalyTrackers);
-
-    MaxDurationTracker(const MaxDurationTracker& tracker) = default;
-
-    void noteStart(const HashableDimensionKey& key, bool condition, const int64_t eventTime,
-                   const ConditionKey& conditionKey) override;
-    void noteStop(const HashableDimensionKey& key, const int64_t eventTime,
-                  const bool stopAll) override;
-    void noteStopAll(const int64_t eventTime) override;
-
-    bool flushIfNeeded(
-            int64_t timestampNs,
-            std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) override;
-    bool flushCurrentBucket(
-            const int64_t& eventTimeNs,
-            std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>*) override;
-
-    void onSlicedConditionMayChange(bool overallCondition, const int64_t timestamp) override;
-    void onConditionChanged(bool condition, const int64_t timestamp) override;
-
-    void onStateChanged(const int64_t timestamp, const int32_t atomId,
-                        const FieldValue& newState) override;
-
-    int64_t predictAnomalyTimestampNs(const AnomalyTracker& anomalyTracker,
-                                      const int64_t currentTimestamp) const override;
-    void dumpStates(FILE* out, bool verbose) const override;
-
-    int64_t getCurrentStateKeyDuration() const override;
-
-    int64_t getCurrentStateKeyFullBucketDuration() const override;
-
-    void updateCurrentStateKey(const int32_t atomId, const FieldValue& newState);
-
-private:
-    // Returns true if at least one of the mInfos is started.
-    bool anyStarted();
-
-    std::unordered_map<HashableDimensionKey, DurationInfo> mInfos;
-
-    void noteConditionChanged(const HashableDimensionKey& key, bool conditionMet,
-                              const int64_t timestamp);
-
-    // return true if we should not allow newKey to be tracked because we are above the threshold
-    bool hitGuardRail(const HashableDimensionKey& newKey);
-
-    FRIEND_TEST(MaxDurationTrackerTest, TestSimpleMaxDuration);
-    FRIEND_TEST(MaxDurationTrackerTest, TestCrossBucketBoundary);
-    FRIEND_TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition);
-    FRIEND_TEST(MaxDurationTrackerTest, TestStopAll);
-    FRIEND_TEST(MaxDurationTrackerTest, TestAnomalyDetection);
-    FRIEND_TEST(MaxDurationTrackerTest, TestAnomalyPredictedTimestamp);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-#endif  // MAX_DURATION_TRACKER_H
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
deleted file mode 100644
index 247e2e0..0000000
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define DEBUG false
-#include "Log.h"
-#include "OringDurationTracker.h"
-#include "guardrail/StatsdStats.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using std::pair;
-
-OringDurationTracker::OringDurationTracker(
-        const ConfigKey& key, const int64_t& id, const MetricDimensionKey& eventKey,
-        sp<ConditionWizard> wizard, int conditionIndex, bool nesting, int64_t currentBucketStartNs,
-        int64_t currentBucketNum, int64_t startTimeNs, int64_t bucketSizeNs, bool conditionSliced,
-        bool fullLink, const vector<sp<AnomalyTracker>>& anomalyTrackers)
-    : DurationTracker(key, id, eventKey, wizard, conditionIndex, nesting, currentBucketStartNs,
-                      currentBucketNum, startTimeNs, bucketSizeNs, conditionSliced, fullLink,
-                      anomalyTrackers),
-      mStarted(),
-      mPaused() {
-    mLastStartTime = 0;
-}
-
-bool OringDurationTracker::hitGuardRail(const HashableDimensionKey& newKey) {
-    // ===========GuardRail==============
-    // 1. Report the tuple count if the tuple count > soft limit
-    if (mConditionKeyMap.find(newKey) != mConditionKeyMap.end()) {
-        return false;
-    }
-    if (mConditionKeyMap.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) {
-        size_t newTupleCount = mConditionKeyMap.size() + 1;
-        StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mTrackerId, newTupleCount);
-        // 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
-        if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
-            ALOGE("OringDurTracker %lld dropping data for dimension key %s",
-                (long long)mTrackerId, newKey.toString().c_str());
-            return true;
-        }
-    }
-    return false;
-}
-
-void OringDurationTracker::noteStart(const HashableDimensionKey& key, bool condition,
-                                     const int64_t eventTime, const ConditionKey& conditionKey) {
-    if (hitGuardRail(key)) {
-        return;
-    }
-    if (condition) {
-        if (mStarted.size() == 0) {
-            mLastStartTime = eventTime;
-            VLOG("record first start....");
-            startAnomalyAlarm(eventTime);
-        }
-        mStarted[key]++;
-    } else {
-        mPaused[key]++;
-    }
-
-    if (mConditionSliced && mConditionKeyMap.find(key) == mConditionKeyMap.end()) {
-        mConditionKeyMap[key] = conditionKey;
-    }
-    VLOG("Oring: %s start, condition %d", key.toString().c_str(), condition);
-}
-
-void OringDurationTracker::noteStop(const HashableDimensionKey& key, const int64_t timestamp,
-                                    const bool stopAll) {
-    VLOG("Oring: %s stop", key.toString().c_str());
-    auto it = mStarted.find(key);
-    if (it != mStarted.end()) {
-        (it->second)--;
-        if (stopAll || !mNested || it->second <= 0) {
-            mStarted.erase(it);
-            mConditionKeyMap.erase(key);
-        }
-        if (mStarted.empty()) {
-            mStateKeyDurationMap[mEventKey.getStateValuesKey()].mDuration +=
-                    (timestamp - mLastStartTime);
-            detectAndDeclareAnomaly(
-                    timestamp, mCurrentBucketNum,
-                    getCurrentStateKeyDuration() + getCurrentStateKeyFullBucketDuration());
-            VLOG("record duration %lld, total duration %lld for state key %s",
-                 (long long)timestamp - mLastStartTime, (long long)getCurrentStateKeyDuration(),
-                 mEventKey.getStateValuesKey().toString().c_str());
-        }
-    }
-
-    auto pausedIt = mPaused.find(key);
-    if (pausedIt != mPaused.end()) {
-        (pausedIt->second)--;
-        if (stopAll || !mNested || pausedIt->second <= 0) {
-            mPaused.erase(pausedIt);
-            mConditionKeyMap.erase(key);
-        }
-    }
-    if (mStarted.empty()) {
-        stopAnomalyAlarm(timestamp);
-    }
-}
-
-void OringDurationTracker::noteStopAll(const int64_t timestamp) {
-    if (!mStarted.empty()) {
-        mStateKeyDurationMap[mEventKey.getStateValuesKey()].mDuration +=
-                (timestamp - mLastStartTime);
-        VLOG("Oring Stop all: record duration %lld, total duration %lld for state key %s",
-             (long long)timestamp - mLastStartTime, (long long)getCurrentStateKeyDuration(),
-             mEventKey.getStateValuesKey().toString().c_str());
-        detectAndDeclareAnomaly(
-                timestamp, mCurrentBucketNum,
-                getCurrentStateKeyDuration() + getCurrentStateKeyFullBucketDuration());
-    }
-
-    stopAnomalyAlarm(timestamp);
-    mStarted.clear();
-    mPaused.clear();
-    mConditionKeyMap.clear();
-}
-
-bool OringDurationTracker::flushCurrentBucket(
-        const int64_t& eventTimeNs,
-        std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) {
-    VLOG("OringDurationTracker Flushing.............");
-
-    // Note that we have to mimic the bucket time changes we do in the
-    // MetricProducer#notifyAppUpgrade.
-
-    int numBucketsForward = 0;
-    int64_t fullBucketEnd = getCurrentBucketEndTimeNs();
-    int64_t currentBucketEndTimeNs;
-
-    if (eventTimeNs >= fullBucketEnd) {
-        numBucketsForward = 1 + (eventTimeNs - fullBucketEnd) / mBucketSizeNs;
-        currentBucketEndTimeNs = fullBucketEnd;
-    } else {
-        // This must be a partial bucket.
-        currentBucketEndTimeNs = eventTimeNs;
-    }
-
-    // Process the current bucket.
-    if (mStarted.size() > 0) {
-        // Calculate the duration for the current state key.
-        mStateKeyDurationMap[mEventKey.getStateValuesKey()].mDuration +=
-                (currentBucketEndTimeNs - mLastStartTime);
-    }
-    // Store DurationBucket info for each whatKey, stateKey pair.
-    // Note: The whatKey stored in mEventKey is constant for each DurationTracker, while the
-    // stateKey stored in mEventKey is only the current stateKey. mStateKeyDurationMap is used to
-    // store durations for each stateKey, so we need to flush the bucket by creating a
-    // DurationBucket for each stateKey.
-    for (auto& durationIt : mStateKeyDurationMap) {
-        if (durationIt.second.mDuration > 0) {
-            DurationBucket current_info;
-            current_info.mBucketStartNs = mCurrentBucketStartTimeNs;
-            current_info.mBucketEndNs = currentBucketEndTimeNs;
-            current_info.mDuration = durationIt.second.mDuration;
-            (*output)[MetricDimensionKey(mEventKey.getDimensionKeyInWhat(), durationIt.first)]
-                    .push_back(current_info);
-
-            durationIt.second.mDurationFullBucket += durationIt.second.mDuration;
-            VLOG("  duration: %lld", (long long)current_info.mDuration);
-        }
-
-        if (eventTimeNs > fullBucketEnd) {
-            // End of full bucket, can send to anomaly tracker now.
-            addPastBucketToAnomalyTrackers(
-                    MetricDimensionKey(mEventKey.getDimensionKeyInWhat(), durationIt.first),
-                    getCurrentStateKeyFullBucketDuration(), mCurrentBucketNum);
-            durationIt.second.mDurationFullBucket = 0;
-        }
-        durationIt.second.mDuration = 0;
-    }
-
-    if (mStarted.size() > 0) {
-        for (int i = 1; i < numBucketsForward; i++) {
-            DurationBucket info;
-            info.mBucketStartNs = fullBucketEnd + mBucketSizeNs * (i - 1);
-            info.mBucketEndNs = info.mBucketStartNs + mBucketSizeNs;
-            info.mDuration = mBucketSizeNs;
-            // Full duration buckets are attributed to the current stateKey.
-            (*output)[mEventKey].push_back(info);
-            // Safe to send these buckets to anomaly tracker since they must be full buckets.
-            // If it's a partial bucket, numBucketsForward would be 0.
-            addPastBucketToAnomalyTrackers(mEventKey, info.mDuration, mCurrentBucketNum + i);
-            VLOG("  add filling bucket with duration %lld", (long long)info.mDuration);
-        }
-    } else {
-        if (numBucketsForward >= 2) {
-            addPastBucketToAnomalyTrackers(mEventKey, 0, mCurrentBucketNum + numBucketsForward - 1);
-        }
-    }
-
-    if (numBucketsForward > 0) {
-        mCurrentBucketStartTimeNs = fullBucketEnd + (numBucketsForward - 1) * mBucketSizeNs;
-        mCurrentBucketNum += numBucketsForward;
-    } else {  // We must be forming a partial bucket.
-        mCurrentBucketStartTimeNs = eventTimeNs;
-    }
-    mLastStartTime = mCurrentBucketStartTimeNs;
-
-    // if all stopped, then tell owner it's safe to remove this tracker.
-    return mStarted.empty() && mPaused.empty();
-}
-
-bool OringDurationTracker::flushIfNeeded(
-        int64_t eventTimeNs, unordered_map<MetricDimensionKey, vector<DurationBucket>>* output) {
-    if (eventTimeNs < getCurrentBucketEndTimeNs()) {
-        return false;
-    }
-    return flushCurrentBucket(eventTimeNs, output);
-}
-
-void OringDurationTracker::onSlicedConditionMayChange(bool overallCondition,
-                                                      const int64_t timestamp) {
-    vector<pair<HashableDimensionKey, int>> startedToPaused;
-    vector<pair<HashableDimensionKey, int>> pausedToStarted;
-    if (!mStarted.empty()) {
-        for (auto it = mStarted.begin(); it != mStarted.end();) {
-            const auto& key = it->first;
-            const auto& condIt = mConditionKeyMap.find(key);
-            if (condIt == mConditionKeyMap.end()) {
-                VLOG("Key %s dont have condition key", key.toString().c_str());
-                ++it;
-                continue;
-            }
-            ConditionState conditionState =
-                mWizard->query(mConditionTrackerIndex, condIt->second,
-                               !mHasLinksToAllConditionDimensionsInTracker);
-            if (conditionState != ConditionState::kTrue) {
-                startedToPaused.push_back(*it);
-                it = mStarted.erase(it);
-                VLOG("Key %s started -> paused", key.toString().c_str());
-            } else {
-                ++it;
-            }
-        }
-
-        if (mStarted.empty()) {
-            mStateKeyDurationMap[mEventKey.getStateValuesKey()].mDuration +=
-                    (timestamp - mLastStartTime);
-            VLOG("record duration %lld, total duration %lld for state key %s",
-                 (long long)(timestamp - mLastStartTime), (long long)getCurrentStateKeyDuration(),
-                 mEventKey.getStateValuesKey().toString().c_str());
-            detectAndDeclareAnomaly(
-                    timestamp, mCurrentBucketNum,
-                    getCurrentStateKeyDuration() + getCurrentStateKeyFullBucketDuration());
-        }
-    }
-
-    if (!mPaused.empty()) {
-        for (auto it = mPaused.begin(); it != mPaused.end();) {
-            const auto& key = it->first;
-            if (mConditionKeyMap.find(key) == mConditionKeyMap.end()) {
-                VLOG("Key %s dont have condition key", key.toString().c_str());
-                ++it;
-                continue;
-            }
-            ConditionState conditionState =
-                mWizard->query(mConditionTrackerIndex, mConditionKeyMap[key],
-                               !mHasLinksToAllConditionDimensionsInTracker);
-            if (conditionState == ConditionState::kTrue) {
-                pausedToStarted.push_back(*it);
-                it = mPaused.erase(it);
-                VLOG("Key %s paused -> started", key.toString().c_str());
-            } else {
-                ++it;
-            }
-        }
-
-        if (mStarted.empty() && pausedToStarted.size() > 0) {
-            mLastStartTime = timestamp;
-        }
-    }
-
-    if (mStarted.empty() && !pausedToStarted.empty()) {
-        startAnomalyAlarm(timestamp);
-    }
-    mStarted.insert(pausedToStarted.begin(), pausedToStarted.end());
-    mPaused.insert(startedToPaused.begin(), startedToPaused.end());
-
-    if (mStarted.empty()) {
-        stopAnomalyAlarm(timestamp);
-    }
-}
-
-void OringDurationTracker::onConditionChanged(bool condition, const int64_t timestamp) {
-    if (condition) {
-        if (!mPaused.empty()) {
-            VLOG("Condition true, all started");
-            if (mStarted.empty()) {
-                mLastStartTime = timestamp;
-            }
-            if (mStarted.empty() && !mPaused.empty()) {
-                startAnomalyAlarm(timestamp);
-            }
-            mStarted.insert(mPaused.begin(), mPaused.end());
-            mPaused.clear();
-        }
-    } else {
-        if (!mStarted.empty()) {
-            VLOG("Condition false, all paused");
-            mStateKeyDurationMap[mEventKey.getStateValuesKey()].mDuration +=
-                    (timestamp - mLastStartTime);
-            mPaused.insert(mStarted.begin(), mStarted.end());
-            mStarted.clear();
-            detectAndDeclareAnomaly(
-                    timestamp, mCurrentBucketNum,
-                    getCurrentStateKeyDuration() + getCurrentStateKeyFullBucketDuration());
-        }
-    }
-    if (mStarted.empty()) {
-        stopAnomalyAlarm(timestamp);
-    }
-}
-
-void OringDurationTracker::onStateChanged(const int64_t timestamp, const int32_t atomId,
-                                          const FieldValue& newState) {
-    // Nothing needs to be done on a state change if we have not seen a start
-    // event, the metric is currently not active, or condition is false.
-    // For these cases, no keys are being tracked in mStarted, so update
-    // the current state key and return.
-    if (mStarted.empty()) {
-        updateCurrentStateKey(atomId, newState);
-        return;
-    }
-    // Add the current duration length to the previous state key and then update
-    // the last start time and current state key.
-    mStateKeyDurationMap[mEventKey.getStateValuesKey()].mDuration += (timestamp - mLastStartTime);
-    mLastStartTime = timestamp;
-    updateCurrentStateKey(atomId, newState);
-}
-
-int64_t OringDurationTracker::predictAnomalyTimestampNs(const AnomalyTracker& anomalyTracker,
-                                                        const int64_t eventTimestampNs) const {
-    // The anomaly threshold.
-    const int64_t thresholdNs = anomalyTracker.getAnomalyThreshold();
-
-    // The timestamp of the current bucket end.
-    const int64_t currentBucketEndNs = getCurrentBucketEndTimeNs();
-
-    // The past duration ns for the current bucket of the current stateKey.
-    int64_t currentStateBucketPastNs =
-            getCurrentStateKeyDuration() + getCurrentStateKeyFullBucketDuration();
-
-    // As we move into the future, old buckets get overwritten (so their old data is erased).
-    // Sum of past durations. Will change as we overwrite old buckets.
-    int64_t pastNs = currentStateBucketPastNs + anomalyTracker.getSumOverPastBuckets(mEventKey);
-
-    // The refractory period end timestamp for dimension mEventKey.
-    const int64_t refractoryPeriodEndNs =
-            anomalyTracker.getRefractoryPeriodEndsSec(mEventKey) * NS_PER_SEC;
-
-    // The anomaly should happen when accumulated wakelock duration is above the threshold and
-    // not within the refractory period.
-    int64_t anomalyTimestampNs =
-        std::max(eventTimestampNs + thresholdNs - pastNs, refractoryPeriodEndNs);
-    // If the predicted the anomaly timestamp is within the current bucket, return it directly.
-    if (anomalyTimestampNs <= currentBucketEndNs) {
-        return std::max(eventTimestampNs, anomalyTimestampNs);
-    }
-
-    // Remove the old bucket.
-    if (anomalyTracker.getNumOfPastBuckets() > 0) {
-        pastNs -= anomalyTracker.getPastBucketValue(
-                            mEventKey,
-                            mCurrentBucketNum - anomalyTracker.getNumOfPastBuckets());
-        // Add the remaining of the current bucket to the accumulated wakelock duration.
-        pastNs += (currentBucketEndNs - eventTimestampNs);
-    } else {
-        // The anomaly depends on only one bucket.
-        pastNs = 0;
-    }
-
-    // The anomaly will not happen in the current bucket. We need to iterate over the future buckets
-    // to predict the accumulated wakelock duration and determine the anomaly timestamp accordingly.
-    for (int futureBucketIdx = 1; futureBucketIdx <= anomalyTracker.getNumOfPastBuckets() + 1;
-            futureBucketIdx++) {
-        // The alarm candidate timestamp should meet two requirements:
-        // 1. the accumulated wakelock duration is above the threshold.
-        // 2. it is not within the refractory period.
-        // 3. the alarm timestamp falls in this bucket. Otherwise we need to flush the past buckets,
-        //    find the new alarm candidate timestamp and check these requirements again.
-        const int64_t bucketEndNs = currentBucketEndNs + futureBucketIdx * mBucketSizeNs;
-        int64_t anomalyTimestampNs =
-            std::max(bucketEndNs - mBucketSizeNs + thresholdNs - pastNs, refractoryPeriodEndNs);
-        if (anomalyTimestampNs <= bucketEndNs) {
-            return anomalyTimestampNs;
-        }
-        if (anomalyTracker.getNumOfPastBuckets() <= 0) {
-            continue;
-        }
-
-        // No valid alarm timestamp is found in this bucket. The clock moves to the end of the
-        // bucket. Update the pastNs.
-        pastNs += mBucketSizeNs;
-        // 1. If the oldest past bucket is still in the past bucket window, we could fetch the past
-        // bucket and erase it from pastNs.
-        // 2. If the oldest past bucket is the current bucket, we should compute the
-        //   wakelock duration in the current bucket and erase it from pastNs.
-        // 3. Otherwise all othe past buckets are ancient.
-        if (futureBucketIdx < anomalyTracker.getNumOfPastBuckets()) {
-            pastNs -= anomalyTracker.getPastBucketValue(
-                    mEventKey,
-                    mCurrentBucketNum - anomalyTracker.getNumOfPastBuckets() + futureBucketIdx);
-        } else if (futureBucketIdx == anomalyTracker.getNumOfPastBuckets()) {
-            pastNs -= (currentStateBucketPastNs + (currentBucketEndNs - eventTimestampNs));
-        }
-    }
-
-    return std::max(eventTimestampNs + thresholdNs, refractoryPeriodEndNs);
-}
-
-void OringDurationTracker::dumpStates(FILE* out, bool verbose) const {
-    fprintf(out, "\t\t started count %lu\n", (unsigned long)mStarted.size());
-    fprintf(out, "\t\t paused count %lu\n", (unsigned long)mPaused.size());
-    fprintf(out, "\t\t current duration %lld\n", (long long)getCurrentStateKeyDuration());
-}
-
-int64_t OringDurationTracker::getCurrentStateKeyDuration() const {
-    auto it = mStateKeyDurationMap.find(mEventKey.getStateValuesKey());
-    if (it == mStateKeyDurationMap.end()) {
-        return 0;
-    } else {
-        return it->second.mDuration;
-    }
-}
-
-int64_t OringDurationTracker::getCurrentStateKeyFullBucketDuration() const {
-    auto it = mStateKeyDurationMap.find(mEventKey.getStateValuesKey());
-    if (it == mStateKeyDurationMap.end()) {
-        return 0;
-    } else {
-        return it->second.mDurationFullBucket;
-    }
-}
-
-void OringDurationTracker::updateCurrentStateKey(const int32_t atomId, const FieldValue& newState) {
-    HashableDimensionKey* stateValuesKey = mEventKey.getMutableStateValuesKey();
-    for (size_t i = 0; i < stateValuesKey->getValues().size(); i++) {
-        if (stateValuesKey->getValues()[i].mField.getTag() == atomId) {
-            stateValuesKey->mutableValue(i)->mValue = newState.mValue;
-        }
-    }
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
deleted file mode 100644
index 6eddee7..0000000
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ORING_DURATION_TRACKER_H
-#define ORING_DURATION_TRACKER_H
-
-#include "DurationTracker.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// Tracks the "Or'd" duration -- if 2 durations are overlapping, they won't be double counted.
-class OringDurationTracker : public DurationTracker {
-public:
-    OringDurationTracker(const ConfigKey& key, const int64_t& id,
-                         const MetricDimensionKey& eventKey, sp<ConditionWizard> wizard,
-                         int conditionIndex, bool nesting, int64_t currentBucketStartNs,
-                         int64_t currentBucketNum, int64_t startTimeNs, int64_t bucketSizeNs,
-                         bool conditionSliced, bool fullLink,
-                         const std::vector<sp<AnomalyTracker>>& anomalyTrackers);
-
-    OringDurationTracker(const OringDurationTracker& tracker) = default;
-
-    void noteStart(const HashableDimensionKey& key, bool condition, const int64_t eventTime,
-                   const ConditionKey& conditionKey) override;
-    void noteStop(const HashableDimensionKey& key, const int64_t eventTime,
-                  const bool stopAll) override;
-    void noteStopAll(const int64_t eventTime) override;
-
-    void onSlicedConditionMayChange(bool overallCondition, const int64_t timestamp) override;
-    void onConditionChanged(bool condition, const int64_t timestamp) override;
-
-    void onStateChanged(const int64_t timestamp, const int32_t atomId,
-                        const FieldValue& newState) override;
-
-    bool flushCurrentBucket(
-            const int64_t& eventTimeNs,
-            std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) override;
-    bool flushIfNeeded(
-            int64_t timestampNs,
-            std::unordered_map<MetricDimensionKey, std::vector<DurationBucket>>* output) override;
-
-    int64_t predictAnomalyTimestampNs(const AnomalyTracker& anomalyTracker,
-                                      const int64_t currentTimestamp) const override;
-    void dumpStates(FILE* out, bool verbose) const override;
-
-    int64_t getCurrentStateKeyDuration() const override;
-
-    int64_t getCurrentStateKeyFullBucketDuration() const override;
-
-    void updateCurrentStateKey(const int32_t atomId, const FieldValue& newState);
-
-private:
-    // We don't need to keep track of individual durations. The information that's needed is:
-    // 1) which keys are started. We record the first start time.
-    // 2) which keys are paused (started but condition was false)
-    // 3) whenever a key stops, we remove it from the started set. And if the set becomes empty,
-    //    it means everything has stopped, we then record the end time.
-    std::unordered_map<HashableDimensionKey, int> mStarted;
-    std::unordered_map<HashableDimensionKey, int> mPaused;
-    int64_t mLastStartTime;
-    std::unordered_map<HashableDimensionKey, ConditionKey> mConditionKeyMap;
-
-    // return true if we should not allow newKey to be tracked because we are above the threshold
-    bool hitGuardRail(const HashableDimensionKey& newKey);
-
-    FRIEND_TEST(OringDurationTrackerTest, TestDurationOverlap);
-    FRIEND_TEST(OringDurationTrackerTest, TestCrossBucketBoundary);
-    FRIEND_TEST(OringDurationTrackerTest, TestDurationConditionChange);
-    FRIEND_TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp);
-    FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm);
-    FRIEND_TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-#endif  // ORING_DURATION_TRACKER_H
diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
deleted file mode 100644
index 39789cd..0000000
--- a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
+++ /dev/null
@@ -1,1118 +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.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "config_update_utils.h"
-
-#include "external/StatsPullerManager.h"
-#include "hash.h"
-#include "matchers/EventMatcherWizard.h"
-#include "metrics_manager_util.h"
-
-using google::protobuf::MessageLite;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// Recursive function to determine if a matcher needs to be updated. Populates matcherToUpdate.
-// Returns whether the function was successful or not.
-bool determineMatcherUpdateStatus(const StatsdConfig& config, const int matcherIdx,
-                                  const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
-                                  const vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers,
-                                  const unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
-                                  vector<UpdateStatus>& matchersToUpdate,
-                                  vector<bool>& cycleTracker) {
-    // Have already examined this matcher.
-    if (matchersToUpdate[matcherIdx] != UPDATE_UNKNOWN) {
-        return true;
-    }
-
-    const AtomMatcher& matcher = config.atom_matcher(matcherIdx);
-    int64_t id = matcher.id();
-    // Check if new matcher.
-    const auto& oldAtomMatchingTrackerIt = oldAtomMatchingTrackerMap.find(id);
-    if (oldAtomMatchingTrackerIt == oldAtomMatchingTrackerMap.end()) {
-        matchersToUpdate[matcherIdx] = UPDATE_NEW;
-        return true;
-    }
-
-    // This is an existing matcher. Check if it has changed.
-    string serializedMatcher;
-    if (!matcher.SerializeToString(&serializedMatcher)) {
-        ALOGE("Unable to serialize matcher %lld", (long long)id);
-        return false;
-    }
-    uint64_t newProtoHash = Hash64(serializedMatcher);
-    if (newProtoHash != oldAtomMatchingTrackers[oldAtomMatchingTrackerIt->second]->getProtoHash()) {
-        matchersToUpdate[matcherIdx] = UPDATE_REPLACE;
-        return true;
-    }
-
-    switch (matcher.contents_case()) {
-        case AtomMatcher::ContentsCase::kSimpleAtomMatcher: {
-            matchersToUpdate[matcherIdx] = UPDATE_PRESERVE;
-            return true;
-        }
-        case AtomMatcher::ContentsCase::kCombination: {
-            // Recurse to check if children have changed.
-            cycleTracker[matcherIdx] = true;
-            UpdateStatus status = UPDATE_PRESERVE;
-            for (const int64_t childMatcherId : matcher.combination().matcher()) {
-                const auto& childIt = newAtomMatchingTrackerMap.find(childMatcherId);
-                if (childIt == newAtomMatchingTrackerMap.end()) {
-                    ALOGW("Matcher %lld not found in the config", (long long)childMatcherId);
-                    return false;
-                }
-                const int childIdx = childIt->second;
-                if (cycleTracker[childIdx]) {
-                    ALOGE("Cycle detected in matcher config");
-                    return false;
-                }
-                if (!determineMatcherUpdateStatus(
-                            config, childIdx, oldAtomMatchingTrackerMap, oldAtomMatchingTrackers,
-                            newAtomMatchingTrackerMap, matchersToUpdate, cycleTracker)) {
-                    return false;
-                }
-
-                if (matchersToUpdate[childIdx] == UPDATE_REPLACE) {
-                    status = UPDATE_REPLACE;
-                    break;
-                }
-            }
-            matchersToUpdate[matcherIdx] = status;
-            cycleTracker[matcherIdx] = false;
-            return true;
-        }
-        default: {
-            ALOGE("Matcher \"%lld\" malformed", (long long)id);
-            return false;
-        }
-    }
-    return true;
-}
-
-bool updateAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap,
-                                const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
-                                const vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers,
-                                set<int>& allTagIds,
-                                unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
-                                vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers,
-                                set<int64_t>& replacedMatchers) {
-    const int atomMatcherCount = config.atom_matcher_size();
-    vector<AtomMatcher> matcherProtos;
-    matcherProtos.reserve(atomMatcherCount);
-    newAtomMatchingTrackers.reserve(atomMatcherCount);
-
-    // Maps matcher id to their position in the config. For fast lookup of dependencies.
-    for (int i = 0; i < atomMatcherCount; i++) {
-        const AtomMatcher& matcher = config.atom_matcher(i);
-        if (newAtomMatchingTrackerMap.find(matcher.id()) != newAtomMatchingTrackerMap.end()) {
-            ALOGE("Duplicate atom matcher found for id %lld", (long long)matcher.id());
-            return false;
-        }
-        newAtomMatchingTrackerMap[matcher.id()] = i;
-        matcherProtos.push_back(matcher);
-    }
-
-    // For combination matchers, we need to determine if any children need to be updated.
-    vector<UpdateStatus> matchersToUpdate(atomMatcherCount, UPDATE_UNKNOWN);
-    vector<bool> cycleTracker(atomMatcherCount, false);
-    for (int i = 0; i < atomMatcherCount; i++) {
-        if (!determineMatcherUpdateStatus(config, i, oldAtomMatchingTrackerMap,
-                                          oldAtomMatchingTrackers, newAtomMatchingTrackerMap,
-                                          matchersToUpdate, cycleTracker)) {
-            return false;
-        }
-    }
-
-    for (int i = 0; i < atomMatcherCount; i++) {
-        const AtomMatcher& matcher = config.atom_matcher(i);
-        const int64_t id = matcher.id();
-        switch (matchersToUpdate[i]) {
-            case UPDATE_PRESERVE: {
-                const auto& oldAtomMatchingTrackerIt = oldAtomMatchingTrackerMap.find(id);
-                if (oldAtomMatchingTrackerIt == oldAtomMatchingTrackerMap.end()) {
-                    ALOGE("Could not find AtomMatcher %lld in the previous config, but expected it "
-                          "to be there",
-                          (long long)id);
-                    return false;
-                }
-                const sp<AtomMatchingTracker>& tracker =
-                        oldAtomMatchingTrackers[oldAtomMatchingTrackerIt->second];
-                if (!tracker->onConfigUpdated(matcherProtos[i], i, newAtomMatchingTrackerMap)) {
-                    ALOGW("Config update failed for matcher %lld", (long long)id);
-                    return false;
-                }
-                newAtomMatchingTrackers.push_back(tracker);
-                break;
-            }
-            case UPDATE_REPLACE:
-                replacedMatchers.insert(id);
-                [[fallthrough]];  // Intentionally fallthrough to create the new matcher.
-            case UPDATE_NEW: {
-                sp<AtomMatchingTracker> tracker = createAtomMatchingTracker(matcher, i, uidMap);
-                if (tracker == nullptr) {
-                    return false;
-                }
-                newAtomMatchingTrackers.push_back(tracker);
-                break;
-            }
-            default: {
-                ALOGE("Matcher \"%lld\" update state is unknown. This should never happen",
-                      (long long)id);
-                return false;
-            }
-        }
-    }
-
-    std::fill(cycleTracker.begin(), cycleTracker.end(), false);
-    for (auto& matcher : newAtomMatchingTrackers) {
-        if (!matcher->init(matcherProtos, newAtomMatchingTrackers, newAtomMatchingTrackerMap,
-                           cycleTracker)) {
-            return false;
-        }
-        // Collect all the tag ids that are interesting. TagIds exist in leaf nodes only.
-        const set<int>& tagIds = matcher->getAtomIds();
-        allTagIds.insert(tagIds.begin(), tagIds.end());
-    }
-
-    return true;
-}
-
-// Recursive function to determine if a condition needs to be updated. Populates conditionsToUpdate.
-// Returns whether the function was successful or not.
-bool determineConditionUpdateStatus(const StatsdConfig& config, const int conditionIdx,
-                                    const unordered_map<int64_t, int>& oldConditionTrackerMap,
-                                    const vector<sp<ConditionTracker>>& oldConditionTrackers,
-                                    const unordered_map<int64_t, int>& newConditionTrackerMap,
-                                    const set<int64_t>& replacedMatchers,
-                                    vector<UpdateStatus>& conditionsToUpdate,
-                                    vector<bool>& cycleTracker) {
-    // Have already examined this condition.
-    if (conditionsToUpdate[conditionIdx] != UPDATE_UNKNOWN) {
-        return true;
-    }
-
-    const Predicate& predicate = config.predicate(conditionIdx);
-    int64_t id = predicate.id();
-    // Check if new condition.
-    const auto& oldConditionTrackerIt = oldConditionTrackerMap.find(id);
-    if (oldConditionTrackerIt == oldConditionTrackerMap.end()) {
-        conditionsToUpdate[conditionIdx] = UPDATE_NEW;
-        return true;
-    }
-
-    // This is an existing condition. Check if it has changed.
-    string serializedCondition;
-    if (!predicate.SerializeToString(&serializedCondition)) {
-        ALOGE("Unable to serialize matcher %lld", (long long)id);
-        return false;
-    }
-    uint64_t newProtoHash = Hash64(serializedCondition);
-    if (newProtoHash != oldConditionTrackers[oldConditionTrackerIt->second]->getProtoHash()) {
-        conditionsToUpdate[conditionIdx] = UPDATE_REPLACE;
-        return true;
-    }
-
-    switch (predicate.contents_case()) {
-        case Predicate::ContentsCase::kSimplePredicate: {
-            // Need to check if any of the underlying matchers changed.
-            const SimplePredicate& simplePredicate = predicate.simple_predicate();
-            if (simplePredicate.has_start()) {
-                if (replacedMatchers.find(simplePredicate.start()) != replacedMatchers.end()) {
-                    conditionsToUpdate[conditionIdx] = UPDATE_REPLACE;
-                    return true;
-                }
-            }
-            if (simplePredicate.has_stop()) {
-                if (replacedMatchers.find(simplePredicate.stop()) != replacedMatchers.end()) {
-                    conditionsToUpdate[conditionIdx] = UPDATE_REPLACE;
-                    return true;
-                }
-            }
-            if (simplePredicate.has_stop_all()) {
-                if (replacedMatchers.find(simplePredicate.stop_all()) != replacedMatchers.end()) {
-                    conditionsToUpdate[conditionIdx] = UPDATE_REPLACE;
-                    return true;
-                }
-            }
-            conditionsToUpdate[conditionIdx] = UPDATE_PRESERVE;
-            return true;
-        }
-        case Predicate::ContentsCase::kCombination: {
-            // Need to recurse on the children to see if any of the child predicates changed.
-            cycleTracker[conditionIdx] = true;
-            UpdateStatus status = UPDATE_PRESERVE;
-            for (const int64_t childPredicateId : predicate.combination().predicate()) {
-                const auto& childIt = newConditionTrackerMap.find(childPredicateId);
-                if (childIt == newConditionTrackerMap.end()) {
-                    ALOGW("Predicate %lld not found in the config", (long long)childPredicateId);
-                    return false;
-                }
-                const int childIdx = childIt->second;
-                if (cycleTracker[childIdx]) {
-                    ALOGE("Cycle detected in predicate config");
-                    return false;
-                }
-                if (!determineConditionUpdateStatus(config, childIdx, oldConditionTrackerMap,
-                                                    oldConditionTrackers, newConditionTrackerMap,
-                                                    replacedMatchers, conditionsToUpdate,
-                                                    cycleTracker)) {
-                    return false;
-                }
-
-                if (conditionsToUpdate[childIdx] == UPDATE_REPLACE) {
-                    status = UPDATE_REPLACE;
-                    break;
-                }
-            }
-            conditionsToUpdate[conditionIdx] = status;
-            cycleTracker[conditionIdx] = false;
-            return true;
-        }
-        default: {
-            ALOGE("Predicate \"%lld\" malformed", (long long)id);
-            return false;
-        }
-    }
-
-    return true;
-}
-
-bool updateConditions(const ConfigKey& key, const StatsdConfig& config,
-                      const unordered_map<int64_t, int>& atomMatchingTrackerMap,
-                      const set<int64_t>& replacedMatchers,
-                      const unordered_map<int64_t, int>& oldConditionTrackerMap,
-                      const vector<sp<ConditionTracker>>& oldConditionTrackers,
-                      unordered_map<int64_t, int>& newConditionTrackerMap,
-                      vector<sp<ConditionTracker>>& newConditionTrackers,
-                      unordered_map<int, vector<int>>& trackerToConditionMap,
-                      vector<ConditionState>& conditionCache, set<int64_t>& replacedConditions) {
-    vector<Predicate> conditionProtos;
-    const int conditionTrackerCount = config.predicate_size();
-    conditionProtos.reserve(conditionTrackerCount);
-    newConditionTrackers.reserve(conditionTrackerCount);
-    conditionCache.assign(conditionTrackerCount, ConditionState::kNotEvaluated);
-
-    for (int i = 0; i < conditionTrackerCount; i++) {
-        const Predicate& condition = config.predicate(i);
-        if (newConditionTrackerMap.find(condition.id()) != newConditionTrackerMap.end()) {
-            ALOGE("Duplicate Predicate found!");
-            return false;
-        }
-        newConditionTrackerMap[condition.id()] = i;
-        conditionProtos.push_back(condition);
-    }
-
-    vector<UpdateStatus> conditionsToUpdate(conditionTrackerCount, UPDATE_UNKNOWN);
-    vector<bool> cycleTracker(conditionTrackerCount, false);
-    for (int i = 0; i < conditionTrackerCount; i++) {
-        if (!determineConditionUpdateStatus(config, i, oldConditionTrackerMap, oldConditionTrackers,
-                                            newConditionTrackerMap, replacedMatchers,
-                                            conditionsToUpdate, cycleTracker)) {
-            return false;
-        }
-    }
-
-    // Update status has been determined for all conditions. Now perform the update.
-    set<int> preservedConditions;
-    for (int i = 0; i < conditionTrackerCount; i++) {
-        const Predicate& predicate = config.predicate(i);
-        const int64_t id = predicate.id();
-        switch (conditionsToUpdate[i]) {
-            case UPDATE_PRESERVE: {
-                preservedConditions.insert(i);
-                const auto& oldConditionTrackerIt = oldConditionTrackerMap.find(id);
-                if (oldConditionTrackerIt == oldConditionTrackerMap.end()) {
-                    ALOGE("Could not find Predicate %lld in the previous config, but expected it "
-                          "to be there",
-                          (long long)id);
-                    return false;
-                }
-                const int oldIndex = oldConditionTrackerIt->second;
-                newConditionTrackers.push_back(oldConditionTrackers[oldIndex]);
-                break;
-            }
-            case UPDATE_REPLACE:
-                replacedConditions.insert(id);
-                [[fallthrough]];  // Intentionally fallthrough to create the new condition tracker.
-            case UPDATE_NEW: {
-                sp<ConditionTracker> tracker =
-                        createConditionTracker(key, predicate, i, atomMatchingTrackerMap);
-                if (tracker == nullptr) {
-                    return false;
-                }
-                newConditionTrackers.push_back(tracker);
-                break;
-            }
-            default: {
-                ALOGE("Condition \"%lld\" update state is unknown. This should never happen",
-                      (long long)id);
-                return false;
-            }
-        }
-    }
-
-    // Update indices of preserved predicates.
-    for (const int conditionIndex : preservedConditions) {
-        if (!newConditionTrackers[conditionIndex]->onConfigUpdated(
-                    conditionProtos, conditionIndex, newConditionTrackers, atomMatchingTrackerMap,
-                    newConditionTrackerMap)) {
-            ALOGE("Failed to update condition %lld",
-                  (long long)newConditionTrackers[conditionIndex]->getConditionId());
-            return false;
-        }
-    }
-
-    std::fill(cycleTracker.begin(), cycleTracker.end(), false);
-    for (int conditionIndex = 0; conditionIndex < conditionTrackerCount; conditionIndex++) {
-        const sp<ConditionTracker>& conditionTracker = newConditionTrackers[conditionIndex];
-        // Calling init on preserved conditions is OK. It is needed to fill the condition cache.
-        if (!conditionTracker->init(conditionProtos, newConditionTrackers, newConditionTrackerMap,
-                                    cycleTracker, conditionCache)) {
-            return false;
-        }
-        for (const int trackerIndex : conditionTracker->getAtomMatchingTrackerIndex()) {
-            vector<int>& conditionList = trackerToConditionMap[trackerIndex];
-            conditionList.push_back(conditionIndex);
-        }
-    }
-    return true;
-}
-
-bool updateStates(const StatsdConfig& config, const map<int64_t, uint64_t>& oldStateProtoHashes,
-                  unordered_map<int64_t, int>& stateAtomIdMap,
-                  unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
-                  map<int64_t, uint64_t>& newStateProtoHashes, set<int64_t>& replacedStates) {
-    // Share with metrics_manager_util.
-    if (!initStates(config, stateAtomIdMap, allStateGroupMaps, newStateProtoHashes)) {
-        return false;
-    }
-
-    for (const auto& [stateId, stateHash] : oldStateProtoHashes) {
-        const auto& it = newStateProtoHashes.find(stateId);
-        if (it != newStateProtoHashes.end() && it->second != stateHash) {
-            replacedStates.insert(stateId);
-        }
-    }
-    return true;
-}
-// Returns true if any matchers in the metric activation were replaced.
-bool metricActivationDepsChange(const StatsdConfig& config,
-                                const unordered_map<int64_t, int>& metricToActivationMap,
-                                const int64_t metricId, const set<int64_t>& replacedMatchers) {
-    const auto& metricActivationIt = metricToActivationMap.find(metricId);
-    if (metricActivationIt == metricToActivationMap.end()) {
-        return false;
-    }
-    const MetricActivation& metricActivation = config.metric_activation(metricActivationIt->second);
-    for (int i = 0; i < metricActivation.event_activation_size(); i++) {
-        const EventActivation& activation = metricActivation.event_activation(i);
-        if (replacedMatchers.find(activation.atom_matcher_id()) != replacedMatchers.end()) {
-            return true;
-        }
-        if (activation.has_deactivation_atom_matcher_id()) {
-            if (replacedMatchers.find(activation.deactivation_atom_matcher_id()) !=
-                replacedMatchers.end()) {
-                return true;
-            }
-        }
-    }
-    return false;
-}
-
-bool determineMetricUpdateStatus(
-        const StatsdConfig& config, const MessageLite& metric, const int64_t metricId,
-        const MetricType metricType, const set<int64_t>& matcherDependencies,
-        const set<int64_t>& conditionDependencies,
-        const ::google::protobuf::RepeatedField<int64_t>& stateDependencies,
-        const ::google::protobuf::RepeatedPtrField<MetricConditionLink>& conditionLinks,
-        const unordered_map<int64_t, int>& oldMetricProducerMap,
-        const vector<sp<MetricProducer>>& oldMetricProducers,
-        const unordered_map<int64_t, int>& metricToActivationMap,
-        const set<int64_t>& replacedMatchers, const set<int64_t>& replacedConditions,
-        const set<int64_t>& replacedStates, UpdateStatus& updateStatus) {
-    // Check if new metric
-    const auto& oldMetricProducerIt = oldMetricProducerMap.find(metricId);
-    if (oldMetricProducerIt == oldMetricProducerMap.end()) {
-        updateStatus = UPDATE_NEW;
-        return true;
-    }
-
-    // This is an existing metric, check if it has changed.
-    uint64_t metricHash;
-    if (!getMetricProtoHash(config, metric, metricId, metricToActivationMap, metricHash)) {
-        return false;
-    }
-    const sp<MetricProducer> oldMetricProducer = oldMetricProducers[oldMetricProducerIt->second];
-    if (oldMetricProducer->getMetricType() != metricType ||
-        oldMetricProducer->getProtoHash() != metricHash) {
-        updateStatus = UPDATE_REPLACE;
-        return true;
-    }
-
-    // Take intersections of the matchers/predicates/states that the metric
-    // depends on with those that have been replaced. If a metric depends on any
-    // replaced component, it too must be replaced.
-    set<int64_t> intersection;
-    set_intersection(matcherDependencies.begin(), matcherDependencies.end(),
-                     replacedMatchers.begin(), replacedMatchers.end(),
-                     inserter(intersection, intersection.begin()));
-    if (intersection.size() > 0) {
-        updateStatus = UPDATE_REPLACE;
-        return true;
-    }
-    set_intersection(conditionDependencies.begin(), conditionDependencies.end(),
-                     replacedConditions.begin(), replacedConditions.end(),
-                     inserter(intersection, intersection.begin()));
-    if (intersection.size() > 0) {
-        updateStatus = UPDATE_REPLACE;
-        return true;
-    }
-    set_intersection(stateDependencies.begin(), stateDependencies.end(), replacedStates.begin(),
-                     replacedStates.end(), inserter(intersection, intersection.begin()));
-    if (intersection.size() > 0) {
-        updateStatus = UPDATE_REPLACE;
-        return true;
-    }
-
-    for (const auto& metricConditionLink : conditionLinks) {
-        if (replacedConditions.find(metricConditionLink.condition()) != replacedConditions.end()) {
-            updateStatus = UPDATE_REPLACE;
-            return true;
-        }
-    }
-
-    if (metricActivationDepsChange(config, metricToActivationMap, metricId, replacedMatchers)) {
-        updateStatus = UPDATE_REPLACE;
-        return true;
-    }
-
-    updateStatus = UPDATE_PRESERVE;
-    return true;
-}
-
-bool determineAllMetricUpdateStatuses(const StatsdConfig& config,
-                                      const unordered_map<int64_t, int>& oldMetricProducerMap,
-                                      const vector<sp<MetricProducer>>& oldMetricProducers,
-                                      const unordered_map<int64_t, int>& metricToActivationMap,
-                                      const set<int64_t>& replacedMatchers,
-                                      const set<int64_t>& replacedConditions,
-                                      const set<int64_t>& replacedStates,
-                                      vector<UpdateStatus>& metricsToUpdate) {
-    int metricIndex = 0;
-    for (int i = 0; i < config.count_metric_size(); i++, metricIndex++) {
-        const CountMetric& metric = config.count_metric(i);
-        set<int64_t> conditionDependencies;
-        if (metric.has_condition()) {
-            conditionDependencies.insert(metric.condition());
-        }
-        if (!determineMetricUpdateStatus(
-                    config, metric, metric.id(), METRIC_TYPE_COUNT, {metric.what()},
-                    conditionDependencies, metric.slice_by_state(), metric.links(),
-                    oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
-                    replacedMatchers, replacedConditions, replacedStates,
-                    metricsToUpdate[metricIndex])) {
-            return false;
-        }
-    }
-    for (int i = 0; i < config.duration_metric_size(); i++, metricIndex++) {
-        const DurationMetric& metric = config.duration_metric(i);
-        set<int64_t> conditionDependencies({metric.what()});
-        if (metric.has_condition()) {
-            conditionDependencies.insert(metric.condition());
-        }
-        if (!determineMetricUpdateStatus(
-                    config, metric, metric.id(), METRIC_TYPE_DURATION, /*matcherDependencies=*/{},
-                    conditionDependencies, metric.slice_by_state(), metric.links(),
-                    oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
-                    replacedMatchers, replacedConditions, replacedStates,
-                    metricsToUpdate[metricIndex])) {
-            return false;
-        }
-    }
-    for (int i = 0; i < config.event_metric_size(); i++, metricIndex++) {
-        const EventMetric& metric = config.event_metric(i);
-        set<int64_t> conditionDependencies;
-        if (metric.has_condition()) {
-            conditionDependencies.insert(metric.condition());
-        }
-        if (!determineMetricUpdateStatus(
-                    config, metric, metric.id(), METRIC_TYPE_EVENT, {metric.what()},
-                    conditionDependencies, ::google::protobuf::RepeatedField<int64_t>(),
-                    metric.links(), oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
-                    replacedMatchers, replacedConditions, replacedStates,
-                    metricsToUpdate[metricIndex])) {
-            return false;
-        }
-    }
-    for (int i = 0; i < config.value_metric_size(); i++, metricIndex++) {
-        const ValueMetric& metric = config.value_metric(i);
-        set<int64_t> conditionDependencies;
-        if (metric.has_condition()) {
-            conditionDependencies.insert(metric.condition());
-        }
-        if (!determineMetricUpdateStatus(
-                    config, metric, metric.id(), METRIC_TYPE_VALUE, {metric.what()},
-                    conditionDependencies, metric.slice_by_state(), metric.links(),
-                    oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
-                    replacedMatchers, replacedConditions, replacedStates,
-                    metricsToUpdate[metricIndex])) {
-            return false;
-        }
-    }
-    for (int i = 0; i < config.gauge_metric_size(); i++, metricIndex++) {
-        const GaugeMetric& metric = config.gauge_metric(i);
-        set<int64_t> conditionDependencies;
-        if (metric.has_condition()) {
-            conditionDependencies.insert(metric.condition());
-        }
-        set<int64_t> matcherDependencies({metric.what()});
-        if (metric.has_trigger_event()) {
-            matcherDependencies.insert(metric.trigger_event());
-        }
-        if (!determineMetricUpdateStatus(
-                    config, metric, metric.id(), METRIC_TYPE_GAUGE, matcherDependencies,
-                    conditionDependencies, ::google::protobuf::RepeatedField<int64_t>(),
-                    metric.links(), oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
-                    replacedMatchers, replacedConditions, replacedStates,
-                    metricsToUpdate[metricIndex])) {
-            return false;
-        }
-    }
-    return true;
-}
-
-// Called when a metric is preserved during a config update. Finds the metric in oldMetricProducers
-// and calls onConfigUpdated to update all indices.
-optional<sp<MetricProducer>> updateMetric(
-        const StatsdConfig& config, const int configIndex, const int metricIndex,
-        const int64_t metricId, const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-        const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
-        const unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
-        const sp<EventMatcherWizard>& matcherWizard,
-        const vector<sp<ConditionTracker>>& allConditionTrackers,
-        const unordered_map<int64_t, int>& conditionTrackerMap, const sp<ConditionWizard>& wizard,
-        const unordered_map<int64_t, int>& oldMetricProducerMap,
-        const vector<sp<MetricProducer>>& oldMetricProducers,
-        const unordered_map<int64_t, int>& metricToActivationMap,
-        unordered_map<int, vector<int>>& trackerToMetricMap,
-        unordered_map<int, vector<int>>& conditionToMetricMap,
-        unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
-        unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
-        vector<int>& metricsWithActivation) {
-    const auto& oldMetricProducerIt = oldMetricProducerMap.find(metricId);
-    if (oldMetricProducerIt == oldMetricProducerMap.end()) {
-        ALOGE("Could not find Metric %lld in the previous config, but expected it "
-              "to be there",
-              (long long)metricId);
-        return nullopt;
-    }
-    const int oldIndex = oldMetricProducerIt->second;
-    sp<MetricProducer> producer = oldMetricProducers[oldIndex];
-    if (!producer->onConfigUpdated(config, configIndex, metricIndex, allAtomMatchingTrackers,
-                                   oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap,
-                                   matcherWizard, allConditionTrackers, conditionTrackerMap, wizard,
-                                   metricToActivationMap, trackerToMetricMap, conditionToMetricMap,
-                                   activationAtomTrackerToMetricMap,
-                                   deactivationAtomTrackerToMetricMap, metricsWithActivation)) {
-        return nullopt;
-    }
-    return {producer};
-}
-
-bool updateMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
-                   const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
-                   const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
-                   const unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
-                   const set<int64_t>& replacedMatchers,
-                   const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-                   const unordered_map<int64_t, int>& conditionTrackerMap,
-                   const set<int64_t>& replacedConditions,
-                   vector<sp<ConditionTracker>>& allConditionTrackers,
-                   const vector<ConditionState>& initialConditionCache,
-                   const unordered_map<int64_t, int>& stateAtomIdMap,
-                   const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
-                   const set<int64_t>& replacedStates,
-                   const unordered_map<int64_t, int>& oldMetricProducerMap,
-                   const vector<sp<MetricProducer>>& oldMetricProducers,
-                   unordered_map<int64_t, int>& newMetricProducerMap,
-                   vector<sp<MetricProducer>>& newMetricProducers,
-                   unordered_map<int, vector<int>>& conditionToMetricMap,
-                   unordered_map<int, vector<int>>& trackerToMetricMap,
-                   set<int64_t>& noReportMetricIds,
-                   unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
-                   unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
-                   vector<int>& metricsWithActivation, set<int64_t>& replacedMetrics) {
-    sp<ConditionWizard> wizard = new ConditionWizard(allConditionTrackers);
-    sp<EventMatcherWizard> matcherWizard = new EventMatcherWizard(allAtomMatchingTrackers);
-    const int allMetricsCount = config.count_metric_size() + config.duration_metric_size() +
-                                config.event_metric_size() + config.gauge_metric_size() +
-                                config.value_metric_size();
-    newMetricProducers.reserve(allMetricsCount);
-
-    // Construct map from metric id to metric activation index. The map will be used to determine
-    // the metric activation corresponding to a metric.
-    unordered_map<int64_t, int> metricToActivationMap;
-    for (int i = 0; i < config.metric_activation_size(); i++) {
-        const MetricActivation& metricActivation = config.metric_activation(i);
-        int64_t metricId = metricActivation.metric_id();
-        if (metricToActivationMap.find(metricId) != metricToActivationMap.end()) {
-            ALOGE("Metric %lld has multiple MetricActivations", (long long)metricId);
-            return false;
-        }
-        metricToActivationMap.insert({metricId, i});
-    }
-
-    vector<UpdateStatus> metricsToUpdate(allMetricsCount, UPDATE_UNKNOWN);
-    if (!determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
-                                          metricToActivationMap, replacedMatchers,
-                                          replacedConditions, replacedStates, metricsToUpdate)) {
-        return false;
-    }
-
-    // Now, perform the update. Must iterate the metric types in the same order
-    int metricIndex = 0;
-    for (int i = 0; i < config.count_metric_size(); i++, metricIndex++) {
-        const CountMetric& metric = config.count_metric(i);
-        newMetricProducerMap[metric.id()] = metricIndex;
-        optional<sp<MetricProducer>> producer;
-        switch (metricsToUpdate[metricIndex]) {
-            case UPDATE_PRESERVE: {
-                producer = updateMetric(
-                        config, i, metricIndex, metric.id(), allAtomMatchingTrackers,
-                        oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, matcherWizard,
-                        allConditionTrackers, conditionTrackerMap, wizard, oldMetricProducerMap,
-                        oldMetricProducers, metricToActivationMap, trackerToMetricMap,
-                        conditionToMetricMap, activationAtomTrackerToMetricMap,
-                        deactivationAtomTrackerToMetricMap, metricsWithActivation);
-                break;
-            }
-            case UPDATE_REPLACE:
-                replacedMetrics.insert(metric.id());
-                [[fallthrough]];  // Intentionally fallthrough to create the new metric producer.
-            case UPDATE_NEW: {
-                producer = createCountMetricProducerAndUpdateMetadata(
-                        key, config, timeBaseNs, currentTimeNs, metric, metricIndex,
-                        allAtomMatchingTrackers, newAtomMatchingTrackerMap, allConditionTrackers,
-                        conditionTrackerMap, initialConditionCache, wizard, stateAtomIdMap,
-                        allStateGroupMaps, metricToActivationMap, trackerToMetricMap,
-                        conditionToMetricMap, activationAtomTrackerToMetricMap,
-                        deactivationAtomTrackerToMetricMap, metricsWithActivation);
-                break;
-            }
-            default: {
-                ALOGE("Metric \"%lld\" update state is unknown. This should never happen",
-                      (long long)metric.id());
-                return false;
-            }
-        }
-        if (!producer) {
-            return false;
-        }
-        newMetricProducers.push_back(producer.value());
-    }
-    for (int i = 0; i < config.duration_metric_size(); i++, metricIndex++) {
-        const DurationMetric& metric = config.duration_metric(i);
-        newMetricProducerMap[metric.id()] = metricIndex;
-        optional<sp<MetricProducer>> producer;
-        switch (metricsToUpdate[metricIndex]) {
-            case UPDATE_PRESERVE: {
-                producer = updateMetric(
-                        config, i, metricIndex, metric.id(), allAtomMatchingTrackers,
-                        oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, matcherWizard,
-                        allConditionTrackers, conditionTrackerMap, wizard, oldMetricProducerMap,
-                        oldMetricProducers, metricToActivationMap, trackerToMetricMap,
-                        conditionToMetricMap, activationAtomTrackerToMetricMap,
-                        deactivationAtomTrackerToMetricMap, metricsWithActivation);
-                break;
-            }
-            case UPDATE_REPLACE:
-                replacedMetrics.insert(metric.id());
-                [[fallthrough]];  // Intentionally fallthrough to create the new metric producer.
-            case UPDATE_NEW: {
-                producer = createDurationMetricProducerAndUpdateMetadata(
-                        key, config, timeBaseNs, currentTimeNs, metric, metricIndex,
-                        allAtomMatchingTrackers, newAtomMatchingTrackerMap, allConditionTrackers,
-                        conditionTrackerMap, initialConditionCache, wizard, stateAtomIdMap,
-                        allStateGroupMaps, metricToActivationMap, trackerToMetricMap,
-                        conditionToMetricMap, activationAtomTrackerToMetricMap,
-                        deactivationAtomTrackerToMetricMap, metricsWithActivation);
-                break;
-            }
-            default: {
-                ALOGE("Metric \"%lld\" update state is unknown. This should never happen",
-                      (long long)metric.id());
-                return false;
-            }
-        }
-        if (!producer) {
-            return false;
-        }
-        newMetricProducers.push_back(producer.value());
-    }
-    for (int i = 0; i < config.event_metric_size(); i++, metricIndex++) {
-        const EventMetric& metric = config.event_metric(i);
-        newMetricProducerMap[metric.id()] = metricIndex;
-        optional<sp<MetricProducer>> producer;
-        switch (metricsToUpdate[metricIndex]) {
-            case UPDATE_PRESERVE: {
-                producer = updateMetric(
-                        config, i, metricIndex, metric.id(), allAtomMatchingTrackers,
-                        oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, matcherWizard,
-                        allConditionTrackers, conditionTrackerMap, wizard, oldMetricProducerMap,
-                        oldMetricProducers, metricToActivationMap, trackerToMetricMap,
-                        conditionToMetricMap, activationAtomTrackerToMetricMap,
-                        deactivationAtomTrackerToMetricMap, metricsWithActivation);
-                break;
-            }
-            case UPDATE_REPLACE:
-                replacedMetrics.insert(metric.id());
-                [[fallthrough]];  // Intentionally fallthrough to create the new metric producer.
-            case UPDATE_NEW: {
-                producer = createEventMetricProducerAndUpdateMetadata(
-                        key, config, timeBaseNs, metric, metricIndex, allAtomMatchingTrackers,
-                        newAtomMatchingTrackerMap, allConditionTrackers, conditionTrackerMap,
-                        initialConditionCache, wizard, metricToActivationMap, trackerToMetricMap,
-                        conditionToMetricMap, activationAtomTrackerToMetricMap,
-                        deactivationAtomTrackerToMetricMap, metricsWithActivation);
-                break;
-            }
-            default: {
-                ALOGE("Metric \"%lld\" update state is unknown. This should never happen",
-                      (long long)metric.id());
-                return false;
-            }
-        }
-        if (!producer) {
-            return false;
-        }
-        newMetricProducers.push_back(producer.value());
-    }
-
-    for (int i = 0; i < config.value_metric_size(); i++, metricIndex++) {
-        const ValueMetric& metric = config.value_metric(i);
-        newMetricProducerMap[metric.id()] = metricIndex;
-        optional<sp<MetricProducer>> producer;
-        switch (metricsToUpdate[metricIndex]) {
-            case UPDATE_PRESERVE: {
-                producer = updateMetric(
-                        config, i, metricIndex, metric.id(), allAtomMatchingTrackers,
-                        oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, matcherWizard,
-                        allConditionTrackers, conditionTrackerMap, wizard, oldMetricProducerMap,
-                        oldMetricProducers, metricToActivationMap, trackerToMetricMap,
-                        conditionToMetricMap, activationAtomTrackerToMetricMap,
-                        deactivationAtomTrackerToMetricMap, metricsWithActivation);
-                break;
-            }
-            case UPDATE_REPLACE:
-                replacedMetrics.insert(metric.id());
-                [[fallthrough]];  // Intentionally fallthrough to create the new metric producer.
-            case UPDATE_NEW: {
-                producer = createValueMetricProducerAndUpdateMetadata(
-                        key, config, timeBaseNs, currentTimeNs, pullerManager, metric, metricIndex,
-                        allAtomMatchingTrackers, newAtomMatchingTrackerMap, allConditionTrackers,
-                        conditionTrackerMap, initialConditionCache, wizard, matcherWizard,
-                        stateAtomIdMap, allStateGroupMaps, metricToActivationMap,
-                        trackerToMetricMap, conditionToMetricMap, activationAtomTrackerToMetricMap,
-                        deactivationAtomTrackerToMetricMap, metricsWithActivation);
-                break;
-            }
-            default: {
-                ALOGE("Metric \"%lld\" update state is unknown. This should never happen",
-                      (long long)metric.id());
-                return false;
-            }
-        }
-        if (!producer) {
-            return false;
-        }
-        newMetricProducers.push_back(producer.value());
-    }
-
-    for (int i = 0; i < config.gauge_metric_size(); i++, metricIndex++) {
-        const GaugeMetric& metric = config.gauge_metric(i);
-        newMetricProducerMap[metric.id()] = metricIndex;
-        optional<sp<MetricProducer>> producer;
-        switch (metricsToUpdate[metricIndex]) {
-            case UPDATE_PRESERVE: {
-                producer = updateMetric(
-                        config, i, metricIndex, metric.id(), allAtomMatchingTrackers,
-                        oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, matcherWizard,
-                        allConditionTrackers, conditionTrackerMap, wizard, oldMetricProducerMap,
-                        oldMetricProducers, metricToActivationMap, trackerToMetricMap,
-                        conditionToMetricMap, activationAtomTrackerToMetricMap,
-                        deactivationAtomTrackerToMetricMap, metricsWithActivation);
-                break;
-            }
-            case UPDATE_REPLACE:
-                replacedMetrics.insert(metric.id());
-                [[fallthrough]];  // Intentionally fallthrough to create the new metric producer.
-            case UPDATE_NEW: {
-                producer = createGaugeMetricProducerAndUpdateMetadata(
-                        key, config, timeBaseNs, currentTimeNs, pullerManager, metric, metricIndex,
-                        allAtomMatchingTrackers, newAtomMatchingTrackerMap, allConditionTrackers,
-                        conditionTrackerMap, initialConditionCache, wizard, matcherWizard,
-                        metricToActivationMap, trackerToMetricMap, conditionToMetricMap,
-                        activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
-                        metricsWithActivation);
-                break;
-            }
-            default: {
-                ALOGE("Metric \"%lld\" update state is unknown. This should never happen",
-                      (long long)metric.id());
-                return false;
-            }
-        }
-        if (!producer) {
-            return false;
-        }
-        newMetricProducers.push_back(producer.value());
-    }
-
-    for (int i = 0; i < config.no_report_metric_size(); ++i) {
-        const int64_t noReportMetric = config.no_report_metric(i);
-        if (newMetricProducerMap.find(noReportMetric) == newMetricProducerMap.end()) {
-            ALOGW("no_report_metric %" PRId64 " not exist", noReportMetric);
-            return false;
-        }
-        noReportMetricIds.insert(noReportMetric);
-    }
-    const set<int> atomsAllowedFromAnyUid(config.whitelisted_atom_ids().begin(),
-                                          config.whitelisted_atom_ids().end());
-    for (int i = 0; i < allMetricsCount; i++) {
-        sp<MetricProducer> producer = newMetricProducers[i];
-        // Register metrics to StateTrackers
-        for (int atomId : producer->getSlicedStateAtoms()) {
-            // Register listener for atoms that use allowed_log_sources.
-            // Using atoms allowed from any uid as a sliced state atom is not allowed.
-            // Redo this check for all metrics in case the atoms allowed from any uid changed.
-            if (atomsAllowedFromAnyUid.find(atomId) != atomsAllowedFromAnyUid.end()) {
-                return false;
-                // Preserved metrics should've already registered.`
-            } else if (metricsToUpdate[i] != UPDATE_PRESERVE) {
-                StateManager::getInstance().registerListener(atomId, producer);
-            }
-        }
-    }
-
-    // Init new/replaced metrics.
-    for (size_t i = 0; i < newMetricProducers.size(); i++) {
-        if (metricsToUpdate[i] == UPDATE_REPLACE || metricsToUpdate[i] == UPDATE_NEW) {
-            newMetricProducers[i]->prepareFirstBucket();
-        }
-    }
-    return true;
-}
-
-bool determineAlertUpdateStatus(const Alert& alert,
-                                const unordered_map<int64_t, int>& oldAlertTrackerMap,
-                                const vector<sp<AnomalyTracker>>& oldAnomalyTrackers,
-                                const set<int64_t>& replacedMetrics, UpdateStatus& updateStatus) {
-    // Check if new alert.
-    const auto& oldAnomalyTrackerIt = oldAlertTrackerMap.find(alert.id());
-    if (oldAnomalyTrackerIt == oldAlertTrackerMap.end()) {
-        updateStatus = UPDATE_NEW;
-        return true;
-    }
-
-    // This is an existing alert, check if it has changed.
-    string serializedAlert;
-    if (!alert.SerializeToString(&serializedAlert)) {
-        ALOGW("Unable to serialize alert %lld", (long long)alert.id());
-        return false;
-    }
-    uint64_t newProtoHash = Hash64(serializedAlert);
-    const auto [success, oldProtoHash] =
-            oldAnomalyTrackers[oldAnomalyTrackerIt->second]->getProtoHash();
-    if (!success) {
-        return false;
-    }
-    if (newProtoHash != oldProtoHash) {
-        updateStatus = UPDATE_REPLACE;
-        return true;
-    }
-
-    // Check if the metric this alert relies on has changed.
-    if (replacedMetrics.find(alert.metric_id()) != replacedMetrics.end()) {
-        updateStatus = UPDATE_REPLACE;
-        return true;
-    }
-
-    updateStatus = UPDATE_PRESERVE;
-    return true;
-}
-
-bool updateAlerts(const StatsdConfig& config, const unordered_map<int64_t, int>& metricProducerMap,
-                  const set<int64_t>& replacedMetrics,
-                  const unordered_map<int64_t, int>& oldAlertTrackerMap,
-                  const vector<sp<AnomalyTracker>>& oldAnomalyTrackers,
-                  const sp<AlarmMonitor>& anomalyAlarmMonitor,
-                  vector<sp<MetricProducer>>& allMetricProducers,
-                  unordered_map<int64_t, int>& newAlertTrackerMap,
-                  vector<sp<AnomalyTracker>>& newAnomalyTrackers) {
-    int alertCount = config.alert_size();
-    vector<UpdateStatus> alertUpdateStatuses(alertCount);
-    for (int i = 0; i < alertCount; i++) {
-        if (!determineAlertUpdateStatus(config.alert(i), oldAlertTrackerMap, oldAnomalyTrackers,
-                                        replacedMetrics, alertUpdateStatuses[i])) {
-            return false;
-        }
-    }
-
-    for (int i = 0; i < alertCount; i++) {
-        const Alert& alert = config.alert(i);
-        newAlertTrackerMap[alert.id()] = newAnomalyTrackers.size();
-        switch (alertUpdateStatuses[i]) {
-            case UPDATE_PRESERVE: {
-                // Find the alert and update it.
-                const auto& oldAnomalyTrackerIt = oldAlertTrackerMap.find(alert.id());
-                if (oldAnomalyTrackerIt == oldAlertTrackerMap.end()) {
-                    ALOGW("Could not find AnomalyTracker %lld in the previous config, but "
-                          "expected it to be there",
-                          (long long)alert.id());
-                    return false;
-                }
-                sp<AnomalyTracker> anomalyTracker = oldAnomalyTrackers[oldAnomalyTrackerIt->second];
-                anomalyTracker->onConfigUpdated();
-                // Add the alert to the relevant metric.
-                const auto& metricProducerIt = metricProducerMap.find(alert.metric_id());
-                if (metricProducerIt == metricProducerMap.end()) {
-                    ALOGW("alert \"%lld\" has unknown metric id: \"%lld\"", (long long)alert.id(),
-                          (long long)alert.metric_id());
-                    return false;
-                }
-                allMetricProducers[metricProducerIt->second]->addAnomalyTracker(anomalyTracker);
-                newAnomalyTrackers.push_back(anomalyTracker);
-                break;
-            }
-            case UPDATE_REPLACE:
-            case UPDATE_NEW: {
-                optional<sp<AnomalyTracker>> anomalyTracker = createAnomalyTracker(
-                        alert, anomalyAlarmMonitor, metricProducerMap, allMetricProducers);
-                if (!anomalyTracker) {
-                    return false;
-                }
-                newAnomalyTrackers.push_back(anomalyTracker.value());
-                break;
-            }
-            default: {
-                ALOGE("Alert \"%lld\" update state is unknown. This should never happen",
-                      (long long)alert.id());
-                return false;
-            }
-        }
-    }
-    if (!initSubscribersForSubscriptionType(config, Subscription::ALERT, newAlertTrackerMap,
-                                            newAnomalyTrackers)) {
-        return false;
-    }
-    return true;
-}
-
-bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap,
-                        const sp<StatsPullerManager>& pullerManager,
-                        const sp<AlarmMonitor>& anomalyAlarmMonitor,
-                        const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs,
-                        const int64_t currentTimeNs,
-                        const vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers,
-                        const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
-                        const vector<sp<ConditionTracker>>& oldConditionTrackers,
-                        const unordered_map<int64_t, int>& oldConditionTrackerMap,
-                        const vector<sp<MetricProducer>>& oldMetricProducers,
-                        const unordered_map<int64_t, int>& oldMetricProducerMap,
-                        const vector<sp<AnomalyTracker>>& oldAnomalyTrackers,
-                        const unordered_map<int64_t, int>& oldAlertTrackerMap,
-                        const map<int64_t, uint64_t>& oldStateProtoHashes, set<int>& allTagIds,
-                        vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers,
-                        unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
-                        vector<sp<ConditionTracker>>& newConditionTrackers,
-                        unordered_map<int64_t, int>& newConditionTrackerMap,
-                        vector<sp<MetricProducer>>& newMetricProducers,
-                        unordered_map<int64_t, int>& newMetricProducerMap,
-                        vector<sp<AnomalyTracker>>& newAnomalyTrackers,
-                        unordered_map<int64_t, int>& newAlertTrackerMap,
-                        vector<sp<AlarmTracker>>& newPeriodicAlarmTrackers,
-                        unordered_map<int, vector<int>>& conditionToMetricMap,
-                        unordered_map<int, vector<int>>& trackerToMetricMap,
-                        unordered_map<int, vector<int>>& trackerToConditionMap,
-                        unordered_map<int, vector<int>>& activationTrackerToMetricMap,
-                        unordered_map<int, vector<int>>& deactivationTrackerToMetricMap,
-                        vector<int>& metricsWithActivation,
-                        map<int64_t, uint64_t>& newStateProtoHashes,
-                        set<int64_t>& noReportMetricIds) {
-    set<int64_t> replacedMatchers;
-    set<int64_t> replacedConditions;
-    set<int64_t> replacedStates;
-    set<int64_t> replacedMetrics;
-    vector<ConditionState> conditionCache;
-    unordered_map<int64_t, int> stateAtomIdMap;
-    unordered_map<int64_t, unordered_map<int, int64_t>> allStateGroupMaps;
-
-    if (!updateAtomMatchingTrackers(config, uidMap, oldAtomMatchingTrackerMap,
-                                    oldAtomMatchingTrackers, allTagIds, newAtomMatchingTrackerMap,
-                                    newAtomMatchingTrackers, replacedMatchers)) {
-        ALOGE("updateAtomMatchingTrackers failed");
-        return false;
-    }
-
-    if (!updateConditions(key, config, newAtomMatchingTrackerMap, replacedMatchers,
-                          oldConditionTrackerMap, oldConditionTrackers, newConditionTrackerMap,
-                          newConditionTrackers, trackerToConditionMap, conditionCache,
-                          replacedConditions)) {
-        ALOGE("updateConditions failed");
-        return false;
-    }
-
-    if (!updateStates(config, oldStateProtoHashes, stateAtomIdMap, allStateGroupMaps,
-                      newStateProtoHashes, replacedStates)) {
-        ALOGE("updateStates failed");
-        return false;
-    }
-    if (!updateMetrics(key, config, timeBaseNs, currentTimeNs, pullerManager,
-                       oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, replacedMatchers,
-                       newAtomMatchingTrackers, newConditionTrackerMap, replacedConditions,
-                       newConditionTrackers, conditionCache, stateAtomIdMap, allStateGroupMaps,
-                       replacedStates, oldMetricProducerMap, oldMetricProducers,
-                       newMetricProducerMap, newMetricProducers, conditionToMetricMap,
-                       trackerToMetricMap, noReportMetricIds, activationTrackerToMetricMap,
-                       deactivationTrackerToMetricMap, metricsWithActivation, replacedMetrics)) {
-        ALOGE("updateMetrics failed");
-        return false;
-    }
-
-    if (!updateAlerts(config, newMetricProducerMap, replacedMetrics, oldAlertTrackerMap,
-                      oldAnomalyTrackers, anomalyAlarmMonitor, newMetricProducers,
-                      newAlertTrackerMap, newAnomalyTrackers)) {
-        ALOGE("updateAlerts failed");
-        return false;
-    }
-
-    // Alarms do not have any state, so we can reuse the initialization logic.
-    if (!initAlarms(config, key, periodicAlarmMonitor, timeBaseNs, currentTimeNs,
-                    newPeriodicAlarmTrackers)) {
-        ALOGE("initAlarms failed");
-        return false;
-    }
-    return true;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h
deleted file mode 100644
index 8e2be68..0000000
--- a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h
+++ /dev/null
@@ -1,276 +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.
- */
-
-#pragma once
-
-#include <vector>
-
-#include "anomaly/AlarmMonitor.h"
-#include "anomaly/AlarmTracker.h"
-#include "condition/ConditionTracker.h"
-#include "external/StatsPullerManager.h"
-#include "matchers/AtomMatchingTracker.h"
-#include "metrics/MetricProducer.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// Helper functions for MetricsManager to update itself from a new StatsdConfig.
-// *Note*: only updateStatsdConfig() should be called from outside this file.
-// All other functions are intermediate steps, created to make unit testing easier.
-
-// Possible update states for a component. PRESERVE means we should keep the existing one.
-// REPLACE means we should create a new one because the existing one changed
-// NEW means we should create a new one because one does not currently exist.
-enum UpdateStatus {
-    UPDATE_UNKNOWN = 0,
-    UPDATE_PRESERVE = 1,
-    UPDATE_REPLACE = 2,
-    UPDATE_NEW = 3,
-};
-
-// Recursive function to determine if a matcher needs to be updated.
-// input:
-// [config]: the input StatsdConfig
-// [matcherIdx]: the index of the current matcher to be updated
-// [oldAtomMatchingTrackerMap]: matcher id to index mapping in the existing MetricsManager
-// [oldAtomMatchingTrackers]: stores the existing AtomMatchingTrackers
-// [newAtomMatchingTrackerMap]: matcher id to index mapping in the input StatsdConfig
-// output:
-// [matchersToUpdate]: vector of the update status of each matcher. The matcherIdx index will
-//                     be updated from UPDATE_UNKNOWN after this call.
-// [cycleTracker]: intermediate param used during recursion.
-// Returns whether the function was successful or not.
-bool determineMatcherUpdateStatus(
-        const StatsdConfig& config, const int matcherIdx,
-        const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
-        const std::vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers,
-        const std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
-        std::vector<UpdateStatus>& matchersToUpdate, std::vector<bool>& cycleTracker);
-
-// Updates the AtomMatchingTrackers.
-// input:
-// [config]: the input StatsdConfig
-// [oldAtomMatchingTrackerMap]: existing matcher id to index mapping
-// [oldAtomMatchingTrackers]: stores the existing AtomMatchingTrackers
-// output:
-// [allTagIds]: contains the set of all interesting tag ids to this config.
-// [newAtomMatchingTrackerMap]: new matcher id to index mapping
-// [newAtomMatchingTrackers]: stores the new AtomMatchingTrackers
-// [replacedMatchers]: set of matcher ids that changed and have been replaced
-bool updateAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap,
-                                const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
-                                const std::vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers,
-                                std::set<int>& allTagIds,
-                                std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
-                                std::vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers,
-                                std::set<int64_t>& replacedMatchers);
-
-// Recursive function to determine if a condition needs to be updated.
-// input:
-// [config]: the input StatsdConfig
-// [conditionIdx]: the index of the current condition to be updated
-// [oldConditionTrackerMap]: condition id to index mapping in the existing MetricsManager
-// [oldConditionTrackers]: stores the existing ConditionTrackers
-// [newConditionTrackerMap]: condition id to index mapping in the input StatsdConfig
-// [replacedMatchers]: set of replaced matcher ids. conditions using these matchers must be replaced
-// output:
-// [conditionsToUpdate]: vector of the update status of each condition. The conditionIdx index will
-//                       be updated from UPDATE_UNKNOWN after this call.
-// [cycleTracker]: intermediate param used during recursion.
-// Returns whether the function was successful or not.
-bool determineConditionUpdateStatus(const StatsdConfig& config, const int conditionIdx,
-                                    const std::unordered_map<int64_t, int>& oldConditionTrackerMap,
-                                    const std::vector<sp<ConditionTracker>>& oldConditionTrackers,
-                                    const std::unordered_map<int64_t, int>& newConditionTrackerMap,
-                                    const std::set<int64_t>& replacedMatchers,
-                                    std::vector<UpdateStatus>& conditionsToUpdate,
-                                    std::vector<bool>& cycleTracker);
-
-// Updates ConditionTrackers
-// input:
-// [config]: the input config
-// [atomMatchingTrackerMap]: AtomMatchingTracker name to index mapping from previous step.
-// [replacedMatchers]: ids of replaced matchers. conditions depending on these must also be replaced
-// [oldConditionTrackerMap]: existing matcher id to index mapping
-// [oldConditionTrackers]: stores the existing ConditionTrackers
-// output:
-// [newConditionTrackerMap]: new condition id to index mapping
-// [newConditionTrackers]: stores the sp to all the ConditionTrackers
-// [trackerToConditionMap]: contains the mapping from the index of an atom matcher
-//                          to indices of condition trackers that use the matcher
-// [conditionCache]: stores the current conditions for each ConditionTracker
-// [replacedConditions]: set of condition ids that have changed and have been replaced
-bool updateConditions(const ConfigKey& key, const StatsdConfig& config,
-                      const std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
-                      const std::set<int64_t>& replacedMatchers,
-                      const std::unordered_map<int64_t, int>& oldConditionTrackerMap,
-                      const std::vector<sp<ConditionTracker>>& oldConditionTrackers,
-                      std::unordered_map<int64_t, int>& newConditionTrackerMap,
-                      std::vector<sp<ConditionTracker>>& newConditionTrackers,
-                      std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
-                      std::vector<ConditionState>& conditionCache,
-                      std::set<int64_t>& replacedConditions);
-
-bool updateStates(const StatsdConfig& config,
-                  const std::map<int64_t, uint64_t>& oldStateProtoHashes,
-                  std::unordered_map<int64_t, int>& stateAtomIdMap,
-                  std::unordered_map<int64_t, std::unordered_map<int, int64_t>>& allStateGroupMaps,
-                  std::map<int64_t, uint64_t>& newStateProtoHashes,
-                  std::set<int64_t>& replacedStates);
-
-// Function to determine the update status (preserve/replace/new) of all metrics in the config.
-// [config]: the input StatsdConfig
-// [oldMetricProducerMap]: metric id to index mapping in the existing MetricsManager
-// [oldMetricProducers]: stores the existing MetricProducers
-// [metricToActivationMap]:  map from metric id to metric activation index
-// [replacedMatchers]: set of replaced matcher ids. metrics using these matchers must be replaced
-// [replacedConditions]: set of replaced conditions. metrics using these conditions must be replaced
-// [replacedStates]: set of replaced state ids. metrics using these states must be replaced
-// output:
-// [metricsToUpdate]: update status of each metric. Will be changed from UPDATE_UNKNOWN
-// Returns whether the function was successful or not.
-bool determineAllMetricUpdateStatuses(const StatsdConfig& config,
-                                      const unordered_map<int64_t, int>& oldMetricProducerMap,
-                                      const vector<sp<MetricProducer>>& oldMetricProducers,
-                                      const unordered_map<int64_t, int>& metricToActivationMap,
-                                      const set<int64_t>& replacedMatchers,
-                                      const set<int64_t>& replacedConditions,
-                                      const set<int64_t>& replacedStates,
-                                      vector<UpdateStatus>& metricsToUpdate);
-
-// Update MetricProducers.
-// input:
-// [key]: the config key that this config belongs to
-// [config]: the input config
-// [timeBaseNs]: start time base for all metrics
-// [currentTimeNs]: time of the config update
-// [atomMatchingTrackerMap]: AtomMatchingTracker name to index mapping from previous step.
-// [replacedMatchers]: ids of replaced matchers. Metrics depending on these must also be replaced
-// [allAtomMatchingTrackers]: stores the sp of the atom matchers.
-// [conditionTrackerMap]: condition name to index mapping
-// [replacedConditions]: set of condition ids that have changed and have been replaced
-// [stateAtomIdMap]: contains the mapping from state ids to atom ids
-// [allStateGroupMaps]: contains the mapping from atom ids and state values to
-//                      state group ids for all states
-// output:
-// [allMetricProducers]: contains the list of sp to the MetricProducers created.
-// [conditionToMetricMap]: contains the mapping from condition tracker index to
-//                          the list of MetricProducer index
-// [trackerToMetricMap]: contains the mapping from log tracker to MetricProducer index.
-bool updateMetrics(
-        const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
-        const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
-        const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
-        const std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
-        const std::set<int64_t>& replacedMatchers,
-        const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-        const std::unordered_map<int64_t, int>& conditionTrackerMap,
-        const std::set<int64_t>& replacedConditions,
-        std::vector<sp<ConditionTracker>>& allConditionTrackers,
-        const std::vector<ConditionState>& initialConditionCache,
-        const std::unordered_map<int64_t, int>& stateAtomIdMap,
-        const std::unordered_map<int64_t, std::unordered_map<int, int64_t>>& allStateGroupMaps,
-        const std::set<int64_t>& replacedStates,
-        const std::unordered_map<int64_t, int>& oldMetricProducerMap,
-        const std::vector<sp<MetricProducer>>& oldMetricProducers,
-        std::unordered_map<int64_t, int>& newMetricProducerMap,
-        std::vector<sp<MetricProducer>>& newMetricProducers,
-        std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
-        std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
-        std::set<int64_t>& noReportMetricIds,
-        std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
-        std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
-        std::vector<int>& metricsWithActivation, std::set<int64_t>& replacedMetrics);
-
-// Function to determine the update status (preserve/replace/new) of an alert.
-// [alert]: the input Alert
-// [oldAlertTrackerMap]: alert id to index mapping in the existing MetricsManager
-// [oldAnomalyTrackers]: stores the existing AnomalyTrackers
-// [replacedMetrics]: set of replaced metric ids. alerts using these metrics must be replaced
-// output:
-// [updateStatus]: update status of the alert. Will be changed from UPDATE_UNKNOWN
-// Returns whether the function was successful or not.
-bool determineAlertUpdateStatus(const Alert& alert,
-                                const std::unordered_map<int64_t, int>& oldAlertTrackerMap,
-                                const std::vector<sp<AnomalyTracker>>& oldAnomalyTrackers,
-                                const std::set<int64_t>& replacedMetrics,
-                                UpdateStatus& updateStatus);
-
-// Update MetricProducers.
-// input:
-// [config]: the input config
-// [metricProducerMap]: metric id to index mapping in the new config
-// [replacedMetrics]: set of metric ids that have changed and were replaced
-// [oldAlertTrackerMap]: alert id to index mapping in the existing MetricsManager.
-// [oldAnomalyTrackers]: stores the existing AnomalyTrackers
-// [anomalyAlarmMonitor]: AlarmMonitor used for duration metric anomaly detection
-// [allMetricProducers]: stores the sp of the metric producers, AnomalyTrackers need to be added.
-// [stateAtomIdMap]: contains the mapping from state ids to atom ids
-// [allStateGroupMaps]: contains the mapping from atom ids and state values to
-//                      state group ids for all states
-// output:
-// [newAlertTrackerMap]: mapping of alert id to index in the new config
-// [newAnomalyTrackers]: contains the list of sp to the AnomalyTrackers created.
-bool updateAlerts(const StatsdConfig& config,
-                  const std::unordered_map<int64_t, int>& metricProducerMap,
-                  const std::set<int64_t>& replacedMetrics,
-                  const std::unordered_map<int64_t, int>& oldAlertTrackerMap,
-                  const std::vector<sp<AnomalyTracker>>& oldAnomalyTrackers,
-                  const sp<AlarmMonitor>& anomalyAlarmMonitor,
-                  std::vector<sp<MetricProducer>>& allMetricProducers,
-                  std::unordered_map<int64_t, int>& newAlertTrackerMap,
-                  std::vector<sp<AnomalyTracker>>& newAnomalyTrackers);
-
-// Updates the existing MetricsManager from a new StatsdConfig.
-// Parameters are the members of MetricsManager. See MetricsManager for declaration.
-bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap,
-                        const sp<StatsPullerManager>& pullerManager,
-                        const sp<AlarmMonitor>& anomalyAlarmMonitor,
-                        const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs,
-                        const int64_t currentTimeNs,
-                        const std::vector<sp<AtomMatchingTracker>>& oldAtomMatchingTrackers,
-                        const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
-                        const std::vector<sp<ConditionTracker>>& oldConditionTrackers,
-                        const std::unordered_map<int64_t, int>& oldConditionTrackerMap,
-                        const std::vector<sp<MetricProducer>>& oldMetricProducers,
-                        const std::unordered_map<int64_t, int>& oldMetricProducerMap,
-                        const std::vector<sp<AnomalyTracker>>& oldAnomalyTrackers,
-                        const std::unordered_map<int64_t, int>& oldAlertTrackerMap,
-                        const std::map<int64_t, uint64_t>& oldStateProtoHashes,
-                        std::set<int>& allTagIds,
-                        std::vector<sp<AtomMatchingTracker>>& newAtomMatchingTrackers,
-                        std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
-                        std::vector<sp<ConditionTracker>>& newConditionTrackers,
-                        std::unordered_map<int64_t, int>& newConditionTrackerMap,
-                        std::vector<sp<MetricProducer>>& newMetricProducers,
-                        std::unordered_map<int64_t, int>& newMetricProducerMap,
-                        std::vector<sp<AnomalyTracker>>& newAlertTrackers,
-                        std::unordered_map<int64_t, int>& newAlertTrackerMap,
-                        std::vector<sp<AlarmTracker>>& newPeriodicAlarmTrackers,
-                        std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
-                        std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
-                        std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
-                        std::unordered_map<int, std::vector<int>>& activationTrackerToMetricMap,
-                        std::unordered_map<int, std::vector<int>>& deactivationTrackerToMetricMap,
-                        std::vector<int>& metricsWithActivation,
-                        std::map<int64_t, uint64_t>& newStateProtoHashes,
-                        std::set<int64_t>& noReportMetricIds);
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
deleted file mode 100644
index bfa409c..0000000
--- a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp
+++ /dev/null
@@ -1,1228 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "metrics_manager_util.h"
-
-#include <inttypes.h>
-
-#include "FieldValue.h"
-#include "condition/CombinationConditionTracker.h"
-#include "condition/SimpleConditionTracker.h"
-#include "external/StatsPullerManager.h"
-#include "hash.h"
-#include "matchers/CombinationAtomMatchingTracker.h"
-#include "matchers/EventMatcherWizard.h"
-#include "matchers/SimpleAtomMatchingTracker.h"
-#include "metrics/CountMetricProducer.h"
-#include "metrics/DurationMetricProducer.h"
-#include "metrics/EventMetricProducer.h"
-#include "metrics/GaugeMetricProducer.h"
-#include "metrics/MetricProducer.h"
-#include "metrics/ValueMetricProducer.h"
-#include "state/StateManager.h"
-#include "stats_util.h"
-
-using google::protobuf::MessageLite;
-using std::set;
-using std::unordered_map;
-using std::vector;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-namespace {
-
-bool hasLeafNode(const FieldMatcher& matcher) {
-    if (!matcher.has_field()) {
-        return false;
-    }
-    for (int i = 0; i < matcher.child_size(); ++i) {
-        if (hasLeafNode(matcher.child(i))) {
-            return true;
-        }
-    }
-    return true;
-}
-
-}  // namespace
-
-sp<AtomMatchingTracker> createAtomMatchingTracker(const AtomMatcher& logMatcher, const int index,
-                                                  const sp<UidMap>& uidMap) {
-    string serializedMatcher;
-    if (!logMatcher.SerializeToString(&serializedMatcher)) {
-        ALOGE("Unable to serialize matcher %lld", (long long)logMatcher.id());
-        return nullptr;
-    }
-    uint64_t protoHash = Hash64(serializedMatcher);
-    switch (logMatcher.contents_case()) {
-        case AtomMatcher::ContentsCase::kSimpleAtomMatcher:
-            return new SimpleAtomMatchingTracker(logMatcher.id(), index, protoHash,
-                                                 logMatcher.simple_atom_matcher(), uidMap);
-        case AtomMatcher::ContentsCase::kCombination:
-            return new CombinationAtomMatchingTracker(logMatcher.id(), index, protoHash);
-        default:
-            ALOGE("Matcher \"%lld\" malformed", (long long)logMatcher.id());
-            return nullptr;
-    }
-}
-
-sp<ConditionTracker> createConditionTracker(
-        const ConfigKey& key, const Predicate& predicate, const int index,
-        const unordered_map<int64_t, int>& atomMatchingTrackerMap) {
-    string serializedPredicate;
-    if (!predicate.SerializeToString(&serializedPredicate)) {
-        ALOGE("Unable to serialize predicate %lld", (long long)predicate.id());
-        return nullptr;
-    }
-    uint64_t protoHash = Hash64(serializedPredicate);
-    switch (predicate.contents_case()) {
-        case Predicate::ContentsCase::kSimplePredicate: {
-            return new SimpleConditionTracker(key, predicate.id(), protoHash, index,
-                                              predicate.simple_predicate(), atomMatchingTrackerMap);
-        }
-        case Predicate::ContentsCase::kCombination: {
-            return new CombinationConditionTracker(predicate.id(), index, protoHash);
-        }
-        default:
-            ALOGE("Predicate \"%lld\" malformed", (long long)predicate.id());
-            return nullptr;
-    }
-}
-
-bool getMetricProtoHash(const StatsdConfig& config, const MessageLite& metric, const int64_t id,
-                        const unordered_map<int64_t, int>& metricToActivationMap,
-                        uint64_t& metricHash) {
-    string serializedMetric;
-    if (!metric.SerializeToString(&serializedMetric)) {
-        ALOGE("Unable to serialize metric %lld", (long long)id);
-        return false;
-    }
-    metricHash = Hash64(serializedMetric);
-
-    // Combine with activation hash, if applicable
-    const auto& metricActivationIt = metricToActivationMap.find(id);
-    if (metricActivationIt != metricToActivationMap.end()) {
-        string serializedActivation;
-        const MetricActivation& activation = config.metric_activation(metricActivationIt->second);
-        if (!activation.SerializeToString(&serializedActivation)) {
-            ALOGE("Unable to serialize metric activation for metric %lld", (long long)id);
-            return false;
-        }
-        metricHash = Hash64(to_string(metricHash).append(to_string(Hash64(serializedActivation))));
-    }
-    return true;
-}
-
-bool handleMetricWithAtomMatchingTrackers(
-        const int64_t matcherId, const int metricIndex, const bool enforceOneAtom,
-        const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-        const unordered_map<int64_t, int>& atomMatchingTrackerMap,
-        unordered_map<int, vector<int>>& trackerToMetricMap, int& logTrackerIndex) {
-    auto logTrackerIt = atomMatchingTrackerMap.find(matcherId);
-    if (logTrackerIt == atomMatchingTrackerMap.end()) {
-        ALOGW("cannot find the AtomMatcher \"%lld\" in config", (long long)matcherId);
-        return false;
-    }
-    if (enforceOneAtom && allAtomMatchingTrackers[logTrackerIt->second]->getAtomIds().size() > 1) {
-        ALOGE("AtomMatcher \"%lld\" has more than one tag ids. When a metric has dimension, "
-              "the \"what\" can only be about one atom type. trigger_event matchers can also only "
-              "be about one atom type.",
-              (long long)matcherId);
-        return false;
-    }
-    logTrackerIndex = logTrackerIt->second;
-    auto& metric_list = trackerToMetricMap[logTrackerIndex];
-    metric_list.push_back(metricIndex);
-    return true;
-}
-
-bool handleMetricWithConditions(
-        const int64_t condition, const int metricIndex,
-        const unordered_map<int64_t, int>& conditionTrackerMap,
-        const ::google::protobuf::RepeatedPtrField<::android::os::statsd::MetricConditionLink>&
-                links,
-        const vector<sp<ConditionTracker>>& allConditionTrackers, int& conditionIndex,
-        unordered_map<int, vector<int>>& conditionToMetricMap) {
-    auto condition_it = conditionTrackerMap.find(condition);
-    if (condition_it == conditionTrackerMap.end()) {
-        ALOGW("cannot find Predicate \"%lld\" in the config", (long long)condition);
-        return false;
-    }
-
-    for (const auto& link : links) {
-        auto it = conditionTrackerMap.find(link.condition());
-        if (it == conditionTrackerMap.end()) {
-            ALOGW("cannot find Predicate \"%lld\" in the config", (long long)link.condition());
-            return false;
-        }
-    }
-    conditionIndex = condition_it->second;
-
-    // will create new vector if not exist before.
-    auto& metricList = conditionToMetricMap[condition_it->second];
-    metricList.push_back(metricIndex);
-    return true;
-}
-
-// Initializes state data structures for a metric.
-// input:
-// [config]: the input config
-// [stateIds]: the slice_by_state ids for this metric
-// [stateAtomIdMap]: this map contains the mapping from all state ids to atom ids
-// [allStateGroupMaps]: this map contains the mapping from state ids and state
-//                      values to state group ids for all states
-// output:
-// [slicedStateAtoms]: a vector of atom ids of all the slice_by_states
-// [stateGroupMap]: this map should contain the mapping from states ids and state
-//                      values to state group ids for all states that this metric
-//                      is interested in
-bool handleMetricWithStates(
-        const StatsdConfig& config, const ::google::protobuf::RepeatedField<int64_t>& stateIds,
-        const unordered_map<int64_t, int>& stateAtomIdMap,
-        const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
-        vector<int>& slicedStateAtoms,
-        unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap) {
-    for (const auto& stateId : stateIds) {
-        auto it = stateAtomIdMap.find(stateId);
-        if (it == stateAtomIdMap.end()) {
-            ALOGW("cannot find State %" PRId64 " in the config", stateId);
-            return false;
-        }
-        int atomId = it->second;
-        slicedStateAtoms.push_back(atomId);
-
-        auto stateIt = allStateGroupMaps.find(stateId);
-        if (stateIt != allStateGroupMaps.end()) {
-            stateGroupMap[atomId] = stateIt->second;
-        }
-    }
-    return true;
-}
-
-bool handleMetricWithStateLink(const FieldMatcher& stateMatcher,
-                               const vector<Matcher>& dimensionsInWhat) {
-    vector<Matcher> stateMatchers;
-    translateFieldMatcher(stateMatcher, &stateMatchers);
-
-    return subsetDimensions(stateMatchers, dimensionsInWhat);
-}
-
-// Validates a metricActivation and populates state.
-// EventActivationMap and EventDeactivationMap are supplied to a MetricProducer
-//      to provide the producer with state about its activators and deactivators.
-// Returns false if there are errors.
-bool handleMetricActivation(
-        const StatsdConfig& config, const int64_t metricId, const int metricIndex,
-        const unordered_map<int64_t, int>& metricToActivationMap,
-        const unordered_map<int64_t, int>& atomMatchingTrackerMap,
-        unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
-        unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
-        vector<int>& metricsWithActivation,
-        unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
-        unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap) {
-    // Check if metric has an associated activation
-    auto itr = metricToActivationMap.find(metricId);
-    if (itr == metricToActivationMap.end()) {
-        return true;
-    }
-
-    int activationIndex = itr->second;
-    const MetricActivation& metricActivation = config.metric_activation(activationIndex);
-
-    for (int i = 0; i < metricActivation.event_activation_size(); i++) {
-        const EventActivation& activation = metricActivation.event_activation(i);
-
-        auto itr = atomMatchingTrackerMap.find(activation.atom_matcher_id());
-        if (itr == atomMatchingTrackerMap.end()) {
-            ALOGE("Atom matcher not found for event activation.");
-            return false;
-        }
-
-        ActivationType activationType = (activation.has_activation_type())
-                                                ? activation.activation_type()
-                                                : metricActivation.activation_type();
-        std::shared_ptr<Activation> activationWrapper =
-                std::make_shared<Activation>(activationType, activation.ttl_seconds() * NS_PER_SEC);
-
-        int atomMatcherIndex = itr->second;
-        activationAtomTrackerToMetricMap[atomMatcherIndex].push_back(metricIndex);
-        eventActivationMap.emplace(atomMatcherIndex, activationWrapper);
-
-        if (activation.has_deactivation_atom_matcher_id()) {
-            itr = atomMatchingTrackerMap.find(activation.deactivation_atom_matcher_id());
-            if (itr == atomMatchingTrackerMap.end()) {
-                ALOGE("Atom matcher not found for event deactivation.");
-                return false;
-            }
-            int deactivationAtomMatcherIndex = itr->second;
-            deactivationAtomTrackerToMetricMap[deactivationAtomMatcherIndex].push_back(metricIndex);
-            eventDeactivationMap[deactivationAtomMatcherIndex].push_back(activationWrapper);
-        }
-    }
-
-    metricsWithActivation.push_back(metricIndex);
-    return true;
-}
-
-// Validates a metricActivation and populates state.
-// Fills the new event activation/deactivation maps, preserving the existing activations
-// Returns false if there are errors.
-bool handleMetricActivationOnConfigUpdate(
-        const StatsdConfig& config, const int64_t metricId, const int metricIndex,
-        const unordered_map<int64_t, int>& metricToActivationMap,
-        const unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
-        const unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
-        const unordered_map<int, shared_ptr<Activation>>& oldEventActivationMap,
-        unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
-        unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
-        vector<int>& metricsWithActivation,
-        unordered_map<int, shared_ptr<Activation>>& newEventActivationMap,
-        unordered_map<int, vector<shared_ptr<Activation>>>& newEventDeactivationMap) {
-    // Check if metric has an associated activation.
-    const auto& itr = metricToActivationMap.find(metricId);
-    if (itr == metricToActivationMap.end()) {
-        return true;
-    }
-
-    int activationIndex = itr->second;
-    const MetricActivation& metricActivation = config.metric_activation(activationIndex);
-
-    for (int i = 0; i < metricActivation.event_activation_size(); i++) {
-        const int64_t activationMatcherId = metricActivation.event_activation(i).atom_matcher_id();
-
-        const auto& newActivationIt = newAtomMatchingTrackerMap.find(activationMatcherId);
-        if (newActivationIt == newAtomMatchingTrackerMap.end()) {
-            ALOGE("Atom matcher not found in new config for event activation.");
-            return false;
-        }
-        int newActivationMatcherIndex = newActivationIt->second;
-
-        // Find the old activation struct and copy it over.
-        const auto& oldActivationIt = oldAtomMatchingTrackerMap.find(activationMatcherId);
-        if (oldActivationIt == oldAtomMatchingTrackerMap.end()) {
-            ALOGE("Atom matcher not found in existing config for event activation.");
-            return false;
-        }
-        int oldActivationMatcherIndex = oldActivationIt->second;
-        const auto& oldEventActivationIt = oldEventActivationMap.find(oldActivationMatcherIndex);
-        if (oldEventActivationIt == oldEventActivationMap.end()) {
-            ALOGE("Could not find existing event activation to update");
-            return false;
-        }
-        newEventActivationMap.emplace(newActivationMatcherIndex, oldEventActivationIt->second);
-        activationAtomTrackerToMetricMap[newActivationMatcherIndex].push_back(metricIndex);
-
-        if (metricActivation.event_activation(i).has_deactivation_atom_matcher_id()) {
-            const int64_t deactivationMatcherId =
-                    metricActivation.event_activation(i).deactivation_atom_matcher_id();
-            const auto& newDeactivationIt = newAtomMatchingTrackerMap.find(deactivationMatcherId);
-            if (newDeactivationIt == newAtomMatchingTrackerMap.end()) {
-                ALOGE("Deactivation atom matcher not found in new config for event activation.");
-                return false;
-            }
-            int newDeactivationMatcherIndex = newDeactivationIt->second;
-            newEventDeactivationMap[newDeactivationMatcherIndex].push_back(
-                    oldEventActivationIt->second);
-            deactivationAtomTrackerToMetricMap[newDeactivationMatcherIndex].push_back(metricIndex);
-        }
-    }
-
-    metricsWithActivation.push_back(metricIndex);
-    return true;
-}
-
-optional<sp<MetricProducer>> createCountMetricProducerAndUpdateMetadata(
-        const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
-        const int64_t currentTimeNs, const CountMetric& metric, const int metricIndex,
-        const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-        const unordered_map<int64_t, int>& atomMatchingTrackerMap,
-        vector<sp<ConditionTracker>>& allConditionTrackers,
-        const unordered_map<int64_t, int>& conditionTrackerMap,
-        const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
-        const unordered_map<int64_t, int>& stateAtomIdMap,
-        const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
-        const unordered_map<int64_t, int>& metricToActivationMap,
-        unordered_map<int, vector<int>>& trackerToMetricMap,
-        unordered_map<int, vector<int>>& conditionToMetricMap,
-        unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
-        unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
-        vector<int>& metricsWithActivation) {
-    if (!metric.has_id() || !metric.has_what()) {
-        ALOGE("cannot find metric id or \"what\" in CountMetric \"%lld\"", (long long)metric.id());
-        return nullopt;
-    }
-    int trackerIndex;
-    if (!handleMetricWithAtomMatchingTrackers(metric.what(), metricIndex,
-                                              metric.has_dimensions_in_what(),
-                                              allAtomMatchingTrackers, atomMatchingTrackerMap,
-                                              trackerToMetricMap, trackerIndex)) {
-        return nullopt;
-    }
-
-    int conditionIndex = -1;
-    if (metric.has_condition()) {
-        if (!handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
-                                        metric.links(), allConditionTrackers, conditionIndex,
-                                        conditionToMetricMap)) {
-            return nullopt;
-        }
-    } else {
-        if (metric.links_size() > 0) {
-            ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
-            return nullopt;
-        }
-    }
-
-    std::vector<int> slicedStateAtoms;
-    unordered_map<int, unordered_map<int, int64_t>> stateGroupMap;
-    if (metric.slice_by_state_size() > 0) {
-        if (!handleMetricWithStates(config, metric.slice_by_state(), stateAtomIdMap,
-                                    allStateGroupMaps, slicedStateAtoms, stateGroupMap)) {
-            return nullopt;
-        }
-    } else {
-        if (metric.state_link_size() > 0) {
-            ALOGW("CountMetric has a MetricStateLink but doesn't have a slice_by_state");
-            return nullopt;
-        }
-    }
-
-    unordered_map<int, shared_ptr<Activation>> eventActivationMap;
-    unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
-    if (!handleMetricActivation(config, metric.id(), metricIndex, metricToActivationMap,
-                                atomMatchingTrackerMap, activationAtomTrackerToMetricMap,
-                                deactivationAtomTrackerToMetricMap, metricsWithActivation,
-                                eventActivationMap, eventDeactivationMap)) {
-        return nullopt;
-    }
-
-    uint64_t metricHash;
-    if (!getMetricProtoHash(config, metric, metric.id(), metricToActivationMap, metricHash)) {
-        return nullopt;
-    }
-
-    return {new CountMetricProducer(key, metric, conditionIndex, initialConditionCache, wizard,
-                                    metricHash, timeBaseNs, currentTimeNs, eventActivationMap,
-                                    eventDeactivationMap, slicedStateAtoms, stateGroupMap)};
-}
-
-optional<sp<MetricProducer>> createDurationMetricProducerAndUpdateMetadata(
-        const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
-        const int64_t currentTimeNs, const DurationMetric& metric, const int metricIndex,
-        const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-        const unordered_map<int64_t, int>& atomMatchingTrackerMap,
-        vector<sp<ConditionTracker>>& allConditionTrackers,
-        const unordered_map<int64_t, int>& conditionTrackerMap,
-        const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
-        const unordered_map<int64_t, int>& stateAtomIdMap,
-        const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
-        const unordered_map<int64_t, int>& metricToActivationMap,
-        unordered_map<int, vector<int>>& trackerToMetricMap,
-        unordered_map<int, vector<int>>& conditionToMetricMap,
-        unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
-        unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
-        vector<int>& metricsWithActivation) {
-    if (!metric.has_id() || !metric.has_what()) {
-        ALOGE("cannot find metric id or \"what\" in DurationMetric \"%lld\"",
-              (long long)metric.id());
-        return nullopt;
-    }
-    const auto& what_it = conditionTrackerMap.find(metric.what());
-    if (what_it == conditionTrackerMap.end()) {
-        ALOGE("DurationMetric's \"what\" is not present in the condition trackers");
-        return nullopt;
-    }
-
-    const int whatIndex = what_it->second;
-    const Predicate& durationWhat = config.predicate(whatIndex);
-    if (durationWhat.contents_case() != Predicate::ContentsCase::kSimplePredicate) {
-        ALOGE("DurationMetric's \"what\" must be a simple condition");
-        return nullopt;
-    }
-
-    const SimplePredicate& simplePredicate = durationWhat.simple_predicate();
-    bool nesting = simplePredicate.count_nesting();
-
-    int startIndex = -1, stopIndex = -1, stopAllIndex = -1;
-    if (!simplePredicate.has_start() ||
-        !handleMetricWithAtomMatchingTrackers(
-                simplePredicate.start(), metricIndex, metric.has_dimensions_in_what(),
-                allAtomMatchingTrackers, atomMatchingTrackerMap, trackerToMetricMap, startIndex)) {
-        ALOGE("Duration metrics must specify a valid start event matcher");
-        return nullopt;
-    }
-
-    if (simplePredicate.has_stop() &&
-        !handleMetricWithAtomMatchingTrackers(
-                simplePredicate.stop(), metricIndex, metric.has_dimensions_in_what(),
-                allAtomMatchingTrackers, atomMatchingTrackerMap, trackerToMetricMap, stopIndex)) {
-        return nullopt;
-    }
-
-    if (simplePredicate.has_stop_all() &&
-        !handleMetricWithAtomMatchingTrackers(simplePredicate.stop_all(), metricIndex,
-                                              metric.has_dimensions_in_what(),
-                                              allAtomMatchingTrackers, atomMatchingTrackerMap,
-                                              trackerToMetricMap, stopAllIndex)) {
-        return nullopt;
-    }
-
-    FieldMatcher internalDimensions = simplePredicate.dimensions();
-
-    int conditionIndex = -1;
-    if (metric.has_condition()) {
-        if (!handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
-                                        metric.links(), allConditionTrackers, conditionIndex,
-                                        conditionToMetricMap)) {
-            return nullopt;
-        }
-    } else if (metric.links_size() > 0) {
-        ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
-        return nullopt;
-    }
-
-    std::vector<int> slicedStateAtoms;
-    unordered_map<int, unordered_map<int, int64_t>> stateGroupMap;
-    if (metric.slice_by_state_size() > 0) {
-        if (metric.aggregation_type() == DurationMetric::MAX_SPARSE) {
-            ALOGE("DurationMetric with aggregation type MAX_SPARSE cannot be sliced by state");
-            return nullopt;
-        }
-        if (!handleMetricWithStates(config, metric.slice_by_state(), stateAtomIdMap,
-                                    allStateGroupMaps, slicedStateAtoms, stateGroupMap)) {
-            return nullopt;
-        }
-    } else if (metric.state_link_size() > 0) {
-        ALOGW("DurationMetric has a MetricStateLink but doesn't have a sliced state");
-        return nullopt;
-    }
-
-    // Check that all metric state links are a subset of dimensions_in_what fields.
-    std::vector<Matcher> dimensionsInWhat;
-    translateFieldMatcher(metric.dimensions_in_what(), &dimensionsInWhat);
-    for (const auto& stateLink : metric.state_link()) {
-        if (!handleMetricWithStateLink(stateLink.fields_in_what(), dimensionsInWhat)) {
-            ALOGW("DurationMetric's MetricStateLinks must be a subset of dimensions in what");
-            return nullopt;
-        }
-    }
-
-    unordered_map<int, shared_ptr<Activation>> eventActivationMap;
-    unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
-    if (!handleMetricActivation(config, metric.id(), metricIndex, metricToActivationMap,
-                                atomMatchingTrackerMap, activationAtomTrackerToMetricMap,
-                                deactivationAtomTrackerToMetricMap, metricsWithActivation,
-                                eventActivationMap, eventDeactivationMap)) {
-        return nullopt;
-    }
-
-    uint64_t metricHash;
-    if (!getMetricProtoHash(config, metric, metric.id(), metricToActivationMap, metricHash)) {
-        return nullopt;
-    }
-
-    sp<MetricProducer> producer = new DurationMetricProducer(
-            key, metric, conditionIndex, initialConditionCache, whatIndex, startIndex, stopIndex,
-            stopAllIndex, nesting, wizard, metricHash, internalDimensions, timeBaseNs,
-            currentTimeNs, eventActivationMap, eventDeactivationMap, slicedStateAtoms,
-            stateGroupMap);
-    if (!producer->isValid()) {
-        return nullopt;
-    }
-    return {producer};
-}
-
-optional<sp<MetricProducer>> createEventMetricProducerAndUpdateMetadata(
-        const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
-        const EventMetric& metric, const int metricIndex,
-        const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-        const unordered_map<int64_t, int>& atomMatchingTrackerMap,
-        vector<sp<ConditionTracker>>& allConditionTrackers,
-        const unordered_map<int64_t, int>& conditionTrackerMap,
-        const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
-        const unordered_map<int64_t, int>& metricToActivationMap,
-        unordered_map<int, vector<int>>& trackerToMetricMap,
-        unordered_map<int, vector<int>>& conditionToMetricMap,
-        unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
-        unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
-        vector<int>& metricsWithActivation) {
-    if (!metric.has_id() || !metric.has_what()) {
-        ALOGE("cannot find the metric name or what in config");
-        return nullopt;
-    }
-    int trackerIndex;
-    if (!handleMetricWithAtomMatchingTrackers(metric.what(), metricIndex, false,
-                                              allAtomMatchingTrackers, atomMatchingTrackerMap,
-                                              trackerToMetricMap, trackerIndex)) {
-        return nullopt;
-    }
-
-    int conditionIndex = -1;
-    if (metric.has_condition()) {
-        if (!handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
-                                        metric.links(), allConditionTrackers, conditionIndex,
-                                        conditionToMetricMap)) {
-            return nullopt;
-        }
-    } else {
-        if (metric.links_size() > 0) {
-            ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
-            return nullopt;
-        }
-    }
-
-    unordered_map<int, shared_ptr<Activation>> eventActivationMap;
-    unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
-    bool success = handleMetricActivation(config, metric.id(), metricIndex, metricToActivationMap,
-                                          atomMatchingTrackerMap, activationAtomTrackerToMetricMap,
-                                          deactivationAtomTrackerToMetricMap, metricsWithActivation,
-                                          eventActivationMap, eventDeactivationMap);
-    if (!success) return nullptr;
-
-    uint64_t metricHash;
-    if (!getMetricProtoHash(config, metric, metric.id(), metricToActivationMap, metricHash)) {
-        return nullopt;
-    }
-
-    return {new EventMetricProducer(key, metric, conditionIndex, initialConditionCache, wizard,
-                                    metricHash, timeBaseNs, eventActivationMap,
-                                    eventDeactivationMap)};
-}
-
-optional<sp<MetricProducer>> createValueMetricProducerAndUpdateMetadata(
-        const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
-        const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
-        const ValueMetric& metric, const int metricIndex,
-        const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-        const unordered_map<int64_t, int>& atomMatchingTrackerMap,
-        vector<sp<ConditionTracker>>& allConditionTrackers,
-        const unordered_map<int64_t, int>& conditionTrackerMap,
-        const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
-        const sp<EventMatcherWizard>& matcherWizard,
-        const unordered_map<int64_t, int>& stateAtomIdMap,
-        const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
-        const unordered_map<int64_t, int>& metricToActivationMap,
-        unordered_map<int, vector<int>>& trackerToMetricMap,
-        unordered_map<int, vector<int>>& conditionToMetricMap,
-        unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
-        unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
-        vector<int>& metricsWithActivation) {
-    if (!metric.has_id() || !metric.has_what()) {
-        ALOGE("cannot find metric id or \"what\" in ValueMetric \"%lld\"", (long long)metric.id());
-        return nullopt;
-    }
-    if (!metric.has_value_field()) {
-        ALOGE("cannot find \"value_field\" in ValueMetric \"%lld\"", (long long)metric.id());
-        return nullopt;
-    }
-    std::vector<Matcher> fieldMatchers;
-    translateFieldMatcher(metric.value_field(), &fieldMatchers);
-    if (fieldMatchers.size() < 1) {
-        ALOGE("incorrect \"value_field\" in ValueMetric \"%lld\"", (long long)metric.id());
-        return nullopt;
-    }
-
-    int trackerIndex;
-    if (!handleMetricWithAtomMatchingTrackers(metric.what(), metricIndex,
-                                              metric.has_dimensions_in_what(),
-                                              allAtomMatchingTrackers, atomMatchingTrackerMap,
-                                              trackerToMetricMap, trackerIndex)) {
-        return nullopt;
-    }
-
-    sp<AtomMatchingTracker> atomMatcher = allAtomMatchingTrackers.at(trackerIndex);
-    // If it is pulled atom, it should be simple matcher with one tagId.
-    if (atomMatcher->getAtomIds().size() != 1) {
-        return nullopt;
-    }
-    int atomTagId = *(atomMatcher->getAtomIds().begin());
-    int pullTagId = pullerManager->PullerForMatcherExists(atomTagId) ? atomTagId : -1;
-
-    int conditionIndex = -1;
-    if (metric.has_condition()) {
-        if (!handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
-                                        metric.links(), allConditionTrackers, conditionIndex,
-                                        conditionToMetricMap)) {
-            return nullopt;
-        }
-    } else if (metric.links_size() > 0) {
-        ALOGE("metrics has a MetricConditionLink but doesn't have a condition");
-        return nullopt;
-    }
-
-    std::vector<int> slicedStateAtoms;
-    unordered_map<int, unordered_map<int, int64_t>> stateGroupMap;
-    if (metric.slice_by_state_size() > 0) {
-        if (!handleMetricWithStates(config, metric.slice_by_state(), stateAtomIdMap,
-                                    allStateGroupMaps, slicedStateAtoms, stateGroupMap)) {
-            return nullopt;
-        }
-    } else if (metric.state_link_size() > 0) {
-        ALOGE("ValueMetric has a MetricStateLink but doesn't have a sliced state");
-        return nullopt;
-    }
-
-    // Check that all metric state links are a subset of dimensions_in_what fields.
-    std::vector<Matcher> dimensionsInWhat;
-    translateFieldMatcher(metric.dimensions_in_what(), &dimensionsInWhat);
-    for (const auto& stateLink : metric.state_link()) {
-        if (!handleMetricWithStateLink(stateLink.fields_in_what(), dimensionsInWhat)) {
-            ALOGW("ValueMetric's MetricStateLinks must be a subset of the dimensions in what");
-            return nullopt;
-        }
-    }
-
-    unordered_map<int, shared_ptr<Activation>> eventActivationMap;
-    unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
-    if (!handleMetricActivation(config, metric.id(), metricIndex, metricToActivationMap,
-                                          atomMatchingTrackerMap, activationAtomTrackerToMetricMap,
-                                          deactivationAtomTrackerToMetricMap, metricsWithActivation,
-                                          eventActivationMap, eventDeactivationMap)) {
-        return nullopt;
-    }
-
-    uint64_t metricHash;
-    if (!getMetricProtoHash(config, metric, metric.id(), metricToActivationMap, metricHash)) {
-        return nullopt;
-    }
-
-    return {new ValueMetricProducer(key, metric, conditionIndex, initialConditionCache, wizard,
-                                    metricHash, trackerIndex, matcherWizard, pullTagId, timeBaseNs,
-                                    currentTimeNs, pullerManager, eventActivationMap,
-                                    eventDeactivationMap, slicedStateAtoms, stateGroupMap)};
-}
-
-optional<sp<MetricProducer>> createGaugeMetricProducerAndUpdateMetadata(
-        const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
-        const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
-        const GaugeMetric& metric, const int metricIndex,
-        const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-        const unordered_map<int64_t, int>& atomMatchingTrackerMap,
-        vector<sp<ConditionTracker>>& allConditionTrackers,
-        const unordered_map<int64_t, int>& conditionTrackerMap,
-        const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
-        const sp<EventMatcherWizard>& matcherWizard,
-        const unordered_map<int64_t, int>& metricToActivationMap,
-        unordered_map<int, vector<int>>& trackerToMetricMap,
-        unordered_map<int, vector<int>>& conditionToMetricMap,
-        unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
-        unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
-        vector<int>& metricsWithActivation) {
-    if (!metric.has_id() || !metric.has_what()) {
-        ALOGE("cannot find metric id or \"what\" in GaugeMetric \"%lld\"", (long long)metric.id());
-        return nullopt;
-    }
-
-    if ((!metric.gauge_fields_filter().has_include_all() ||
-         (metric.gauge_fields_filter().include_all() == false)) &&
-        !hasLeafNode(metric.gauge_fields_filter().fields())) {
-        ALOGW("Incorrect field filter setting in GaugeMetric %lld", (long long)metric.id());
-        return nullopt;
-    }
-    if ((metric.gauge_fields_filter().has_include_all() &&
-         metric.gauge_fields_filter().include_all() == true) &&
-        hasLeafNode(metric.gauge_fields_filter().fields())) {
-        ALOGW("Incorrect field filter setting in GaugeMetric %lld", (long long)metric.id());
-        return nullopt;
-    }
-
-    int trackerIndex;
-    if (!handleMetricWithAtomMatchingTrackers(metric.what(), metricIndex,
-                                              metric.has_dimensions_in_what(),
-                                              allAtomMatchingTrackers, atomMatchingTrackerMap,
-                                              trackerToMetricMap, trackerIndex)) {
-        return nullopt;
-    }
-
-    sp<AtomMatchingTracker> atomMatcher = allAtomMatchingTrackers.at(trackerIndex);
-    // For GaugeMetric atom, it should be simple matcher with one tagId.
-    if (atomMatcher->getAtomIds().size() != 1) {
-        return nullopt;
-    }
-    int atomTagId = *(atomMatcher->getAtomIds().begin());
-    int pullTagId = pullerManager->PullerForMatcherExists(atomTagId) ? atomTagId : -1;
-
-    int triggerTrackerIndex;
-    int triggerAtomId = -1;
-    if (metric.has_trigger_event()) {
-        if (pullTagId == -1) {
-            ALOGW("Pull atom not specified for trigger");
-            return nullopt;
-        }
-        // trigger_event should be used with FIRST_N_SAMPLES
-        if (metric.sampling_type() != GaugeMetric::FIRST_N_SAMPLES) {
-            ALOGW("Gauge Metric with trigger event must have sampling type FIRST_N_SAMPLES");
-            return nullopt;
-        }
-        if (!handleMetricWithAtomMatchingTrackers(metric.trigger_event(), metricIndex,
-                                                  /*enforceOneAtom=*/true, allAtomMatchingTrackers,
-                                                  atomMatchingTrackerMap, trackerToMetricMap,
-                                                  triggerTrackerIndex)) {
-            return nullopt;
-        }
-        sp<AtomMatchingTracker> triggerAtomMatcher =
-                allAtomMatchingTrackers.at(triggerTrackerIndex);
-        triggerAtomId = *(triggerAtomMatcher->getAtomIds().begin());
-    }
-
-    if (!metric.has_trigger_event() && pullTagId != -1 &&
-        metric.sampling_type() == GaugeMetric::FIRST_N_SAMPLES) {
-        ALOGW("FIRST_N_SAMPLES is only for pushed event or pull_on_trigger");
-        return nullopt;
-    }
-
-    int conditionIndex = -1;
-    if (metric.has_condition()) {
-        if (!handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
-                                        metric.links(), allConditionTrackers, conditionIndex,
-                                        conditionToMetricMap)) {
-            return nullopt;
-        }
-    } else {
-        if (metric.links_size() > 0) {
-            ALOGW("metrics has a MetricConditionLink but doesn't have a condition");
-            return nullopt;
-        }
-    }
-
-    unordered_map<int, shared_ptr<Activation>> eventActivationMap;
-    unordered_map<int, vector<shared_ptr<Activation>>> eventDeactivationMap;
-    if (!handleMetricActivation(config, metric.id(), metricIndex, metricToActivationMap,
-                                atomMatchingTrackerMap, activationAtomTrackerToMetricMap,
-                                deactivationAtomTrackerToMetricMap, metricsWithActivation,
-                                eventActivationMap, eventDeactivationMap)) {
-        return nullopt;
-    }
-
-    uint64_t metricHash;
-    if (!getMetricProtoHash(config, metric, metric.id(), metricToActivationMap, metricHash)) {
-        return nullopt;
-    }
-
-    return {new GaugeMetricProducer(key, metric, conditionIndex, initialConditionCache, wizard,
-                                    metricHash, trackerIndex, matcherWizard, pullTagId,
-                                    triggerAtomId, atomTagId, timeBaseNs, currentTimeNs,
-                                    pullerManager, eventActivationMap, eventDeactivationMap)};
-}
-
-optional<sp<AnomalyTracker>> createAnomalyTracker(
-        const Alert& alert, const sp<AlarmMonitor>& anomalyAlarmMonitor,
-        const unordered_map<int64_t, int>& metricProducerMap,
-        vector<sp<MetricProducer>>& allMetricProducers) {
-    const auto& itr = metricProducerMap.find(alert.metric_id());
-    if (itr == metricProducerMap.end()) {
-        ALOGW("alert \"%lld\" has unknown metric id: \"%lld\"", (long long)alert.id(),
-              (long long)alert.metric_id());
-        return nullopt;
-    }
-    if (!alert.has_trigger_if_sum_gt()) {
-        ALOGW("invalid alert: missing threshold");
-        return nullopt;
-    }
-    if (alert.trigger_if_sum_gt() < 0 || alert.num_buckets() <= 0) {
-        ALOGW("invalid alert: threshold=%f num_buckets= %d", alert.trigger_if_sum_gt(),
-              alert.num_buckets());
-        return nullopt;
-    }
-    const int metricIndex = itr->second;
-    sp<MetricProducer> metric = allMetricProducers[metricIndex];
-    sp<AnomalyTracker> anomalyTracker = metric->addAnomalyTracker(alert, anomalyAlarmMonitor);
-    if (anomalyTracker == nullptr) {
-        // The ALOGW for this invalid alert was already displayed in addAnomalyTracker().
-        return nullopt;
-    }
-    return {anomalyTracker};
-}
-
-bool initAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap,
-                              unordered_map<int64_t, int>& atomMatchingTrackerMap,
-                              vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-                              set<int>& allTagIds) {
-    vector<AtomMatcher> matcherConfigs;
-    const int atomMatcherCount = config.atom_matcher_size();
-    matcherConfigs.reserve(atomMatcherCount);
-    allAtomMatchingTrackers.reserve(atomMatcherCount);
-
-    for (int i = 0; i < atomMatcherCount; i++) {
-        const AtomMatcher& logMatcher = config.atom_matcher(i);
-        sp<AtomMatchingTracker> tracker = createAtomMatchingTracker(logMatcher, i, uidMap);
-        if (tracker == nullptr) {
-            return false;
-        }
-        allAtomMatchingTrackers.push_back(tracker);
-        if (atomMatchingTrackerMap.find(logMatcher.id()) != atomMatchingTrackerMap.end()) {
-            ALOGE("Duplicate AtomMatcher found!");
-            return false;
-        }
-        atomMatchingTrackerMap[logMatcher.id()] = i;
-        matcherConfigs.push_back(logMatcher);
-    }
-
-    vector<bool> stackTracker2(allAtomMatchingTrackers.size(), false);
-    for (auto& matcher : allAtomMatchingTrackers) {
-        if (!matcher->init(matcherConfigs, allAtomMatchingTrackers, atomMatchingTrackerMap,
-                           stackTracker2)) {
-            return false;
-        }
-        // Collect all the tag ids that are interesting. TagIds exist in leaf nodes only.
-        const set<int>& tagIds = matcher->getAtomIds();
-        allTagIds.insert(tagIds.begin(), tagIds.end());
-    }
-    return true;
-}
-
-bool initConditions(const ConfigKey& key, const StatsdConfig& config,
-                    const unordered_map<int64_t, int>& atomMatchingTrackerMap,
-                    unordered_map<int64_t, int>& conditionTrackerMap,
-                    vector<sp<ConditionTracker>>& allConditionTrackers,
-                    unordered_map<int, std::vector<int>>& trackerToConditionMap,
-                    vector<ConditionState>& initialConditionCache) {
-    vector<Predicate> conditionConfigs;
-    const int conditionTrackerCount = config.predicate_size();
-    conditionConfigs.reserve(conditionTrackerCount);
-    allConditionTrackers.reserve(conditionTrackerCount);
-    initialConditionCache.assign(conditionTrackerCount, ConditionState::kNotEvaluated);
-
-    for (int i = 0; i < conditionTrackerCount; i++) {
-        const Predicate& condition = config.predicate(i);
-        sp<ConditionTracker> tracker =
-                createConditionTracker(key, condition, i, atomMatchingTrackerMap);
-        if (tracker == nullptr) {
-            return false;
-        }
-        allConditionTrackers.push_back(tracker);
-        if (conditionTrackerMap.find(condition.id()) != conditionTrackerMap.end()) {
-            ALOGE("Duplicate Predicate found!");
-            return false;
-        }
-        conditionTrackerMap[condition.id()] = i;
-        conditionConfigs.push_back(condition);
-    }
-
-    vector<bool> stackTracker(allConditionTrackers.size(), false);
-    for (size_t i = 0; i < allConditionTrackers.size(); i++) {
-        auto& conditionTracker = allConditionTrackers[i];
-        if (!conditionTracker->init(conditionConfigs, allConditionTrackers, conditionTrackerMap,
-                                    stackTracker, initialConditionCache)) {
-            return false;
-        }
-        for (const int trackerIndex : conditionTracker->getAtomMatchingTrackerIndex()) {
-            auto& conditionList = trackerToConditionMap[trackerIndex];
-            conditionList.push_back(i);
-        }
-    }
-    return true;
-}
-
-bool initStates(const StatsdConfig& config, unordered_map<int64_t, int>& stateAtomIdMap,
-                unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
-                map<int64_t, uint64_t>& stateProtoHashes) {
-    for (int i = 0; i < config.state_size(); i++) {
-        const State& state = config.state(i);
-        const int64_t stateId = state.id();
-        stateAtomIdMap[stateId] = state.atom_id();
-
-        string serializedState;
-        if (!state.SerializeToString(&serializedState)) {
-            ALOGE("Unable to serialize state %lld", (long long)stateId);
-            return false;
-        }
-        stateProtoHashes[stateId] = Hash64(serializedState);
-
-        const StateMap& stateMap = state.map();
-        for (auto group : stateMap.group()) {
-            for (auto value : group.value()) {
-                allStateGroupMaps[stateId][value] = group.group_id();
-            }
-        }
-    }
-
-    return true;
-}
-
-bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseTimeNs,
-                 const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
-                 const unordered_map<int64_t, int>& atomMatchingTrackerMap,
-                 const unordered_map<int64_t, int>& conditionTrackerMap,
-                 const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-                 const unordered_map<int64_t, int>& stateAtomIdMap,
-                 const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
-                 vector<sp<ConditionTracker>>& allConditionTrackers,
-                 const vector<ConditionState>& initialConditionCache,
-                 vector<sp<MetricProducer>>& allMetricProducers,
-                 unordered_map<int, vector<int>>& conditionToMetricMap,
-                 unordered_map<int, vector<int>>& trackerToMetricMap,
-                 unordered_map<int64_t, int>& metricMap, std::set<int64_t>& noReportMetricIds,
-                 unordered_map<int, vector<int>>& activationAtomTrackerToMetricMap,
-                 unordered_map<int, vector<int>>& deactivationAtomTrackerToMetricMap,
-                 vector<int>& metricsWithActivation) {
-    sp<ConditionWizard> wizard = new ConditionWizard(allConditionTrackers);
-    sp<EventMatcherWizard> matcherWizard = new EventMatcherWizard(allAtomMatchingTrackers);
-    const int allMetricsCount = config.count_metric_size() + config.duration_metric_size() +
-                                config.event_metric_size() + config.gauge_metric_size() +
-                                config.value_metric_size();
-    allMetricProducers.reserve(allMetricsCount);
-
-    // Construct map from metric id to metric activation index. The map will be used to determine
-    // the metric activation corresponding to a metric.
-    unordered_map<int64_t, int> metricToActivationMap;
-    for (int i = 0; i < config.metric_activation_size(); i++) {
-        const MetricActivation& metricActivation = config.metric_activation(i);
-        int64_t metricId = metricActivation.metric_id();
-        if (metricToActivationMap.find(metricId) != metricToActivationMap.end()) {
-            ALOGE("Metric %lld has multiple MetricActivations", (long long)metricId);
-            return false;
-        }
-        metricToActivationMap.insert({metricId, i});
-    }
-
-    // Build MetricProducers for each metric defined in config.
-    // build CountMetricProducer
-    for (int i = 0; i < config.count_metric_size(); i++) {
-        int metricIndex = allMetricProducers.size();
-        const CountMetric& metric = config.count_metric(i);
-        metricMap.insert({metric.id(), metricIndex});
-        optional<sp<MetricProducer>> producer = createCountMetricProducerAndUpdateMetadata(
-                key, config, timeBaseTimeNs, currentTimeNs, metric, metricIndex,
-                allAtomMatchingTrackers, atomMatchingTrackerMap, allConditionTrackers,
-                conditionTrackerMap, initialConditionCache, wizard, stateAtomIdMap,
-                allStateGroupMaps, metricToActivationMap, trackerToMetricMap, conditionToMetricMap,
-                activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
-                metricsWithActivation);
-        if (!producer) {
-            return false;
-        }
-        allMetricProducers.push_back(producer.value());
-    }
-
-    // build DurationMetricProducer
-    for (int i = 0; i < config.duration_metric_size(); i++) {
-        int metricIndex = allMetricProducers.size();
-        const DurationMetric& metric = config.duration_metric(i);
-        metricMap.insert({metric.id(), metricIndex});
-
-        optional<sp<MetricProducer>> producer = createDurationMetricProducerAndUpdateMetadata(
-                key, config, timeBaseTimeNs, currentTimeNs, metric, metricIndex,
-                allAtomMatchingTrackers, atomMatchingTrackerMap, allConditionTrackers,
-                conditionTrackerMap, initialConditionCache, wizard, stateAtomIdMap,
-                allStateGroupMaps, metricToActivationMap, trackerToMetricMap, conditionToMetricMap,
-                activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
-                metricsWithActivation);
-        if (!producer) {
-            return false;
-        }
-        allMetricProducers.push_back(producer.value());
-    }
-
-    // build EventMetricProducer
-    for (int i = 0; i < config.event_metric_size(); i++) {
-        int metricIndex = allMetricProducers.size();
-        const EventMetric& metric = config.event_metric(i);
-        metricMap.insert({metric.id(), metricIndex});
-        optional<sp<MetricProducer>> producer = createEventMetricProducerAndUpdateMetadata(
-                key, config, timeBaseTimeNs, metric, metricIndex, allAtomMatchingTrackers,
-                atomMatchingTrackerMap, allConditionTrackers, conditionTrackerMap,
-                initialConditionCache, wizard, metricToActivationMap, trackerToMetricMap,
-                conditionToMetricMap, activationAtomTrackerToMetricMap,
-                deactivationAtomTrackerToMetricMap, metricsWithActivation);
-        if (!producer) {
-            return false;
-        }
-        allMetricProducers.push_back(producer.value());
-    }
-
-    // build ValueMetricProducer
-    for (int i = 0; i < config.value_metric_size(); i++) {
-        int metricIndex = allMetricProducers.size();
-        const ValueMetric& metric = config.value_metric(i);
-        metricMap.insert({metric.id(), metricIndex});
-        optional<sp<MetricProducer>> producer = createValueMetricProducerAndUpdateMetadata(
-                key, config, timeBaseTimeNs, currentTimeNs, pullerManager, metric, metricIndex,
-                allAtomMatchingTrackers, atomMatchingTrackerMap, allConditionTrackers,
-                conditionTrackerMap, initialConditionCache, wizard, matcherWizard, stateAtomIdMap,
-                allStateGroupMaps, metricToActivationMap, trackerToMetricMap, conditionToMetricMap,
-                activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
-                metricsWithActivation);
-        if (!producer) {
-            return false;
-        }
-        allMetricProducers.push_back(producer.value());
-    }
-
-    // Gauge metrics.
-    for (int i = 0; i < config.gauge_metric_size(); i++) {
-        int metricIndex = allMetricProducers.size();
-        const GaugeMetric& metric = config.gauge_metric(i);
-        metricMap.insert({metric.id(), metricIndex});
-        optional<sp<MetricProducer>> producer = createGaugeMetricProducerAndUpdateMetadata(
-                key, config, timeBaseTimeNs, currentTimeNs, pullerManager, metric, metricIndex,
-                allAtomMatchingTrackers, atomMatchingTrackerMap, allConditionTrackers,
-                conditionTrackerMap, initialConditionCache, wizard, matcherWizard,
-                metricToActivationMap, trackerToMetricMap, conditionToMetricMap,
-                activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
-                metricsWithActivation);
-        if (!producer) {
-            return false;
-        }
-        allMetricProducers.push_back(producer.value());
-    }
-    for (int i = 0; i < config.no_report_metric_size(); ++i) {
-        const auto no_report_metric = config.no_report_metric(i);
-        if (metricMap.find(no_report_metric) == metricMap.end()) {
-            ALOGW("no_report_metric %" PRId64 " not exist", no_report_metric);
-            return false;
-        }
-        noReportMetricIds.insert(no_report_metric);
-    }
-
-    const set<int> whitelistedAtomIds(config.whitelisted_atom_ids().begin(),
-                                      config.whitelisted_atom_ids().end());
-    for (const auto& it : allMetricProducers) {
-        // Register metrics to StateTrackers
-        for (int atomId : it->getSlicedStateAtoms()) {
-            // Register listener for non-whitelisted atoms only. Using whitelisted atom as a sliced
-            // state atom is not allowed.
-            if (whitelistedAtomIds.find(atomId) == whitelistedAtomIds.end()) {
-                StateManager::getInstance().registerListener(atomId, it);
-            } else {
-                return false;
-            }
-        }
-    }
-    return true;
-}
-
-bool initAlerts(const StatsdConfig& config, const unordered_map<int64_t, int>& metricProducerMap,
-                unordered_map<int64_t, int>& alertTrackerMap,
-                const sp<AlarmMonitor>& anomalyAlarmMonitor,
-                vector<sp<MetricProducer>>& allMetricProducers,
-                vector<sp<AnomalyTracker>>& allAnomalyTrackers) {
-    for (int i = 0; i < config.alert_size(); i++) {
-        const Alert& alert = config.alert(i);
-        alertTrackerMap.insert(std::make_pair(alert.id(), allAnomalyTrackers.size()));
-        optional<sp<AnomalyTracker>> anomalyTracker = createAnomalyTracker(
-                alert, anomalyAlarmMonitor, metricProducerMap, allMetricProducers);
-        if (!anomalyTracker) {
-            return false;
-        }
-        allAnomalyTrackers.push_back(anomalyTracker.value());
-    }
-    if (!initSubscribersForSubscriptionType(config, Subscription::ALERT, alertTrackerMap,
-                                            allAnomalyTrackers)) {
-        return false;
-    }
-    return true;
-}
-
-bool initAlarms(const StatsdConfig& config, const ConfigKey& key,
-                const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs,
-                const int64_t currentTimeNs, vector<sp<AlarmTracker>>& allAlarmTrackers) {
-    unordered_map<int64_t, int> alarmTrackerMap;
-    int64_t startMillis = timeBaseNs / 1000 / 1000;
-    int64_t currentTimeMillis = currentTimeNs / 1000 / 1000;
-    for (int i = 0; i < config.alarm_size(); i++) {
-        const Alarm& alarm = config.alarm(i);
-        if (alarm.offset_millis() <= 0) {
-            ALOGW("Alarm offset_millis should be larger than 0.");
-            return false;
-        }
-        if (alarm.period_millis() <= 0) {
-            ALOGW("Alarm period_millis should be larger than 0.");
-            return false;
-        }
-        alarmTrackerMap.insert(std::make_pair(alarm.id(), allAlarmTrackers.size()));
-        allAlarmTrackers.push_back(
-                new AlarmTracker(startMillis, currentTimeMillis, alarm, key, periodicAlarmMonitor));
-    }
-    if (!initSubscribersForSubscriptionType(config, Subscription::ALARM, alarmTrackerMap,
-                                            allAlarmTrackers)) {
-        return false;
-    }
-    return true;
-}
-
-bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap,
-                      const sp<StatsPullerManager>& pullerManager,
-                      const sp<AlarmMonitor>& anomalyAlarmMonitor,
-                      const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs,
-                      const int64_t currentTimeNs, set<int>& allTagIds,
-                      vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-                      unordered_map<int64_t, int>& atomMatchingTrackerMap,
-                      vector<sp<ConditionTracker>>& allConditionTrackers,
-                      unordered_map<int64_t, int>& conditionTrackerMap,
-                      vector<sp<MetricProducer>>& allMetricProducers,
-                      unordered_map<int64_t, int>& metricProducerMap,
-                      vector<sp<AnomalyTracker>>& allAnomalyTrackers,
-                      vector<sp<AlarmTracker>>& allPeriodicAlarmTrackers,
-                      unordered_map<int, std::vector<int>>& conditionToMetricMap,
-                      unordered_map<int, std::vector<int>>& trackerToMetricMap,
-                      unordered_map<int, std::vector<int>>& trackerToConditionMap,
-                      unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
-                      unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
-                      unordered_map<int64_t, int>& alertTrackerMap,
-                      vector<int>& metricsWithActivation, map<int64_t, uint64_t>& stateProtoHashes,
-                      set<int64_t>& noReportMetricIds) {
-    vector<ConditionState> initialConditionCache;
-    unordered_map<int64_t, int> stateAtomIdMap;
-    unordered_map<int64_t, unordered_map<int, int64_t>> allStateGroupMaps;
-
-    if (!initAtomMatchingTrackers(config, uidMap, atomMatchingTrackerMap, allAtomMatchingTrackers,
-                                  allTagIds)) {
-        ALOGE("initAtomMatchingTrackers failed");
-        return false;
-    }
-    VLOG("initAtomMatchingTrackers succeed...");
-
-    if (!initConditions(key, config, atomMatchingTrackerMap, conditionTrackerMap,
-                        allConditionTrackers, trackerToConditionMap, initialConditionCache)) {
-        ALOGE("initConditionTrackers failed");
-        return false;
-    }
-
-    if (!initStates(config, stateAtomIdMap, allStateGroupMaps, stateProtoHashes)) {
-        ALOGE("initStates failed");
-        return false;
-    }
-    if (!initMetrics(key, config, timeBaseNs, currentTimeNs, pullerManager, atomMatchingTrackerMap,
-                     conditionTrackerMap, allAtomMatchingTrackers, stateAtomIdMap,
-                     allStateGroupMaps, allConditionTrackers, initialConditionCache,
-                     allMetricProducers, conditionToMetricMap, trackerToMetricMap,
-                     metricProducerMap, noReportMetricIds, activationAtomTrackerToMetricMap,
-                     deactivationAtomTrackerToMetricMap, metricsWithActivation)) {
-        ALOGE("initMetricProducers failed");
-        return false;
-    }
-    if (!initAlerts(config, metricProducerMap, alertTrackerMap, anomalyAlarmMonitor,
-                    allMetricProducers, allAnomalyTrackers)) {
-        ALOGE("initAlerts failed");
-        return false;
-    }
-    if (!initAlarms(config, key, periodicAlarmMonitor, timeBaseNs, currentTimeNs,
-                    allPeriodicAlarmTrackers)) {
-        ALOGE("initAlarms failed");
-        return false;
-    }
-
-    return true;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h
deleted file mode 100644
index 84e1e4e..0000000
--- a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.h
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <set>
-#include <unordered_map>
-#include <vector>
-
-#include "anomaly/AlarmTracker.h"
-#include "condition/ConditionTracker.h"
-#include "external/StatsPullerManager.h"
-#include "matchers/AtomMatchingTracker.h"
-#include "metrics/MetricProducer.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// Helper functions for creating, validating, and updating config components from StatsdConfig.
-// Should only be called from metrics_manager_util and config_update_utils.
-
-// Create a AtomMatchingTracker.
-// input:
-// [logMatcher]: the input AtomMatcher from the StatsdConfig
-// [index]: the index of the matcher
-// output:
-// new AtomMatchingTracker, or null if the tracker is unable to be created
-sp<AtomMatchingTracker> createAtomMatchingTracker(const AtomMatcher& logMatcher, const int index,
-                                                  const sp<UidMap>& uidMap);
-
-// Create a ConditionTracker.
-// input:
-// [predicate]: the input Predicate from the StatsdConfig
-// [index]: the index of the condition tracker
-// [atomMatchingTrackerMap]: map of atom matcher id to its index in allAtomMatchingTrackers
-// output:
-// new ConditionTracker, or null if the tracker is unable to be created
-sp<ConditionTracker> createConditionTracker(
-        const ConfigKey& key, const Predicate& predicate, const int index,
-        const unordered_map<int64_t, int>& atomMatchingTrackerMap);
-
-// Get the hash of a metric, combining the activation if the metric has one.
-bool getMetricProtoHash(const StatsdConfig& config, const google::protobuf::MessageLite& metric,
-                        const int64_t id,
-                        const std::unordered_map<int64_t, int>& metricToActivationMap,
-                        uint64_t& metricHash);
-
-// 1. Validates matcher existence
-// 2. Enforces matchers with dimensions and those used for trigger_event are about one atom
-// 3. Gets matcher index and updates tracker to metric map
-bool handleMetricWithAtomMatchingTrackers(
-        const int64_t matcherId, const int metricIndex, const bool enforceOneAtom,
-        const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-        const std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
-        std::unordered_map<int, std::vector<int>>& trackerToMetricMap, int& logTrackerIndex);
-
-// 1. Validates condition existence, including those in links
-// 2. Gets condition index and updates condition to metric map
-bool handleMetricWithConditions(
-        const int64_t condition, const int metricIndex,
-        const std::unordered_map<int64_t, int>& conditionTrackerMap,
-        const ::google::protobuf::RepeatedPtrField<::android::os::statsd::MetricConditionLink>&
-                links,
-        const std::vector<sp<ConditionTracker>>& allConditionTrackers, int& conditionIndex,
-        std::unordered_map<int, std::vector<int>>& conditionToMetricMap);
-
-// Validates a metricActivation and populates state.
-// Fills the new event activation/deactivation maps, preserving the existing activations.
-// Returns false if there are errors.
-bool handleMetricActivationOnConfigUpdate(
-        const StatsdConfig& config, const int64_t metricId, const int metricIndex,
-        const std::unordered_map<int64_t, int>& metricToActivationMap,
-        const std::unordered_map<int64_t, int>& oldAtomMatchingTrackerMap,
-        const std::unordered_map<int64_t, int>& newAtomMatchingTrackerMap,
-        const std::unordered_map<int, shared_ptr<Activation>>& oldEventActivationMap,
-        std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
-        std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
-        std::vector<int>& metricsWithActivation,
-        std::unordered_map<int, shared_ptr<Activation>>& newEventActivationMap,
-        std::unordered_map<int, std::vector<shared_ptr<Activation>>>& newEventDeactivationMap);
-
-// Creates a CountMetricProducer and updates the vectors/maps used by MetricsManager with
-// the appropriate indices. Returns an sp to the producer, or nullopt if there was an error.
-optional<sp<MetricProducer>> createCountMetricProducerAndUpdateMetadata(
-        const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
-        const int64_t currentTimeNs, const CountMetric& metric, const int metricIndex,
-        const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-        const std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
-        std::vector<sp<ConditionTracker>>& allConditionTrackers,
-        const std::unordered_map<int64_t, int>& conditionTrackerMap,
-        const std::vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
-        const std::unordered_map<int64_t, int>& stateAtomIdMap,
-        const std::unordered_map<int64_t, std::unordered_map<int, int64_t>>& allStateGroupMaps,
-        const std::unordered_map<int64_t, int>& metricToActivationMap,
-        std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
-        std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
-        std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
-        std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
-        std::vector<int>& metricsWithActivation);
-
-// Creates a DurationMetricProducer and updates the vectors/maps used by MetricsManager with
-// the appropriate indices. Returns an sp to the producer, or nullopt if there was an error.
-optional<sp<MetricProducer>> createDurationMetricProducerAndUpdateMetadata(
-        const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
-        const int64_t currentTimeNs, const DurationMetric& metric, const int metricIndex,
-        const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-        const std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
-        std::vector<sp<ConditionTracker>>& allConditionTrackers,
-        const std::unordered_map<int64_t, int>& conditionTrackerMap,
-        const std::vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
-        const std::unordered_map<int64_t, int>& stateAtomIdMap,
-        const std::unordered_map<int64_t, std::unordered_map<int, int64_t>>& allStateGroupMaps,
-        const std::unordered_map<int64_t, int>& metricToActivationMap,
-        std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
-        std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
-        std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
-        std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
-        std::vector<int>& metricsWithActivation);
-
-// Creates an EventMetricProducer and updates the vectors/maps used by MetricsManager with
-// the appropriate indices. Returns an sp to the producer, or nullopt if there was an error.
-optional<sp<MetricProducer>> createEventMetricProducerAndUpdateMetadata(
-        const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
-        const EventMetric& metric, const int metricIndex,
-        const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-        const std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
-        std::vector<sp<ConditionTracker>>& allConditionTrackers,
-        const std::unordered_map<int64_t, int>& conditionTrackerMap,
-        const std::vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
-        const std::unordered_map<int64_t, int>& metricToActivationMap,
-        std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
-        std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
-        std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
-        std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
-        std::vector<int>& metricsWithActivation);
-
-// Creates a CountMetricProducer and updates the vectors/maps used by MetricsManager with
-// the appropriate indices. Returns an sp to the producer, or nullopt if there was an error.
-optional<sp<MetricProducer>> createValueMetricProducerAndUpdateMetadata(
-        const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
-        const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
-        const ValueMetric& metric, const int metricIndex,
-        const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-        const std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
-        std::vector<sp<ConditionTracker>>& allConditionTrackers,
-        const std::unordered_map<int64_t, int>& conditionTrackerMap,
-        const std::vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
-        const sp<EventMatcherWizard>& matcherWizard,
-        const std::unordered_map<int64_t, int>& stateAtomIdMap,
-        const std::unordered_map<int64_t, std::unordered_map<int, int64_t>>& allStateGroupMaps,
-        const std::unordered_map<int64_t, int>& metricToActivationMap,
-        std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
-        std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
-        std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
-        std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
-        std::vector<int>& metricsWithActivation);
-
-// Creates a GaugeMetricProducer and updates the vectors/maps used by MetricsManager with
-// the appropriate indices. Returns an sp to the producer, or nullopt if there was an error.
-optional<sp<MetricProducer>> createGaugeMetricProducerAndUpdateMetadata(
-        const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseNs,
-        const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
-        const GaugeMetric& metric, const int metricIndex,
-        const std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-        const std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
-        std::vector<sp<ConditionTracker>>& allConditionTrackers,
-        const std::unordered_map<int64_t, int>& conditionTrackerMap,
-        const std::vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
-        const sp<EventMatcherWizard>& matcherWizard,
-        const std::unordered_map<int64_t, int>& metricToActivationMap,
-        std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
-        std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
-        std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
-        std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
-        std::vector<int>& metricsWithActivation);
-
-// Creates an AnomalyTracker and adds it to the appropriate metric.
-// Returns an sp to the AnomalyTracker, or nullopt if there was an error.
-optional<sp<AnomalyTracker>> createAnomalyTracker(
-        const Alert& alert, const sp<AlarmMonitor>& anomalyAlarmMonitor,
-        const std::unordered_map<int64_t, int>& metricProducerMap,
-        std::vector<sp<MetricProducer>>& allMetricProducers);
-
-// Templated function for adding subscriptions to alarms or alerts. Returns true if successful.
-template <typename T>
-bool initSubscribersForSubscriptionType(const StatsdConfig& config,
-                                        const Subscription_RuleType ruleType,
-                                        const std::unordered_map<int64_t, int>& ruleMap,
-                                        std::vector<T>& allRules) {
-    for (int i = 0; i < config.subscription_size(); ++i) {
-        const Subscription& subscription = config.subscription(i);
-        if (subscription.rule_type() != ruleType) {
-            continue;
-        }
-        if (subscription.subscriber_information_case() ==
-            Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) {
-            ALOGW("subscription \"%lld\" has no subscriber info.\"", (long long)subscription.id());
-            return false;
-        }
-        const auto& itr = ruleMap.find(subscription.rule_id());
-        if (itr == ruleMap.end()) {
-            ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"",
-                  (long long)subscription.id(), (long long)subscription.rule_id());
-            return false;
-        }
-        const int ruleIndex = itr->second;
-        allRules[ruleIndex]->addSubscription(subscription);
-    }
-    return true;
-}
-
-// Helper functions for MetricsManager to initialize from StatsdConfig.
-// *Note*: only initStatsdConfig() should be called from outside.
-// All other functions are intermediate
-// steps, created to make unit tests easier. And most of the parameters in these
-// functions are temporary objects in the initialization phase.
-
-// Initialize the AtomMatchingTrackers.
-// input:
-// [key]: the config key that this config belongs to
-// [config]: the input StatsdConfig
-// output:
-// [atomMatchingTrackerMap]: this map should contain matcher name to index mapping
-// [allAtomMatchingTrackers]: should store the sp to all the AtomMatchingTracker
-// [allTagIds]: contains the set of all interesting tag ids to this config.
-bool initAtomMatchingTrackers(const StatsdConfig& config, const sp<UidMap>& uidMap,
-                              std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
-                              std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-                              std::set<int>& allTagIds);
-
-// Initialize ConditionTrackers
-// input:
-// [key]: the config key that this config belongs to
-// [config]: the input config
-// [atomMatchingTrackerMap]: AtomMatchingTracker name to index mapping from previous step.
-// output:
-// [conditionTrackerMap]: this map should contain condition name to index mapping
-// [allConditionTrackers]: stores the sp to all the ConditionTrackers
-// [trackerToConditionMap]: contain the mapping from index of
-//                        log tracker to condition trackers that use the log tracker
-// [initialConditionCache]: stores the initial conditions for each ConditionTracker
-bool initConditions(const ConfigKey& key, const StatsdConfig& config,
-                    const std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
-                    std::unordered_map<int64_t, int>& conditionTrackerMap,
-                    std::vector<sp<ConditionTracker>>& allConditionTrackers,
-                    std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
-                    std::vector<ConditionState>& initialConditionCache);
-
-// Initialize State maps using State protos in the config. These maps will
-// eventually be passed to MetricProducers to initialize their state info.
-// input:
-// [config]: the input config
-// output:
-// [stateAtomIdMap]: this map should contain the mapping from state ids to atom ids
-// [allStateGroupMaps]: this map should contain the mapping from states ids and state
-//                      values to state group ids for all states
-// [stateProtoHashes]: contains a map of state id to the hash of the State proto from the config
-bool initStates(const StatsdConfig& config, unordered_map<int64_t, int>& stateAtomIdMap,
-                unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
-                std::map<int64_t, uint64_t>& stateProtoHashes);
-
-// Initialize MetricProducers.
-// input:
-// [key]: the config key that this config belongs to
-// [config]: the input config
-// [timeBaseSec]: start time base for all metrics
-// [atomMatchingTrackerMap]: AtomMatchingTracker name to index mapping from previous step.
-// [conditionTrackerMap]: condition name to index mapping
-// [stateAtomIdMap]: contains the mapping from state ids to atom ids
-// [allStateGroupMaps]: contains the mapping from atom ids and state values to
-//                      state group ids for all states
-// output:
-// [allMetricProducers]: contains the list of sp to the MetricProducers created.
-// [conditionToMetricMap]: contains the mapping from condition tracker index to
-//                          the list of MetricProducer index
-// [trackerToMetricMap]: contains the mapping from log tracker to MetricProducer index.
-bool initMetrics(
-        const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseTimeNs,
-        const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
-        const std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
-        const std::unordered_map<int64_t, int>& conditionTrackerMap,
-        const vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-        const unordered_map<int64_t, int>& stateAtomIdMap,
-        const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
-        vector<sp<ConditionTracker>>& allConditionTrackers,
-        const std::vector<ConditionState>& initialConditionCache,
-        std::vector<sp<MetricProducer>>& allMetricProducers,
-        std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
-        std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
-        std::set<int64_t>& noReportMetricIds,
-        std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
-        std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
-        std::vector<int>& metricsWithActivation);
-
-// Initialize alarms
-// Is called both on initialize new configs and config updates since alarms do not have any state.
-bool initAlarms(const StatsdConfig& config, const ConfigKey& key,
-                const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs,
-                const int64_t currentTimeNs, std::vector<sp<AlarmTracker>>& allAlarmTrackers);
-
-// Initialize MetricsManager from StatsdConfig.
-// Parameters are the members of MetricsManager. See MetricsManager for declaration.
-bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const sp<UidMap>& uidMap,
-                      const sp<StatsPullerManager>& pullerManager,
-                      const sp<AlarmMonitor>& anomalyAlarmMonitor,
-                      const sp<AlarmMonitor>& periodicAlarmMonitor, const int64_t timeBaseNs,
-                      const int64_t currentTimeNs, std::set<int>& allTagIds,
-                      std::vector<sp<AtomMatchingTracker>>& allAtomMatchingTrackers,
-                      std::unordered_map<int64_t, int>& atomMatchingTrackerMap,
-                      std::vector<sp<ConditionTracker>>& allConditionTrackers,
-                      std::unordered_map<int64_t, int>& conditionTrackerMap,
-                      std::vector<sp<MetricProducer>>& allMetricProducers,
-                      std::unordered_map<int64_t, int>& metricProducerMap,
-                      vector<sp<AnomalyTracker>>& allAnomalyTrackers,
-                      vector<sp<AlarmTracker>>& allPeriodicAlarmTrackers,
-                      std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
-                      std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
-                      std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
-                      std::unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
-                      std::unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
-                      std::unordered_map<int64_t, int>& alertTrackerMap,
-                      std::vector<int>& metricsWithActivation,
-                      std::map<int64_t, uint64_t>& stateProtoHashes,
-                      std::set<int64_t>& noReportMetricIds);
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/packages/PackageInfoListener.h b/cmds/statsd/src/packages/PackageInfoListener.h
deleted file mode 100644
index 1bc84c5..0000000
--- a/cmds/statsd/src/packages/PackageInfoListener.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef STATSD_PACKAGE_INFO_LISTENER_H
-#define STATSD_PACKAGE_INFO_LISTENER_H
-
-#include <utils/RefBase.h>
-
-#include <string>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class PackageInfoListener : public virtual android::RefBase {
-public:
-    // Uid map will notify this listener that the app with apk name and uid has been upgraded to
-    // the specified version.
-    virtual void notifyAppUpgrade(const int64_t& eventTimeNs, const std::string& apk,
-                                  const int uid, const int64_t version) = 0;
-
-    // Notify interested listeners that the given apk and uid combination no longer exits.
-    virtual void notifyAppRemoved(const int64_t& eventTimeNs, const std::string& apk,
-                                  const int uid) = 0;
-
-    // Notify the listener that the UidMap snapshot is available.
-    virtual void onUidMapReceived(const int64_t& eventTimeNs) = 0;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-#endif  // STATSD_PACKAGE_INFO_LISTENER_H
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
deleted file mode 100644
index acf40c8..0000000
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ /dev/null
@@ -1,563 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, versionCode 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "hash.h"
-#include "stats_log_util.h"
-#include "guardrail/StatsdStats.h"
-#include "packages/UidMap.h"
-
-#include <inttypes.h>
-
-using namespace android;
-
-using android::base::StringPrintf;
-using android::util::FIELD_COUNT_REPEATED;
-using android::util::FIELD_TYPE_BOOL;
-using android::util::FIELD_TYPE_FLOAT;
-using android::util::FIELD_TYPE_INT32;
-using android::util::FIELD_TYPE_INT64;
-using android::util::FIELD_TYPE_UINT64;
-using android::util::FIELD_TYPE_MESSAGE;
-using android::util::FIELD_TYPE_STRING;
-using android::util::ProtoOutputStream;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-const int FIELD_ID_SNAPSHOT_PACKAGE_NAME = 1;
-const int FIELD_ID_SNAPSHOT_PACKAGE_VERSION = 2;
-const int FIELD_ID_SNAPSHOT_PACKAGE_UID = 3;
-const int FIELD_ID_SNAPSHOT_PACKAGE_DELETED = 4;
-const int FIELD_ID_SNAPSHOT_PACKAGE_NAME_HASH = 5;
-const int FIELD_ID_SNAPSHOT_PACKAGE_VERSION_STRING = 6;
-const int FIELD_ID_SNAPSHOT_PACKAGE_VERSION_STRING_HASH = 7;
-const int FIELD_ID_SNAPSHOT_PACKAGE_INSTALLER = 8;
-const int FIELD_ID_SNAPSHOT_PACKAGE_INSTALLER_HASH = 9;
-const int FIELD_ID_SNAPSHOT_TIMESTAMP = 1;
-const int FIELD_ID_SNAPSHOT_PACKAGE_INFO = 2;
-const int FIELD_ID_SNAPSHOTS = 1;
-const int FIELD_ID_CHANGES = 2;
-const int FIELD_ID_CHANGE_DELETION = 1;
-const int FIELD_ID_CHANGE_TIMESTAMP = 2;
-const int FIELD_ID_CHANGE_PACKAGE = 3;
-const int FIELD_ID_CHANGE_UID = 4;
-const int FIELD_ID_CHANGE_NEW_VERSION = 5;
-const int FIELD_ID_CHANGE_PREV_VERSION = 6;
-const int FIELD_ID_CHANGE_PACKAGE_HASH = 7;
-const int FIELD_ID_CHANGE_NEW_VERSION_STRING = 8;
-const int FIELD_ID_CHANGE_PREV_VERSION_STRING = 9;
-const int FIELD_ID_CHANGE_NEW_VERSION_STRING_HASH = 10;
-const int FIELD_ID_CHANGE_PREV_VERSION_STRING_HASH = 11;
-
-UidMap::UidMap() : mBytesUsed(0) {}
-
-UidMap::~UidMap() {}
-
-sp<UidMap> UidMap::getInstance() {
-    static sp<UidMap> sInstance = new UidMap();
-    return sInstance;
-}
-
-bool UidMap::hasApp(int uid, const string& packageName) const {
-    lock_guard<mutex> lock(mMutex);
-
-    auto it = mMap.find(std::make_pair(uid, packageName));
-    return it != mMap.end() && !it->second.deleted;
-}
-
-string UidMap::normalizeAppName(const string& appName) const {
-    string normalizedName = appName;
-    std::transform(normalizedName.begin(), normalizedName.end(), normalizedName.begin(), ::tolower);
-    return normalizedName;
-}
-
-std::set<string> UidMap::getAppNamesFromUid(const int32_t& uid, bool returnNormalized) const {
-    lock_guard<mutex> lock(mMutex);
-    return getAppNamesFromUidLocked(uid,returnNormalized);
-}
-
-std::set<string> UidMap::getAppNamesFromUidLocked(const int32_t& uid, bool returnNormalized) const {
-    std::set<string> names;
-    for (const auto& kv : mMap) {
-        if (kv.first.first == uid && !kv.second.deleted) {
-            names.insert(returnNormalized ? normalizeAppName(kv.first.second) : kv.first.second);
-        }
-    }
-    return names;
-}
-
-int64_t UidMap::getAppVersion(int uid, const string& packageName) const {
-    lock_guard<mutex> lock(mMutex);
-
-    auto it = mMap.find(std::make_pair(uid, packageName));
-    if (it == mMap.end() || it->second.deleted) {
-        return 0;
-    }
-    return it->second.versionCode;
-}
-
-void UidMap::updateMap(const int64_t& timestamp, const vector<int32_t>& uid,
-                       const vector<int64_t>& versionCode, const vector<String16>& versionString,
-                       const vector<String16>& packageName, const vector<String16>& installer) {
-    wp<PackageInfoListener> broadcast = NULL;
-    {
-        lock_guard<mutex> lock(mMutex);  // Exclusively lock for updates.
-
-        std::unordered_map<std::pair<int, string>, AppData, PairHash> deletedApps;
-
-        // Copy all the deleted apps.
-        for (const auto& kv : mMap) {
-            if (kv.second.deleted) {
-                deletedApps[kv.first] = kv.second;
-            }
-        }
-
-        mMap.clear();
-        for (size_t j = 0; j < uid.size(); j++) {
-            string package = string(String8(packageName[j]).string());
-            mMap[std::make_pair(uid[j], package)] =
-                    AppData(versionCode[j], string(String8(versionString[j]).string()),
-                            string(String8(installer[j]).string()));
-        }
-
-        for (const auto& kv : deletedApps) {
-            auto mMapIt = mMap.find(kv.first);
-            if (mMapIt != mMap.end()) {
-                // Insert this deleted app back into the current map.
-                mMap[kv.first] = kv.second;
-            }
-        }
-
-        ensureBytesUsedBelowLimit();
-        StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
-        broadcast = mSubscriber;
-    }
-    // To avoid invoking callback while holding the internal lock. we get a copy of the listener
-    // and invoke the callback. It's still possible that after we copy the listener, it removes
-    // itself before we call it. It's then the listener's job to handle it (expect the callback to
-    // be called after listener is removed, and the listener should properly ignore it).
-    auto strongPtr = broadcast.promote();
-    if (strongPtr != NULL) {
-        strongPtr->onUidMapReceived(timestamp);
-    }
-}
-
-void UidMap::updateApp(const int64_t& timestamp, const String16& app_16, const int32_t& uid,
-                       const int64_t& versionCode, const String16& versionString,
-                       const String16& installer) {
-    wp<PackageInfoListener> broadcast = NULL;
-    string appName = string(String8(app_16).string());
-    {
-        lock_guard<mutex> lock(mMutex);
-        int32_t prevVersion = 0;
-        string prevVersionString = "";
-        string newVersionString = string(String8(versionString).string());
-        bool found = false;
-        auto it = mMap.find(std::make_pair(uid, appName));
-        if (it != mMap.end()) {
-            found = true;
-            prevVersion = it->second.versionCode;
-            prevVersionString = it->second.versionString;
-            it->second.versionCode = versionCode;
-            it->second.versionString = newVersionString;
-            it->second.installer = string(String8(installer).string());
-            it->second.deleted = false;
-        }
-        if (!found) {
-            // Otherwise, we need to add an app at this uid.
-            mMap[std::make_pair(uid, appName)] =
-                    AppData(versionCode, newVersionString, string(String8(installer).string()));
-        } else {
-            // Only notify the listeners if this is an app upgrade. If this app is being installed
-            // for the first time, then we don't notify the listeners.
-            // It's also OK to split again if we're forming a partial bucket after re-installing an
-            // app after deletion.
-            broadcast = mSubscriber;
-        }
-        mChanges.emplace_back(false, timestamp, appName, uid, versionCode, newVersionString,
-                              prevVersion, prevVersionString);
-        mBytesUsed += kBytesChangeRecord;
-        ensureBytesUsedBelowLimit();
-        StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
-        StatsdStats::getInstance().setUidMapChanges(mChanges.size());
-    }
-
-    auto strongPtr = broadcast.promote();
-    if (strongPtr != NULL) {
-        strongPtr->notifyAppUpgrade(timestamp, appName, uid, versionCode);
-    }
-}
-
-void UidMap::ensureBytesUsedBelowLimit() {
-    size_t limit;
-    if (maxBytesOverride <= 0) {
-        limit = StatsdStats::kMaxBytesUsedUidMap;
-    } else {
-        limit = maxBytesOverride;
-    }
-    while (mBytesUsed > limit) {
-        ALOGI("Bytes used %zu is above limit %zu, need to delete something", mBytesUsed, limit);
-        if (mChanges.size() > 0) {
-            mBytesUsed -= kBytesChangeRecord;
-            mChanges.pop_front();
-            StatsdStats::getInstance().noteUidMapDropped(1);
-        }
-    }
-}
-
-void UidMap::removeApp(const int64_t& timestamp, const String16& app_16, const int32_t& uid) {
-    wp<PackageInfoListener> broadcast = NULL;
-    string app = string(String8(app_16).string());
-    {
-        lock_guard<mutex> lock(mMutex);
-
-        int64_t prevVersion = 0;
-        string prevVersionString = "";
-        auto key = std::make_pair(uid, app);
-        auto it = mMap.find(key);
-        if (it != mMap.end() && !it->second.deleted) {
-            prevVersion = it->second.versionCode;
-            prevVersionString = it->second.versionString;
-            it->second.deleted = true;
-            mDeletedApps.push_back(key);
-        }
-        if (mDeletedApps.size() > StatsdStats::kMaxDeletedAppsInUidMap) {
-            // Delete the oldest one.
-            auto oldest = mDeletedApps.front();
-            mDeletedApps.pop_front();
-            mMap.erase(oldest);
-            StatsdStats::getInstance().noteUidMapAppDeletionDropped();
-        }
-        mChanges.emplace_back(true, timestamp, app, uid, 0, "", prevVersion, prevVersionString);
-        mBytesUsed += kBytesChangeRecord;
-        ensureBytesUsedBelowLimit();
-        StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
-        StatsdStats::getInstance().setUidMapChanges(mChanges.size());
-        broadcast = mSubscriber;
-    }
-
-    auto strongPtr = broadcast.promote();
-    if (strongPtr != NULL) {
-        strongPtr->notifyAppRemoved(timestamp, app, uid);
-    }
-}
-
-void UidMap::setListener(wp<PackageInfoListener> listener) {
-    lock_guard<mutex> lock(mMutex);  // Lock for updates
-    mSubscriber = listener;
-}
-
-void UidMap::assignIsolatedUid(int isolatedUid, int parentUid) {
-    lock_guard<mutex> lock(mIsolatedMutex);
-
-    mIsolatedUidMap[isolatedUid] = parentUid;
-}
-
-void UidMap::removeIsolatedUid(int isolatedUid) {
-    lock_guard<mutex> lock(mIsolatedMutex);
-
-    auto it = mIsolatedUidMap.find(isolatedUid);
-    if (it != mIsolatedUidMap.end()) {
-        mIsolatedUidMap.erase(it);
-    }
-}
-
-int UidMap::getHostUidOrSelf(int uid) const {
-    lock_guard<mutex> lock(mIsolatedMutex);
-
-    auto it = mIsolatedUidMap.find(uid);
-    if (it != mIsolatedUidMap.end()) {
-        return it->second;
-    }
-    return uid;
-}
-
-void UidMap::clearOutput() {
-    mChanges.clear();
-    // Also update the guardrail trackers.
-    StatsdStats::getInstance().setUidMapChanges(0);
-    mBytesUsed = 0;
-    StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
-}
-
-int64_t UidMap::getMinimumTimestampNs() {
-    int64_t m = 0;
-    for (const auto& kv : mLastUpdatePerConfigKey) {
-        if (m == 0) {
-            m = kv.second;
-        } else if (kv.second < m) {
-            m = kv.second;
-        }
-    }
-    return m;
-}
-
-size_t UidMap::getBytesUsed() const {
-    return mBytesUsed;
-}
-
-void UidMap::writeUidMapSnapshot(int64_t timestamp, bool includeVersionStrings,
-                                 bool includeInstaller, const std::set<int32_t>& interestingUids,
-                                 std::set<string>* str_set, ProtoOutputStream* proto) {
-    lock_guard<mutex> lock(mMutex);
-
-    writeUidMapSnapshotLocked(timestamp, includeVersionStrings, includeInstaller, interestingUids,
-                              str_set, proto);
-}
-
-void UidMap::writeUidMapSnapshotLocked(int64_t timestamp, bool includeVersionStrings,
-                                       bool includeInstaller,
-                                       const std::set<int32_t>& interestingUids,
-                                       std::set<string>* str_set, ProtoOutputStream* proto) {
-    proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_TIMESTAMP, (long long)timestamp);
-    for (const auto& kv : mMap) {
-        if (!interestingUids.empty() &&
-            interestingUids.find(kv.first.first) == interestingUids.end()) {
-            continue;
-        }
-        uint64_t token = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                      FIELD_ID_SNAPSHOT_PACKAGE_INFO);
-        if (str_set != nullptr) {
-            str_set->insert(kv.first.second);
-            proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_NAME_HASH,
-                         (long long)Hash64(kv.first.second));
-            if (includeVersionStrings) {
-                str_set->insert(kv.second.versionString);
-                proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION_STRING_HASH,
-                             (long long)Hash64(kv.second.versionString));
-            }
-            if (includeInstaller) {
-                str_set->insert(kv.second.installer);
-                proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_INSTALLER_HASH,
-                             (long long)Hash64(kv.second.installer));
-            }
-        } else {
-            proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_NAME, kv.first.second);
-            if (includeVersionStrings) {
-                proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_VERSION_STRING,
-                             kv.second.versionString);
-            }
-            if (includeInstaller) {
-                proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_INSTALLER,
-                             kv.second.installer);
-            }
-        }
-
-        proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION,
-                     (long long)kv.second.versionCode);
-        proto->write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_UID, kv.first.first);
-        proto->write(FIELD_TYPE_BOOL | FIELD_ID_SNAPSHOT_PACKAGE_DELETED, kv.second.deleted);
-        proto->end(token);
-    }
-}
-
-void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key, std::set<string>* str_set,
-                          bool includeVersionStrings, bool includeInstaller,
-                          ProtoOutputStream* proto) {
-    lock_guard<mutex> lock(mMutex);  // Lock for updates
-
-    for (const ChangeRecord& record : mChanges) {
-        if (record.timestampNs > mLastUpdatePerConfigKey[key]) {
-            uint64_t changesToken =
-                    proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_CHANGES);
-            proto->write(FIELD_TYPE_BOOL | FIELD_ID_CHANGE_DELETION, (bool)record.deletion);
-            proto->write(FIELD_TYPE_INT64 | FIELD_ID_CHANGE_TIMESTAMP,
-                         (long long)record.timestampNs);
-            if (str_set != nullptr) {
-                str_set->insert(record.package);
-                proto->write(FIELD_TYPE_UINT64 | FIELD_ID_CHANGE_PACKAGE_HASH,
-                             (long long)Hash64(record.package));
-                if (includeVersionStrings) {
-                    str_set->insert(record.versionString);
-                    proto->write(FIELD_TYPE_UINT64 | FIELD_ID_CHANGE_NEW_VERSION_STRING_HASH,
-                                 (long long)Hash64(record.versionString));
-                    str_set->insert(record.prevVersionString);
-                    proto->write(FIELD_TYPE_UINT64 | FIELD_ID_CHANGE_PREV_VERSION_STRING_HASH,
-                                 (long long)Hash64(record.prevVersionString));
-                }
-            } else {
-                proto->write(FIELD_TYPE_STRING | FIELD_ID_CHANGE_PACKAGE, record.package);
-                if (includeVersionStrings) {
-                    proto->write(FIELD_TYPE_STRING | FIELD_ID_CHANGE_NEW_VERSION_STRING,
-                                 record.versionString);
-                    proto->write(FIELD_TYPE_STRING | FIELD_ID_CHANGE_PREV_VERSION_STRING,
-                                 record.prevVersionString);
-                }
-            }
-
-            proto->write(FIELD_TYPE_INT32 | FIELD_ID_CHANGE_UID, (int)record.uid);
-            proto->write(FIELD_TYPE_INT64 | FIELD_ID_CHANGE_NEW_VERSION, (long long)record.version);
-            proto->write(FIELD_TYPE_INT64 | FIELD_ID_CHANGE_PREV_VERSION,
-                         (long long)record.prevVersion);
-            proto->end(changesToken);
-        }
-    }
-
-    // Write snapshot from current uid map state.
-    uint64_t snapshotsToken =
-            proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_SNAPSHOTS);
-    writeUidMapSnapshotLocked(timestamp, includeVersionStrings, includeInstaller,
-                              std::set<int32_t>() /*empty uid set means including every uid*/,
-                              str_set, proto);
-    proto->end(snapshotsToken);
-
-    int64_t prevMin = getMinimumTimestampNs();
-    mLastUpdatePerConfigKey[key] = timestamp;
-    int64_t newMin = getMinimumTimestampNs();
-
-    if (newMin > prevMin) {  // Delete anything possible now that the minimum has
-                             // moved forward.
-        int64_t cutoff_nanos = newMin;
-        for (auto it_changes = mChanges.begin(); it_changes != mChanges.end();) {
-            if (it_changes->timestampNs < cutoff_nanos) {
-                mBytesUsed -= kBytesChangeRecord;
-                it_changes = mChanges.erase(it_changes);
-            } else {
-                ++it_changes;
-            }
-        }
-    }
-    StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
-    StatsdStats::getInstance().setUidMapChanges(mChanges.size());
-}
-
-void UidMap::printUidMap(int out) const {
-    lock_guard<mutex> lock(mMutex);
-
-    for (const auto& kv : mMap) {
-        if (!kv.second.deleted) {
-            dprintf(out, "%s, v%" PRId64 ", %s, %s (%i)\n", kv.first.second.c_str(),
-                    kv.second.versionCode, kv.second.versionString.c_str(),
-                    kv.second.installer.c_str(), kv.first.first);
-        }
-    }
-}
-
-void UidMap::OnConfigUpdated(const ConfigKey& key) {
-    mLastUpdatePerConfigKey[key] = -1;
-}
-
-void UidMap::OnConfigRemoved(const ConfigKey& key) {
-    mLastUpdatePerConfigKey.erase(key);
-}
-
-set<int32_t> UidMap::getAppUid(const string& package) const {
-    lock_guard<mutex> lock(mMutex);
-
-    set<int32_t> results;
-    for (const auto& kv : mMap) {
-        if (kv.first.second == package && !kv.second.deleted) {
-            results.insert(kv.first.first);
-        }
-    }
-    return results;
-}
-
-// Note not all the following AIDs are used as uids. Some are used only for gids.
-// It's ok to leave them in the map, but we won't ever see them in the log's uid field.
-// App's uid starts from 10000, and will not overlap with the following AIDs.
-const std::map<string, uint32_t> UidMap::sAidToUidMapping = {{"AID_ROOT", 0},
-                                                             {"AID_SYSTEM", 1000},
-                                                             {"AID_RADIO", 1001},
-                                                             {"AID_BLUETOOTH", 1002},
-                                                             {"AID_GRAPHICS", 1003},
-                                                             {"AID_INPUT", 1004},
-                                                             {"AID_AUDIO", 1005},
-                                                             {"AID_CAMERA", 1006},
-                                                             {"AID_LOG", 1007},
-                                                             {"AID_COMPASS", 1008},
-                                                             {"AID_MOUNT", 1009},
-                                                             {"AID_WIFI", 1010},
-                                                             {"AID_ADB", 1011},
-                                                             {"AID_INSTALL", 1012},
-                                                             {"AID_MEDIA", 1013},
-                                                             {"AID_DHCP", 1014},
-                                                             {"AID_SDCARD_RW", 1015},
-                                                             {"AID_VPN", 1016},
-                                                             {"AID_KEYSTORE", 1017},
-                                                             {"AID_USB", 1018},
-                                                             {"AID_DRM", 1019},
-                                                             {"AID_MDNSR", 1020},
-                                                             {"AID_GPS", 1021},
-                                                             // {"AID_UNUSED1", 1022},
-                                                             {"AID_MEDIA_RW", 1023},
-                                                             {"AID_MTP", 1024},
-                                                             // {"AID_UNUSED2", 1025},
-                                                             {"AID_DRMRPC", 1026},
-                                                             {"AID_NFC", 1027},
-                                                             {"AID_SDCARD_R", 1028},
-                                                             {"AID_CLAT", 1029},
-                                                             {"AID_LOOP_RADIO", 1030},
-                                                             {"AID_MEDIA_DRM", 1031},
-                                                             {"AID_PACKAGE_INFO", 1032},
-                                                             {"AID_SDCARD_PICS", 1033},
-                                                             {"AID_SDCARD_AV", 1034},
-                                                             {"AID_SDCARD_ALL", 1035},
-                                                             {"AID_LOGD", 1036},
-                                                             {"AID_SHARED_RELRO", 1037},
-                                                             {"AID_DBUS", 1038},
-                                                             {"AID_TLSDATE", 1039},
-                                                             {"AID_MEDIA_EX", 1040},
-                                                             {"AID_AUDIOSERVER", 1041},
-                                                             {"AID_METRICS_COLL", 1042},
-                                                             {"AID_METRICSD", 1043},
-                                                             {"AID_WEBSERV", 1044},
-                                                             {"AID_DEBUGGERD", 1045},
-                                                             {"AID_MEDIA_CODEC", 1046},
-                                                             {"AID_CAMERASERVER", 1047},
-                                                             {"AID_FIREWALL", 1048},
-                                                             {"AID_TRUNKS", 1049},
-                                                             {"AID_NVRAM", 1050},
-                                                             {"AID_DNS", 1051},
-                                                             {"AID_DNS_TETHER", 1052},
-                                                             {"AID_WEBVIEW_ZYGOTE", 1053},
-                                                             {"AID_VEHICLE_NETWORK", 1054},
-                                                             {"AID_MEDIA_AUDIO", 1055},
-                                                             {"AID_MEDIA_VIDEO", 1056},
-                                                             {"AID_MEDIA_IMAGE", 1057},
-                                                             {"AID_TOMBSTONED", 1058},
-                                                             {"AID_MEDIA_OBB", 1059},
-                                                             {"AID_ESE", 1060},
-                                                             {"AID_OTA_UPDATE", 1061},
-                                                             {"AID_AUTOMOTIVE_EVS", 1062},
-                                                             {"AID_LOWPAN", 1063},
-                                                             {"AID_HSM", 1064},
-                                                             {"AID_RESERVED_DISK", 1065},
-                                                             {"AID_STATSD", 1066},
-                                                             {"AID_INCIDENTD", 1067},
-                                                             {"AID_SECURE_ELEMENT", 1068},
-                                                             {"AID_LMKD", 1069},
-                                                             {"AID_LLKD", 1070},
-                                                             {"AID_IORAPD", 1071},
-                                                             {"AID_GPU_SERVICE", 1072},
-                                                             {"AID_NETWORK_STACK", 1073},
-                                                             {"AID_GSID", 1074},
-                                                             {"AID_FSVERITY_CERT", 1075},
-                                                             {"AID_CREDSTORE", 1076},
-                                                             {"AID_EXTERNAL_STORAGE", 1077},
-                                                             {"AID_EXT_DATA_RW", 1078},
-                                                             {"AID_EXT_OBB_RW", 1079},
-                                                             {"AID_CONTEXT_HUB", 1080},
-                                                             {"AID_SHELL", 2000},
-                                                             {"AID_CACHE", 2001},
-                                                             {"AID_DIAG", 2002}};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
deleted file mode 100644
index 622321b..0000000
--- a/cmds/statsd/src/packages/UidMap.h
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "config/ConfigKey.h"
-#include "packages/PackageInfoListener.h"
-#include "stats_util.h"
-
-#include <gtest/gtest_prod.h>
-#include <stdio.h>
-#include <utils/RefBase.h>
-#include <utils/String16.h>
-
-#include <list>
-#include <mutex>
-#include <set>
-#include <string>
-#include <unordered_map>
-
-using namespace android;
-using namespace std;
-
-using android::util::ProtoOutputStream;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-struct AppData {
-    int64_t versionCode;
-    string versionString;
-    string installer;
-    bool deleted;
-
-    // Empty constructor needed for unordered map.
-    AppData() {
-    }
-
-    AppData(const int64_t v, const string& versionString, const string& installer)
-        : versionCode(v), versionString(versionString), installer(installer), deleted(false){};
-};
-
-// When calling appendUidMap, we retrieve all the ChangeRecords since the last
-// timestamp we called appendUidMap for this configuration key.
-struct ChangeRecord {
-    const bool deletion;
-    const int64_t timestampNs;
-    const string package;
-    const int32_t uid;
-    const int64_t version;
-    const int64_t prevVersion;
-    const string versionString;
-    const string prevVersionString;
-
-    ChangeRecord(const bool isDeletion, const int64_t timestampNs, const string& package,
-                 const int32_t uid, const int64_t version, const string versionString,
-                 const int64_t prevVersion, const string prevVersionString)
-        : deletion(isDeletion),
-          timestampNs(timestampNs),
-          package(package),
-          uid(uid),
-          version(version),
-          prevVersion(prevVersion),
-          versionString(versionString),
-          prevVersionString(prevVersionString) {
-    }
-};
-
-const unsigned int kBytesChangeRecord = sizeof(struct ChangeRecord);
-
-// UidMap keeps track of what the corresponding app name (APK name) and version code for every uid
-// at any given moment. This map must be updated by StatsCompanionService.
-class UidMap : public virtual android::RefBase {
-public:
-    UidMap();
-    ~UidMap();
-    static const std::map<std::string, uint32_t> sAidToUidMapping;
-
-    static sp<UidMap> getInstance();
-    /*
-     * All three inputs must be the same size, and the jth element in each array refers to the same
-     * tuple, ie. uid[j] corresponds to packageName[j] with versionCode[j].
-     */
-    void updateMap(const int64_t& timestamp, const vector<int32_t>& uid,
-                   const vector<int64_t>& versionCode, const vector<String16>& versionString,
-                   const vector<String16>& packageName, const vector<String16>& installer);
-
-    void updateApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid,
-                   const int64_t& versionCode, const String16& versionString,
-                   const String16& installer);
-    void removeApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid);
-
-    // Returns true if the given uid contains the specified app (eg. com.google.android.gms).
-    bool hasApp(int uid, const string& packageName) const;
-
-    // Returns the app names from uid.
-    std::set<string> getAppNamesFromUid(const int32_t& uid, bool returnNormalized) const;
-
-    int64_t getAppVersion(int uid, const string& packageName) const;
-
-    // Helper for debugging contents of this uid map. Can be triggered with:
-    // adb shell cmd stats print-uid-map
-    void printUidMap(int outFd) const;
-
-    // Command for indicating to the map that StatsLogProcessor should be notified if an app is
-    // updated. This allows metric producers and managers to distinguish when the same uid or app
-    // represents a different version of an app.
-    void setListener(wp<PackageInfoListener> listener);
-
-    // Informs uid map that a config is added/updated. Used for keeping mConfigKeys up to date.
-    void OnConfigUpdated(const ConfigKey& key);
-
-    // Informs uid map that a config is removed. Used for keeping mConfigKeys up to date.
-    void OnConfigRemoved(const ConfigKey& key);
-
-    void assignIsolatedUid(int isolatedUid, int parentUid);
-    void removeIsolatedUid(int isolatedUid);
-
-    // Returns the host uid if it exists. Otherwise, returns the same uid that was passed-in.
-    virtual int getHostUidOrSelf(int uid) const;
-
-    // Gets all snapshots and changes that have occurred since the last output.
-    // If every config key has received a change or snapshot record, then this
-    // record is deleted.
-    void appendUidMap(const int64_t& timestamp, const ConfigKey& key, std::set<string>* str_set,
-                      bool includeVersionStrings, bool includeInstaller,
-                      ProtoOutputStream* proto);
-
-    // Forces the output to be cleared. We still generate a snapshot based on the current state.
-    // This results in extra data uploaded but helps us reconstruct the uid mapping on the server
-    // in case we lose a previous upload.
-    void clearOutput();
-
-    // Get currently cached value of memory used by UID map.
-    size_t getBytesUsed() const;
-
-    virtual std::set<int32_t> getAppUid(const string& package) const;
-
-    // Write current PackageInfoSnapshot to ProtoOutputStream.
-    // interestingUids: If not empty, only write the package info for these uids. If empty, write
-    //                  package info for all uids.
-    // str_set: if not null, add new string to the set and write str_hash to proto
-    //          if null, write string to proto.
-    void writeUidMapSnapshot(int64_t timestamp, bool includeVersionStrings, bool includeInstaller,
-                             const std::set<int32_t>& interestingUids, std::set<string>* str_set,
-                             ProtoOutputStream* proto);
-
-private:
-    std::set<string> getAppNamesFromUidLocked(const int32_t& uid, bool returnNormalized) const;
-    string normalizeAppName(const string& appName) const;
-
-    void writeUidMapSnapshotLocked(int64_t timestamp, bool includeVersionStrings,
-                                   bool includeInstaller, const std::set<int32_t>& interestingUids,
-                                   std::set<string>* str_set, ProtoOutputStream* proto);
-
-    mutable mutex mMutex;
-    mutable mutex mIsolatedMutex;
-
-    struct PairHash {
-        size_t operator()(std::pair<int, string> p) const noexcept {
-            std::hash<std::string> hash_fn;
-            return hash_fn(std::to_string(p.first) + p.second);
-        }
-    };
-    // Maps uid and package name to application data.
-    std::unordered_map<std::pair<int, string>, AppData, PairHash> mMap;
-
-    // Maps isolated uid to the parent uid. Any metrics for an isolated uid will instead contribute
-    // to the parent uid.
-    std::unordered_map<int, int> mIsolatedUidMap;
-
-    // Record the changes that can be provided with the uploads.
-    std::list<ChangeRecord> mChanges;
-
-    // Store which uid and apps represent deleted ones.
-    std::list<std::pair<int, string>> mDeletedApps;
-
-    // Notify StatsLogProcessor if there's an upgrade/removal in any app.
-    wp<PackageInfoListener> mSubscriber;
-
-    // Mapping of config keys we're aware of to the epoch time they last received an update. This
-    // lets us know it's safe to delete events older than the oldest update. The value is nanosec.
-    // Value of -1 denotes this config key has never received an upload.
-    std::unordered_map<ConfigKey, int64_t> mLastUpdatePerConfigKey;
-
-    // Returns the minimum value from mConfigKeys.
-    int64_t getMinimumTimestampNs();
-
-    // If our current used bytes is above the limit, then we clear out the earliest snapshot. If
-    // there are no more snapshots, then we clear out the earliest delta. We repeat the deletions
-    // until the memory consumed by mOutput is below the specified limit.
-    void ensureBytesUsedBelowLimit();
-
-    // Override used for testing the max memory allowed by uid map. 0 means we use the value
-    // specified in StatsdStats.h with the rest of the guardrails.
-    size_t maxBytesOverride = 0;
-
-    // Cache the size of mOutput;
-    size_t mBytesUsed;
-
-    // Allows unit-test to access private methods.
-    FRIEND_TEST(UidMapTest, TestClearingOutput);
-    FRIEND_TEST(UidMapTest, TestRemovedAppRetained);
-    FRIEND_TEST(UidMapTest, TestRemovedAppOverGuardrail);
-    FRIEND_TEST(UidMapTest, TestOutputIncludesAtLeastOneSnapshot);
-    FRIEND_TEST(UidMapTest, TestMemoryComputed);
-    FRIEND_TEST(UidMapTest, TestMemoryGuardrail);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/shell/ShellSubscriber.cpp b/cmds/statsd/src/shell/ShellSubscriber.cpp
deleted file mode 100644
index 9d8f0c2..0000000
--- a/cmds/statsd/src/shell/ShellSubscriber.cpp
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "ShellSubscriber.h"
-
-#include <android-base/file.h>
-
-#include "matchers/matcher_util.h"
-#include "stats_log_util.h"
-
-using android::util::ProtoOutputStream;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-const static int FIELD_ID_ATOM = 1;
-
-void ShellSubscriber::startNewSubscription(int in, int out, int timeoutSec) {
-    int myToken = claimToken();
-    VLOG("ShellSubscriber: new subscription %d has come in", myToken);
-    mSubscriptionShouldEnd.notify_one();
-
-    shared_ptr<SubscriptionInfo> mySubscriptionInfo = make_shared<SubscriptionInfo>(in, out);
-    if (!readConfig(mySubscriptionInfo)) return;
-
-    {
-        std::unique_lock<std::mutex> lock(mMutex);
-        mSubscriptionInfo = mySubscriptionInfo;
-        spawnHelperThread(myToken);
-        waitForSubscriptionToEndLocked(mySubscriptionInfo, myToken, lock, timeoutSec);
-
-        if (mSubscriptionInfo == mySubscriptionInfo) {
-            mSubscriptionInfo = nullptr;
-        }
-
-    }
-}
-
-void ShellSubscriber::spawnHelperThread(int myToken) {
-    std::thread t([this, myToken] { pullAndSendHeartbeats(myToken); });
-    t.detach();
-}
-
-void ShellSubscriber::waitForSubscriptionToEndLocked(shared_ptr<SubscriptionInfo> myInfo,
-                                                     int myToken,
-                                                     std::unique_lock<std::mutex>& lock,
-                                                     int timeoutSec) {
-    if (timeoutSec > 0) {
-        mSubscriptionShouldEnd.wait_for(lock, timeoutSec * 1s, [this, myToken, &myInfo] {
-            return mToken != myToken || !myInfo->mClientAlive;
-        });
-    } else {
-        mSubscriptionShouldEnd.wait(lock, [this, myToken, &myInfo] {
-            return mToken != myToken || !myInfo->mClientAlive;
-        });
-    }
-}
-
-// Atomically claim the next token. Token numbers denote subscriber ordering.
-int ShellSubscriber::claimToken() {
-    std::unique_lock<std::mutex> lock(mMutex);
-    int myToken = ++mToken;
-    return myToken;
-}
-
-// Read and parse single config. There should only one config per input.
-bool ShellSubscriber::readConfig(shared_ptr<SubscriptionInfo> subscriptionInfo) {
-    // Read the size of the config.
-    size_t bufferSize;
-    if (!android::base::ReadFully(subscriptionInfo->mInputFd, &bufferSize, sizeof(bufferSize))) {
-        return false;
-    }
-
-    // Read the config.
-    vector<uint8_t> buffer(bufferSize);
-    if (!android::base::ReadFully(subscriptionInfo->mInputFd, buffer.data(), bufferSize)) {
-        return false;
-    }
-
-    // Parse the config.
-    ShellSubscription config;
-    if (!config.ParseFromArray(buffer.data(), bufferSize)) {
-        return false;
-    }
-
-    // Update SubscriptionInfo with state from config
-    for (const auto& pushed : config.pushed()) {
-        subscriptionInfo->mPushedMatchers.push_back(pushed);
-    }
-
-    for (const auto& pulled : config.pulled()) {
-        vector<string> packages;
-        vector<int32_t> uids;
-        for (const string& pkg : pulled.packages()) {
-            auto it = UidMap::sAidToUidMapping.find(pkg);
-            if (it != UidMap::sAidToUidMapping.end()) {
-                uids.push_back(it->second);
-            } else {
-                packages.push_back(pkg);
-            }
-        }
-
-        subscriptionInfo->mPulledInfo.emplace_back(pulled.matcher(), pulled.freq_millis(), packages,
-                                                   uids);
-        VLOG("adding matcher for pulled atom %d", pulled.matcher().atom_id());
-    }
-
-    return true;
-}
-
-void ShellSubscriber::pullAndSendHeartbeats(int myToken) {
-    VLOG("ShellSubscriber: helper thread %d starting", myToken);
-    while (true) {
-        int64_t sleepTimeMs = INT_MAX;
-        {
-            std::lock_guard<std::mutex> lock(mMutex);
-            if (!mSubscriptionInfo || mToken != myToken) {
-                VLOG("ShellSubscriber: helper thread %d done!", myToken);
-                return;
-            }
-
-            int64_t nowMillis = getElapsedRealtimeMillis();
-            int64_t nowNanos = getElapsedRealtimeNs();
-            for (PullInfo& pullInfo : mSubscriptionInfo->mPulledInfo) {
-                if (pullInfo.mPrevPullElapsedRealtimeMs + pullInfo.mInterval >= nowMillis) {
-                    continue;
-                }
-
-                vector<int32_t> uids;
-                getUidsForPullAtom(&uids, pullInfo);
-
-                vector<std::shared_ptr<LogEvent>> data;
-                mPullerMgr->Pull(pullInfo.mPullerMatcher.atom_id(), uids, nowNanos, &data);
-                VLOG("Pulled %zu atoms with id %d", data.size(), pullInfo.mPullerMatcher.atom_id());
-                writePulledAtomsLocked(data, pullInfo.mPullerMatcher);
-
-                pullInfo.mPrevPullElapsedRealtimeMs = nowMillis;
-            }
-
-            // Send a heartbeat, consisting of a data size of 0, if perfd hasn't recently received
-            // data from statsd. When it receives the data size of 0, perfd will not expect any
-            // atoms and recheck whether the subscription should end.
-            if (nowMillis - mLastWriteMs > kMsBetweenHeartbeats) {
-                attemptWriteToPipeLocked(/*dataSize=*/0);
-            }
-
-            // Determine how long to sleep before doing more work.
-            for (PullInfo& pullInfo : mSubscriptionInfo->mPulledInfo) {
-                int64_t nextPullTime = pullInfo.mPrevPullElapsedRealtimeMs + pullInfo.mInterval;
-                int64_t timeBeforePull = nextPullTime - nowMillis; // guaranteed to be non-negative
-                if (timeBeforePull < sleepTimeMs) sleepTimeMs = timeBeforePull;
-            }
-            int64_t timeBeforeHeartbeat = (mLastWriteMs + kMsBetweenHeartbeats) - nowMillis;
-            if (timeBeforeHeartbeat < sleepTimeMs) sleepTimeMs = timeBeforeHeartbeat;
-        }
-
-        VLOG("ShellSubscriber: helper thread %d sleeping for %lld ms", myToken,
-             (long long)sleepTimeMs);
-        std::this_thread::sleep_for(std::chrono::milliseconds(sleepTimeMs));
-    }
-}
-
-void ShellSubscriber::getUidsForPullAtom(vector<int32_t>* uids, const PullInfo& pullInfo) {
-    uids->insert(uids->end(), pullInfo.mPullUids.begin(), pullInfo.mPullUids.end());
-    // This is slow. Consider storing the uids per app and listening to uidmap updates.
-    for (const string& pkg : pullInfo.mPullPackages) {
-        set<int32_t> uidsForPkg = mUidMap->getAppUid(pkg);
-        uids->insert(uids->end(), uidsForPkg.begin(), uidsForPkg.end());
-    }
-    uids->push_back(DEFAULT_PULL_UID);
-}
-
-void ShellSubscriber::writePulledAtomsLocked(const vector<std::shared_ptr<LogEvent>>& data,
-                                             const SimpleAtomMatcher& matcher) {
-    mProto.clear();
-    int count = 0;
-    for (const auto& event : data) {
-        if (matchesSimple(mUidMap, matcher, *event)) {
-            count++;
-            uint64_t atomToken = mProto.start(util::FIELD_TYPE_MESSAGE |
-                                              util::FIELD_COUNT_REPEATED | FIELD_ID_ATOM);
-            event->ToProto(mProto);
-            mProto.end(atomToken);
-        }
-    }
-
-    if (count > 0) attemptWriteToPipeLocked(mProto.size());
-}
-
-void ShellSubscriber::onLogEvent(const LogEvent& event) {
-    std::lock_guard<std::mutex> lock(mMutex);
-    if (!mSubscriptionInfo) return;
-
-    mProto.clear();
-    for (const auto& matcher : mSubscriptionInfo->mPushedMatchers) {
-        if (matchesSimple(mUidMap, matcher, event)) {
-            uint64_t atomToken = mProto.start(util::FIELD_TYPE_MESSAGE |
-                                              util::FIELD_COUNT_REPEATED | FIELD_ID_ATOM);
-            event.ToProto(mProto);
-            mProto.end(atomToken);
-            attemptWriteToPipeLocked(mProto.size());
-        }
-    }
-}
-
-// Tries to write the atom encoded in mProto to the pipe. If the write fails
-// because the read end of the pipe has closed, signals to other threads that
-// the subscription should end.
-void ShellSubscriber::attemptWriteToPipeLocked(size_t dataSize) {
-    // First, write the payload size.
-    if (!android::base::WriteFully(mSubscriptionInfo->mOutputFd, &dataSize, sizeof(dataSize))) {
-        mSubscriptionInfo->mClientAlive = false;
-        mSubscriptionShouldEnd.notify_one();
-        return;
-    }
-
-    // Then, write the payload if this is not just a heartbeat.
-    if (dataSize > 0 && !mProto.flush(mSubscriptionInfo->mOutputFd)) {
-        mSubscriptionInfo->mClientAlive = false;
-        mSubscriptionShouldEnd.notify_one();
-        return;
-    }
-
-    mLastWriteMs = getElapsedRealtimeMillis();
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/shell/ShellSubscriber.h b/cmds/statsd/src/shell/ShellSubscriber.h
deleted file mode 100644
index 4c05fa7..0000000
--- a/cmds/statsd/src/shell/ShellSubscriber.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <android/util/ProtoOutputStream.h>
-#include <private/android_filesystem_config.h>
-
-#include <condition_variable>
-#include <mutex>
-#include <thread>
-
-#include "external/StatsPullerManager.h"
-#include "frameworks/base/cmds/statsd/src/shell/shell_config.pb.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "logd/LogEvent.h"
-#include "packages/UidMap.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/**
- * Handles atoms subscription via shell cmd.
- *
- * A shell subscription lasts *until shell exits*. Unlike config based clients, a shell client
- * communicates with statsd via file descriptors. They can subscribe pushed and pulled atoms.
- * The atoms are sent back to the client in real time, as opposed to keeping the data in memory.
- * Shell clients do not subscribe aggregated metrics, as they are responsible for doing the
- * aggregation after receiving the atom events.
- *
- * Shell clients pass ShellSubscription in the proto binary format. Clients can update the
- * subscription by sending a new subscription. The new subscription would replace the old one.
- * Input data stream format is:
- *
- * |size_t|subscription proto|size_t|subscription proto|....
- *
- * statsd sends the events back in Atom proto binary format. Each Atom message is preceded
- * with sizeof(size_t) bytes indicating the size of the proto message payload.
- *
- * The stream would be in the following format:
- * |size_t|shellData proto|size_t|shellData proto|....
- *
- * Only one shell subscriber is allowed at a time because each shell subscriber blocks one thread
- * until it exits.
- */
-class ShellSubscriber : public virtual RefBase {
-public:
-    ShellSubscriber(sp<UidMap> uidMap, sp<StatsPullerManager> pullerMgr)
-        : mUidMap(uidMap), mPullerMgr(pullerMgr){};
-
-    void startNewSubscription(int inFd, int outFd, int timeoutSec);
-
-    void onLogEvent(const LogEvent& event);
-
-private:
-    struct PullInfo {
-        PullInfo(const SimpleAtomMatcher& matcher, int64_t interval,
-                 const std::vector<std::string>& packages, const std::vector<int32_t>& uids)
-            : mPullerMatcher(matcher),
-              mInterval(interval),
-              mPrevPullElapsedRealtimeMs(0),
-              mPullPackages(packages),
-              mPullUids(uids) {
-        }
-        SimpleAtomMatcher mPullerMatcher;
-        int64_t mInterval;
-        int64_t mPrevPullElapsedRealtimeMs;
-        std::vector<std::string> mPullPackages;
-        std::vector<int32_t> mPullUids;
-    };
-
-    struct SubscriptionInfo {
-        SubscriptionInfo(const int& inputFd, const int& outputFd)
-            : mInputFd(inputFd), mOutputFd(outputFd), mClientAlive(true) {
-        }
-
-        int mInputFd;
-        int mOutputFd;
-        std::vector<SimpleAtomMatcher> mPushedMatchers;
-        std::vector<PullInfo> mPulledInfo;
-        bool mClientAlive;
-    };
-
-    int claimToken();
-
-    bool readConfig(std::shared_ptr<SubscriptionInfo> subscriptionInfo);
-
-    void spawnHelperThread(int myToken);
-
-    void waitForSubscriptionToEndLocked(std::shared_ptr<SubscriptionInfo> myInfo,
-                                        int myToken,
-                                        std::unique_lock<std::mutex>& lock,
-                                        int timeoutSec);
-
-    // Helper thread that pulls atoms at a regular frequency and sends
-    // heartbeats to perfd if statsd hasn't recently sent any data. Statsd must
-    // send heartbeats for perfd to escape a blocking read call and recheck if
-    // the user has terminated the subscription.
-    void pullAndSendHeartbeats(int myToken);
-
-    void writePulledAtomsLocked(const vector<std::shared_ptr<LogEvent>>& data,
-                                const SimpleAtomMatcher& matcher);
-
-    void getUidsForPullAtom(vector<int32_t>* uids, const PullInfo& pullInfo);
-
-    void attemptWriteToPipeLocked(size_t dataSize);
-
-    sp<UidMap> mUidMap;
-
-    sp<StatsPullerManager> mPullerMgr;
-
-    android::util::ProtoOutputStream mProto;
-
-    mutable std::mutex mMutex;
-
-    std::condition_variable mSubscriptionShouldEnd;
-
-    std::shared_ptr<SubscriptionInfo> mSubscriptionInfo = nullptr;
-
-    int mToken = 0;
-
-    const int32_t DEFAULT_PULL_UID = AID_SYSTEM;
-
-    // Tracks when we last send data to perfd. We need that time to determine
-    // when next to send a heartbeat.
-    int64_t mLastWriteMs = 0;
-    const int64_t kMsBetweenHeartbeats = 1000;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/shell/shell_config.proto b/cmds/statsd/src/shell/shell_config.proto
deleted file mode 100644
index 07d0310..0000000
--- a/cmds/statsd/src/shell/shell_config.proto
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.os.statsd;
-
-option java_package = "com.android.os";
-option java_outer_classname = "ShellConfig";
-
-import "frameworks/base/cmds/statsd/src/statsd_config.proto";
-
-message PulledAtomSubscription {
-    optional SimpleAtomMatcher matcher = 1;
-
-    /* gap between two pulls in milliseconds */
-    optional int32 freq_millis = 2;
-
-    /* Packages that the pull is requested from */
-    repeated string packages = 3;
-}
-
-message ShellSubscription {
-    repeated SimpleAtomMatcher pushed = 1;
-    repeated PulledAtomSubscription pulled = 2;
-}
\ No newline at end of file
diff --git a/cmds/statsd/src/shell/shell_data.proto b/cmds/statsd/src/shell/shell_data.proto
deleted file mode 100644
index ec41cbc..0000000
--- a/cmds/statsd/src/shell/shell_data.proto
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.os.statsd;
-
-option java_package = "com.android.os.statsd";
-option java_outer_classname = "ShellDataProto";
-
-import "frameworks/proto_logging/stats/atoms.proto";
-
-// The output of shell subscription, including both pulled and pushed subscriptions.
-message ShellData {
-    repeated Atom atom = 1;
-}
diff --git a/cmds/statsd/src/socket/StatsSocketListener.cpp b/cmds/statsd/src/socket/StatsSocketListener.cpp
deleted file mode 100755
index b877cc9..0000000
--- a/cmds/statsd/src/socket/StatsSocketListener.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include <ctype.h>
-#include <limits.h>
-#include <stdio.h>
-#include <sys/cdefs.h>
-#include <sys/prctl.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <unistd.h>
-
-#include <cutils/sockets.h>
-
-#include "StatsSocketListener.h"
-#include "guardrail/StatsdStats.h"
-#include "stats_log_util.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-StatsSocketListener::StatsSocketListener(std::shared_ptr<LogEventQueue> queue)
-    : SocketListener(getLogSocket(), false /*start listen*/), mQueue(queue) {
-}
-
-StatsSocketListener::~StatsSocketListener() {
-}
-
-bool StatsSocketListener::onDataAvailable(SocketClient* cli) {
-    static bool name_set;
-    if (!name_set) {
-        prctl(PR_SET_NAME, "statsd.writer");
-        name_set = true;
-    }
-
-    // + 1 to ensure null terminator if MAX_PAYLOAD buffer is received
-    char buffer[sizeof(android_log_header_t) + LOGGER_ENTRY_MAX_PAYLOAD + 1];
-    struct iovec iov = {buffer, sizeof(buffer) - 1};
-
-    alignas(4) char control[CMSG_SPACE(sizeof(struct ucred))];
-    struct msghdr hdr = {
-            NULL, 0, &iov, 1, control, sizeof(control), 0,
-    };
-
-    int socket = cli->getSocket();
-
-    // To clear the entire buffer is secure/safe, but this contributes to 1.68%
-    // overhead under logging load. We are safe because we check counts, but
-    // still need to clear null terminator
-    // memset(buffer, 0, sizeof(buffer));
-    ssize_t n = recvmsg(socket, &hdr, 0);
-    if (n <= (ssize_t)(sizeof(android_log_header_t))) {
-        return false;
-    }
-
-    buffer[n] = 0;
-
-    struct ucred* cred = NULL;
-
-    struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
-    while (cmsg != NULL) {
-        if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) {
-            cred = (struct ucred*)CMSG_DATA(cmsg);
-            break;
-        }
-        cmsg = CMSG_NXTHDR(&hdr, cmsg);
-    }
-
-    struct ucred fake_cred;
-    if (cred == NULL) {
-        cred = &fake_cred;
-        cred->pid = 0;
-        cred->uid = DEFAULT_OVERFLOWUID;
-    }
-
-    uint8_t* ptr = ((uint8_t*)buffer) + sizeof(android_log_header_t);
-    n -= sizeof(android_log_header_t);
-
-    // When a log failed to write to statsd socket (e.g., due ot EBUSY), a special message would
-    // be sent to statsd when the socket communication becomes available again.
-    // The format is android_log_event_int_t with a single integer in the payload indicating the
-    // number of logs that failed. (*FORMAT MUST BE IN SYNC WITH system/core/libstats*)
-    // Note that all normal stats logs are in the format of event_list, so there won't be confusion.
-    //
-    // TODO(b/80538532): In addition to log it in StatsdStats, we should properly reset the config.
-    if (n == sizeof(android_log_event_long_t)) {
-        android_log_event_long_t* long_event = reinterpret_cast<android_log_event_long_t*>(ptr);
-        if (long_event->payload.type == EVENT_TYPE_LONG) {
-            int64_t composed_long = long_event->payload.data;
-
-            // format:
-            // |last_tag|dropped_count|
-            int32_t dropped_count = (int32_t)(0xffffffff & composed_long);
-            int32_t last_atom_tag = (int32_t)((0xffffffff00000000 & (uint64_t)composed_long) >> 32);
-
-            ALOGE("Found dropped events: %d error %d last atom tag %d from uid %d", dropped_count,
-                  long_event->header.tag, last_atom_tag, cred->uid);
-            StatsdStats::getInstance().noteLogLost((int32_t)getWallClockSec(), dropped_count,
-                                                   long_event->header.tag, last_atom_tag, cred->uid,
-                                                   cred->pid);
-            return true;
-        }
-    }
-
-    // move past the 4-byte StatsEventTag
-    uint8_t* msg = ptr + sizeof(uint32_t);
-    uint32_t len = n - sizeof(uint32_t);
-    uint32_t uid = cred->uid;
-    uint32_t pid = cred->pid;
-
-    int64_t oldestTimestamp;
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(uid, pid);
-    logEvent->parseBuffer(msg, len);
-
-    if (!mQueue->push(std::move(logEvent), &oldestTimestamp)) {
-        StatsdStats::getInstance().noteEventQueueOverflow(oldestTimestamp);
-    }
-
-    return true;
-}
-
-int StatsSocketListener::getLogSocket() {
-    static const char socketName[] = "statsdw";
-    int sock = android_get_control_socket(socketName);
-
-    if (sock < 0) {  // statsd started up in init.sh
-        sock = socket_local_server(socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_DGRAM);
-
-        int on = 1;
-        if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
-            return -1;
-        }
-    }
-    return sock;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/socket/StatsSocketListener.h b/cmds/statsd/src/socket/StatsSocketListener.h
deleted file mode 100644
index 2167a56..0000000
--- a/cmds/statsd/src/socket/StatsSocketListener.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <sysutils/SocketListener.h>
-#include <utils/RefBase.h>
-#include "logd/LogEventQueue.h"
-
-// DEFAULT_OVERFLOWUID is defined in linux/highuid.h, which is not part of
-// the uapi headers for userspace to use.  This value is filled in on the
-// out-of-band socket credentials if the OS fails to find one available.
-// One of the causes of this is if SO_PASSCRED is set, all the packets before
-// that point will have this value.  We also use it in a fake credential if
-// no socket credentials are supplied.
-#ifndef DEFAULT_OVERFLOWUID
-#define DEFAULT_OVERFLOWUID 65534
-#endif
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class StatsSocketListener : public SocketListener, public virtual android::RefBase {
-public:
-    explicit StatsSocketListener(std::shared_ptr<LogEventQueue> queue);
-
-    virtual ~StatsSocketListener();
-
-protected:
-    virtual bool onDataAvailable(SocketClient* cli);
-
-private:
-    static int getLogSocket();
-    /**
-     * Who is going to get the events when they're read.
-     */
-    std::shared_ptr<LogEventQueue> mQueue;
-};
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/state/StateListener.h b/cmds/statsd/src/state/StateListener.h
deleted file mode 100644
index 6388001..0000000
--- a/cmds/statsd/src/state/StateListener.h
+++ /dev/null
@@ -1,54 +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.
- */
-#pragma once
-
-#include <utils/RefBase.h>
-
-#include "HashableDimensionKey.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class StateListener : public virtual RefBase {
-public:
-    StateListener(){};
-
-    virtual ~StateListener(){};
-
-    /**
-     * Interface for handling a state change.
-     *
-     * The old and new state values map to the original state values.
-     * StateTrackers only track the original state values and are unaware
-     * of higher-level state groups. MetricProducers hold information on
-     * state groups and are responsible for mapping original state values to
-     * the correct state group.
-     *
-     * [eventTimeNs]: Time of the state change log event.
-     * [atomId]: The id of the state atom
-     * [primaryKey]: The primary field values of the state atom
-     * [oldState]: Previous state value before state change
-     * [newState]: Current state value after state change
-     */
-    virtual void onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
-                                const HashableDimensionKey& primaryKey, const FieldValue& oldState,
-                                const FieldValue& newState) = 0;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/state/StateManager.cpp b/cmds/statsd/src/state/StateManager.cpp
deleted file mode 100644
index c29afeb..0000000
--- a/cmds/statsd/src/state/StateManager.cpp
+++ /dev/null
@@ -1,112 +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.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "StateManager.h"
-
-#include <private/android_filesystem_config.h>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-StateManager::StateManager()
-    : mAllowedPkg({
-              "com.android.systemui",
-      }) {
-}
-
-StateManager& StateManager::getInstance() {
-    static StateManager sStateManager;
-    return sStateManager;
-}
-
-void StateManager::clear() {
-    mStateTrackers.clear();
-}
-
-void StateManager::onLogEvent(const LogEvent& event) {
-    // Only process state events from uids in AID_* and packages that are whitelisted in
-    // mAllowedPkg.
-    // Whitelisted AIDs are AID_ROOT and all AIDs in [1000, 2000)
-    if (event.GetUid() == AID_ROOT || (event.GetUid() >= 1000 && event.GetUid() < 2000) ||
-        mAllowedLogSources.find(event.GetUid()) != mAllowedLogSources.end()) {
-        if (mStateTrackers.find(event.GetTagId()) != mStateTrackers.end()) {
-            mStateTrackers[event.GetTagId()]->onLogEvent(event);
-        }
-    }
-}
-
-void StateManager::registerListener(const int32_t atomId, wp<StateListener> listener) {
-    // Check if state tracker already exists.
-    if (mStateTrackers.find(atomId) == mStateTrackers.end()) {
-        mStateTrackers[atomId] = new StateTracker(atomId);
-    }
-    mStateTrackers[atomId]->registerListener(listener);
-}
-
-void StateManager::unregisterListener(const int32_t atomId, wp<StateListener> listener) {
-    std::unique_lock<std::mutex> lock(mMutex);
-
-    // Hold the sp<> until the lock is released so that ~StateTracker() is
-    // not called while the lock is held.
-    sp<StateTracker> toRemove;
-
-    // Unregister listener from correct StateTracker
-    auto it = mStateTrackers.find(atomId);
-    if (it != mStateTrackers.end()) {
-        it->second->unregisterListener(listener);
-
-        // Remove the StateTracker if it has no listeners
-        if (it->second->getListenersCount() == 0) {
-            toRemove = it->second;
-            mStateTrackers.erase(it);
-        }
-    } else {
-        ALOGE("StateManager cannot unregister listener, StateTracker for atom %d does not exist",
-              atomId);
-    }
-    lock.unlock();
-}
-
-bool StateManager::getStateValue(const int32_t atomId, const HashableDimensionKey& key,
-                                 FieldValue* output) const {
-    auto it = mStateTrackers.find(atomId);
-    if (it != mStateTrackers.end()) {
-        return it->second->getStateValue(key, output);
-    }
-    return false;
-}
-
-void StateManager::updateLogSources(const sp<UidMap>& uidMap) {
-    mAllowedLogSources.clear();
-    for (const auto& pkg : mAllowedPkg) {
-        auto uids = uidMap->getAppUid(pkg);
-        mAllowedLogSources.insert(uids.begin(), uids.end());
-    }
-}
-
-void StateManager::notifyAppChanged(const string& apk, const sp<UidMap>& uidMap) {
-    if (mAllowedPkg.find(apk) != mAllowedPkg.end()) {
-        updateLogSources(uidMap);
-    }
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/state/StateManager.h b/cmds/statsd/src/state/StateManager.h
deleted file mode 100644
index 18c404c..0000000
--- a/cmds/statsd/src/state/StateManager.h
+++ /dev/null
@@ -1,103 +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.
- */
-#pragma once
-
-#include <inttypes.h>
-#include <utils/RefBase.h>
-
-#include <set>
-#include <string>
-#include <unordered_map>
-
-#include "HashableDimensionKey.h"
-#include "packages/UidMap.h"
-#include "state/StateListener.h"
-#include "state/StateTracker.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/**
- * This class is NOT thread safe.
- * It should only be used while StatsLogProcessor's lock is held.
- */
-class StateManager : public virtual RefBase {
-public:
-    StateManager();
-
-    ~StateManager(){};
-
-    // Returns a pointer to the single, shared StateManager object.
-    static StateManager& getInstance();
-
-    // Unregisters all listeners and removes all trackers from StateManager.
-    void clear();
-
-    // Notifies the correct StateTracker of an event.
-    void onLogEvent(const LogEvent& event);
-
-    // Notifies the StateTracker for the given atomId to register listener.
-    // If the correct StateTracker does not exist, a new StateTracker is created.
-    // Note: StateTrackers can be created for non-state atoms. They are essentially empty and
-    // do not perform any actions.
-    void registerListener(const int32_t atomId, wp<StateListener> listener);
-
-    // Notifies the correct StateTracker to unregister a listener
-    // and removes the tracker if it no longer has any listeners.
-    void unregisterListener(const int32_t atomId, wp<StateListener> listener);
-
-    // Returns true if the StateTracker exists and queries for the
-    // original state value mapped to the given query key. The state value is
-    // stored and output in a FieldValue class.
-    // Returns false if the StateTracker doesn't exist.
-    bool getStateValue(const int32_t atomId, const HashableDimensionKey& queryKey,
-                       FieldValue* output) const;
-
-    // Updates mAllowedLogSources with the latest uids for the packages that are allowed to log.
-    void updateLogSources(const sp<UidMap>& uidMap);
-
-    void notifyAppChanged(const string& apk, const sp<UidMap>& uidMap);
-
-    inline int getStateTrackersCount() const {
-        return mStateTrackers.size();
-    }
-
-    inline int getListenersCount(const int32_t atomId) const {
-        auto it = mStateTrackers.find(atomId);
-        if (it != mStateTrackers.end()) {
-            return it->second->getListenersCount();
-        }
-        return -1;
-    }
-
-private:
-    mutable std::mutex mMutex;
-
-    // Maps state atom ids to StateTrackers
-    std::unordered_map<int32_t, sp<StateTracker>> mStateTrackers;
-
-    // The package names that can log state events.
-    const std::set<std::string> mAllowedPkg;
-
-    // The combined uid sources (after translating pkg name to uid).
-    // State events from uids that are not in the list will be ignored to avoid state pollution.
-    std::set<int32_t> mAllowedLogSources;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/state/StateTracker.cpp b/cmds/statsd/src/state/StateTracker.cpp
deleted file mode 100644
index 41e525c..0000000
--- a/cmds/statsd/src/state/StateTracker.cpp
+++ /dev/null
@@ -1,190 +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.
- */
-
-#define DEBUG true  // STOPSHIP if true
-#include "Log.h"
-
-#include "stats_util.h"
-
-#include "StateTracker.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-StateTracker::StateTracker(const int32_t atomId) : mField(atomId, 0) {
-}
-
-void StateTracker::onLogEvent(const LogEvent& event) {
-    const int64_t eventTimeNs = event.GetElapsedTimestampNs();
-
-    // Parse event for primary field values i.e. primary key.
-    HashableDimensionKey primaryKey;
-    filterPrimaryKey(event.getValues(), &primaryKey);
-
-    FieldValue newState;
-    if (!getStateFieldValueFromLogEvent(event, &newState)) {
-        ALOGE("StateTracker error extracting state from log event. Missing exclusive state field.");
-        clearStateForPrimaryKey(eventTimeNs, primaryKey);
-        return;
-    }
-
-    mField.setField(newState.mField.getField());
-
-    if (newState.mValue.getType() != INT) {
-        ALOGE("StateTracker error extracting state from log event. Type: %d",
-              newState.mValue.getType());
-        clearStateForPrimaryKey(eventTimeNs, primaryKey);
-        return;
-    }
-
-    if (int resetState = event.getResetState(); resetState != -1) {
-        VLOG("StateTracker new reset state: %d", resetState);
-        const FieldValue resetStateFieldValue(mField, Value(resetState));
-        handleReset(eventTimeNs, resetStateFieldValue);
-        return;
-    }
-
-    const bool nested = newState.mAnnotations.isNested();
-    StateValueInfo* stateValueInfo = &mStateMap[primaryKey];
-    updateStateForPrimaryKey(eventTimeNs, primaryKey, newState, nested, stateValueInfo);
-}
-
-void StateTracker::registerListener(wp<StateListener> listener) {
-    mListeners.insert(listener);
-}
-
-void StateTracker::unregisterListener(wp<StateListener> listener) {
-    mListeners.erase(listener);
-}
-
-bool StateTracker::getStateValue(const HashableDimensionKey& queryKey, FieldValue* output) const {
-    output->mField = mField;
-
-    if (const auto it = mStateMap.find(queryKey); it != mStateMap.end()) {
-        output->mValue = it->second.state;
-        return true;
-    }
-
-    // Set the state value to kStateUnknown if query key is not found in state map.
-    output->mValue = kStateUnknown;
-    return false;
-}
-
-void StateTracker::handleReset(const int64_t eventTimeNs, const FieldValue& newState) {
-    VLOG("StateTracker handle reset");
-    for (auto& [primaryKey, stateValueInfo] : mStateMap) {
-        updateStateForPrimaryKey(eventTimeNs, primaryKey, newState,
-                                 false /* nested; treat this state change as not nested */,
-                                 &stateValueInfo);
-    }
-}
-
-void StateTracker::clearStateForPrimaryKey(const int64_t eventTimeNs,
-                                           const HashableDimensionKey& primaryKey) {
-    VLOG("StateTracker clear state for primary key");
-    const std::unordered_map<HashableDimensionKey, StateValueInfo>::iterator it =
-            mStateMap.find(primaryKey);
-
-    // If there is no entry for the primaryKey in mStateMap, then the state is already
-    // kStateUnknown.
-    const FieldValue state(mField, Value(kStateUnknown));
-    if (it != mStateMap.end()) {
-        updateStateForPrimaryKey(eventTimeNs, primaryKey, state,
-                                 false /* nested; treat this state change as not nested */,
-                                 &it->second);
-    }
-}
-
-void StateTracker::updateStateForPrimaryKey(const int64_t eventTimeNs,
-                                            const HashableDimensionKey& primaryKey,
-                                            const FieldValue& newState, const bool nested,
-                                            StateValueInfo* stateValueInfo) {
-    FieldValue oldState;
-    oldState.mField = mField;
-    oldState.mValue.setInt(stateValueInfo->state);
-    const int32_t oldStateValue = stateValueInfo->state;
-    const int32_t newStateValue = newState.mValue.int_value;
-
-    if (kStateUnknown == newStateValue) {
-        mStateMap.erase(primaryKey);
-    }
-
-    // Update state map for non-nested counting case.
-    // Every state event triggers a state overwrite.
-    if (!nested) {
-        stateValueInfo->state = newStateValue;
-        stateValueInfo->count = 1;
-
-        // Notify listeners if state has changed.
-        if (oldStateValue != newStateValue) {
-            notifyListeners(eventTimeNs, primaryKey, oldState, newState);
-        }
-        return;
-    }
-
-    // Update state map for nested counting case.
-    //
-    // Nested counting is only allowed for binary state events such as ON/OFF or
-    // ACQUIRE/RELEASE. For example, WakelockStateChanged might have the state
-    // events: ON, ON, OFF. The state will still be ON until we see the same
-    // number of OFF events as ON events.
-    //
-    // In atoms.proto, a state atom with nested counting enabled
-    // must only have 2 states. There is no enforcemnt here of this requirement.
-    // The atom must be logged correctly.
-    if (kStateUnknown == newStateValue) {
-        if (kStateUnknown != oldStateValue) {
-            notifyListeners(eventTimeNs, primaryKey, oldState, newState);
-        }
-    } else if (oldStateValue == kStateUnknown) {
-        stateValueInfo->state = newStateValue;
-        stateValueInfo->count = 1;
-        notifyListeners(eventTimeNs, primaryKey, oldState, newState);
-    } else if (oldStateValue == newStateValue) {
-        stateValueInfo->count++;
-    } else if (--stateValueInfo->count == 0) {
-        stateValueInfo->state = newStateValue;
-        stateValueInfo->count = 1;
-        notifyListeners(eventTimeNs, primaryKey, oldState, newState);
-    }
-}
-
-void StateTracker::notifyListeners(const int64_t eventTimeNs,
-                                   const HashableDimensionKey& primaryKey,
-                                   const FieldValue& oldState, const FieldValue& newState) {
-    for (auto l : mListeners) {
-        auto sl = l.promote();
-        if (sl != nullptr) {
-            sl->onStateChanged(eventTimeNs, mField.getTag(), primaryKey, oldState, newState);
-        }
-    }
-}
-
-bool getStateFieldValueFromLogEvent(const LogEvent& event, FieldValue* output) {
-    const int exclusiveStateFieldIndex = event.getExclusiveStateFieldIndex();
-    if (-1 == exclusiveStateFieldIndex) {
-        ALOGE("error extracting state from log event. Missing exclusive state field.");
-        return false;
-    }
-
-    *output = event.getValues()[exclusiveStateFieldIndex];
-    return true;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/state/StateTracker.h b/cmds/statsd/src/state/StateTracker.h
deleted file mode 100644
index abd579e..0000000
--- a/cmds/statsd/src/state/StateTracker.h
+++ /dev/null
@@ -1,94 +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.
- */
-#pragma once
-
-#include <utils/RefBase.h>
-#include "HashableDimensionKey.h"
-#include "logd/LogEvent.h"
-
-#include "state/StateListener.h"
-
-#include <unordered_map>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class StateTracker : public virtual RefBase {
-public:
-    StateTracker(const int32_t atomId);
-
-    virtual ~StateTracker(){};
-
-    // Updates state map and notifies all listeners if a state change occurs.
-    // Checks if a state change has occurred by getting the state value from
-    // the log event and comparing the old and new states.
-    void onLogEvent(const LogEvent& event);
-
-    // Adds new listeners to set of StateListeners. If a listener is already
-    // registered, it is ignored.
-    void registerListener(wp<StateListener> listener);
-
-    void unregisterListener(wp<StateListener> listener);
-
-    // The output is a FieldValue object that has mStateField as the field and
-    // the original state value (found using the given query key) as the value.
-    //
-    // If the key isn't mapped to a state or the key size doesn't match the
-    // number of primary fields, the output value is set to kStateUnknown.
-    bool getStateValue(const HashableDimensionKey& queryKey, FieldValue* output) const;
-
-    inline int getListenersCount() const {
-        return mListeners.size();
-    }
-
-    const static int kStateUnknown = -1;
-
-private:
-    struct StateValueInfo {
-        int32_t state = kStateUnknown;  // state value
-        int count = 0;                  // nested count (only used for binary states)
-    };
-
-    Field mField;
-
-    // Maps primary key to state value info
-    std::unordered_map<HashableDimensionKey, StateValueInfo> mStateMap;
-
-    // Set of all StateListeners (objects listening for state changes)
-    std::set<wp<StateListener>> mListeners;
-
-    // Reset all state values in map to the given state.
-    void handleReset(const int64_t eventTimeNs, const FieldValue& newState);
-
-    // Clears the state value mapped to the given primary key by setting it to kStateUnknown.
-    void clearStateForPrimaryKey(const int64_t eventTimeNs, const HashableDimensionKey& primaryKey);
-
-    // Update the StateMap based on the received state value.
-    void updateStateForPrimaryKey(const int64_t eventTimeNs, const HashableDimensionKey& primaryKey,
-                                  const FieldValue& newState, const bool nested,
-                                  StateValueInfo* stateValueInfo);
-
-    // Notify registered state listeners of state change.
-    void notifyListeners(const int64_t eventTimeNs, const HashableDimensionKey& primaryKey,
-                         const FieldValue& oldState, const FieldValue& newState);
-};
-
-bool getStateFieldValueFromLogEvent(const LogEvent& event, FieldValue* output);
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
deleted file mode 100644
index bb07963..0000000
--- a/cmds/statsd/src/stats_log.proto
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.os.statsd;
-
-option java_package = "com.android.os";
-option java_outer_classname = "StatsLog";
-
-import "frameworks/proto_logging/stats/atoms.proto";
-
-message DimensionsValue {
-  optional int32 field = 1;
-
-  oneof value {
-    string value_str = 2;
-    int32 value_int = 3;
-    int64 value_long = 4;
-    bool value_bool = 5;
-    float value_float = 6;
-    DimensionsValueTuple value_tuple = 7;
-    uint64 value_str_hash = 8;
-  }
-}
-
-message DimensionsValueTuple {
-  repeated DimensionsValue dimensions_value = 1;
-}
-
-message StateValue {
-  optional int32 atom_id = 1;
-
-  oneof contents {
-    int64 group_id = 2;
-    int32 value = 3;
-  }
-}
-
-message EventMetricData {
-  optional int64 elapsed_timestamp_nanos = 1;
-
-  optional Atom atom = 2;
-
-  optional int64 wall_clock_timestamp_nanos = 3 [deprecated = true];
-}
-
-message CountBucketInfo {
-  optional int64 start_bucket_elapsed_nanos = 1;
-
-  optional int64 end_bucket_elapsed_nanos = 2;
-
-  optional int64 count = 3;
-
-  optional int64 bucket_num = 4;
-
-  optional int64 start_bucket_elapsed_millis = 5;
-
-  optional int64 end_bucket_elapsed_millis = 6;
-}
-
-message CountMetricData {
-  optional DimensionsValue dimensions_in_what = 1;
-
-  repeated StateValue slice_by_state = 6;
-
-  repeated CountBucketInfo bucket_info = 3;
-
-  repeated DimensionsValue dimension_leaf_values_in_what = 4;
-
-  optional DimensionsValue dimensions_in_condition = 2 [deprecated = true];
-
-  repeated DimensionsValue dimension_leaf_values_in_condition = 5 [deprecated = true];
-}
-
-message DurationBucketInfo {
-  optional int64 start_bucket_elapsed_nanos = 1;
-
-  optional int64 end_bucket_elapsed_nanos = 2;
-
-  optional int64 duration_nanos = 3;
-
-  optional int64 bucket_num = 4;
-
-  optional int64 start_bucket_elapsed_millis = 5;
-
-  optional int64 end_bucket_elapsed_millis = 6;
-}
-
-message DurationMetricData {
-  optional DimensionsValue dimensions_in_what = 1;
-
-  repeated StateValue slice_by_state = 6;
-
-  repeated DurationBucketInfo bucket_info = 3;
-
-  repeated DimensionsValue dimension_leaf_values_in_what = 4;
-
-  optional DimensionsValue dimensions_in_condition = 2 [deprecated = true];
-
-  repeated DimensionsValue dimension_leaf_values_in_condition = 5 [deprecated = true];
-}
-
-message ValueBucketInfo {
-  optional int64 start_bucket_elapsed_nanos = 1;
-
-  optional int64 end_bucket_elapsed_nanos = 2;
-
-  optional int64 value = 3 [deprecated = true];
-
-  oneof single_value {
-      int64 value_long = 7 [deprecated = true];
-
-      double value_double = 8 [deprecated = true];
-  }
-
-  message Value {
-      optional int32 index = 1;
-      oneof value {
-          int64 value_long = 2;
-          double value_double = 3;
-      }
-  }
-
-  repeated Value values = 9;
-
-  optional int64 bucket_num = 4;
-
-  optional int64 start_bucket_elapsed_millis = 5;
-
-  optional int64 end_bucket_elapsed_millis = 6;
-
-  optional int64 condition_true_nanos = 10;
-}
-
-message ValueMetricData {
-  optional DimensionsValue dimensions_in_what = 1;
-
-  repeated StateValue slice_by_state = 6;
-
-  repeated ValueBucketInfo bucket_info = 3;
-
-  repeated DimensionsValue dimension_leaf_values_in_what = 4;
-
-  optional DimensionsValue dimensions_in_condition = 2 [deprecated = true];
-
-  repeated DimensionsValue dimension_leaf_values_in_condition = 5 [deprecated = true];
-}
-
-message GaugeBucketInfo {
-  optional int64 start_bucket_elapsed_nanos = 1;
-
-  optional int64 end_bucket_elapsed_nanos = 2;
-
-  repeated Atom atom = 3;
-
-  repeated int64 elapsed_timestamp_nanos = 4;
-
-  repeated int64 wall_clock_timestamp_nanos = 5 [deprecated = true];
-
-  optional int64 bucket_num = 6;
-
-  optional int64 start_bucket_elapsed_millis = 7;
-
-  optional int64 end_bucket_elapsed_millis = 8;
-}
-
-message GaugeMetricData {
-  optional DimensionsValue dimensions_in_what = 1;
-
-  // Currently unsupported
-  repeated StateValue slice_by_state = 6;
-
-  repeated GaugeBucketInfo bucket_info = 3;
-
-  repeated DimensionsValue dimension_leaf_values_in_what = 4;
-
-  optional DimensionsValue dimensions_in_condition = 2 [deprecated = true];
-
-  repeated DimensionsValue dimension_leaf_values_in_condition = 5 [deprecated = true];
-}
-
-message StatsLogReport {
-  optional int64 metric_id = 1;
-
-  // Fields 2 and 3 are reserved.
-
-  // Keep this in sync with BucketDropReason enum in MetricProducer.h.
-  enum BucketDropReason {
-      // For ValueMetric, a bucket is dropped during a dump report request iff
-      // current bucket should be included, a pull is needed (pulled metric and
-      // condition is true), and we are under fast time constraints.
-      DUMP_REPORT_REQUESTED = 1;
-      EVENT_IN_WRONG_BUCKET = 2;
-      CONDITION_UNKNOWN = 3;
-      PULL_FAILED = 4;
-      PULL_DELAYED = 5;
-      DIMENSION_GUARDRAIL_REACHED = 6;
-      MULTIPLE_BUCKETS_SKIPPED = 7;
-      // Not an invalid bucket case, but the bucket is dropped.
-      BUCKET_TOO_SMALL = 8;
-      // Not an invalid bucket case, but the bucket is skipped.
-      NO_DATA = 9;
-  };
-
-  message DropEvent {
-      optional BucketDropReason drop_reason = 1;
-
-      optional int64 drop_time_millis = 2;
-  }
-
-  message SkippedBuckets {
-      optional int64 start_bucket_elapsed_nanos = 1;
-
-      optional int64 end_bucket_elapsed_nanos = 2;
-
-      optional int64 start_bucket_elapsed_millis = 3;
-
-      optional int64 end_bucket_elapsed_millis = 4;
-
-      // The number of drop events is capped by StatsdStats::kMaxLoggedBucketDropEvents.
-      // The current maximum is 10 drop events.
-      repeated DropEvent drop_event = 5;
-  }
-
-  message EventMetricDataWrapper {
-    repeated EventMetricData data = 1;
-  }
-  message CountMetricDataWrapper {
-    repeated CountMetricData data = 1;
-  }
-  message DurationMetricDataWrapper {
-    repeated DurationMetricData data = 1;
-  }
-  message ValueMetricDataWrapper {
-    repeated ValueMetricData data = 1;
-    repeated SkippedBuckets skipped = 2;
-  }
-
-  message GaugeMetricDataWrapper {
-    repeated GaugeMetricData data = 1;
-    repeated SkippedBuckets skipped = 2;
-  }
-
-  oneof data {
-    EventMetricDataWrapper event_metrics = 4;
-    CountMetricDataWrapper count_metrics = 5;
-    DurationMetricDataWrapper duration_metrics = 6;
-    ValueMetricDataWrapper value_metrics = 7;
-    GaugeMetricDataWrapper gauge_metrics = 8;
-  }
-
-  optional int64 time_base_elapsed_nano_seconds = 9;
-
-  optional int64 bucket_size_nano_seconds = 10;
-
-  optional DimensionsValue dimensions_path_in_what = 11;
-
-  optional DimensionsValue dimensions_path_in_condition = 12 [deprecated = true];
-
-  // DO NOT USE field 13.
-
-  optional bool is_active = 14;
-}
-
-message UidMapping {
-    message PackageInfoSnapshot {
-        message PackageInfo {
-            optional string name = 1;
-
-            optional int64 version = 2;
-
-            optional int32 uid = 3;
-
-            optional bool deleted = 4;
-
-            optional uint64 name_hash = 5;
-
-            optional string version_string = 6;
-
-            optional uint64 version_string_hash = 7;
-
-            optional string installer = 8;
-
-            optional uint64 installer_hash = 9;
-        }
-        optional int64 elapsed_timestamp_nanos = 1;
-
-        repeated PackageInfo package_info = 2;
-    }
-    repeated PackageInfoSnapshot snapshots = 1;
-
-    message Change {
-        optional bool deletion = 1;
-
-        optional int64 elapsed_timestamp_nanos = 2;
-        optional string app = 3;
-        optional int32 uid = 4;
-
-        optional int64 new_version = 5;
-        optional int64 prev_version = 6;
-        optional uint64 app_hash = 7;
-        optional string new_version_string = 8;
-        optional string prev_version_string = 9;
-        optional uint64 new_version_string_hash = 10;
-        optional uint64 prev_version_string_hash = 11;
-    }
-    repeated Change changes = 2;
-}
-
-message ConfigMetricsReport {
-  repeated StatsLogReport metrics = 1;
-
-  optional UidMapping uid_map = 2;
-
-  optional int64 last_report_elapsed_nanos = 3;
-
-  optional int64 current_report_elapsed_nanos = 4;
-
-  optional int64 last_report_wall_clock_nanos = 5;
-
-  optional int64 current_report_wall_clock_nanos = 6;
-
-  message Annotation {
-      optional int64 field_int64 = 1;
-      optional int32 field_int32 = 2;
-  }
-  repeated Annotation annotation = 7;
-
-  enum DumpReportReason {
-      DEVICE_SHUTDOWN = 1;
-      CONFIG_UPDATED = 2;
-      CONFIG_REMOVED = 3;
-      GET_DATA_CALLED = 4;
-      ADB_DUMP = 5;
-      CONFIG_RESET = 6;
-      STATSCOMPANION_DIED = 7;
-      TERMINATION_SIGNAL_RECEIVED = 8;
-  }
-  optional DumpReportReason dump_report_reason = 8;
-
-  repeated string strings = 9;
-}
-
-message ConfigMetricsReportList {
-  message ConfigKey {
-    optional int32 uid = 1;
-    optional int64 id = 2;
-  }
-  optional ConfigKey config_key = 1;
-
-  repeated ConfigMetricsReport reports = 2;
-
-  reserved 10;
-}
-
-message StatsdStatsReport {
-    optional int32 stats_begin_time_sec = 1;
-
-    optional int32 stats_end_time_sec = 2;
-
-    message MatcherStats {
-        optional int64 id = 1;
-        optional int32 matched_times = 2;
-    }
-
-    message ConditionStats {
-        optional int64 id = 1;
-        optional int32 max_tuple_counts = 2;
-    }
-
-    message MetricStats {
-        optional int64 id = 1;
-        optional int32 max_tuple_counts = 2;
-    }
-
-    message AlertStats {
-        optional int64 id = 1;
-        optional int32 alerted_times = 2;
-    }
-
-    message ConfigStats {
-        optional int32 uid = 1;
-        optional int64 id = 2;
-        optional int32 creation_time_sec = 3;
-        optional int32 deletion_time_sec = 4;
-        optional int32 reset_time_sec = 19;
-        optional int32 metric_count = 5;
-        optional int32 condition_count = 6;
-        optional int32 matcher_count = 7;
-        optional int32 alert_count = 8;
-        optional bool is_valid = 9;
-        repeated int32 broadcast_sent_time_sec = 10;
-        repeated int32 data_drop_time_sec = 11;
-        repeated int64 data_drop_bytes = 21;
-        repeated int32 dump_report_time_sec = 12;
-        repeated int32 dump_report_data_size = 20;
-        repeated MatcherStats matcher_stats = 13;
-        repeated ConditionStats condition_stats = 14;
-        repeated MetricStats metric_stats = 15;
-        repeated AlertStats alert_stats = 16;
-        repeated MetricStats metric_dimension_in_condition_stats = 17 [deprecated = true];
-        message Annotation {
-            optional int64 field_int64 = 1;
-            optional int32 field_int32 = 2;
-        }
-        repeated Annotation annotation = 18;
-        repeated int32 activation_time_sec = 22;
-        repeated int32 deactivation_time_sec = 23;
-    }
-
-    repeated ConfigStats config_stats = 3;
-
-    message AtomStats {
-        optional int32 tag = 1;
-        optional int32 count = 2;
-        optional int32 error_count = 3;
-    }
-
-    repeated AtomStats atom_stats = 7;
-
-    message UidMapStats {
-        optional int32 changes = 1;
-        optional int32 bytes_used = 2;
-        optional int32 dropped_changes = 3;
-        optional int32 deleted_apps = 4;
-    }
-    optional UidMapStats uidmap_stats = 8;
-
-    message AnomalyAlarmStats {
-        optional int32 alarms_registered = 1;
-    }
-    optional AnomalyAlarmStats anomaly_alarm_stats = 9;
-
-    message PulledAtomStats {
-        optional int32 atom_id = 1;
-        optional int64 total_pull = 2;
-        optional int64 total_pull_from_cache = 3;
-        optional int64 min_pull_interval_sec = 4;
-        optional int64 average_pull_time_nanos = 5;
-        optional int64 max_pull_time_nanos = 6;
-        optional int64 average_pull_delay_nanos = 7;
-        optional int64 max_pull_delay_nanos = 8;
-        optional int64 data_error = 9;
-        optional int64 pull_timeout = 10;
-        optional int64 pull_exceed_max_delay = 11;
-        optional int64 pull_failed = 12;
-        optional int64 stats_companion_pull_failed = 13 [deprecated = true];
-        optional int64 stats_companion_pull_binder_transaction_failed = 14 [deprecated = true];
-        optional int64 empty_data = 15;
-        optional int64 registered_count = 16;
-        optional int64 unregistered_count = 17;
-        optional int32 atom_error_count = 18;
-        optional int64 binder_call_failed = 19;
-        optional int64 failed_uid_provider_not_found = 20;
-        optional int64 puller_not_found = 21;
-        message PullTimeoutMetadata {
-          optional int64 pull_timeout_uptime_millis = 1;
-          optional int64 pull_timeout_elapsed_millis = 2;
-        }
-        repeated PullTimeoutMetadata pull_atom_metadata = 22;
-    }
-    repeated PulledAtomStats pulled_atom_stats = 10;
-
-    message AtomMetricStats {
-      optional int64 metric_id = 1;
-      optional int64 hard_dimension_limit_reached = 2;
-      optional int64 late_log_event_skipped = 3;
-      optional int64 skipped_forward_buckets = 4;
-      optional int64 bad_value_type = 5;
-      optional int64 condition_change_in_next_bucket = 6;
-      optional int64 invalidated_bucket = 7;
-      optional int64 bucket_dropped = 8;
-      optional int64 min_bucket_boundary_delay_ns = 9;
-      optional int64 max_bucket_boundary_delay_ns = 10;
-      optional int64 bucket_unknown_condition = 11;
-      optional int64 bucket_count = 12;
-    }
-    repeated AtomMetricStats atom_metric_stats = 17;
-
-    message LoggerErrorStats {
-        optional int32 logger_disconnection_sec = 1;
-        optional int32 error_code = 2;
-    }
-    repeated LoggerErrorStats logger_error_stats = 11;
-
-    message PeriodicAlarmStats {
-        optional int32 alarms_registered = 1;
-    }
-    optional PeriodicAlarmStats periodic_alarm_stats = 12;
-
-    message  SkippedLogEventStats {
-        optional int32 tag = 1;
-        optional int64 elapsed_timestamp_nanos = 2;
-    }
-    repeated SkippedLogEventStats skipped_log_event_stats = 13;
-
-    repeated int64 log_loss_stats = 14;
-
-    repeated int32 system_restart_sec = 15;
-
-    message LogLossStats {
-        optional int32 detected_time_sec = 1;
-        optional int32 count = 2;
-        optional int32 last_error = 3;
-        optional int32 last_tag = 4;
-        optional int32 uid = 5;
-        optional int32 pid = 6;
-    }
-    repeated LogLossStats detected_log_loss = 16;
-
-    message EventQueueOverflow {
-        optional int32 count = 1;
-        optional int64 max_queue_history_ns = 2;
-        optional int64 min_queue_history_ns = 3;
-    }
-
-    optional EventQueueOverflow queue_overflow = 18;
-
-    message ActivationBroadcastGuardrail {
-        optional int32 uid = 1;
-        repeated int32 guardrail_met_sec = 2;
-    }
-
-    repeated ActivationBroadcastGuardrail activation_guardrail_stats = 19;
-}
-
-message AlertTriggerDetails {
-    message MetricValue {
-        optional int64 metric_id = 1;
-        optional DimensionsValue dimension_in_what = 2;
-        optional DimensionsValue dimension_in_condition = 3 [deprecated = true];
-        optional int64 value = 4;
-    }
-    oneof value {
-        MetricValue trigger_metric = 1;
-        EventMetricData trigger_event = 2;
-    }
-    optional UidMapping.PackageInfoSnapshot package_info = 3;
-}
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
deleted file mode 100644
index 423bae8..0000000
--- a/cmds/statsd/src/stats_log_util.cpp
+++ /dev/null
@@ -1,609 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "hash.h"
-#include "stats_log_util.h"
-
-#include <aidl/android/os/IStatsCompanionService.h>
-#include <private/android_filesystem_config.h>
-#include <set>
-#include <utils/SystemClock.h>
-
-#include "statscompanion_util.h"
-
-using android::util::FIELD_COUNT_REPEATED;
-using android::util::FIELD_TYPE_BOOL;
-using android::util::FIELD_TYPE_FIXED64;
-using android::util::FIELD_TYPE_FLOAT;
-using android::util::FIELD_TYPE_INT32;
-using android::util::FIELD_TYPE_INT64;
-using android::util::FIELD_TYPE_MESSAGE;
-using android::util::FIELD_TYPE_STRING;
-using android::util::FIELD_TYPE_UINT64;
-using android::util::ProtoOutputStream;
-
-using aidl::android::os::IStatsCompanionService;
-using std::shared_ptr;
-using std::string;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// for DimensionsValue Proto
-const int DIMENSIONS_VALUE_FIELD = 1;
-const int DIMENSIONS_VALUE_VALUE_STR = 2;
-const int DIMENSIONS_VALUE_VALUE_INT = 3;
-const int DIMENSIONS_VALUE_VALUE_LONG = 4;
-// const int DIMENSIONS_VALUE_VALUE_BOOL = 5; // logd doesn't have bool data type.
-const int DIMENSIONS_VALUE_VALUE_FLOAT = 6;
-const int DIMENSIONS_VALUE_VALUE_TUPLE = 7;
-const int DIMENSIONS_VALUE_VALUE_STR_HASH = 8;
-
-const int DIMENSIONS_VALUE_TUPLE_VALUE = 1;
-
-// for StateValue Proto
-const int STATE_VALUE_ATOM_ID = 1;
-const int STATE_VALUE_CONTENTS_GROUP_ID = 2;
-const int STATE_VALUE_CONTENTS_VALUE = 3;
-
-// for PulledAtomStats proto
-const int FIELD_ID_PULLED_ATOM_STATS = 10;
-const int FIELD_ID_PULL_ATOM_ID = 1;
-const int FIELD_ID_TOTAL_PULL = 2;
-const int FIELD_ID_TOTAL_PULL_FROM_CACHE = 3;
-const int FIELD_ID_MIN_PULL_INTERVAL_SEC = 4;
-const int FIELD_ID_AVERAGE_PULL_TIME_NANOS = 5;
-const int FIELD_ID_MAX_PULL_TIME_NANOS = 6;
-const int FIELD_ID_AVERAGE_PULL_DELAY_NANOS = 7;
-const int FIELD_ID_MAX_PULL_DELAY_NANOS = 8;
-const int FIELD_ID_DATA_ERROR = 9;
-const int FIELD_ID_PULL_TIMEOUT = 10;
-const int FIELD_ID_PULL_EXCEED_MAX_DELAY = 11;
-const int FIELD_ID_PULL_FAILED = 12;
-const int FIELD_ID_EMPTY_DATA = 15;
-const int FIELD_ID_PULL_REGISTERED_COUNT = 16;
-const int FIELD_ID_PULL_UNREGISTERED_COUNT = 17;
-const int FIELD_ID_ATOM_ERROR_COUNT = 18;
-const int FIELD_ID_BINDER_CALL_FAIL_COUNT = 19;
-const int FIELD_ID_PULL_UID_PROVIDER_NOT_FOUND = 20;
-const int FIELD_ID_PULLER_NOT_FOUND = 21;
-const int FIELD_ID_PULL_TIMEOUT_METADATA = 22;
-const int FIELD_ID_PULL_TIMEOUT_METADATA_UPTIME_MILLIS = 1;
-const int FIELD_ID_PULL_TIMEOUT_METADATA_ELAPSED_MILLIS = 2;
-
-// for AtomMetricStats proto
-const int FIELD_ID_ATOM_METRIC_STATS = 17;
-const int FIELD_ID_METRIC_ID = 1;
-const int FIELD_ID_HARD_DIMENSION_LIMIT_REACHED = 2;
-const int FIELD_ID_LATE_LOG_EVENT_SKIPPED = 3;
-const int FIELD_ID_SKIPPED_FORWARD_BUCKETS = 4;
-const int FIELD_ID_BAD_VALUE_TYPE = 5;
-const int FIELD_ID_CONDITION_CHANGE_IN_NEXT_BUCKET = 6;
-const int FIELD_ID_INVALIDATED_BUCKET = 7;
-const int FIELD_ID_BUCKET_DROPPED = 8;
-const int FIELD_ID_MIN_BUCKET_BOUNDARY_DELAY_NS = 9;
-const int FIELD_ID_MAX_BUCKET_BOUNDARY_DELAY_NS = 10;
-const int FIELD_ID_BUCKET_UNKNOWN_CONDITION = 11;
-const int FIELD_ID_BUCKET_COUNT = 12;
-
-namespace {
-
-void writeDimensionToProtoHelper(const std::vector<FieldValue>& dims, size_t* index, int depth,
-                                 int prefix, std::set<string> *str_set,
-                                 ProtoOutputStream* protoOutput) {
-    size_t count = dims.size();
-    while (*index < count) {
-        const auto& dim = dims[*index];
-        const int valueDepth = dim.mField.getDepth();
-        const int valuePrefix = dim.mField.getPrefix(depth);
-        const int fieldNum = dim.mField.getPosAtDepth(depth);
-        if (valueDepth > 2) {
-            ALOGE("Depth > 2 not supported");
-            return;
-        }
-
-        if (depth == valueDepth && valuePrefix == prefix) {
-            uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                                 DIMENSIONS_VALUE_TUPLE_VALUE);
-            protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
-            switch (dim.mValue.getType()) {
-                case INT:
-                    protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_VALUE_INT,
-                                       dim.mValue.int_value);
-                    break;
-                case LONG:
-                    protoOutput->write(FIELD_TYPE_INT64 | DIMENSIONS_VALUE_VALUE_LONG,
-                                       (long long)dim.mValue.long_value);
-                    break;
-                case FLOAT:
-                    protoOutput->write(FIELD_TYPE_FLOAT | DIMENSIONS_VALUE_VALUE_FLOAT,
-                                       dim.mValue.float_value);
-                    break;
-                case STRING:
-                    if (str_set == nullptr) {
-                        protoOutput->write(FIELD_TYPE_STRING | DIMENSIONS_VALUE_VALUE_STR,
-                                           dim.mValue.str_value);
-                    } else {
-                        str_set->insert(dim.mValue.str_value);
-                        protoOutput->write(
-                                FIELD_TYPE_UINT64 | DIMENSIONS_VALUE_VALUE_STR_HASH,
-                                (long long)Hash64(dim.mValue.str_value));
-                    }
-                    break;
-                default:
-                    break;
-            }
-            if (token != 0) {
-                protoOutput->end(token);
-            }
-            (*index)++;
-        } else if (valueDepth > depth && valuePrefix == prefix) {
-            // Writing the sub tree
-            uint64_t dimensionToken = protoOutput->start(
-                    FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | DIMENSIONS_VALUE_TUPLE_VALUE);
-            protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
-            uint64_t tupleToken =
-                    protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
-            writeDimensionToProtoHelper(dims, index, valueDepth, dim.mField.getPrefix(valueDepth),
-                                        str_set, protoOutput);
-            protoOutput->end(tupleToken);
-            protoOutput->end(dimensionToken);
-        } else {
-            // Done with the prev sub tree
-            return;
-        }
-    }
-}
-
-void writeDimensionLeafToProtoHelper(const std::vector<FieldValue>& dims,
-                                     const int dimensionLeafField,
-                                     size_t* index, int depth,
-                                     int prefix, std::set<string> *str_set,
-                                     ProtoOutputStream* protoOutput) {
-    size_t count = dims.size();
-    while (*index < count) {
-        const auto& dim = dims[*index];
-        const int valueDepth = dim.mField.getDepth();
-        const int valuePrefix = dim.mField.getPrefix(depth);
-        if (valueDepth > 2) {
-            ALOGE("Depth > 2 not supported");
-            return;
-        }
-
-        if (depth == valueDepth && valuePrefix == prefix) {
-            uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                                dimensionLeafField);
-            switch (dim.mValue.getType()) {
-                case INT:
-                    protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_VALUE_INT,
-                                       dim.mValue.int_value);
-                    break;
-                case LONG:
-                    protoOutput->write(FIELD_TYPE_INT64 | DIMENSIONS_VALUE_VALUE_LONG,
-                                       (long long)dim.mValue.long_value);
-                    break;
-                case FLOAT:
-                    protoOutput->write(FIELD_TYPE_FLOAT | DIMENSIONS_VALUE_VALUE_FLOAT,
-                                       dim.mValue.float_value);
-                    break;
-                case STRING:
-                    if (str_set == nullptr) {
-                        protoOutput->write(FIELD_TYPE_STRING | DIMENSIONS_VALUE_VALUE_STR,
-                                           dim.mValue.str_value);
-                    } else {
-                        str_set->insert(dim.mValue.str_value);
-                        protoOutput->write(
-                                FIELD_TYPE_UINT64 | DIMENSIONS_VALUE_VALUE_STR_HASH,
-                                (long long)Hash64(dim.mValue.str_value));
-                    }
-                    break;
-                default:
-                    break;
-            }
-            if (token != 0) {
-                protoOutput->end(token);
-            }
-            (*index)++;
-        } else if (valueDepth > depth && valuePrefix == prefix) {
-            writeDimensionLeafToProtoHelper(dims, dimensionLeafField,
-                                            index, valueDepth, dim.mField.getPrefix(valueDepth),
-                                            str_set, protoOutput);
-        } else {
-            // Done with the prev sub tree
-            return;
-        }
-    }
-}
-
-void writeDimensionPathToProtoHelper(const std::vector<Matcher>& fieldMatchers,
-                                     size_t* index, int depth, int prefix,
-                                     ProtoOutputStream* protoOutput) {
-    size_t count = fieldMatchers.size();
-    while (*index < count) {
-        const Field& field = fieldMatchers[*index].mMatcher;
-        const int valueDepth = field.getDepth();
-        const int valuePrefix = field.getPrefix(depth);
-        const int fieldNum = field.getPosAtDepth(depth);
-        if (valueDepth > 2) {
-            ALOGE("Depth > 2 not supported");
-            return;
-        }
-
-        if (depth == valueDepth && valuePrefix == prefix) {
-            uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                                 DIMENSIONS_VALUE_TUPLE_VALUE);
-            protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
-            if (token != 0) {
-                protoOutput->end(token);
-            }
-            (*index)++;
-        } else if (valueDepth > depth && valuePrefix == prefix) {
-            // Writing the sub tree
-            uint64_t dimensionToken = protoOutput->start(
-                    FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | DIMENSIONS_VALUE_TUPLE_VALUE);
-            protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD, fieldNum);
-            uint64_t tupleToken =
-                    protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
-            writeDimensionPathToProtoHelper(fieldMatchers, index, valueDepth,
-                                            field.getPrefix(valueDepth), protoOutput);
-            protoOutput->end(tupleToken);
-            protoOutput->end(dimensionToken);
-        } else {
-            // Done with the prev sub tree
-            return;
-        }
-    }
-}
-
-}  // namespace
-
-void writeDimensionToProto(const HashableDimensionKey& dimension, std::set<string> *str_set,
-                           ProtoOutputStream* protoOutput) {
-    if (dimension.getValues().size() == 0) {
-        return;
-    }
-    protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD,
-                       dimension.getValues()[0].mField.getTag());
-    uint64_t topToken = protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
-    size_t index = 0;
-    writeDimensionToProtoHelper(dimension.getValues(), &index, 0, 0, str_set, protoOutput);
-    protoOutput->end(topToken);
-}
-
-void writeDimensionLeafNodesToProto(const HashableDimensionKey& dimension,
-                                    const int dimensionLeafFieldId,
-                                    std::set<string> *str_set,
-                                    ProtoOutputStream* protoOutput) {
-    if (dimension.getValues().size() == 0) {
-        return;
-    }
-    size_t index = 0;
-    writeDimensionLeafToProtoHelper(dimension.getValues(), dimensionLeafFieldId,
-                                    &index, 0, 0, str_set, protoOutput);
-}
-
-void writeDimensionPathToProto(const std::vector<Matcher>& fieldMatchers,
-                               ProtoOutputStream* protoOutput) {
-    if (fieldMatchers.size() == 0) {
-        return;
-    }
-    protoOutput->write(FIELD_TYPE_INT32 | DIMENSIONS_VALUE_FIELD,
-                       fieldMatchers[0].mMatcher.getTag());
-    uint64_t topToken = protoOutput->start(FIELD_TYPE_MESSAGE | DIMENSIONS_VALUE_VALUE_TUPLE);
-    size_t index = 0;
-    writeDimensionPathToProtoHelper(fieldMatchers, &index, 0, 0, protoOutput);
-    protoOutput->end(topToken);
-}
-
-// Supported Atoms format
-// XYZ_Atom {
-//     repeated SubMsg field_1 = 1;
-//     SubMsg2 field_2 = 2;
-//     int32/float/string/int63 field_3 = 3;
-// }
-// logd's msg format, doesn't allow us to distinguish between the 2 cases below
-// Case (1):
-// Atom {
-//   SubMsg {
-//     int i = 1;
-//     int j = 2;
-//   }
-//   repeated SubMsg
-// }
-//
-// and case (2):
-// Atom {
-//   SubMsg {
-//     repeated int i = 1;
-//     repeated int j = 2;
-//   }
-//   optional SubMsg = 1;
-// }
-//
-//
-void writeFieldValueTreeToStreamHelper(int tagId, const std::vector<FieldValue>& dims,
-                                       size_t* index, int depth, int prefix,
-                                       ProtoOutputStream* protoOutput) {
-    size_t count = dims.size();
-    while (*index < count) {
-        const auto& dim = dims[*index];
-        const int valueDepth = dim.mField.getDepth();
-        const int valuePrefix = dim.mField.getPrefix(depth);
-        const int fieldNum = dim.mField.getPosAtDepth(depth);
-        if (valueDepth > 2) {
-            ALOGE("Depth > 2 not supported");
-            return;
-        }
-
-        if (depth == valueDepth && valuePrefix == prefix) {
-            switch (dim.mValue.getType()) {
-                case INT:
-                    protoOutput->write(FIELD_TYPE_INT32 | fieldNum, dim.mValue.int_value);
-                    break;
-                case LONG:
-                    protoOutput->write(FIELD_TYPE_INT64 | fieldNum,
-                                       (long long)dim.mValue.long_value);
-                    break;
-                case FLOAT:
-                    protoOutput->write(FIELD_TYPE_FLOAT | fieldNum, dim.mValue.float_value);
-                    break;
-                case STRING: {
-                    protoOutput->write(FIELD_TYPE_STRING | fieldNum, dim.mValue.str_value);
-                    break;
-                }
-                case STORAGE:
-                    protoOutput->write(FIELD_TYPE_MESSAGE | fieldNum,
-                                       (const char*)dim.mValue.storage_value.data(),
-                                       dim.mValue.storage_value.size());
-                    break;
-                default:
-                    break;
-            }
-            (*index)++;
-        } else if (valueDepth > depth && valuePrefix == prefix) {
-            // Writing the sub tree
-            uint64_t msg_token = 0ULL;
-            if (valueDepth == depth + 2) {
-                msg_token =
-                        protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | fieldNum);
-            } else if (valueDepth == depth + 1) {
-                msg_token = protoOutput->start(FIELD_TYPE_MESSAGE | fieldNum);
-            }
-            // Directly jump to the leaf value because the repeated position field is implied
-            // by the position of the sub msg in the parent field.
-            writeFieldValueTreeToStreamHelper(tagId, dims, index, valueDepth,
-                                              dim.mField.getPrefix(valueDepth), protoOutput);
-            if (msg_token != 0) {
-                protoOutput->end(msg_token);
-            }
-        } else {
-            // Done with the prev sub tree
-            return;
-        }
-    }
-}
-
-void writeFieldValueTreeToStream(int tagId, const std::vector<FieldValue>& values,
-                                 util::ProtoOutputStream* protoOutput) {
-    uint64_t atomToken = protoOutput->start(FIELD_TYPE_MESSAGE | tagId);
-
-    size_t index = 0;
-    writeFieldValueTreeToStreamHelper(tagId, values, &index, 0, 0, protoOutput);
-    protoOutput->end(atomToken);
-}
-
-void writeStateToProto(const FieldValue& state, util::ProtoOutputStream* protoOutput) {
-    protoOutput->write(FIELD_TYPE_INT32 | STATE_VALUE_ATOM_ID, state.mField.getTag());
-
-    switch (state.mValue.getType()) {
-        case INT:
-            protoOutput->write(FIELD_TYPE_INT32 | STATE_VALUE_CONTENTS_VALUE,
-                               state.mValue.int_value);
-            break;
-        case LONG:
-            protoOutput->write(FIELD_TYPE_INT64 | STATE_VALUE_CONTENTS_GROUP_ID,
-                               state.mValue.long_value);
-            break;
-        default:
-            break;
-    }
-}
-
-int64_t TimeUnitToBucketSizeInMillisGuardrailed(int uid, TimeUnit unit) {
-    int64_t bucketSizeMillis = TimeUnitToBucketSizeInMillis(unit);
-    if (bucketSizeMillis > 1000 && bucketSizeMillis < 5 * 60 * 1000LL && uid != AID_SHELL &&
-        uid != AID_ROOT) {
-        bucketSizeMillis = 5 * 60 * 1000LL;
-    }
-    return bucketSizeMillis;
-}
-
-int64_t TimeUnitToBucketSizeInMillis(TimeUnit unit) {
-    switch (unit) {
-        case ONE_MINUTE:
-            return 60 * 1000LL;
-        case FIVE_MINUTES:
-            return 5 * 60 * 1000LL;
-        case TEN_MINUTES:
-            return 10 * 60 * 1000LL;
-        case THIRTY_MINUTES:
-            return 30 * 60 * 1000LL;
-        case ONE_HOUR:
-            return 60 * 60 * 1000LL;
-        case THREE_HOURS:
-            return 3 * 60 * 60 * 1000LL;
-        case SIX_HOURS:
-            return 6 * 60 * 60 * 1000LL;
-        case TWELVE_HOURS:
-            return 12 * 60 * 60 * 1000LL;
-        case ONE_DAY:
-            return 24 * 60 * 60 * 1000LL;
-        case ONE_WEEK:
-            return 7 * 24 * 60 * 60 * 1000LL;
-        case CTS:
-            return 1000;
-        case TIME_UNIT_UNSPECIFIED:
-        default:
-            return -1;
-    }
-}
-
-void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats>& pair,
-                              util::ProtoOutputStream* protoOutput) {
-    uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_PULLED_ATOM_STATS |
-                                         FIELD_COUNT_REPEATED);
-    protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_PULL_ATOM_ID, (int32_t)pair.first);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TOTAL_PULL, (long long)pair.second.totalPull);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TOTAL_PULL_FROM_CACHE,
-                       (long long)pair.second.totalPullFromCache);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MIN_PULL_INTERVAL_SEC,
-                       (long long)pair.second.minPullIntervalSec);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_AVERAGE_PULL_TIME_NANOS,
-                       (long long)pair.second.avgPullTimeNs);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MAX_PULL_TIME_NANOS,
-                       (long long)pair.second.maxPullTimeNs);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_AVERAGE_PULL_DELAY_NANOS,
-                       (long long)pair.second.avgPullDelayNs);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MAX_PULL_DELAY_NANOS,
-                       (long long)pair.second.maxPullDelayNs);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_DATA_ERROR, (long long)pair.second.dataError);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_TIMEOUT,
-                       (long long)pair.second.pullTimeout);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_EXCEED_MAX_DELAY,
-                       (long long)pair.second.pullExceedMaxDelay);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_FAILED,
-                       (long long)pair.second.pullFailed);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_EMPTY_DATA,
-                       (long long)pair.second.emptyData);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_REGISTERED_COUNT,
-                       (long long) pair.second.registeredCount);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_UNREGISTERED_COUNT,
-                       (long long) pair.second.unregisteredCount);
-    protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_ATOM_ERROR_COUNT, pair.second.atomErrorCount);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BINDER_CALL_FAIL_COUNT,
-                       (long long)pair.second.binderCallFailCount);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_UID_PROVIDER_NOT_FOUND,
-                       (long long)pair.second.pullUidProviderNotFound);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULLER_NOT_FOUND,
-                       (long long)pair.second.pullerNotFound);
-    for (const auto& pullTimeoutMetadata : pair.second.pullTimeoutMetadata) {
-        uint64_t timeoutMetadataToken = protoOutput->start(FIELD_TYPE_MESSAGE |
-                                                           FIELD_ID_PULL_TIMEOUT_METADATA |
-                                                           FIELD_COUNT_REPEATED);
-        protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_TIMEOUT_METADATA_UPTIME_MILLIS,
-                           pullTimeoutMetadata.pullTimeoutUptimeMillis);
-        protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_TIMEOUT_METADATA_ELAPSED_MILLIS,
-                           pullTimeoutMetadata.pullTimeoutElapsedMillis);
-        protoOutput->end(timeoutMetadataToken);
-    }
-    protoOutput->end(token);
-}
-
-void writeAtomMetricStatsToStream(const std::pair<int64_t, StatsdStats::AtomMetricStats> &pair,
-                                  util::ProtoOutputStream *protoOutput) {
-    uint64_t token = protoOutput->start(FIELD_TYPE_MESSAGE | FIELD_ID_ATOM_METRIC_STATS |
-                                        FIELD_COUNT_REPEATED);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_ID, (long long)pair.first);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_HARD_DIMENSION_LIMIT_REACHED,
-                       (long long)pair.second.hardDimensionLimitReached);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_LATE_LOG_EVENT_SKIPPED,
-                       (long long)pair.second.lateLogEventSkipped);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_SKIPPED_FORWARD_BUCKETS,
-                       (long long)pair.second.skippedForwardBuckets);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BAD_VALUE_TYPE,
-                       (long long)pair.second.badValueType);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_CONDITION_CHANGE_IN_NEXT_BUCKET,
-                       (long long)pair.second.conditionChangeInNextBucket);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_INVALIDATED_BUCKET,
-                       (long long)pair.second.invalidatedBucket);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_DROPPED,
-                       (long long)pair.second.bucketDropped);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MIN_BUCKET_BOUNDARY_DELAY_NS,
-                       (long long)pair.second.minBucketBoundaryDelayNs);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MAX_BUCKET_BOUNDARY_DELAY_NS,
-                       (long long)pair.second.maxBucketBoundaryDelayNs);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_UNKNOWN_CONDITION,
-                       (long long)pair.second.bucketUnknownCondition);
-    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_COUNT,
-                       (long long)pair.second.bucketCount);
-    protoOutput->end(token);
-}
-
-int64_t getElapsedRealtimeNs() {
-    return ::android::elapsedRealtimeNano();
-}
-
-int64_t getElapsedRealtimeSec() {
-    return ::android::elapsedRealtimeNano() / NS_PER_SEC;
-}
-
-int64_t getElapsedRealtimeMillis() {
-    return ::android::elapsedRealtime();
-}
-
-int64_t getSystemUptimeMillis() {
-    return ::android::uptimeMillis();
-}
-
-int64_t getWallClockNs() {
-    return time(nullptr) * NS_PER_SEC;
-}
-
-int64_t getWallClockSec() {
-    return time(nullptr);
-}
-
-int64_t getWallClockMillis() {
-    return time(nullptr) * MS_PER_SEC;
-}
-
-int64_t truncateTimestampIfNecessary(const LogEvent& event) {
-    if (event.shouldTruncateTimestamp() ||
-        (event.GetTagId() >= StatsdStats::kTimestampTruncationStartTag &&
-         event.GetTagId() <= StatsdStats::kTimestampTruncationEndTag)) {
-        return event.GetElapsedTimestampNs() / NS_PER_SEC / (5 * 60) * NS_PER_SEC * (5 * 60);
-    } else {
-        return event.GetElapsedTimestampNs();
-    }
-}
-
-int64_t NanoToMillis(const int64_t nano) {
-    return nano / 1000000;
-}
-
-int64_t MillisToNano(const int64_t millis) {
-    return millis * 1000000;
-}
-
-bool checkPermissionForIds(const char* permission, pid_t pid, uid_t uid) {
-    shared_ptr<IStatsCompanionService> scs = getStatsCompanionService();
-    if (scs == nullptr) {
-        return false;
-    }
-
-    bool success;
-    ::ndk::ScopedAStatus status = scs->checkPermission(string(permission), pid, uid, &success);
-    if (!status.isOk()) {
-        return false;
-    }
-
-    return success;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/stats_log_util.h b/cmds/statsd/src/stats_log_util.h
deleted file mode 100644
index 10e065e..0000000
--- a/cmds/statsd/src/stats_log_util.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <android/util/ProtoOutputStream.h>
-
-#include "FieldValue.h"
-#include "HashableDimensionKey.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "guardrail/StatsdStats.h"
-#include "logd/LogEvent.h"
-
-using android::util::ProtoOutputStream;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-void writeFieldValueTreeToStream(int tagId, const std::vector<FieldValue>& values,
-                                 ProtoOutputStream* protoOutput);
-void writeDimensionToProto(const HashableDimensionKey& dimension, std::set<string> *str_set,
-                           ProtoOutputStream* protoOutput);
-
-void writeDimensionLeafNodesToProto(const HashableDimensionKey& dimension,
-                                    const int dimensionLeafFieldId,
-                                    std::set<string> *str_set,
-                                    ProtoOutputStream* protoOutput);
-
-void writeDimensionPathToProto(const std::vector<Matcher>& fieldMatchers,
-                               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.
-int64_t TimeUnitToBucketSizeInMillisGuardrailed(int uid, TimeUnit unit);
-
-// Convert the TimeUnit enum to the bucket size in millis.
-int64_t TimeUnitToBucketSizeInMillis(TimeUnit unit);
-
-// Gets the elapsed timestamp in ns.
-int64_t getElapsedRealtimeNs();
-
-// Gets the elapsed timestamp in millis.
-int64_t getElapsedRealtimeMillis();
-
-// Gets the elapsed timestamp in seconds.
-int64_t getElapsedRealtimeSec();
-
-// Gets the system uptime in millis.
-int64_t getSystemUptimeMillis();
-
-// Gets the wall clock timestamp in ns.
-int64_t getWallClockNs();
-
-// Gets the wall clock timestamp in millis.
-int64_t getWallClockMillis();
-
-// Gets the wall clock timestamp in seconds.
-int64_t getWallClockSec();
-
-int64_t NanoToMillis(const int64_t nano);
-
-int64_t MillisToNano(const int64_t millis);
-
-// Helper function to write PulledAtomStats to ProtoOutputStream
-void writePullerStatsToStream(const std::pair<int, StatsdStats::PulledAtomStats>& pair,
-                              ProtoOutputStream* protoOutput);
-
-// Helper function to write AtomMetricStats to ProtoOutputStream
-void writeAtomMetricStatsToStream(const std::pair<int64_t, StatsdStats::AtomMetricStats> &pair,
-                                  ProtoOutputStream *protoOutput);
-
-template<class T>
-bool parseProtoOutputStream(ProtoOutputStream& protoOutput, T* message) {
-    std::string pbBytes;
-    sp<android::util::ProtoReader> reader = protoOutput.data();
-    while (reader->readBuffer() != NULL) {
-        size_t toRead = reader->currentToRead();
-         pbBytes.append(reinterpret_cast<const char*>(reader->readBuffer()), toRead);
-        reader->move(toRead);
-    }
-    return message->ParseFromArray(pbBytes.c_str(), pbBytes.size());
-}
-
-// Checks the truncate timestamp annotation as well as the restricted range of 300,000 - 304,999.
-// Returns the truncated timestamp to the nearest 5 minutes if needed.
-int64_t truncateTimestampIfNecessary(const LogEvent& event);
-
-// Checks permission for given pid and uid.
-bool checkPermissionForIds(const char* permission, pid_t pid, uid_t uid);
-
-inline bool isVendorPulledAtom(int atomId) {
-    return atomId >= StatsdStats::kVendorPulledAtomStartTag && atomId < StatsdStats::kMaxAtomTag;
-}
-
-inline bool isPulledAtom(int atomId) {
-    return atomId >= StatsdStats::kPullAtomStartTag && atomId < StatsdStats::kVendorAtomStartTag;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/stats_util.h b/cmds/statsd/src/stats_util.h
deleted file mode 100644
index cfc411f..0000000
--- a/cmds/statsd/src/stats_util.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "HashableDimensionKey.h"
-
-#include <unordered_map>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-const HashableDimensionKey DEFAULT_DIMENSION_KEY = HashableDimensionKey();
-const MetricDimensionKey DEFAULT_METRIC_DIMENSION_KEY = MetricDimensionKey();
-
-typedef std::map<int64_t, HashableDimensionKey> ConditionKey;
-
-typedef std::unordered_map<MetricDimensionKey, int64_t> DimToValMap;
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/statscompanion_util.cpp b/cmds/statsd/src/statscompanion_util.cpp
deleted file mode 100644
index ce07ec0..0000000
--- a/cmds/statsd/src/statscompanion_util.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "statscompanion_util.h"
-#include <android/binder_auto_utils.h>
-#include <android/binder_manager.h>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-shared_ptr<IStatsCompanionService> getStatsCompanionService() {
-    ::ndk::SpAIBinder binder(AServiceManager_getService("statscompanion"));
-    return IStatsCompanionService::fromBinder(binder);
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/statscompanion_util.h b/cmds/statsd/src/statscompanion_util.h
deleted file mode 100644
index e20c40b..0000000
--- a/cmds/statsd/src/statscompanion_util.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <aidl/android/os/IStatsCompanionService.h>
-
-using aidl::android::os::IStatsCompanionService;
-using std::shared_ptr;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/** Fetches and returns the StatsCompanionService. */
-shared_ptr<IStatsCompanionService> getStatsCompanionService();
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
deleted file mode 100644
index acdffd3..0000000
--- a/cmds/statsd/src/statsd_config.proto
+++ /dev/null
@@ -1,511 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package android.os.statsd;
-
-option java_package = "com.android.internal.os";
-option java_outer_classname = "StatsdConfigProto";
-
-enum Position {
-  POSITION_UNKNOWN = 0;
-
-  FIRST = 1;
-
-  LAST = 2;
-
-  ANY = 3;
-
-  ALL = 4;
-}
-
-enum TimeUnit {
-  TIME_UNIT_UNSPECIFIED = 0;
-  ONE_MINUTE = 1;  // WILL BE GUARDRAILED TO 5 MINS UNLESS UID = SHELL OR ROOT
-  FIVE_MINUTES = 2;
-  TEN_MINUTES = 3;
-  THIRTY_MINUTES = 4;
-  ONE_HOUR = 5;
-  THREE_HOURS = 6;
-  SIX_HOURS = 7;
-  TWELVE_HOURS = 8;
-  ONE_DAY = 9;
-  ONE_WEEK = 10;
-  CTS = 1000;
-}
-
-message FieldMatcher {
-  optional int32 field = 1;
-
-  optional Position position = 2;
-
-  repeated FieldMatcher child = 3;
-}
-
-message FieldValueMatcher {
-  optional int32 field = 1;
-
-  optional Position position = 2;
-
-  oneof value_matcher {
-    bool eq_bool = 3;
-    string eq_string = 4;
-    int64 eq_int = 5;
-
-    int64 lt_int = 6;
-    int64 gt_int = 7;
-    float lt_float = 8;
-    float gt_float = 9;
-
-    int64 lte_int = 10;
-    int64 gte_int = 11;
-
-    MessageMatcher matches_tuple = 12;
-
-    StringListMatcher eq_any_string = 13;
-    StringListMatcher neq_any_string = 14;
-  }
-}
-
-message MessageMatcher {
-  repeated FieldValueMatcher field_value_matcher = 1;
-}
-
-message StringListMatcher {
-    repeated string str_value = 1;
-}
-
-enum LogicalOperation {
-  LOGICAL_OPERATION_UNSPECIFIED = 0;
-  AND = 1;
-  OR = 2;
-  NOT = 3;
-  NAND = 4;
-  NOR = 5;
-}
-
-message SimpleAtomMatcher {
-  optional int32 atom_id = 1;
-
-  repeated FieldValueMatcher field_value_matcher = 2;
-}
-
-message AtomMatcher {
-  optional int64 id = 1;
-
-  message Combination {
-    optional LogicalOperation operation = 1;
-
-    repeated int64 matcher = 2;
-  }
-  oneof contents {
-    SimpleAtomMatcher simple_atom_matcher = 2;
-    Combination combination = 3;
-  }
-}
-
-message SimplePredicate {
-  optional int64 start = 1;
-
-  optional int64 stop = 2;
-
-  optional bool count_nesting = 3 [default = true];
-
-  optional int64 stop_all = 4;
-
-  enum InitialValue {
-    UNKNOWN = 0;
-    FALSE = 1;
-  }
-  optional InitialValue initial_value = 5 [default = UNKNOWN];
-
-  optional FieldMatcher dimensions = 6;
-}
-
-message Predicate {
-  optional int64 id = 1;
-
-  message Combination {
-    optional LogicalOperation operation = 1;
-
-    repeated int64 predicate = 2;
-  }
-
-  oneof contents {
-    SimplePredicate simple_predicate = 2;
-    Combination combination = 3;
-  }
-}
-
-message StateMap {
-  message StateGroup {
-    optional int64 group_id = 1;
-
-    repeated int32 value = 2;
-  }
-
-  repeated StateGroup group = 1;
-}
-
-message State {
-  optional int64 id = 1;
-
-  optional int32 atom_id = 2;
-
-  optional StateMap map = 3;
-}
-
-message MetricConditionLink {
-  optional int64 condition = 1;
-
-  optional FieldMatcher fields_in_what = 2;
-
-  optional FieldMatcher fields_in_condition = 3;
-}
-
-message MetricStateLink {
-  optional int32 state_atom_id = 1;
-
-  optional FieldMatcher fields_in_what = 2;
-
-  optional FieldMatcher fields_in_state = 3;
-}
-
-message FieldFilter {
-  optional bool include_all = 1 [default = false];
-  optional FieldMatcher fields = 2;
-}
-
-message EventMetric {
-  optional int64 id = 1;
-
-  optional int64 what = 2;
-
-  optional int64 condition = 3;
-
-  repeated MetricConditionLink links = 4;
-
-  reserved 100;
-  reserved 101;
-}
-
-message CountMetric {
-  optional int64 id = 1;
-
-  optional int64 what = 2;
-
-  optional int64 condition = 3;
-
-  optional FieldMatcher dimensions_in_what = 4;
-
-  repeated int64 slice_by_state = 8;
-
-  optional TimeUnit bucket = 5;
-
-  repeated MetricConditionLink links = 6;
-
-  repeated MetricStateLink state_link = 9;
-
-  optional FieldMatcher dimensions_in_condition = 7 [deprecated = true];
-
-  reserved 100;
-  reserved 101;
-}
-
-message DurationMetric {
-  optional int64 id = 1;
-
-  optional int64 what = 2;
-
-  optional int64 condition = 3;
-
-  repeated int64 slice_by_state = 9;
-
-  repeated MetricConditionLink links = 4;
-
-  repeated MetricStateLink state_link = 10;
-
-  enum AggregationType {
-    SUM = 1;
-
-    MAX_SPARSE = 2;
-  }
-  optional AggregationType aggregation_type = 5 [default = SUM];
-
-  optional FieldMatcher dimensions_in_what = 6;
-
-  optional TimeUnit bucket = 7;
-
-  optional FieldMatcher dimensions_in_condition = 8 [deprecated = true];
-
-  reserved 100;
-  reserved 101;
-}
-
-message GaugeMetric {
-  optional int64 id = 1;
-
-  optional int64 what = 2;
-
-  optional int64 trigger_event = 12;
-
-  optional FieldFilter gauge_fields_filter = 3;
-
-  optional int64 condition = 4;
-
-  optional FieldMatcher dimensions_in_what = 5;
-
-  optional FieldMatcher dimensions_in_condition = 8 [deprecated = true];
-
-  optional TimeUnit bucket = 6;
-
-  repeated MetricConditionLink links = 7;
-
-  enum SamplingType {
-    RANDOM_ONE_SAMPLE = 1;
-    ALL_CONDITION_CHANGES = 2 [deprecated = true];
-    CONDITION_CHANGE_TO_TRUE = 3;
-    FIRST_N_SAMPLES = 4;
-  }
-  optional SamplingType sampling_type = 9 [default = RANDOM_ONE_SAMPLE] ;
-
-  optional int64 min_bucket_size_nanos = 10;
-
-  optional int64 max_num_gauge_atoms_per_bucket = 11 [default = 10];
-
-  optional int32 max_pull_delay_sec = 13 [default = 30];
-
-  optional bool split_bucket_for_app_upgrade = 14 [default = true];
-
-  reserved 100;
-  reserved 101;
-}
-
-message ValueMetric {
-  optional int64 id = 1;
-
-  optional int64 what = 2;
-
-  optional FieldMatcher value_field = 3;
-
-  optional int64 condition = 4;
-
-  optional FieldMatcher dimensions_in_what = 5;
-
-  repeated int64 slice_by_state = 18;
-
-  optional TimeUnit bucket = 6;
-
-  repeated MetricConditionLink links = 7;
-
-  repeated MetricStateLink state_link = 19;
-
-  enum AggregationType {
-    SUM = 1;
-    MIN = 2;
-    MAX = 3;
-    AVG = 4;
-  }
-  optional AggregationType aggregation_type = 8 [default = SUM];
-
-  optional int64 min_bucket_size_nanos = 10;
-
-  optional bool use_absolute_value_on_reset = 11 [default = false];
-
-  optional bool use_diff = 12;
-
-  optional bool use_zero_default_base = 15 [default = false];
-
-  enum ValueDirection {
-      UNKNOWN = 0;
-      INCREASING = 1;
-      DECREASING = 2;
-      ANY = 3;
-  }
-  optional ValueDirection value_direction = 13 [default = INCREASING];
-
-  optional bool skip_zero_diff_output = 14 [default = true];
-
-  optional int32 max_pull_delay_sec = 16 [default = 30];
-
-  optional bool split_bucket_for_app_upgrade = 17 [default = true];
-
-  optional FieldMatcher dimensions_in_condition = 9 [deprecated = true];
-
-  reserved 100;
-  reserved 101;
-}
-
-message Alert {
-  optional int64 id = 1;
-
-  optional int64 metric_id = 2;
-
-  optional int32 num_buckets = 3;
-
-  optional int32 refractory_period_secs = 4;
-
-  optional double trigger_if_sum_gt = 5;
-}
-
-message Alarm {
-  optional int64 id = 1;
-
-  optional int64 offset_millis = 2;
-
-  optional int64 period_millis = 3;
-}
-
-message IncidentdDetails {
-  repeated int32 section = 1;
-
-  enum Destination {
-    AUTOMATIC = 0;
-    EXPLICIT = 1;
-  }
-  optional Destination dest = 2;
-
-  // Package name of the incident report receiver.
-  optional string receiver_pkg = 3;
-
-  // Class name of the incident report receiver.
-  optional string receiver_cls = 4;
-
-  optional string alert_description = 5;
-}
-
-message PerfettoDetails {
-  // The |trace_config| field is a proto-encoded message of type
-  // perfetto.protos.TraceConfig defined in
-  // //external/perfetto/protos/perfetto/config/. On device,
-  // statsd doesn't need to deserialize the message as it's just
-  // passed binary-encoded to the perfetto cmdline client.
-  optional bytes trace_config = 1;
-}
-
-message BroadcastSubscriberDetails {
-  optional int64 subscriber_id = 1;
-  repeated string cookie = 2;
-}
-
-message Subscription {
-  optional int64 id = 1;
-
-  enum RuleType {
-    RULE_TYPE_UNSPECIFIED = 0;
-    ALARM = 1;
-    ALERT = 2;
-  }
-  optional RuleType rule_type = 2;
-
-  optional int64 rule_id = 3;
-
-  oneof subscriber_information {
-    IncidentdDetails incidentd_details = 4;
-    PerfettoDetails perfetto_details = 5;
-    BroadcastSubscriberDetails broadcast_subscriber_details = 6;
-  }
-
-  optional float probability_of_informing = 7 [default = 1.1];
-
-  // This was used for perfprofd historically.
-  reserved 8;
-}
-
-enum ActivationType {
-  ACTIVATION_TYPE_UNKNOWN = 0;
-  ACTIVATE_IMMEDIATELY = 1;
-  ACTIVATE_ON_BOOT = 2;
-}
-
-message EventActivation {
-  optional int64 atom_matcher_id = 1;
-  optional int64 ttl_seconds = 2;
-  optional int64 deactivation_atom_matcher_id = 3;
-  optional ActivationType activation_type = 4;
-}
-
-message MetricActivation {
-  optional int64 metric_id = 1;
-
-  optional ActivationType activation_type = 3 [deprecated = true];
-
-  repeated EventActivation event_activation = 2;
-}
-
-message PullAtomPackages {
-    optional int32 atom_id = 1;
-
-    repeated string packages = 2;
-}
-
-message StatsdConfig {
-  optional int64 id = 1;
-
-  repeated EventMetric event_metric = 2;
-
-  repeated CountMetric count_metric = 3;
-
-  repeated ValueMetric value_metric = 4;
-
-  repeated GaugeMetric gauge_metric = 5;
-
-  repeated DurationMetric duration_metric = 6;
-
-  repeated AtomMatcher atom_matcher = 7;
-
-  repeated Predicate predicate = 8;
-
-  repeated Alert alert = 9;
-
-  repeated Alarm alarm = 10;
-
-  repeated Subscription subscription = 11;
-
-  repeated string allowed_log_source = 12;
-
-  repeated int64 no_report_metric = 13;
-
-  message Annotation {
-    optional int64 field_int64 = 1;
-    optional int32 field_int32 = 2;
-  }
-  repeated Annotation annotation = 14;
-
-  optional int64 ttl_in_seconds = 15;
-
-  optional bool hash_strings_in_metric_report = 16 [default = true];
-
-  repeated MetricActivation metric_activation = 17;
-
-  optional bool version_strings_in_metric_report = 18;
-
-  optional bool installer_in_metric_report = 19;
-
-  optional bool persist_locally = 20 [default = false];
-
-  repeated State state = 21;
-
-  repeated string default_pull_packages = 22;
-
-  repeated PullAtomPackages pull_atom_packages = 23;
-
-  repeated int32 whitelisted_atom_ids = 24;
-
-  // Field number 1000 is reserved for later use.
-  reserved 1000;
-}
diff --git a/cmds/statsd/src/statsd_metadata.proto b/cmds/statsd/src/statsd_metadata.proto
deleted file mode 100644
index 200b392..0000000
--- a/cmds/statsd/src/statsd_metadata.proto
+++ /dev/null
@@ -1,67 +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.
- */
-
-syntax = "proto2";
-
-package android.os.statsd.metadata;
-
-message ConfigKey {
-  optional int64 config_id = 1;
-  optional int32 uid = 2;
-}
-
-message Field {
-  optional int32 tag = 1;
-  optional int32 field = 2;
-}
-
-message FieldValue {
-  optional Field field = 1;
-  oneof value {
-    int32 value_int = 2;
-    int64 value_long = 3;
-    float value_float = 4;
-    double value_double = 5;
-    string value_str = 6;
-    bytes value_storage = 7;
-  }
-}
-
-message MetricDimensionKey {
-  repeated FieldValue dimension_key_in_what = 1;
-  repeated FieldValue state_values_key = 2;
-}
-
-message AlertDimensionKeyedData {
-  // The earliest time the alert can be fired again in wall clock time.
-  optional int32 last_refractory_ends_sec = 1;
-  optional MetricDimensionKey dimension_key = 2;
-}
-
-message AlertMetadata {
-  optional int64 alert_id = 1;
-  repeated AlertDimensionKeyedData alert_dim_keyed_data = 2;
-}
-
-// All metadata for a config in statsd
-message StatsMetadata {
-  optional ConfigKey config_key = 1;
-  repeated AlertMetadata alert_metadata = 2;
-}
-
-message StatsMetadataList {
-  repeated StatsMetadata stats_metadata = 1;
-}
\ No newline at end of file
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
deleted file mode 100644
index dcfdfe3..0000000
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ /dev/null
@@ -1,781 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "android-base/stringprintf.h"
-#include "guardrail/StatsdStats.h"
-#include "storage/StorageManager.h"
-#include "stats_log_util.h"
-
-#include <android-base/file.h>
-#include <private/android_filesystem_config.h>
-#include <fstream>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using android::util::FIELD_COUNT_REPEATED;
-using android::util::FIELD_TYPE_MESSAGE;
-using std::map;
-
-/**
- * NOTE: these directories are protected by SELinux, any changes here must also update
- * the SELinux policies.
- */
-#define STATS_DATA_DIR "/data/misc/stats-data"
-#define STATS_SERVICE_DIR "/data/misc/stats-service"
-#define TRAIN_INFO_DIR "/data/misc/train-info"
-#define TRAIN_INFO_PATH "/data/misc/train-info/train-info.bin"
-
-// Magic word at the start of the train info file, change this if changing the file format
-const uint32_t TRAIN_INFO_FILE_MAGIC = 0xfb7447bf;
-
-// for ConfigMetricsReportList
-const int FIELD_ID_REPORTS = 2;
-
-std::mutex StorageManager::sTrainInfoMutex;
-
-using android::base::StringPrintf;
-using std::unique_ptr;
-
-struct FileName {
-    int64_t mTimestampSec;
-    int mUid;
-    int64_t mConfigId;
-    bool mIsHistory;
-    string getFullFileName(const char* path) {
-        return StringPrintf("%s/%lld_%d_%lld%s", path, (long long)mTimestampSec, (int)mUid,
-                            (long long)mConfigId, (mIsHistory ? "_history" : ""));
-    };
-};
-
-string StorageManager::getDataFileName(long wallClockSec, int uid, int64_t id) {
-    return StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR, wallClockSec, uid,
-                        (long long)id);
-}
-
-string StorageManager::getDataHistoryFileName(long wallClockSec, int uid, int64_t id) {
-    return StringPrintf("%s/%ld_%d_%lld_history", STATS_DATA_DIR, wallClockSec, uid,
-                        (long long)id);
-}
-
-static string findTrainInfoFileNameLocked(const string& trainName) {
-    unique_ptr<DIR, decltype(&closedir)> dir(opendir(TRAIN_INFO_DIR), closedir);
-    if (dir == NULL) {
-        VLOG("Path %s does not exist", TRAIN_INFO_DIR);
-        return "";
-    }
-    dirent* de;
-    while ((de = readdir(dir.get()))) {
-        char* fileName = de->d_name;
-        if (fileName[0] == '.') continue;
-
-        size_t fileNameLength = strlen(fileName);
-        if (fileNameLength >= trainName.length()) {
-            if (0 == strncmp(fileName + fileNameLength - trainName.length(), trainName.c_str(),
-                             trainName.length())) {
-              return string(fileName);
-            }
-        }
-    }
-
-    return "";
-}
-
-// Returns array of int64_t which contains timestamp in seconds, uid,
-// configID and whether the file is a local history file.
-static void parseFileName(char* name, FileName* output) {
-    int64_t result[3];
-    int index = 0;
-    char* substr = strtok(name, "_");
-    while (substr != nullptr && index < 3) {
-        result[index] = StrToInt64(substr);
-        index++;
-        substr = strtok(nullptr, "_");
-    }
-    // When index ends before hitting 3, file name is corrupted. We
-    // intentionally put -1 at index 0 to indicate the error to caller.
-    // TODO(b/110563137): consider removing files with unexpected name format.
-    if (index < 3) {
-        result[0] = -1;
-    }
-
-    output->mTimestampSec = result[0];
-    output->mUid = result[1];
-    output->mConfigId = result[2];
-    // check if the file is a local history.
-    output->mIsHistory = (substr != nullptr && strcmp("history", substr) == 0);
-}
-
-void StorageManager::writeFile(const char* file, const void* buffer, int numBytes) {
-    int fd = open(file, O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
-    if (fd == -1) {
-        VLOG("Attempt to access %s but failed", file);
-        return;
-    }
-    trimToFit(STATS_SERVICE_DIR);
-    trimToFit(STATS_DATA_DIR);
-
-    if (android::base::WriteFully(fd, buffer, numBytes)) {
-        VLOG("Successfully wrote %s", file);
-    } else {
-        ALOGE("Failed to write %s", file);
-    }
-
-    int result = fchown(fd, AID_STATSD, AID_STATSD);
-    if (result) {
-        VLOG("Failed to chown %s to statsd", file);
-    }
-
-    close(fd);
-}
-
-bool StorageManager::writeTrainInfo(const InstallTrainInfo& trainInfo) {
-    std::lock_guard<std::mutex> lock(sTrainInfoMutex);
-
-    if (trainInfo.trainName.empty()) {
-      return false;
-    }
-    deleteSuffixedFiles(TRAIN_INFO_DIR, trainInfo.trainName.c_str());
-
-    std::string fileName =
-            StringPrintf("%s/%ld_%s", TRAIN_INFO_DIR, (long) getWallClockSec(),
-                         trainInfo.trainName.c_str());
-
-    int fd = open(fileName.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
-    if (fd == -1) {
-        VLOG("Attempt to access %s but failed", fileName.c_str());
-        return false;
-    }
-
-    size_t result;
-    // Write the magic word
-    result = write(fd, &TRAIN_INFO_FILE_MAGIC, sizeof(TRAIN_INFO_FILE_MAGIC));
-    if (result != sizeof(TRAIN_INFO_FILE_MAGIC)) {
-        VLOG("Failed to wrtie train info magic");
-        close(fd);
-        return false;
-    }
-
-    // Write the train version
-    const size_t trainVersionCodeByteCount = sizeof(trainInfo.trainVersionCode);
-    result = write(fd, &trainInfo.trainVersionCode, trainVersionCodeByteCount);
-    if (result != trainVersionCodeByteCount) {
-        VLOG("Failed to wrtie train version code");
-        close(fd);
-        return false;
-    }
-
-    // Write # of bytes in trainName to file
-    const size_t trainNameSize = trainInfo.trainName.size();
-    const size_t trainNameSizeByteCount = sizeof(trainNameSize);
-    result = write(fd, (uint8_t*)&trainNameSize, trainNameSizeByteCount);
-    if (result != trainNameSizeByteCount) {
-        VLOG("Failed to write train name size");
-        close(fd);
-        return false;
-    }
-
-    // Write trainName to file
-    result = write(fd, trainInfo.trainName.c_str(), trainNameSize);
-    if (result != trainNameSize) {
-        VLOG("Failed to write train name");
-        close(fd);
-        return false;
-    }
-
-    // Write status to file
-    const size_t statusByteCount = sizeof(trainInfo.status);
-    result = write(fd, (uint8_t*)&trainInfo.status, statusByteCount);
-    if (result != statusByteCount) {
-        VLOG("Failed to write status");
-        close(fd);
-        return false;
-    }
-
-    // Write experiment id count to file.
-    const size_t experimentIdsCount = trainInfo.experimentIds.size();
-    const size_t experimentIdsCountByteCount = sizeof(experimentIdsCount);
-    result = write(fd, (uint8_t*) &experimentIdsCount, experimentIdsCountByteCount);
-    if (result != experimentIdsCountByteCount) {
-        VLOG("Failed to write experiment id count");
-        close(fd);
-        return false;
-    }
-
-    // Write experimentIds to file
-    for (size_t i = 0; i < experimentIdsCount; i++) {
-        const int64_t experimentId = trainInfo.experimentIds[i];
-        const size_t experimentIdByteCount = sizeof(experimentId);
-        result = write(fd, &experimentId, experimentIdByteCount);
-        if (result == experimentIdByteCount) {
-            VLOG("Successfully wrote experiment IDs");
-        } else {
-            VLOG("Failed to write experiment ids");
-            close(fd);
-            return false;
-        }
-    }
-
-    // Write bools to file
-    const size_t boolByteCount = sizeof(trainInfo.requiresStaging);
-    result = write(fd, (uint8_t*)&trainInfo.requiresStaging, boolByteCount);
-    if (result != boolByteCount) {
-      VLOG("Failed to write requires staging");
-      close(fd);
-      return false;
-    }
-
-    result = write(fd, (uint8_t*)&trainInfo.rollbackEnabled, boolByteCount);
-    if (result != boolByteCount) {
-      VLOG("Failed to write rollback enabled");
-      close(fd);
-      return false;
-    }
-
-    result = write(fd, (uint8_t*)&trainInfo.requiresLowLatencyMonitor, boolByteCount);
-    if (result != boolByteCount) {
-      VLOG("Failed to write requires log latency monitor");
-      close(fd);
-      return false;
-    }
-
-    close(fd);
-    return true;
-}
-
-bool StorageManager::readTrainInfo(const std::string& trainName, InstallTrainInfo& trainInfo) {
-    std::lock_guard<std::mutex> lock(sTrainInfoMutex);
-    return readTrainInfoLocked(trainName, trainInfo);
-}
-
-bool StorageManager::readTrainInfoLocked(const std::string& trainName, InstallTrainInfo& trainInfo) {
-    trimToFit(TRAIN_INFO_DIR, /*parseTimestampOnly=*/ true);
-    string fileName = findTrainInfoFileNameLocked(trainName);
-    if (fileName.empty()) {
-        return false;
-    }
-    int fd = open(StringPrintf("%s/%s", TRAIN_INFO_DIR, fileName.c_str()).c_str(), O_RDONLY | O_CLOEXEC);
-    if (fd == -1) {
-        VLOG("Failed to open %s", fileName.c_str());
-        return false;
-    }
-
-    // Read the magic word
-    uint32_t magic;
-    size_t result = read(fd, &magic, sizeof(magic));
-    if (result != sizeof(magic)) {
-        VLOG("Failed to read train info magic");
-        close(fd);
-        return false;
-    }
-
-    if (magic != TRAIN_INFO_FILE_MAGIC) {
-        VLOG("Train info magic was 0x%08x, expected 0x%08x", magic, TRAIN_INFO_FILE_MAGIC);
-        close(fd);
-        return false;
-    }
-
-    // Read the train version code
-    const size_t trainVersionCodeByteCount(sizeof(trainInfo.trainVersionCode));
-    result = read(fd, &trainInfo.trainVersionCode, trainVersionCodeByteCount);
-    if (result != trainVersionCodeByteCount) {
-        VLOG("Failed to read train version code from train info file");
-        close(fd);
-        return false;
-    }
-
-    // Read # of bytes taken by trainName in the file.
-    size_t trainNameSize;
-    result = read(fd, &trainNameSize, sizeof(size_t));
-    if (result != sizeof(size_t)) {
-        VLOG("Failed to read train name size from train info file");
-        close(fd);
-        return false;
-    }
-
-    // Read trainName
-    trainInfo.trainName.resize(trainNameSize);
-    result = read(fd, trainInfo.trainName.data(), trainNameSize);
-    if (result != trainNameSize) {
-        VLOG("Failed to read train name from train info file");
-        close(fd);
-        return false;
-    }
-
-    // Read status
-    const size_t statusByteCount = sizeof(trainInfo.status);
-    result = read(fd, &trainInfo.status, statusByteCount);
-    if (result != statusByteCount) {
-        VLOG("Failed to read train status from train info file");
-        close(fd);
-        return false;
-    }
-
-    // Read experiment ids count.
-    size_t experimentIdsCount;
-    result = read(fd, &experimentIdsCount, sizeof(size_t));
-    if (result != sizeof(size_t)) {
-        VLOG("Failed to read train experiment id count from train info file");
-        close(fd);
-        return false;
-    }
-
-    // Read experimentIds
-    for (size_t i = 0; i < experimentIdsCount; i++) {
-        int64_t experimentId;
-        result = read(fd, &experimentId, sizeof(experimentId));
-        if (result != sizeof(experimentId)) {
-            VLOG("Failed to read train experiment id from train info file");
-            close(fd);
-            return false;
-        }
-        trainInfo.experimentIds.push_back(experimentId);
-    }
-
-    // Read bools
-    const size_t boolByteCount = sizeof(trainInfo.requiresStaging);
-    result = read(fd, &trainInfo.requiresStaging, boolByteCount);
-    if (result != boolByteCount) {
-        VLOG("Failed to read requires requires staging from train info file");
-        close(fd);
-        return false;
-    }
-
-    result = read(fd, &trainInfo.rollbackEnabled, boolByteCount);
-    if (result != boolByteCount) {
-        VLOG("Failed to read requires rollback enabled from train info file");
-        close(fd);
-        return false;
-    }
-
-    result = read(fd, &trainInfo.requiresLowLatencyMonitor, boolByteCount);
-    if (result != boolByteCount) {
-        VLOG("Failed to read requires requires low latency monitor from train info file");
-        close(fd);
-        return false;
-    }
-
-    // Expect to be at EOF.
-    char c;
-    result = read(fd, &c, 1);
-    if (result != 0) {
-        VLOG("Failed to read train info from file. Did not get expected EOF.");
-        close(fd);
-        return false;
-    }
-
-    VLOG("Read train info file successful");
-    close(fd);
-    return true;
-}
-
-vector<InstallTrainInfo> StorageManager::readAllTrainInfo() {
-    std::lock_guard<std::mutex> lock(sTrainInfoMutex);
-    vector<InstallTrainInfo> trainInfoList;
-    unique_ptr<DIR, decltype(&closedir)> dir(opendir(TRAIN_INFO_DIR), closedir);
-    if (dir == NULL) {
-        VLOG("Directory does not exist: %s", TRAIN_INFO_DIR);
-        return trainInfoList;
-    }
-
-    dirent* de;
-    while ((de = readdir(dir.get()))) {
-        char* name = de->d_name;
-        if (name[0] == '.') {
-            continue;
-        }
-
-        InstallTrainInfo trainInfo;
-        bool readSuccess = StorageManager::readTrainInfoLocked(name, trainInfo);
-        if (!readSuccess) {
-            continue;
-        }
-        trainInfoList.push_back(trainInfo);
-    }
-    return trainInfoList;
-}
-
-void StorageManager::deleteFile(const char* file) {
-    if (remove(file) != 0) {
-        VLOG("Attempt to delete %s but is not found", file);
-    } else {
-        VLOG("Successfully deleted %s", file);
-    }
-}
-
-void StorageManager::deleteAllFiles(const char* path) {
-    unique_ptr<DIR, decltype(&closedir)> dir(opendir(path), closedir);
-    if (dir == NULL) {
-        VLOG("Directory does not exist: %s", path);
-        return;
-    }
-
-    dirent* de;
-    while ((de = readdir(dir.get()))) {
-        char* name = de->d_name;
-        if (name[0] == '.') continue;
-        deleteFile(StringPrintf("%s/%s", path, name).c_str());
-    }
-}
-
-void StorageManager::deleteSuffixedFiles(const char* path, const char* suffix) {
-    unique_ptr<DIR, decltype(&closedir)> dir(opendir(path), closedir);
-    if (dir == NULL) {
-        VLOG("Directory does not exist: %s", path);
-        return;
-    }
-
-    dirent* de;
-    while ((de = readdir(dir.get()))) {
-        char* name = de->d_name;
-        if (name[0] == '.') {
-            continue;
-        }
-        size_t nameLen = strlen(name);
-        size_t suffixLen = strlen(suffix);
-        if (suffixLen <= nameLen && strncmp(name + nameLen - suffixLen, suffix, suffixLen) == 0) {
-            deleteFile(StringPrintf("%s/%s", path, name).c_str());
-        }
-    }
-}
-
-void StorageManager::sendBroadcast(const char* path,
-                                   const std::function<void(const ConfigKey&)>& sendBroadcast) {
-    unique_ptr<DIR, decltype(&closedir)> dir(opendir(path), closedir);
-    if (dir == NULL) {
-        VLOG("no stats-data directory on disk");
-        return;
-    }
-
-    dirent* de;
-    while ((de = readdir(dir.get()))) {
-        char* name = de->d_name;
-        if (name[0] == '.') continue;
-        VLOG("file %s", name);
-
-        FileName output;
-        parseFileName(name, &output);
-        if (output.mTimestampSec == -1 || output.mIsHistory) continue;
-        sendBroadcast(ConfigKey((int)output.mUid, output.mConfigId));
-    }
-}
-
-bool StorageManager::hasConfigMetricsReport(const ConfigKey& key) {
-    unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_DATA_DIR), closedir);
-    if (dir == NULL) {
-        VLOG("Path %s does not exist", STATS_DATA_DIR);
-        return false;
-    }
-
-    string suffix = StringPrintf("%d_%lld", key.GetUid(), (long long)key.GetId());
-
-    dirent* de;
-    while ((de = readdir(dir.get()))) {
-        char* name = de->d_name;
-        if (name[0] == '.') continue;
-
-        size_t nameLen = strlen(name);
-        size_t suffixLen = suffix.length();
-        if (suffixLen <= nameLen &&
-            strncmp(name + nameLen - suffixLen, suffix.c_str(), suffixLen) == 0) {
-            // Check again that the file name is parseable.
-            FileName output;
-            parseFileName(name, &output);
-            if (output.mTimestampSec == -1 || output.mIsHistory) continue;
-            return true;
-        }
-    }
-    return false;
-}
-
-void StorageManager::appendConfigMetricsReport(const ConfigKey& key, ProtoOutputStream* proto,
-                                               bool erase_data, bool isAdb) {
-    unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_DATA_DIR), closedir);
-    if (dir == NULL) {
-        VLOG("Path %s does not exist", STATS_DATA_DIR);
-        return;
-    }
-
-    dirent* de;
-    while ((de = readdir(dir.get()))) {
-        char* name = de->d_name;
-        string fileName(name);
-        if (name[0] == '.') continue;
-        FileName output;
-        parseFileName(name, &output);
-
-        if (output.mTimestampSec == -1 || (output.mIsHistory && !isAdb) ||
-            output.mUid != key.GetUid() || output.mConfigId != key.GetId()) {
-            continue;
-        }
-
-        auto fullPathName = StringPrintf("%s/%s", STATS_DATA_DIR, fileName.c_str());
-        int fd = open(fullPathName.c_str(), O_RDONLY | O_CLOEXEC);
-        if (fd != -1) {
-            string content;
-            if (android::base::ReadFdToString(fd, &content)) {
-                proto->write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS,
-                             content.c_str(), content.size());
-            }
-            close(fd);
-        } else {
-            ALOGE("file cannot be opened");
-        }
-
-        if (erase_data) {
-            remove(fullPathName.c_str());
-        } else if (!output.mIsHistory && !isAdb) {
-            // This means a real data owner has called to get this data. But the config says it
-            // wants to keep a local history. So now this file must be renamed as a history file.
-            // So that next time, when owner calls getData() again, this data won't be uploaded
-            // again. rename returns 0 on success
-            if (rename(fullPathName.c_str(), (fullPathName + "_history").c_str())) {
-                ALOGE("Failed to rename file %s", fullPathName.c_str());
-            }
-        }
-    }
-}
-
-bool StorageManager::readFileToString(const char* file, string* content) {
-    int fd = open(file, O_RDONLY | O_CLOEXEC);
-    bool res = false;
-    if (fd != -1) {
-        if (android::base::ReadFdToString(fd, content)) {
-            res = true;
-        } else {
-            VLOG("Failed to read file %s\n", file);
-        }
-        close(fd);
-    }
-    return res;
-}
-
-void StorageManager::readConfigFromDisk(map<ConfigKey, StatsdConfig>& configsMap) {
-    unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_SERVICE_DIR), closedir);
-    if (dir == NULL) {
-        VLOG("no default config on disk");
-        return;
-    }
-    trimToFit(STATS_SERVICE_DIR);
-
-    dirent* de;
-    while ((de = readdir(dir.get()))) {
-        char* name = de->d_name;
-        if (name[0] == '.') continue;
-
-        FileName output;
-        parseFileName(name, &output);
-        if (output.mTimestampSec == -1) continue;
-        string file_name = output.getFullFileName(STATS_SERVICE_DIR);
-        int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC);
-        if (fd != -1) {
-            string content;
-            if (android::base::ReadFdToString(fd, &content)) {
-                StatsdConfig config;
-                if (config.ParseFromString(content)) {
-                    configsMap[ConfigKey(output.mUid, output.mConfigId)] = config;
-                    VLOG("map key uid=%lld|configID=%lld", (long long)output.mUid,
-                         (long long)output.mConfigId);
-                }
-            }
-            close(fd);
-        }
-    }
-}
-
-bool StorageManager::readConfigFromDisk(const ConfigKey& key, StatsdConfig* config) {
-    string content;
-    return config != nullptr &&
-        StorageManager::readConfigFromDisk(key, &content) && config->ParseFromString(content);
-}
-
-bool StorageManager::readConfigFromDisk(const ConfigKey& key, string* content) {
-    unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_SERVICE_DIR),
-                                             closedir);
-    if (dir == NULL) {
-        VLOG("Directory does not exist: %s", STATS_SERVICE_DIR);
-        return false;
-    }
-
-    string suffix = StringPrintf("%d_%lld", key.GetUid(), (long long)key.GetId());
-    dirent* de;
-    while ((de = readdir(dir.get()))) {
-        char* name = de->d_name;
-        if (name[0] == '.') {
-            continue;
-        }
-        size_t nameLen = strlen(name);
-        size_t suffixLen = suffix.length();
-        // There can be at most one file that matches this suffix (config key).
-        if (suffixLen <= nameLen &&
-            strncmp(name + nameLen - suffixLen, suffix.c_str(), suffixLen) == 0) {
-            int fd = open(StringPrintf("%s/%s", STATS_SERVICE_DIR, name).c_str(),
-                                  O_RDONLY | O_CLOEXEC);
-            if (fd != -1) {
-                if (android::base::ReadFdToString(fd, content)) {
-                    return true;
-                }
-                close(fd);
-            }
-        }
-    }
-    return false;
-}
-
-bool StorageManager::hasIdenticalConfig(const ConfigKey& key,
-                                        const vector<uint8_t>& config) {
-    string content;
-    if (StorageManager::readConfigFromDisk(key, &content)) {
-        vector<uint8_t> vec(content.begin(), content.end());
-        if (vec == config) {
-            return true;
-        }
-    }
-    return false;
-}
-
-void StorageManager::sortFiles(vector<FileInfo>* fileNames) {
-    // Reverse sort to effectively remove from the back (oldest entries).
-    // This will sort files in reverse-chronological order. Local history files have lower
-    // priority than regular data files.
-    sort(fileNames->begin(), fileNames->end(), [](FileInfo& lhs, FileInfo& rhs) {
-        // first consider if the file is a local history
-        if (lhs.mIsHistory && !rhs.mIsHistory) {
-            return false;
-        } else if (rhs.mIsHistory && !lhs.mIsHistory) {
-            return true;
-        }
-
-        // then consider the age.
-        if (lhs.mFileAgeSec < rhs.mFileAgeSec) {
-            return true;
-        } else if (lhs.mFileAgeSec > rhs.mFileAgeSec) {
-            return false;
-        }
-
-        // then good luck.... use string::compare
-        return lhs.mFileName.compare(rhs.mFileName) > 0;
-    });
-}
-
-void StorageManager::trimToFit(const char* path, bool parseTimestampOnly) {
-    unique_ptr<DIR, decltype(&closedir)> dir(opendir(path), closedir);
-    if (dir == NULL) {
-        VLOG("Path %s does not exist", path);
-        return;
-    }
-    dirent* de;
-    int totalFileSize = 0;
-    vector<FileInfo> fileNames;
-    auto nowSec = getWallClockSec();
-    while ((de = readdir(dir.get()))) {
-        char* name = de->d_name;
-        if (name[0] == '.') continue;
-
-        FileName output;
-        string file_name;
-        if (parseTimestampOnly) {
-            file_name = StringPrintf("%s/%s", path, name);
-            output.mTimestampSec = StrToInt64(strtok(name, "_"));
-            output.mIsHistory = false;
-        } else {
-            parseFileName(name, &output);
-            file_name = output.getFullFileName(path);
-        }
-        if (output.mTimestampSec == -1) continue;
-
-        // Check for timestamp and delete if it's too old.
-        long fileAge = nowSec - output.mTimestampSec;
-        if (fileAge > StatsdStats::kMaxAgeSecond ||
-            (output.mIsHistory && fileAge > StatsdStats::kMaxLocalHistoryAgeSecond)) {
-            deleteFile(file_name.c_str());
-            continue;
-        }
-
-        ifstream file(file_name.c_str(), ifstream::in | ifstream::binary);
-        int fileSize = 0;
-        if (file.is_open()) {
-            file.seekg(0, ios::end);
-            fileSize = file.tellg();
-            file.close();
-            totalFileSize += fileSize;
-        }
-        fileNames.emplace_back(file_name, output.mIsHistory, fileSize, fileAge);
-    }
-
-    if (fileNames.size() > StatsdStats::kMaxFileNumber ||
-        totalFileSize > StatsdStats::kMaxFileSize) {
-        sortFiles(&fileNames);
-    }
-
-    // Start removing files from oldest to be under the limit.
-    while (fileNames.size() > 0 && (fileNames.size() > StatsdStats::kMaxFileNumber ||
-                                    totalFileSize > StatsdStats::kMaxFileSize)) {
-        totalFileSize -= fileNames.at(fileNames.size() - 1).mFileSizeBytes;
-        deleteFile(fileNames.at(fileNames.size() - 1).mFileName.c_str());
-        fileNames.pop_back();
-    }
-}
-
-void StorageManager::printStats(int outFd) {
-    printDirStats(outFd, STATS_SERVICE_DIR);
-    printDirStats(outFd, STATS_DATA_DIR);
-}
-
-void StorageManager::printDirStats(int outFd, const char* path) {
-    dprintf(outFd, "Printing stats of %s\n", path);
-    unique_ptr<DIR, decltype(&closedir)> dir(opendir(path), closedir);
-    if (dir == NULL) {
-        VLOG("Path %s does not exist", path);
-        return;
-    }
-    dirent* de;
-    int fileCount = 0;
-    int totalFileSize = 0;
-    while ((de = readdir(dir.get()))) {
-        char* name = de->d_name;
-        if (name[0] == '.') {
-            continue;
-        }
-        FileName output;
-        parseFileName(name, &output);
-        if (output.mTimestampSec == -1) continue;
-        dprintf(outFd, "\t #%d, Last updated: %lld, UID: %d, Config ID: %lld, %s", fileCount + 1,
-                (long long)output.mTimestampSec, output.mUid, (long long)output.mConfigId,
-                (output.mIsHistory ? "local history" : ""));
-        string file_name = output.getFullFileName(path);
-        ifstream file(file_name.c_str(), ifstream::in | ifstream::binary);
-        if (file.is_open()) {
-            file.seekg(0, ios::end);
-            int fileSize = file.tellg();
-            file.close();
-            dprintf(outFd, ", File Size: %d bytes", fileSize);
-            totalFileSize += fileSize;
-        }
-        dprintf(outFd, "\n");
-        fileCount++;
-    }
-    dprintf(outFd, "\tTotal number of files: %d, Total size of files: %d bytes.\n", fileCount,
-            totalFileSize);
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/storage/StorageManager.h b/cmds/statsd/src/storage/StorageManager.h
deleted file mode 100644
index d59046d..0000000
--- a/cmds/statsd/src/storage/StorageManager.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef STORAGE_MANAGER_H
-#define STORAGE_MANAGER_H
-
-#include <android/util/ProtoOutputStream.h>
-#include <utils/Log.h>
-#include <utils/RefBase.h>
-
-#include "packages/UidMap.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using android::util::ProtoOutputStream;
-
-class StorageManager : public virtual RefBase {
-public:
-    struct FileInfo {
-        FileInfo(std::string name, bool isHistory, int fileSize, long fileAge)
-            : mFileName(name),
-              mIsHistory(isHistory),
-              mFileSizeBytes(fileSize),
-              mFileAgeSec(fileAge) {
-        }
-        std::string mFileName;
-        bool mIsHistory;
-        int mFileSizeBytes;
-        long mFileAgeSec;
-    };
-
-    /**
-     * Writes a given byte array as a file to the specified file path.
-     */
-    static void writeFile(const char* file, const void* buffer, int numBytes);
-
-    /**
-     * Writes train info.
-     */
-    static bool writeTrainInfo(const InstallTrainInfo& trainInfo);
-
-    /**
-     * Reads train info.
-     */
-    static bool readTrainInfo(const std::string& trainName, InstallTrainInfo& trainInfo);
-
-    /**
-     * Reads train info assuming lock is obtained.
-     */
-    static bool readTrainInfoLocked(const std::string& trainName, InstallTrainInfo& trainInfo);
-
-    /**
-     * Reads all train info and returns a vector of train info.
-     */
-    static vector<InstallTrainInfo> readAllTrainInfo();
-
-    /**
-     * Reads the file content to the buffer.
-     */
-    static bool readFileToString(const char* file, string* content);
-
-    /**
-     * Deletes a single file given a file name.
-     */
-    static void deleteFile(const char* file);
-
-    /**
-     * Deletes all files in a given directory.
-     */
-    static void deleteAllFiles(const char* path);
-
-    /**
-     * Deletes all files whose name matches with a provided suffix.
-     */
-    static void deleteSuffixedFiles(const char* path, const char* suffix);
-
-    /**
-     * Send broadcasts to relevant receiver for each data stored on disk.
-     */
-    static void sendBroadcast(const char* path,
-                              const std::function<void(const ConfigKey&)>& sendBroadcast);
-
-    /**
-     * Returns true if there's at least one report on disk.
-     */
-    static bool hasConfigMetricsReport(const ConfigKey& key);
-
-    /**
-     * Appends the ConfigMetricsReport found on disk to the specifid proto
-     * and, if erase_data, deletes it from disk.
-     *
-     * [isAdb]: if the caller is adb dump. This includes local adb dump or dumpsys by
-     * bugreport or incidentd. When true, we will append any local history data too.
-     *
-     * When
-     * erase_data=true, isAdb=true:   append history data to output, remove all data after read
-     * erase_data=false, isAdb=true:  append history data to output, keep data after read
-     * erase_data=true, isAdb=false:  do not append history data, and remove data after read
-     * erase_data=false, isAdb=false: do not append history data and *rename* all data files to
-     *                                history files.
-     */
-    static void appendConfigMetricsReport(const ConfigKey& key, ProtoOutputStream* proto,
-                                          bool erase_data, bool isAdb);
-
-    /**
-     * Call to load the saved configs from disk.
-     */
-    static void readConfigFromDisk(std::map<ConfigKey, StatsdConfig>& configsMap);
-
-    /**
-     * Call to load the specified config from disk. Returns false if the config file does not
-     * exist or error occurs when reading the file.
-     */
-    static bool readConfigFromDisk(const ConfigKey& key, StatsdConfig* config);
-    static bool readConfigFromDisk(const ConfigKey& key, string* config);
-
-    /**
-     * Trims files in the provided directory to limit the total size, number of
-     * files, accumulation of outdated files.
-     */
-    static void trimToFit(const char* dir, bool parseTimestampOnly = false);
-
-    /**
-     * Returns true if there already exists identical configuration on device.
-     */
-    static bool hasIdenticalConfig(const ConfigKey& key,
-                                   const vector<uint8_t>& config);
-
-    /**
-     * Prints disk usage statistics related to statsd.
-     */
-    static void printStats(int out);
-
-    static string getDataFileName(long wallClockSec, int uid, int64_t id);
-
-    static string getDataHistoryFileName(long wallClockSec, int uid, int64_t id);
-
-    static void sortFiles(vector<FileInfo>* fileNames);
-
-private:
-    /**
-     * Prints disk usage statistics about a directory related to statsd.
-     */
-    static void printDirStats(int out, const char* path);
-
-    static std::mutex sTrainInfoMutex;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-#endif  // STORAGE_MANAGER_H
diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.cpp b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
deleted file mode 100644
index 1d77513..0000000
--- a/cmds/statsd/src/subscriber/IncidentdReporter.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define DEBUG false
-#include "Log.h"
-
-#include "FieldValue.h"
-#include "IncidentdReporter.h"
-#include "packages/UidMap.h"
-#include "stats_log_util.h"
-
-#include <android/util/ProtoOutputStream.h>
-#include <incident/incident_report.h>
-
-#include <vector>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using android::util::ProtoOutputStream;
-using std::vector;
-
-using util::FIELD_TYPE_INT32;
-using util::FIELD_TYPE_INT64;
-using util::FIELD_TYPE_MESSAGE;
-using util::FIELD_TYPE_STRING;
-
-// field ids in IncidentHeaderProto
-const int FIELD_ID_ALERT_ID = 1;
-const int FIELD_ID_REASON = 2;
-const int FIELD_ID_CONFIG_KEY = 3;
-const int FIELD_ID_CONFIG_KEY_UID = 1;
-const int FIELD_ID_CONFIG_KEY_ID = 2;
-
-const int FIELD_ID_TRIGGER_DETAILS = 4;
-const int FIELD_ID_TRIGGER_DETAILS_TRIGGER_METRIC = 1;
-const int FIELD_ID_METRIC_VALUE_METRIC_ID = 1;
-const int FIELD_ID_METRIC_VALUE_DIMENSION_IN_WHAT = 2;
-const int FIELD_ID_METRIC_VALUE_VALUE = 4;
-
-const int FIELD_ID_PACKAGE_INFO = 3;
-
-namespace {
-void getProtoData(const int64_t& rule_id, int64_t metricId, const MetricDimensionKey& dimensionKey,
-                  int64_t metricValue, const ConfigKey& configKey, const string& reason,
-                  vector<uint8_t>* protoData) {
-    ProtoOutputStream headerProto;
-    headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_ALERT_ID, (long long)rule_id);
-    headerProto.write(FIELD_TYPE_STRING | FIELD_ID_REASON, reason);
-    uint64_t token =
-            headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_CONFIG_KEY);
-    headerProto.write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_KEY_UID, configKey.GetUid());
-    headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_CONFIG_KEY_ID, (long long)configKey.GetId());
-    headerProto.end(token);
-
-    token = headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_TRIGGER_DETAILS);
-
-    // MetricValue trigger_metric = 1;
-    uint64_t metricToken =
-            headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_TRIGGER_DETAILS_TRIGGER_METRIC);
-    // message MetricValue {
-    // optional int64 metric_id = 1;
-    headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_VALUE_METRIC_ID, (long long)metricId);
-    // optional DimensionsValue dimension_in_what = 2;
-    uint64_t dimToken =
-            headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_METRIC_VALUE_DIMENSION_IN_WHAT);
-    writeDimensionToProto(dimensionKey.getDimensionKeyInWhat(), nullptr, &headerProto);
-    headerProto.end(dimToken);
-
-    // deprecated field
-    // optional DimensionsValue dimension_in_condition = 3;
-
-    // optional int64 value = 4;
-    headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_VALUE_VALUE, (long long)metricValue);
-
-    // }
-    headerProto.end(metricToken);
-
-    // write relevant uid package info
-    std::set<int32_t> uids;
-
-    for (const auto& dim : dimensionKey.getDimensionKeyInWhat().getValues()) {
-        int uid = getUidIfExists(dim);
-        // any uid <= 2000 are predefined AID_*
-        if (uid > 2000) {
-            uids.insert(uid);
-        }
-    }
-
-    if (!uids.empty()) {
-        uint64_t token = headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_PACKAGE_INFO);
-        UidMap::getInstance()->writeUidMapSnapshot(getElapsedRealtimeNs(), true, true, uids,
-                                                   nullptr /*string set*/, &headerProto);
-        headerProto.end(token);
-    }
-
-    headerProto.end(token);
-
-    protoData->resize(headerProto.size());
-    size_t pos = 0;
-    sp<android::util::ProtoReader> reader = headerProto.data();
-    while (reader->readBuffer() != NULL) {
-        size_t toRead = reader->currentToRead();
-        std::memcpy(&((*protoData)[pos]), reader->readBuffer(), toRead);
-        pos += toRead;
-        reader->move(toRead);
-    }
-}
-}  // namespace
-
-bool GenerateIncidentReport(const IncidentdDetails& config, int64_t rule_id, int64_t metricId,
-                            const MetricDimensionKey& dimensionKey, int64_t metricValue,
-                            const ConfigKey& configKey) {
-    if (config.section_size() == 0) {
-        VLOG("The alert %lld contains zero section in config(%d,%lld)", (unsigned long long)rule_id,
-             configKey.GetUid(), (long long)configKey.GetId());
-        return false;
-    }
-
-    AIncidentReportArgs* args = AIncidentReportArgs_init();
-
-    vector<uint8_t> protoData;
-    getProtoData(rule_id, metricId, dimensionKey, metricValue, configKey,
-                 config.alert_description(), &protoData);
-    AIncidentReportArgs_addHeader(args, protoData.data(), protoData.size());
-
-    for (int i = 0; i < config.section_size(); i++) {
-        AIncidentReportArgs_addSection(args, config.section(i));
-    }
-
-    uint8_t dest;
-    switch (config.dest()) {
-        case IncidentdDetails_Destination_AUTOMATIC:
-            dest = INCIDENT_REPORT_PRIVACY_POLICY_AUTOMATIC;
-            break;
-        case IncidentdDetails_Destination_EXPLICIT:
-            dest = INCIDENT_REPORT_PRIVACY_POLICY_EXPLICIT;
-            break;
-        default:
-            dest = INCIDENT_REPORT_PRIVACY_POLICY_AUTOMATIC;
-    }
-    AIncidentReportArgs_setPrivacyPolicy(args, dest);
-
-    AIncidentReportArgs_setReceiverPackage(args, config.receiver_pkg().c_str());
-
-    AIncidentReportArgs_setReceiverClass(args, config.receiver_cls().c_str());
-
-    int err = AIncidentReportArgs_takeReport(args);
-    AIncidentReportArgs_delete(args);
-
-    return err == NO_ERROR;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.h b/cmds/statsd/src/subscriber/IncidentdReporter.h
deleted file mode 100644
index e78a4d9..0000000
--- a/cmds/statsd/src/subscriber/IncidentdReporter.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "HashableDimensionKey.h"
-#include "config/ConfigKey.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"  // Alert, IncidentdDetails
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/**
- * Calls incidentd to trigger an incident report and put in dropbox for uploading.
- */
-bool GenerateIncidentReport(const IncidentdDetails& config, int64_t rule_id, int64_t metricId,
-                            const MetricDimensionKey& dimensionKey, int64_t metricValue,
-                            const ConfigKey& configKey);
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.cpp b/cmds/statsd/src/subscriber/SubscriberReporter.cpp
deleted file mode 100644
index c915ef3..0000000
--- a/cmds/statsd/src/subscriber/SubscriberReporter.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false  // STOPSHIP if true
-#include "Log.h"
-
-#include "SubscriberReporter.h"
-
-using std::lock_guard;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using std::vector;
-
-struct BroadcastSubscriberDeathCookie {
-    BroadcastSubscriberDeathCookie(const ConfigKey& configKey, int64_t subscriberId,
-                                   const shared_ptr<IPendingIntentRef>& pir):
-        mConfigKey(configKey),
-        mSubscriberId(subscriberId),
-        mPir(pir) {}
-
-    ConfigKey mConfigKey;
-    int64_t mSubscriberId;
-    shared_ptr<IPendingIntentRef> mPir;
-};
-
-void SubscriberReporter::broadcastSubscriberDied(void* cookie) {
-    auto cookie_ = static_cast<BroadcastSubscriberDeathCookie*>(cookie);
-    ConfigKey& configKey = cookie_->mConfigKey;
-    int64_t subscriberId = cookie_->mSubscriberId;
-    shared_ptr<IPendingIntentRef>& pir = cookie_->mPir;
-
-    SubscriberReporter& thiz = getInstance();
-
-    // Erase the mapping from a (config_key, subscriberId) to a pir if the
-    // mapping exists.
-    lock_guard<mutex> lock(thiz.mLock);
-    auto subscriberMapIt = thiz.mIntentMap.find(configKey);
-    if (subscriberMapIt != thiz.mIntentMap.end()) {
-        auto subscriberMap = subscriberMapIt->second;
-        auto pirIt = subscriberMap.find(subscriberId);
-        if (pirIt != subscriberMap.end() && pirIt->second == pir) {
-            subscriberMap.erase(subscriberId);
-            if (subscriberMap.empty()) {
-                thiz.mIntentMap.erase(configKey);
-            }
-        }
-    }
-
-    // The death recipient corresponding to this specific pir can never be
-    // triggered again, so free up resources.
-    delete cookie_;
-}
-
-SubscriberReporter::SubscriberReporter() :
-    mBroadcastSubscriberDeathRecipient(AIBinder_DeathRecipient_new(broadcastSubscriberDied)) {
-}
-
-void SubscriberReporter::setBroadcastSubscriber(const ConfigKey& configKey,
-                                                int64_t subscriberId,
-                                                const shared_ptr<IPendingIntentRef>& pir) {
-    VLOG("SubscriberReporter::setBroadcastSubscriber called.");
-    {
-        lock_guard<mutex> lock(mLock);
-        mIntentMap[configKey][subscriberId] = pir;
-    }
-    AIBinder_linkToDeath(pir->asBinder().get(), mBroadcastSubscriberDeathRecipient.get(),
-                         new BroadcastSubscriberDeathCookie(configKey, subscriberId, pir));
-}
-
-void SubscriberReporter::unsetBroadcastSubscriber(const ConfigKey& configKey,
-                                                  int64_t subscriberId) {
-    VLOG("SubscriberReporter::unsetBroadcastSubscriber called.");
-    lock_guard<mutex> lock(mLock);
-    auto subscriberMapIt = mIntentMap.find(configKey);
-    if (subscriberMapIt != mIntentMap.end()) {
-        subscriberMapIt->second.erase(subscriberId);
-        if (subscriberMapIt->second.empty()) {
-            mIntentMap.erase(configKey);
-        }
-    }
-}
-
-void SubscriberReporter::alertBroadcastSubscriber(const ConfigKey& configKey,
-                                                  const Subscription& subscription,
-                                                  const MetricDimensionKey& dimKey) const {
-    // Reminder about ids:
-    //  subscription id - name of the Subscription (that ties the Alert to the broadcast)
-    //  subscription rule_id - the name of the Alert (that triggers the broadcast)
-    //  subscriber_id - name of the PendingIntent to use to send the broadcast
-    //  config uid - the uid that uploaded the config (and therefore gave the PendingIntent,
-    //                 although the intent may be to broadcast to a different uid)
-    //  config id - the name of this config (for this particular uid)
-
-    VLOG("SubscriberReporter::alertBroadcastSubscriber called.");
-    lock_guard<mutex> lock(mLock);
-
-    if (!subscription.has_broadcast_subscriber_details()
-            || !subscription.broadcast_subscriber_details().has_subscriber_id()) {
-        ALOGE("Broadcast subscriber does not have an id.");
-        return;
-    }
-    int64_t subscriberId = subscription.broadcast_subscriber_details().subscriber_id();
-
-    vector<string> cookies;
-    cookies.reserve(subscription.broadcast_subscriber_details().cookie_size());
-    for (auto& cookie : subscription.broadcast_subscriber_details().cookie()) {
-        cookies.push_back(cookie);
-    }
-
-    auto it1 = mIntentMap.find(configKey);
-    if (it1 == mIntentMap.end()) {
-        ALOGW("Cannot inform subscriber for missing config key %s ", configKey.ToString().c_str());
-        return;
-    }
-    auto it2 = it1->second.find(subscriberId);
-    if (it2 == it1->second.end()) {
-        ALOGW("Cannot inform subscriber of config %s for missing subscriberId %lld ",
-                configKey.ToString().c_str(), (long long)subscriberId);
-        return;
-    }
-    sendBroadcastLocked(it2->second, configKey, subscription, cookies, dimKey);
-}
-
-void SubscriberReporter::sendBroadcastLocked(const shared_ptr<IPendingIntentRef>& pir,
-                                             const ConfigKey& configKey,
-                                             const Subscription& subscription,
-                                             const vector<string>& cookies,
-                                             const MetricDimensionKey& dimKey) const {
-    VLOG("SubscriberReporter::sendBroadcastLocked called.");
-    pir->sendSubscriberBroadcast(
-            configKey.GetUid(),
-            configKey.GetId(),
-            subscription.id(),
-            subscription.rule_id(),
-            cookies,
-            dimKey.getDimensionKeyInWhat().toStatsDimensionsValueParcel());
-}
-
-shared_ptr<IPendingIntentRef> SubscriberReporter::getBroadcastSubscriber(const ConfigKey& configKey,
-                                                                         int64_t subscriberId) {
-    lock_guard<mutex> lock(mLock);
-    auto subscriberMapIt = mIntentMap.find(configKey);
-    if (subscriberMapIt == mIntentMap.end()) {
-        return nullptr;
-    }
-    auto pirMapIt = subscriberMapIt->second.find(subscriberId);
-    if (pirMapIt == subscriberMapIt->second.end()) {
-        return nullptr;
-    }
-    return pirMapIt->second;
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.h b/cmds/statsd/src/subscriber/SubscriberReporter.h
deleted file mode 100644
index 4fe4281..0000000
--- a/cmds/statsd/src/subscriber/SubscriberReporter.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <aidl/android/os/IPendingIntentRef.h>
-#include <utils/RefBase.h>
-#include <utils/String16.h>
-
-#include "config/ConfigKey.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"  // subscription
-#include "HashableDimensionKey.h"
-
-#include <mutex>
-#include <unordered_map>
-#include <vector>
-
-using aidl::android::os::IPendingIntentRef;
-using std::mutex;
-using std::shared_ptr;
-using std::string;
-using std::unordered_map;
-using std::vector;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// Reports information to subscribers.
-// Single instance shared across the process. All methods are thread safe.
-class SubscriberReporter {
-public:
-    /** Get (singleton) instance of SubscriberReporter. */
-    static SubscriberReporter& getInstance() {
-        static SubscriberReporter subscriberReporter;
-        return subscriberReporter;
-    }
-
-    ~SubscriberReporter(){};
-    SubscriberReporter(SubscriberReporter const&) = delete;
-    void operator=(SubscriberReporter const&) = delete;
-
-    /**
-     * Stores the given intentSender, associating it with the given (configKey, subscriberId) pair.
-     */
-    void setBroadcastSubscriber(const ConfigKey& configKey,
-                                int64_t subscriberId,
-                                const shared_ptr<IPendingIntentRef>& pir);
-
-    /**
-     * Erases any intentSender information from the given (configKey, subscriberId) pair.
-     */
-    void unsetBroadcastSubscriber(const ConfigKey& configKey, int64_t subscriberId);
-
-    /**
-     * Sends a broadcast via the intentSender previously stored for the
-     * given (configKey, subscriberId) pair by setBroadcastSubscriber.
-     * Information about the subscriber, as well as information extracted from the dimKey, is sent.
-     */
-    void alertBroadcastSubscriber(const ConfigKey& configKey,
-                                  const Subscription& subscription,
-                                  const MetricDimensionKey& dimKey) const;
-
-    shared_ptr<IPendingIntentRef> getBroadcastSubscriber(const ConfigKey& configKey,
-                                                         int64_t subscriberId);
-
-private:
-    SubscriberReporter();
-
-    mutable mutex mLock;
-
-    /** Maps <ConfigKey, SubscriberId> -> IPendingIntentRef (which represents a PendingIntent). */
-    unordered_map<ConfigKey, unordered_map<int64_t, shared_ptr<IPendingIntentRef>>> mIntentMap;
-
-    /**
-     * Sends a broadcast via the given intentSender (using mStatsCompanionService), along
-     * with the information in the other parameters.
-     */
-    void sendBroadcastLocked(const shared_ptr<IPendingIntentRef>& pir,
-                             const ConfigKey& configKey,
-                             const Subscription& subscription,
-                             const vector<string>& cookies,
-                             const MetricDimensionKey& dimKey) const;
-
-    ::ndk::ScopedAIBinder_DeathRecipient mBroadcastSubscriberDeathRecipient;
-
-    /**
-     * Death recipient callback that is called when a broadcast subscriber dies.
-     * The cookie is a pointer to a BroadcastSubscriberDeathCookie.
-     */
-    static void broadcastSubscriberDied(void* cookie);
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/uid_data.proto b/cmds/statsd/src/uid_data.proto
deleted file mode 100644
index a6fa26c..0000000
--- a/cmds/statsd/src/uid_data.proto
+++ /dev/null
@@ -1,36 +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.
- */
-
-syntax = "proto2";
-
-package android.os.statsd;
-
-option java_package = "com.android.internal.os";
-option java_outer_classname = "UidDataProto";
-
-message ApplicationInfo {
-  optional int32 uid = 1;
-  optional int64 version = 2;
-  optional string version_string = 3;
-  optional string package_name = 4;
-  optional string installer = 5;
-}
-
-// StatsServiceCompanion uses the proto to supply statsd with uid-package
-// mapping updates.
-message UidData {
-  repeated ApplicationInfo app_info = 1;
-}
diff --git a/cmds/statsd/src/utils/MultiConditionTrigger.cpp b/cmds/statsd/src/utils/MultiConditionTrigger.cpp
deleted file mode 100644
index 43a6933..0000000
--- a/cmds/statsd/src/utils/MultiConditionTrigger.cpp
+++ /dev/null
@@ -1,57 +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.
- */
-#define DEBUG false  // STOPSHIP if true
-
-#include "MultiConditionTrigger.h"
-
-#include <thread>
-
-using namespace std;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-MultiConditionTrigger::MultiConditionTrigger(const set<string>& conditionNames,
-                                             function<void()> trigger)
-    : mRemainingConditionNames(conditionNames),
-      mTrigger(trigger),
-      mCompleted(mRemainingConditionNames.empty()) {
-    if (mCompleted) {
-        thread executorThread([this] { mTrigger(); });
-        executorThread.detach();
-    }
-}
-
-void MultiConditionTrigger::markComplete(const string& conditionName) {
-    bool doTrigger = false;
-    {
-        lock_guard<mutex> lg(mMutex);
-        if (mCompleted) {
-            return;
-        }
-        mRemainingConditionNames.erase(conditionName);
-        mCompleted = mRemainingConditionNames.empty();
-        doTrigger = mCompleted;
-    }
-    if (doTrigger) {
-        std::thread executorThread([this] { mTrigger(); });
-        executorThread.detach();
-    }
-}
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/utils/MultiConditionTrigger.h b/cmds/statsd/src/utils/MultiConditionTrigger.h
deleted file mode 100644
index 51f6029..0000000
--- a/cmds/statsd/src/utils/MultiConditionTrigger.h
+++ /dev/null
@@ -1,55 +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.
- */
-#pragma once
-
-#include <gtest/gtest_prod.h>
-
-#include <mutex>
-#include <set>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/**
- * This class provides a utility to wait for a set of named conditions to occur.
- *
- * It will execute the trigger runnable in a detached thread once all conditions have been marked
- * true.
- */
-class MultiConditionTrigger {
-public:
-    explicit MultiConditionTrigger(const std::set<std::string>& conditionNames,
-                                   std::function<void()> trigger);
-
-    MultiConditionTrigger(const MultiConditionTrigger&) = delete;
-    MultiConditionTrigger& operator=(const MultiConditionTrigger&) = delete;
-
-    // Mark a specific condition as true. If this condition has called markComplete already or if
-    // the event was not specified in the constructor, the function is a no-op.
-    void markComplete(const std::string& eventName);
-
-private:
-    mutable std::mutex mMutex;
-    std::set<std::string> mRemainingConditionNames;
-    std::function<void()> mTrigger;
-    bool mCompleted;
-
-    FRIEND_TEST(MultiConditionTriggerTest, TestCountDownCalledBySameEventName);
-};
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/statsd_test.xml b/cmds/statsd/statsd_test.xml
deleted file mode 100644
index 8f9bb1c..0000000
--- a/cmds/statsd/statsd_test.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?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.
--->
-<configuration description="Runs statsd_test.">
-    <option name="test-suite-tag" value="apct" />
-    <option name="test-suite-tag" value="apct-native" />
-    <option name="test-suite-tag" value="mts" />
-
-    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
-
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-       <option name="cleanup" value="true" />
-       <option name="push" value="statsd_test->/data/local/tmp/statsd_test" />
-       <option name="append-bitness" value="true" />
-    </target_preparer>
-
-    <test class="com.android.tradefed.testtype.GTest" >
-        <option name="native-test-device-path" value="/data/local/tmp" />
-        <option name="module-name" value="statsd_test" />
-    </test>
-
-    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
-        <option name="mainline-module-package-name" value="com.google.android.os.statsd" />
-    </object>
-</configuration>
diff --git a/cmds/statsd/tests/AlarmMonitor_test.cpp b/cmds/statsd/tests/AlarmMonitor_test.cpp
deleted file mode 100644
index 1dc9795..0000000
--- a/cmds/statsd/tests/AlarmMonitor_test.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "anomaly/AlarmMonitor.h"
-
-#include <gtest/gtest.h>
-
-using namespace android::os::statsd;
-using std::shared_ptr;
-
-#ifdef __ANDROID__
-TEST(AlarmMonitor, popSoonerThan) {
-    std::string emptyMetricId;
-    std::string emptyDimensionId;
-    unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> set;
-    AlarmMonitor am(2,
-                    [](const shared_ptr<IStatsCompanionService>&, int64_t){},
-                    [](const shared_ptr<IStatsCompanionService>&){});
-
-    set = am.popSoonerThan(5);
-    EXPECT_TRUE(set.empty());
-
-    sp<const InternalAlarm> a = new InternalAlarm{10};
-    sp<const InternalAlarm> b = new InternalAlarm{20};
-    sp<const InternalAlarm> c = new InternalAlarm{20};
-    sp<const InternalAlarm> d = new InternalAlarm{30};
-    sp<const InternalAlarm> e = new InternalAlarm{40};
-    sp<const InternalAlarm> f = new InternalAlarm{50};
-
-    am.add(a);
-    am.add(b);
-    am.add(c);
-    am.add(d);
-    am.add(e);
-    am.add(f);
-
-    set = am.popSoonerThan(5);
-    EXPECT_TRUE(set.empty());
-
-    set = am.popSoonerThan(30);
-    ASSERT_EQ(4u, set.size());
-    EXPECT_EQ(1u, set.count(a));
-    EXPECT_EQ(1u, set.count(b));
-    EXPECT_EQ(1u, set.count(c));
-    EXPECT_EQ(1u, set.count(d));
-
-    set = am.popSoonerThan(60);
-    ASSERT_EQ(2u, set.size());
-    EXPECT_EQ(1u, set.count(e));
-    EXPECT_EQ(1u, set.count(f));
-
-    set = am.popSoonerThan(80);
-    ASSERT_EQ(0u, set.size());
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/ConfigManager_test.cpp b/cmds/statsd/tests/ConfigManager_test.cpp
deleted file mode 100644
index 24c8f2b..0000000
--- a/cmds/statsd/tests/ConfigManager_test.cpp
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/config/ConfigManager.h"
-#include "src/metrics/MetricsManager.h"
-#include "statsd_test_util.h"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include <stdio.h>
-#include <iostream>
-
-using namespace android;
-using namespace android::os::statsd;
-using namespace testing;
-using namespace std;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-static ostream& operator<<(ostream& os, const StatsdConfig& config) {
-    return os << "StatsdConfig{id=" << config.id() << "}";
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-/**
- * Mock ConfigListener
- */
-class MockListener : public ConfigListener {
-public:
-    MOCK_METHOD3(OnConfigUpdated,
-                 void(const int64_t timestampNs, const ConfigKey& key, const StatsdConfig& config));
-    MOCK_METHOD1(OnConfigRemoved, void(const ConfigKey& key));
-};
-
-/**
- * Validate that the ConfigKey is the one we wanted.
- */
-MATCHER_P2(ConfigKeyEq, uid, id, "") {
-    return arg.GetUid() == uid && (long long)arg.GetId() == (long long)id;
-}
-
-/**
- * Validate that the StatsdConfig is the one we wanted.
- */
-MATCHER_P(StatsdConfigEq, id, 0) {
-    return (long long)arg.id() == (long long)id;
-}
-
-const int64_t testConfigId = 12345;
-
-/**
- * Test the addOrUpdate and remove methods
- */
-TEST(ConfigManagerTest, TestAddUpdateRemove) {
-    sp<MockListener> listener = new StrictMock<MockListener>();
-
-    sp<ConfigManager> manager = new ConfigManager();
-    manager->AddListener(listener);
-
-    StatsdConfig config91;
-    config91.set_id(91);
-    StatsdConfig config92;
-    config92.set_id(92);
-    StatsdConfig config93;
-    config93.set_id(93);
-    StatsdConfig config94;
-    config94.set_id(94);
-
-    {
-        InSequence s;
-
-        manager->StartupForTest();
-
-        // Add another one
-        EXPECT_CALL(*(listener.get()),
-                    OnConfigUpdated(_, ConfigKeyEq(1, StringToId("zzz")), StatsdConfigEq(91)))
-                .RetiresOnSaturation();
-        manager->UpdateConfig(ConfigKey(1, StringToId("zzz")), config91);
-
-        // Update It
-        EXPECT_CALL(*(listener.get()),
-                    OnConfigUpdated(_, ConfigKeyEq(1, StringToId("zzz")), StatsdConfigEq(92)))
-                .RetiresOnSaturation();
-        manager->UpdateConfig(ConfigKey(1, StringToId("zzz")), config92);
-
-        // Add one with the same uid but a different name
-        EXPECT_CALL(*(listener.get()),
-                    OnConfigUpdated(_, ConfigKeyEq(1, StringToId("yyy")), StatsdConfigEq(93)))
-                .RetiresOnSaturation();
-        manager->UpdateConfig(ConfigKey(1, StringToId("yyy")), config93);
-
-        // Add one with the same name but a different uid
-        EXPECT_CALL(*(listener.get()),
-                    OnConfigUpdated(_, ConfigKeyEq(2, StringToId("zzz")), StatsdConfigEq(94)))
-                .RetiresOnSaturation();
-        manager->UpdateConfig(ConfigKey(2, StringToId("zzz")), config94);
-
-        // Remove (1,yyy)
-        EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(1, StringToId("yyy"))))
-                .RetiresOnSaturation();
-        manager->RemoveConfig(ConfigKey(1, StringToId("yyy")));
-
-        // Remove (2,zzz)
-        EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("zzz"))))
-                .RetiresOnSaturation();
-        manager->RemoveConfig(ConfigKey(2, StringToId("zzz")));
-
-        // Remove (1,zzz)
-        EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(1, StringToId("zzz"))))
-                .RetiresOnSaturation();
-        manager->RemoveConfig(ConfigKey(1, StringToId("zzz")));
-
-        // Remove (2,zzz) again and we shouldn't get the callback
-        manager->RemoveConfig(ConfigKey(2, StringToId("zzz")));
-    }
-}
-
-/**
- * Test removing all of the configs for a uid.
- */
-TEST(ConfigManagerTest, TestRemoveUid) {
-    sp<MockListener> listener = new StrictMock<MockListener>();
-
-    sp<ConfigManager> manager = new ConfigManager();
-    manager->AddListener(listener);
-
-    StatsdConfig config;
-
-    EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, _, _)).Times(5);
-    EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("xxx"))));
-    EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("yyy"))));
-    EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("zzz"))));
-
-    manager->StartupForTest();
-    manager->UpdateConfig(ConfigKey(1, StringToId("aaa")), config);
-    manager->UpdateConfig(ConfigKey(2, StringToId("xxx")), config);
-    manager->UpdateConfig(ConfigKey(2, StringToId("yyy")), config);
-    manager->UpdateConfig(ConfigKey(2, StringToId("zzz")), config);
-    manager->UpdateConfig(ConfigKey(3, StringToId("bbb")), config);
-
-    manager->RemoveConfigs(2);
-}
diff --git a/cmds/statsd/tests/FieldValue_test.cpp b/cmds/statsd/tests/FieldValue_test.cpp
deleted file mode 100644
index a21eb9b..0000000
--- a/cmds/statsd/tests/FieldValue_test.cpp
+++ /dev/null
@@ -1,659 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <gtest/gtest.h>
-
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "matchers/matcher_util.h"
-#include "src/logd/LogEvent.h"
-#include "stats_event.h"
-#include "stats_log_util.h"
-#include "stats_util.h"
-#include "subscriber/SubscriberReporter.h"
-#include "tests/statsd_test_util.h"
-
-#ifdef __ANDROID__
-
-using android::util::ProtoReader;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-// These constants must be kept in sync with those in StatsDimensionsValue.java.
-const static int STATS_DIMENSIONS_VALUE_STRING_TYPE = 2;
-const static int STATS_DIMENSIONS_VALUE_INT_TYPE = 3;
-const static int STATS_DIMENSIONS_VALUE_FLOAT_TYPE = 6;
-const static int STATS_DIMENSIONS_VALUE_TUPLE_TYPE = 7;
-
-namespace {
-void makeLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timestamp,
-                  const vector<int>& attributionUids, const vector<string>& attributionTags,
-                  const string& name) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, atomId);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestamp);
-
-    writeAttribution(statsEvent, attributionUids, attributionTags);
-    AStatsEvent_writeString(statsEvent, name.c_str());
-
-    parseStatsEventToLogEvent(statsEvent, logEvent);
-}
-
-void makeLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timestamp,
-                  const vector<int>& attributionUids, const vector<string>& attributionTags,
-                  const int32_t value) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, atomId);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestamp);
-
-    writeAttribution(statsEvent, attributionUids, attributionTags);
-    AStatsEvent_writeInt32(statsEvent, value);
-
-    parseStatsEventToLogEvent(statsEvent, logEvent);
-}
-}  // anonymous namespace
-
-TEST(AtomMatcherTest, TestFieldTranslation) {
-    FieldMatcher matcher1;
-    matcher1.set_field(10);
-    FieldMatcher* child = matcher1.add_child();
-    child->set_field(1);
-    child->set_position(Position::ANY);
-
-    child = child->add_child();
-    child->set_field(1);
-
-    vector<Matcher> output;
-    translateFieldMatcher(matcher1, &output);
-
-    ASSERT_EQ((size_t)1, output.size());
-
-    const auto& matcher12 = output[0];
-    EXPECT_EQ((int32_t)10, matcher12.mMatcher.getTag());
-    EXPECT_EQ((int32_t)0x02010001, matcher12.mMatcher.getField());
-    EXPECT_EQ((int32_t)0xff7f007f, matcher12.mMask);
-}
-
-TEST(AtomMatcherTest, TestFieldTranslation_ALL) {
-    FieldMatcher matcher1;
-    matcher1.set_field(10);
-    FieldMatcher* child = matcher1.add_child();
-    child->set_field(1);
-    child->set_position(Position::ALL);
-
-    child = child->add_child();
-    child->set_field(1);
-
-    vector<Matcher> output;
-    translateFieldMatcher(matcher1, &output);
-
-    ASSERT_EQ((size_t)1, output.size());
-
-    const auto& matcher12 = output[0];
-    EXPECT_EQ((int32_t)10, matcher12.mMatcher.getTag());
-    EXPECT_EQ((int32_t)0x02010001, matcher12.mMatcher.getField());
-    EXPECT_EQ((int32_t)0xff7f7f7f, matcher12.mMask);
-}
-
-TEST(AtomMatcherTest, TestFilter_ALL) {
-    FieldMatcher matcher1;
-    matcher1.set_field(10);
-    FieldMatcher* child = matcher1.add_child();
-    child->set_field(1);
-    child->set_position(Position::ALL);
-
-    child->add_child()->set_field(1);
-    child->add_child()->set_field(2);
-
-    child = matcher1.add_child();
-    child->set_field(2);
-
-    vector<Matcher> matchers;
-    translateFieldMatcher(matcher1, &matchers);
-
-    std::vector<int> attributionUids = {1111, 2222, 3333};
-    std::vector<string> attributionTags = {"location1", "location2", "location3"};
-
-    LogEvent event(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event, 10 /*atomId*/, 1012345, attributionUids, attributionTags, "some value");
-    HashableDimensionKey output;
-
-    filterValues(matchers, event.getValues(), &output);
-
-    ASSERT_EQ((size_t)7, output.getValues().size());
-    EXPECT_EQ((int32_t)0x02010101, output.getValues()[0].mField.getField());
-    EXPECT_EQ((int32_t)1111, output.getValues()[0].mValue.int_value);
-    EXPECT_EQ((int32_t)0x02010102, output.getValues()[1].mField.getField());
-    EXPECT_EQ("location1", output.getValues()[1].mValue.str_value);
-
-    EXPECT_EQ((int32_t)0x02010201, output.getValues()[2].mField.getField());
-    EXPECT_EQ((int32_t)2222, output.getValues()[2].mValue.int_value);
-    EXPECT_EQ((int32_t)0x02010202, output.getValues()[3].mField.getField());
-    EXPECT_EQ("location2", output.getValues()[3].mValue.str_value);
-
-    EXPECT_EQ((int32_t)0x02010301, output.getValues()[4].mField.getField());
-    EXPECT_EQ((int32_t)3333, output.getValues()[4].mValue.int_value);
-    EXPECT_EQ((int32_t)0x02010302, output.getValues()[5].mField.getField());
-    EXPECT_EQ("location3", output.getValues()[5].mValue.str_value);
-
-    EXPECT_EQ((int32_t)0x00020000, output.getValues()[6].mField.getField());
-    EXPECT_EQ("some value", output.getValues()[6].mValue.str_value);
-}
-
-TEST(AtomMatcherTest, TestSubDimension) {
-    HashableDimensionKey dim;
-
-    int pos1[] = {1, 1, 1};
-    int pos2[] = {1, 1, 2};
-    int pos3[] = {1, 1, 3};
-    int pos4[] = {2, 0, 0};
-    Field field1(10, pos1, 2);
-    Field field2(10, pos2, 2);
-
-    Field field3(10, pos3, 2);
-    Field field4(10, pos4, 0);
-
-    Value value1((int32_t)10025);
-    Value value2("tag");
-
-    Value value11((int32_t)10026);
-    Value value22("tag2");
-
-    dim.addValue(FieldValue(field1, value1));
-    dim.addValue(FieldValue(field2, value2));
-
-    HashableDimensionKey subDim1;
-    subDim1.addValue(FieldValue(field1, value1));
-
-    HashableDimensionKey subDim2;
-    subDim1.addValue(FieldValue(field2, value2));
-
-    EXPECT_TRUE(dim.contains(dim));
-    EXPECT_TRUE(dim.contains(subDim1));
-    EXPECT_TRUE(dim.contains(subDim2));
-
-    HashableDimensionKey subDim3;
-    subDim3.addValue(FieldValue(field1, value11));
-    EXPECT_FALSE(dim.contains(subDim3));
-
-    HashableDimensionKey subDim4;
-    // Empty dimension is always a sub dimension of other dimensions
-    EXPECT_TRUE(dim.contains(subDim4));
-}
-
-TEST(AtomMatcherTest, TestMetric2ConditionLink) {
-    std::vector<int> attributionUids = {1111, 2222, 3333};
-    std::vector<string> attributionTags = {"location1", "location2", "location3"};
-
-    LogEvent event(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event, 10 /*atomId*/, 12345, attributionUids, attributionTags, "some value");
-
-    FieldMatcher whatMatcher;
-    whatMatcher.set_field(10);
-    FieldMatcher* child11 = whatMatcher.add_child();
-    child11->set_field(1);
-    child11->set_position(Position::ANY);
-    child11 = child11->add_child();
-    child11->set_field(1);
-
-    FieldMatcher conditionMatcher;
-    conditionMatcher.set_field(27);
-    FieldMatcher* child2 = conditionMatcher.add_child();
-    child2->set_field(2);
-    child2->set_position(Position::LAST);
-
-    child2 = child2->add_child();
-    child2->set_field(2);
-
-    Metric2Condition link;
-
-    translateFieldMatcher(whatMatcher, &link.metricFields);
-    translateFieldMatcher(conditionMatcher, &link.conditionFields);
-
-    ASSERT_EQ((size_t)1, link.metricFields.size());
-    EXPECT_EQ((int32_t)0x02010001, link.metricFields[0].mMatcher.getField());
-    EXPECT_EQ((int32_t)0xff7f007f, link.metricFields[0].mMask);
-    EXPECT_EQ((int32_t)10, link.metricFields[0].mMatcher.getTag());
-
-    ASSERT_EQ((size_t)1, link.conditionFields.size());
-    EXPECT_EQ((int32_t)0x02028002, link.conditionFields[0].mMatcher.getField());
-    EXPECT_EQ((int32_t)0xff7f807f, link.conditionFields[0].mMask);
-    EXPECT_EQ((int32_t)27, link.conditionFields[0].mMatcher.getTag());
-}
-
-TEST(AtomMatcherTest, TestWriteDimensionPath) {
-    for (auto position : {Position::ANY, Position::ALL, Position::FIRST, Position::LAST}) {
-        FieldMatcher matcher1;
-        matcher1.set_field(10);
-        FieldMatcher* child = matcher1.add_child();
-        child->set_field(2);
-        child->set_position(position);
-        child->add_child()->set_field(1);
-        child->add_child()->set_field(3);
-
-        child = matcher1.add_child();
-        child->set_field(4);
-
-        child = matcher1.add_child();
-        child->set_field(6);
-        child->add_child()->set_field(2);
-
-        vector<Matcher> matchers;
-        translateFieldMatcher(matcher1, &matchers);
-
-        android::util::ProtoOutputStream protoOut;
-        writeDimensionPathToProto(matchers, &protoOut);
-
-        vector<uint8_t> outData;
-        outData.resize(protoOut.size());
-        size_t pos = 0;
-        sp<ProtoReader> reader = protoOut.data();
-        while (reader->readBuffer() != NULL) {
-            size_t toRead = reader->currentToRead();
-            std::memcpy(&(outData[pos]), reader->readBuffer(), toRead);
-            pos += toRead;
-            reader->move(toRead);
-        }
-
-        DimensionsValue result;
-        ASSERT_EQ(true, result.ParseFromArray(&outData[0], outData.size()));
-
-        EXPECT_EQ(10, result.field());
-        EXPECT_EQ(DimensionsValue::ValueCase::kValueTuple, result.value_case());
-        ASSERT_EQ(3, result.value_tuple().dimensions_value_size());
-
-        const auto& dim1 = result.value_tuple().dimensions_value(0);
-        EXPECT_EQ(2, dim1.field());
-        ASSERT_EQ(2, dim1.value_tuple().dimensions_value_size());
-
-        const auto& dim11 = dim1.value_tuple().dimensions_value(0);
-        EXPECT_EQ(1, dim11.field());
-
-        const auto& dim12 = dim1.value_tuple().dimensions_value(1);
-        EXPECT_EQ(3, dim12.field());
-
-        const auto& dim2 = result.value_tuple().dimensions_value(1);
-        EXPECT_EQ(4, dim2.field());
-
-        const auto& dim3 = result.value_tuple().dimensions_value(2);
-        EXPECT_EQ(6, dim3.field());
-        ASSERT_EQ(1, dim3.value_tuple().dimensions_value_size());
-        const auto& dim31 = dim3.value_tuple().dimensions_value(0);
-        EXPECT_EQ(2, dim31.field());
-    }
-}
-
-void checkAttributionNodeInDimensionsValueParcel(StatsDimensionsValueParcel& attributionNodeParcel,
-                                                 int32_t nodeDepthInAttributionChain,
-                                                 int32_t uid, string tag) {
-    EXPECT_EQ(attributionNodeParcel.field, nodeDepthInAttributionChain /*position at depth 1*/);
-    ASSERT_EQ(attributionNodeParcel.valueType, STATS_DIMENSIONS_VALUE_TUPLE_TYPE);
-    ASSERT_EQ(attributionNodeParcel.tupleValue.size(), 2);
-
-    StatsDimensionsValueParcel uidParcel = attributionNodeParcel.tupleValue[0];
-    EXPECT_EQ(uidParcel.field, 1 /*position at depth 2*/);
-    EXPECT_EQ(uidParcel.valueType, STATS_DIMENSIONS_VALUE_INT_TYPE);
-    EXPECT_EQ(uidParcel.intValue, uid);
-
-    StatsDimensionsValueParcel tagParcel = attributionNodeParcel.tupleValue[1];
-    EXPECT_EQ(tagParcel.field, 2 /*position at depth 2*/);
-    EXPECT_EQ(tagParcel.valueType, STATS_DIMENSIONS_VALUE_STRING_TYPE);
-    EXPECT_EQ(tagParcel.stringValue, tag);
-}
-
-// Test conversion of a HashableDimensionKey into a StatsDimensionValueParcel
-TEST(AtomMatcherTest, TestSubscriberDimensionWrite) {
-    int atomId = 10;
-    // First four fields form an attribution chain
-    int pos1[] = {1, 1, 1};
-    int pos2[] = {1, 1, 2};
-    int pos3[] = {1, 2, 1};
-    int pos4[] = {1, 2, 2};
-    int pos5[] = {2, 1, 1};
-
-    Field field1(atomId, pos1, /*depth=*/2);
-    Field field2(atomId, pos2, /*depth=*/2);
-    Field field3(atomId, pos3, /*depth=*/2);
-    Field field4(atomId, pos4, /*depth=*/2);
-    Field field5(atomId, pos5, /*depth=*/0);
-
-    Value value1((int32_t)1);
-    Value value2("string2");
-    Value value3((int32_t)3);
-    Value value4("string4");
-    Value value5((float)5.0);
-
-    HashableDimensionKey dimensionKey;
-    dimensionKey.addValue(FieldValue(field1, value1));
-    dimensionKey.addValue(FieldValue(field2, value2));
-    dimensionKey.addValue(FieldValue(field3, value3));
-    dimensionKey.addValue(FieldValue(field4, value4));
-    dimensionKey.addValue(FieldValue(field5, value5));
-
-    StatsDimensionsValueParcel rootParcel = dimensionKey.toStatsDimensionsValueParcel();
-    EXPECT_EQ(rootParcel.field, atomId);
-    ASSERT_EQ(rootParcel.valueType, STATS_DIMENSIONS_VALUE_TUPLE_TYPE);
-    ASSERT_EQ(rootParcel.tupleValue.size(), 2);
-
-    // Check that attribution chain is populated correctly
-    StatsDimensionsValueParcel attributionChainParcel = rootParcel.tupleValue[0];
-    EXPECT_EQ(attributionChainParcel.field, 1 /*position at depth 0*/);
-    ASSERT_EQ(attributionChainParcel.valueType, STATS_DIMENSIONS_VALUE_TUPLE_TYPE);
-    ASSERT_EQ(attributionChainParcel.tupleValue.size(), 2);
-    checkAttributionNodeInDimensionsValueParcel(attributionChainParcel.tupleValue[0],
-                                                /*nodeDepthInAttributionChain=*/1,
-                                                value1.int_value, value2.str_value);
-    checkAttributionNodeInDimensionsValueParcel(attributionChainParcel.tupleValue[1],
-                                                /*nodeDepthInAttributionChain=*/2,
-                                                value3.int_value, value4.str_value);
-
-    // Check that the float is populated correctly
-    StatsDimensionsValueParcel floatParcel = rootParcel.tupleValue[1];
-    EXPECT_EQ(floatParcel.field, 2 /*position at depth 0*/);
-    EXPECT_EQ(floatParcel.valueType, STATS_DIMENSIONS_VALUE_FLOAT_TYPE);
-    EXPECT_EQ(floatParcel.floatValue, value5.float_value);
-}
-
-TEST(AtomMatcherTest, TestWriteDimensionToProto) {
-    HashableDimensionKey dim;
-    int pos1[] = {1, 1, 1};
-    int pos2[] = {1, 1, 2};
-    int pos3[] = {1, 1, 3};
-    int pos4[] = {2, 0, 0};
-    Field field1(10, pos1, 2);
-    Field field2(10, pos2, 2);
-    Field field3(10, pos3, 2);
-    Field field4(10, pos4, 0);
-
-    Value value1((int32_t)10025);
-    Value value2("tag");
-    Value value3((int32_t)987654);
-    Value value4((int32_t)99999);
-
-    dim.addValue(FieldValue(field1, value1));
-    dim.addValue(FieldValue(field2, value2));
-    dim.addValue(FieldValue(field3, value3));
-    dim.addValue(FieldValue(field4, value4));
-
-    android::util::ProtoOutputStream protoOut;
-    writeDimensionToProto(dim, nullptr /* include strings */, &protoOut);
-
-    vector<uint8_t> outData;
-    outData.resize(protoOut.size());
-    size_t pos = 0;
-    sp<ProtoReader> reader = protoOut.data();
-    while (reader->readBuffer() != NULL) {
-        size_t toRead = reader->currentToRead();
-        std::memcpy(&(outData[pos]), reader->readBuffer(), toRead);
-        pos += toRead;
-        reader->move(toRead);
-    }
-
-    DimensionsValue result;
-    ASSERT_EQ(true, result.ParseFromArray(&outData[0], outData.size()));
-    EXPECT_EQ(10, result.field());
-    EXPECT_EQ(DimensionsValue::ValueCase::kValueTuple, result.value_case());
-    ASSERT_EQ(2, result.value_tuple().dimensions_value_size());
-
-    const auto& dim1 = result.value_tuple().dimensions_value(0);
-    EXPECT_EQ(DimensionsValue::ValueCase::kValueTuple, dim1.value_case());
-    ASSERT_EQ(3, dim1.value_tuple().dimensions_value_size());
-
-    const auto& dim11 = dim1.value_tuple().dimensions_value(0);
-    EXPECT_EQ(DimensionsValue::ValueCase::kValueInt, dim11.value_case());
-    EXPECT_EQ(10025, dim11.value_int());
-
-    const auto& dim12 = dim1.value_tuple().dimensions_value(1);
-    EXPECT_EQ(DimensionsValue::ValueCase::kValueStr, dim12.value_case());
-    EXPECT_EQ("tag", dim12.value_str());
-
-    const auto& dim13 = dim1.value_tuple().dimensions_value(2);
-    EXPECT_EQ(DimensionsValue::ValueCase::kValueInt, dim13.value_case());
-    EXPECT_EQ(987654, dim13.value_int());
-
-    const auto& dim2 = result.value_tuple().dimensions_value(1);
-    EXPECT_EQ(DimensionsValue::ValueCase::kValueInt, dim2.value_case());
-    EXPECT_EQ(99999, dim2.value_int());
-}
-
-TEST(AtomMatcherTest, TestWriteDimensionLeafNodesToProto) {
-    HashableDimensionKey dim;
-    int pos1[] = {1, 1, 1};
-    int pos2[] = {1, 1, 2};
-    int pos3[] = {1, 1, 3};
-    int pos4[] = {2, 0, 0};
-    Field field1(10, pos1, 2);
-    Field field2(10, pos2, 2);
-    Field field3(10, pos3, 2);
-    Field field4(10, pos4, 0);
-
-    Value value1((int32_t)10025);
-    Value value2("tag");
-    Value value3((int32_t)987654);
-    Value value4((int64_t)99999);
-
-    dim.addValue(FieldValue(field1, value1));
-    dim.addValue(FieldValue(field2, value2));
-    dim.addValue(FieldValue(field3, value3));
-    dim.addValue(FieldValue(field4, value4));
-
-    android::util::ProtoOutputStream protoOut;
-    writeDimensionLeafNodesToProto(dim, 1, nullptr /* include strings */, &protoOut);
-
-    vector<uint8_t> outData;
-    outData.resize(protoOut.size());
-    size_t pos = 0;
-    sp<ProtoReader> reader = protoOut.data();
-    while (reader->readBuffer() != NULL) {
-        size_t toRead = reader->currentToRead();
-        std::memcpy(&(outData[pos]), reader->readBuffer(), toRead);
-        pos += toRead;
-        reader->move(toRead);
-    }
-
-    DimensionsValueTuple result;
-    ASSERT_EQ(true, result.ParseFromArray(&outData[0], outData.size()));
-    ASSERT_EQ(4, result.dimensions_value_size());
-
-    const auto& dim1 = result.dimensions_value(0);
-    EXPECT_EQ(DimensionsValue::ValueCase::kValueInt, dim1.value_case());
-    EXPECT_EQ(10025, dim1.value_int());
-
-    const auto& dim2 = result.dimensions_value(1);
-    EXPECT_EQ(DimensionsValue::ValueCase::kValueStr, dim2.value_case());
-    EXPECT_EQ("tag", dim2.value_str());
-
-    const auto& dim3 = result.dimensions_value(2);
-    EXPECT_EQ(DimensionsValue::ValueCase::kValueInt, dim3.value_case());
-    EXPECT_EQ(987654, dim3.value_int());
-
-    const auto& dim4 = result.dimensions_value(3);
-    EXPECT_EQ(DimensionsValue::ValueCase::kValueLong, dim4.value_case());
-    EXPECT_EQ(99999, dim4.value_long());
-}
-
-TEST(AtomMatcherTest, TestWriteAtomToProto) {
-    std::vector<int> attributionUids = {1111, 2222};
-    std::vector<string> attributionTags = {"location1", "location2"};
-
-    LogEvent event(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event, 4 /*atomId*/, 12345, attributionUids, attributionTags, 999);
-
-    android::util::ProtoOutputStream protoOutput;
-    writeFieldValueTreeToStream(event.GetTagId(), event.getValues(), &protoOutput);
-
-    vector<uint8_t> outData;
-    outData.resize(protoOutput.size());
-    size_t pos = 0;
-    sp<ProtoReader> reader = protoOutput.data();
-    while (reader->readBuffer() != NULL) {
-        size_t toRead = reader->currentToRead();
-        std::memcpy(&(outData[pos]), reader->readBuffer(), toRead);
-        pos += toRead;
-        reader->move(toRead);
-    }
-
-    Atom result;
-    ASSERT_EQ(true, result.ParseFromArray(&outData[0], outData.size()));
-    EXPECT_EQ(Atom::PushedCase::kBleScanResultReceived, result.pushed_case());
-    const auto& atom = result.ble_scan_result_received();
-    ASSERT_EQ(2, atom.attribution_node_size());
-    EXPECT_EQ(1111, atom.attribution_node(0).uid());
-    EXPECT_EQ("location1", atom.attribution_node(0).tag());
-    EXPECT_EQ(2222, atom.attribution_node(1).uid());
-    EXPECT_EQ("location2", atom.attribution_node(1).tag());
-    EXPECT_EQ(999, atom.num_results());
-}
-
-/*
- * Test two Matchers is not a subset of one Matcher.
- * Test one Matcher is subset of two Matchers.
- */
-TEST(AtomMatcherTest, TestSubsetDimensions1) {
-    // Initialize first set of matchers
-    FieldMatcher matcher1;
-    matcher1.set_field(10);
-
-    FieldMatcher* child = matcher1.add_child();
-    child->set_field(1);
-    child->set_position(Position::ALL);
-    child->add_child()->set_field(1);
-    child->add_child()->set_field(2);
-
-    vector<Matcher> matchers1;
-    translateFieldMatcher(matcher1, &matchers1);
-    ASSERT_EQ(2, matchers1.size());
-
-    // Initialize second set of matchers
-    FieldMatcher matcher2;
-    matcher2.set_field(10);
-
-    child = matcher2.add_child();
-    child->set_field(1);
-    child->set_position(Position::ALL);
-    child->add_child()->set_field(1);
-
-    vector<Matcher> matchers2;
-    translateFieldMatcher(matcher2, &matchers2);
-    ASSERT_EQ(1, matchers2.size());
-
-    EXPECT_FALSE(subsetDimensions(matchers1, matchers2));
-    EXPECT_TRUE(subsetDimensions(matchers2, matchers1));
-}
-/*
- * Test not a subset with one matching Matcher, one non-matching Matcher.
- */
-TEST(AtomMatcherTest, TestSubsetDimensions2) {
-    // Initialize first set of matchers
-    FieldMatcher matcher1;
-    matcher1.set_field(10);
-
-    FieldMatcher* child = matcher1.add_child();
-    child->set_field(1);
-
-    child = matcher1.add_child();
-    child->set_field(2);
-
-    vector<Matcher> matchers1;
-    translateFieldMatcher(matcher1, &matchers1);
-
-    // Initialize second set of matchers
-    FieldMatcher matcher2;
-    matcher2.set_field(10);
-
-    child = matcher2.add_child();
-    child->set_field(1);
-
-    child = matcher2.add_child();
-    child->set_field(3);
-
-    vector<Matcher> matchers2;
-    translateFieldMatcher(matcher2, &matchers2);
-
-    EXPECT_FALSE(subsetDimensions(matchers1, matchers2));
-}
-
-/*
- * Test not a subset if parent field is not equal.
- */
-TEST(AtomMatcherTest, TestSubsetDimensions3) {
-    // Initialize first set of matchers
-    FieldMatcher matcher1;
-    matcher1.set_field(10);
-
-    FieldMatcher* child = matcher1.add_child();
-    child->set_field(1);
-
-    vector<Matcher> matchers1;
-    translateFieldMatcher(matcher1, &matchers1);
-
-    // Initialize second set of matchers
-    FieldMatcher matcher2;
-    matcher2.set_field(5);
-
-    child = matcher2.add_child();
-    child->set_field(1);
-
-    vector<Matcher> matchers2;
-    translateFieldMatcher(matcher2, &matchers2);
-
-    EXPECT_FALSE(subsetDimensions(matchers1, matchers2));
-}
-
-/*
- * Test is subset with two matching Matchers.
- */
-TEST(AtomMatcherTest, TestSubsetDimensions4) {
-    // Initialize first set of matchers
-    FieldMatcher matcher1;
-    matcher1.set_field(10);
-
-    FieldMatcher* child = matcher1.add_child();
-    child->set_field(1);
-
-    child = matcher1.add_child();
-    child->set_field(2);
-
-    vector<Matcher> matchers1;
-    translateFieldMatcher(matcher1, &matchers1);
-
-    // Initialize second set of matchers
-    FieldMatcher matcher2;
-    matcher2.set_field(10);
-
-    child = matcher2.add_child();
-    child->set_field(1);
-
-    child = matcher2.add_child();
-    child->set_field(2);
-
-    child = matcher2.add_child();
-    child->set_field(3);
-
-    vector<Matcher> matchers2;
-    translateFieldMatcher(matcher2, &matchers2);
-
-    EXPECT_TRUE(subsetDimensions(matchers1, matchers2));
-    EXPECT_FALSE(subsetDimensions(matchers2, matchers1));
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/HashableDimensionKey_test.cpp b/cmds/statsd/tests/HashableDimensionKey_test.cpp
deleted file mode 100644
index 29adcd0..0000000
--- a/cmds/statsd/tests/HashableDimensionKey_test.cpp
+++ /dev/null
@@ -1,137 +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.
- */
-#include "src/HashableDimensionKey.h"
-
-#include <gtest/gtest.h>
-
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "statsd_test_util.h"
-
-#ifdef __ANDROID__
-
-using android::util::ProtoReader;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/**
- * Test that #containsLinkedStateValues returns false when the whatKey is
- * smaller than the primaryKey.
- */
-TEST(HashableDimensionKeyTest, TestContainsLinkedStateValues_WhatKeyTooSmall) {
-    std::vector<Metric2State> mMetric2StateLinks;
-
-    int32_t uid1 = 1000;
-    HashableDimensionKey whatKey = DEFAULT_DIMENSION_KEY;
-    HashableDimensionKey primaryKey;
-    getUidProcessKey(uid1, &primaryKey);
-
-    EXPECT_FALSE(containsLinkedStateValues(whatKey, primaryKey, mMetric2StateLinks,
-                                           UID_PROCESS_STATE_ATOM_ID));
-}
-
-/**
- * Test that #containsLinkedStateValues returns false when the linked values
- * are not equal.
- */
-TEST(HashableDimensionKeyTest, TestContainsLinkedStateValues_UnequalLinkedValues) {
-    int stateAtomId = UID_PROCESS_STATE_ATOM_ID;
-
-    FieldMatcher whatMatcher;
-    whatMatcher.set_field(util::OVERLAY_STATE_CHANGED);
-    FieldMatcher* child11 = whatMatcher.add_child();
-    child11->set_field(1);
-
-    FieldMatcher stateMatcher;
-    stateMatcher.set_field(stateAtomId);
-    FieldMatcher* child21 = stateMatcher.add_child();
-    child21->set_field(1);
-
-    std::vector<Metric2State> mMetric2StateLinks;
-    Metric2State ms;
-    ms.stateAtomId = stateAtomId;
-    translateFieldMatcher(whatMatcher, &ms.metricFields);
-    translateFieldMatcher(stateMatcher, &ms.stateFields);
-    mMetric2StateLinks.push_back(ms);
-
-    int32_t uid1 = 1000;
-    int32_t uid2 = 1001;
-    HashableDimensionKey whatKey;
-    getOverlayKey(uid2, "package", &whatKey);
-    HashableDimensionKey primaryKey;
-    getUidProcessKey(uid1, &primaryKey);
-
-    EXPECT_FALSE(containsLinkedStateValues(whatKey, primaryKey, mMetric2StateLinks, stateAtomId));
-}
-
-/**
- * Test that #containsLinkedStateValues returns false when there is no link
- * between the key values.
- */
-TEST(HashableDimensionKeyTest, TestContainsLinkedStateValues_MissingMetric2StateLinks) {
-    int stateAtomId = UID_PROCESS_STATE_ATOM_ID;
-
-    std::vector<Metric2State> mMetric2StateLinks;
-
-    int32_t uid1 = 1000;
-    HashableDimensionKey whatKey;
-    getOverlayKey(uid1, "package", &whatKey);
-    HashableDimensionKey primaryKey;
-    getUidProcessKey(uid1, &primaryKey);
-
-    EXPECT_FALSE(containsLinkedStateValues(whatKey, primaryKey, mMetric2StateLinks, stateAtomId));
-}
-
-/**
- * Test that #containsLinkedStateValues returns true when the key values are
- * linked and equal.
- */
-TEST(HashableDimensionKeyTest, TestContainsLinkedStateValues_AllConditionsMet) {
-    int stateAtomId = UID_PROCESS_STATE_ATOM_ID;
-
-    FieldMatcher whatMatcher;
-    whatMatcher.set_field(util::OVERLAY_STATE_CHANGED);
-    FieldMatcher* child11 = whatMatcher.add_child();
-    child11->set_field(1);
-
-    FieldMatcher stateMatcher;
-    stateMatcher.set_field(stateAtomId);
-    FieldMatcher* child21 = stateMatcher.add_child();
-    child21->set_field(1);
-
-    std::vector<Metric2State> mMetric2StateLinks;
-    Metric2State ms;
-    ms.stateAtomId = stateAtomId;
-    translateFieldMatcher(whatMatcher, &ms.metricFields);
-    translateFieldMatcher(stateMatcher, &ms.stateFields);
-    mMetric2StateLinks.push_back(ms);
-
-    int32_t uid1 = 1000;
-    HashableDimensionKey whatKey;
-    getOverlayKey(uid1, "package", &whatKey);
-    HashableDimensionKey primaryKey;
-    getUidProcessKey(uid1, &primaryKey);
-
-    EXPECT_TRUE(containsLinkedStateValues(whatKey, primaryKey, mMetric2StateLinks, stateAtomId));
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
deleted file mode 100644
index 92cd04f..0000000
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ /dev/null
@@ -1,809 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <gtest/gtest.h>
-#include <stdio.h>
-
-#include "annotations.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "matchers/matcher_util.h"
-#include "stats_event.h"
-#include "stats_log_util.h"
-#include "stats_util.h"
-#include "statsd_test_util.h"
-
-using namespace android::os::statsd;
-using std::unordered_map;
-using std::vector;
-
-const int32_t TAG_ID = 123;
-const int32_t TAG_ID_2 = 28;  // hardcoded tag of atom with uid field
-const int FIELD_ID_1 = 1;
-const int FIELD_ID_2 = 2;
-const int FIELD_ID_3 = 2;
-
-const int ATTRIBUTION_UID_FIELD_ID = 1;
-const int ATTRIBUTION_TAG_FIELD_ID = 2;
-
-
-#ifdef __ANDROID__
-
-namespace {
-
-void makeIntLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timestamp,
-                     const int32_t value) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, atomId);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestamp);
-    AStatsEvent_writeInt32(statsEvent, value);
-
-    parseStatsEventToLogEvent(statsEvent, logEvent);
-}
-
-void makeFloatLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timestamp,
-                       const float floatValue) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, atomId);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestamp);
-    AStatsEvent_writeFloat(statsEvent, floatValue);
-
-    parseStatsEventToLogEvent(statsEvent, logEvent);
-}
-
-void makeStringLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timestamp,
-                        const string& name) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, atomId);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestamp);
-    AStatsEvent_writeString(statsEvent, name.c_str());
-
-    parseStatsEventToLogEvent(statsEvent, logEvent);
-}
-
-void makeIntWithBoolAnnotationLogEvent(LogEvent* logEvent, const int32_t atomId,
-                                       const int32_t field, const uint8_t annotationId,
-                                       const bool annotationValue) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, atomId);
-    AStatsEvent_writeInt32(statsEvent, field);
-    AStatsEvent_addBoolAnnotation(statsEvent, annotationId, annotationValue);
-
-    parseStatsEventToLogEvent(statsEvent, logEvent);
-}
-
-void makeAttributionLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timestamp,
-                             const vector<int>& attributionUids,
-                             const vector<string>& attributionTags, const string& name) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, atomId);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestamp);
-
-    writeAttribution(statsEvent, attributionUids, attributionTags);
-    AStatsEvent_writeString(statsEvent, name.c_str());
-
-    parseStatsEventToLogEvent(statsEvent, logEvent);
-}
-
-void makeBoolLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timestamp,
-                      const bool bool1, const bool bool2) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, atomId);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestamp);
-
-    AStatsEvent_writeBool(statsEvent, bool1);
-    AStatsEvent_writeBool(statsEvent, bool2);
-
-    parseStatsEventToLogEvent(statsEvent, logEvent);
-}
-
-}  // anonymous namespace
-
-TEST(AtomMatcherTest, TestSimpleMatcher) {
-    sp<UidMap> uidMap = new UidMap();
-
-    // Set up the matcher
-    AtomMatcher matcher;
-    auto simpleMatcher = matcher.mutable_simple_atom_matcher();
-    simpleMatcher->set_atom_id(TAG_ID);
-
-    LogEvent event(/*uid=*/0, /*pid=*/0);
-    makeIntLogEvent(&event, TAG_ID, 0, 11);
-
-    // Test
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    // Wrong tag id.
-    simpleMatcher->set_atom_id(TAG_ID + 1);
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-}
-
-TEST(AtomMatcherTest, TestAttributionMatcher) {
-    sp<UidMap> uidMap = new UidMap();
-    std::vector<int> attributionUids = {1111, 2222, 3333};
-    std::vector<string> attributionTags = {"location1", "location2", "location3"};
-
-    // Set up the log event.
-    LogEvent event(/*uid=*/0, /*pid=*/0);
-    makeAttributionLogEvent(&event, TAG_ID, 0, attributionUids, attributionTags, "some value");
-
-    // Set up the matcher
-    AtomMatcher matcher;
-    auto simpleMatcher = matcher.mutable_simple_atom_matcher();
-    simpleMatcher->set_atom_id(TAG_ID);
-
-    // Match first node.
-    auto attributionMatcher = simpleMatcher->add_field_value_matcher();
-    attributionMatcher->set_field(FIELD_ID_1);
-    attributionMatcher->set_position(Position::FIRST);
-    attributionMatcher->mutable_matches_tuple()->add_field_value_matcher()->set_field(
-            ATTRIBUTION_TAG_FIELD_ID);
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "tag");
-
-    auto fieldMatcher = simpleMatcher->add_field_value_matcher();
-    fieldMatcher->set_field(FIELD_ID_2);
-    fieldMatcher->set_eq_string("some value");
-
-    // Tag not matched.
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "location3");
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "location1");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    // Match last node.
-    attributionMatcher->set_position(Position::LAST);
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "location3");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    // Match any node.
-    attributionMatcher->set_position(Position::ANY);
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "location1");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "location2");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "location3");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "location4");
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    // Attribution match but primitive field not match.
-    attributionMatcher->set_position(Position::ANY);
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "location2");
-    fieldMatcher->set_eq_string("wrong value");
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    fieldMatcher->set_eq_string("some value");
-
-    // Uid match.
-    attributionMatcher->set_position(Position::ANY);
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_field(
-            ATTRIBUTION_UID_FIELD_ID);
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg0");
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    uidMap->updateMap(
-            1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
-            {android::String16("v1"), android::String16("v1"), android::String16("v2"),
-             android::String16("v1"), android::String16("v2")},
-            {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"),
-             android::String16("Pkg2"), android::String16("PkG3")} /* package name list */,
-            {android::String16(""), android::String16(""), android::String16(""),
-             android::String16(""), android::String16("")});
-
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg3");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg2");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg1");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg0");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    attributionMatcher->set_position(Position::FIRST);
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg0");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg3");
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg2");
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg1");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    attributionMatcher->set_position(Position::LAST);
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg0");
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg3");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg2");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg1");
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    // Uid + tag.
-    attributionMatcher->set_position(Position::ANY);
-    attributionMatcher->mutable_matches_tuple()->add_field_value_matcher()->set_field(
-            ATTRIBUTION_TAG_FIELD_ID);
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg0");
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
-            "location1");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg1");
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
-            "location1");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg1");
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
-            "location2");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg2");
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
-            "location3");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg3");
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
-            "location3");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg3");
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
-            "location1");
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    attributionMatcher->set_position(Position::FIRST);
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg0");
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
-            "location1");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg1");
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
-            "location1");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg1");
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
-            "location2");
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg2");
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
-            "location3");
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg3");
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
-            "location3");
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg3");
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
-            "location1");
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    attributionMatcher->set_position(Position::LAST);
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg0");
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
-            "location1");
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg1");
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
-            "location1");
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg1");
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
-            "location2");
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg2");
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
-            "location3");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg3");
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
-            "location3");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string(
-            "pkg3");
-    attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(1)->set_eq_string(
-            "location1");
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-}
-
-TEST(AtomMatcherTest, TestUidFieldMatcher) {
-    sp<UidMap> uidMap = new UidMap();
-    uidMap->updateMap(
-            1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
-            {android::String16("v1"), android::String16("v1"), android::String16("v2"),
-             android::String16("v1"), android::String16("v2")},
-            {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"),
-             android::String16("Pkg2"), android::String16("PkG3")} /* package name list */,
-            {android::String16(""), android::String16(""), android::String16(""),
-             android::String16(""), android::String16("")});
-
-    // Set up matcher
-    AtomMatcher matcher;
-    auto simpleMatcher = matcher.mutable_simple_atom_matcher();
-    simpleMatcher->set_atom_id(TAG_ID);
-    simpleMatcher->add_field_value_matcher()->set_field(1);
-    simpleMatcher->mutable_field_value_matcher(0)->set_eq_string("pkg0");
-
-    // Make event without is_uid annotation.
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    makeIntLogEvent(&event1, TAG_ID, 0, 1111);
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event1));
-
-    // Make event with is_uid annotation.
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    makeIntWithBoolAnnotationLogEvent(&event2, TAG_ID_2, 1111, ANNOTATION_ID_IS_UID, true);
-
-    // Event has is_uid annotation, so mapping from uid to package name occurs.
-    simpleMatcher->set_atom_id(TAG_ID_2);
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2));
-
-    // Event has is_uid annotation, but uid maps to different package name.
-    simpleMatcher->mutable_field_value_matcher(0)->set_eq_string("Pkg2");
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event2));
-}
-
-TEST(AtomMatcherTest, TestNeqAnyStringMatcher) {
-    sp<UidMap> uidMap = new UidMap();
-    uidMap->updateMap(
-            1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
-            {android::String16("v1"), android::String16("v1"), android::String16("v2"),
-             android::String16("v1"), android::String16("v2")},
-            {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"),
-             android::String16("Pkg2"), android::String16("PkG3")} /* package name list */,
-            {android::String16(""), android::String16(""), android::String16(""),
-             android::String16(""), android::String16("")});
-
-    std::vector<int> attributionUids = {1111, 2222, 3333, 1066};
-    std::vector<string> attributionTags = {"location1", "location2", "location3", "location3"};
-
-    // Set up the event
-    LogEvent event(/*uid=*/0, /*pid=*/0);
-    makeAttributionLogEvent(&event, TAG_ID, 0, attributionUids, attributionTags, "some value");
-
-    // Set up the matcher
-    AtomMatcher matcher;
-    auto simpleMatcher = matcher.mutable_simple_atom_matcher();
-    simpleMatcher->set_atom_id(TAG_ID);
-
-    // Match first node.
-    auto attributionMatcher = simpleMatcher->add_field_value_matcher();
-    attributionMatcher->set_field(FIELD_ID_1);
-    attributionMatcher->set_position(Position::FIRST);
-    attributionMatcher->mutable_matches_tuple()->add_field_value_matcher()->set_field(
-            ATTRIBUTION_UID_FIELD_ID);
-    auto neqStringList = attributionMatcher->mutable_matches_tuple()
-                                 ->mutable_field_value_matcher(0)
-                                 ->mutable_neq_any_string();
-    neqStringList->add_str_value("pkg2");
-    neqStringList->add_str_value("pkg3");
-
-    auto fieldMatcher = simpleMatcher->add_field_value_matcher();
-    fieldMatcher->set_field(FIELD_ID_2);
-    fieldMatcher->set_eq_string("some value");
-
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    neqStringList->Clear();
-    neqStringList->add_str_value("pkg1");
-    neqStringList->add_str_value("pkg3");
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    attributionMatcher->set_position(Position::ANY);
-    neqStringList->Clear();
-    neqStringList->add_str_value("maps.com");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    neqStringList->Clear();
-    neqStringList->add_str_value("PkG3");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    attributionMatcher->set_position(Position::LAST);
-    neqStringList->Clear();
-    neqStringList->add_str_value("AID_STATSD");
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-}
-
-TEST(AtomMatcherTest, TestEqAnyStringMatcher) {
-    sp<UidMap> uidMap = new UidMap();
-    uidMap->updateMap(
-            1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
-            {android::String16("v1"), android::String16("v1"), android::String16("v2"),
-             android::String16("v1"), android::String16("v2")},
-            {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"),
-             android::String16("Pkg2"), android::String16("PkG3")} /* package name list */,
-            {android::String16(""), android::String16(""), android::String16(""),
-             android::String16(""), android::String16("")});
-
-    std::vector<int> attributionUids = {1067, 2222, 3333, 1066};
-    std::vector<string> attributionTags = {"location1", "location2", "location3", "location3"};
-
-    // Set up the event
-    LogEvent event(/*uid=*/0, /*pid=*/0);
-    makeAttributionLogEvent(&event, TAG_ID, 0, attributionUids, attributionTags, "some value");
-
-    // Set up the matcher
-    AtomMatcher matcher;
-    auto simpleMatcher = matcher.mutable_simple_atom_matcher();
-    simpleMatcher->set_atom_id(TAG_ID);
-
-    // Match first node.
-    auto attributionMatcher = simpleMatcher->add_field_value_matcher();
-    attributionMatcher->set_field(FIELD_ID_1);
-    attributionMatcher->set_position(Position::FIRST);
-    attributionMatcher->mutable_matches_tuple()->add_field_value_matcher()->set_field(
-            ATTRIBUTION_UID_FIELD_ID);
-    auto eqStringList = attributionMatcher->mutable_matches_tuple()
-                                ->mutable_field_value_matcher(0)
-                                ->mutable_eq_any_string();
-    eqStringList->add_str_value("AID_ROOT");
-    eqStringList->add_str_value("AID_INCIDENTD");
-
-    auto fieldMatcher = simpleMatcher->add_field_value_matcher();
-    fieldMatcher->set_field(FIELD_ID_2);
-    fieldMatcher->set_eq_string("some value");
-
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    attributionMatcher->set_position(Position::ANY);
-    eqStringList->Clear();
-    eqStringList->add_str_value("AID_STATSD");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    eqStringList->Clear();
-    eqStringList->add_str_value("pkg1");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    auto normalStringField = fieldMatcher->mutable_eq_any_string();
-    normalStringField->add_str_value("some value123");
-    normalStringField->add_str_value("some value");
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    normalStringField->Clear();
-    normalStringField->add_str_value("AID_STATSD");
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    eqStringList->Clear();
-    eqStringList->add_str_value("maps.com");
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-}
-
-TEST(AtomMatcherTest, TestBoolMatcher) {
-    sp<UidMap> uidMap = new UidMap();
-    // Set up the matcher
-    AtomMatcher matcher;
-    auto simpleMatcher = matcher.mutable_simple_atom_matcher();
-    simpleMatcher->set_atom_id(TAG_ID);
-    auto keyValue1 = simpleMatcher->add_field_value_matcher();
-    keyValue1->set_field(FIELD_ID_1);
-    auto keyValue2 = simpleMatcher->add_field_value_matcher();
-    keyValue2->set_field(FIELD_ID_2);
-
-    // Set up the event
-    LogEvent event(/*uid=*/0, /*pid=*/0);
-    makeBoolLogEvent(&event, TAG_ID, 0, true, false);
-
-    // Test
-    keyValue1->set_eq_bool(true);
-    keyValue2->set_eq_bool(false);
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    keyValue1->set_eq_bool(false);
-    keyValue2->set_eq_bool(false);
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    keyValue1->set_eq_bool(false);
-    keyValue2->set_eq_bool(true);
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    keyValue1->set_eq_bool(true);
-    keyValue2->set_eq_bool(true);
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-}
-
-TEST(AtomMatcherTest, TestStringMatcher) {
-    sp<UidMap> uidMap = new UidMap();
-    // Set up the matcher
-    AtomMatcher matcher;
-    auto simpleMatcher = matcher.mutable_simple_atom_matcher();
-    simpleMatcher->set_atom_id(TAG_ID);
-    auto keyValue = simpleMatcher->add_field_value_matcher();
-    keyValue->set_field(FIELD_ID_1);
-    keyValue->set_eq_string("some value");
-
-    // Set up the event
-    LogEvent event(/*uid=*/0, /*pid=*/0);
-    makeStringLogEvent(&event, TAG_ID, 0, "some value");
-
-    // Test
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-}
-
-TEST(AtomMatcherTest, TestMultiFieldsMatcher) {
-    sp<UidMap> uidMap = new UidMap();
-    // Set up the matcher
-    AtomMatcher matcher;
-    auto simpleMatcher = matcher.mutable_simple_atom_matcher();
-    simpleMatcher->set_atom_id(TAG_ID);
-    auto keyValue1 = simpleMatcher->add_field_value_matcher();
-    keyValue1->set_field(FIELD_ID_1);
-    auto keyValue2 = simpleMatcher->add_field_value_matcher();
-    keyValue2->set_field(FIELD_ID_2);
-
-    // Set up the event
-    LogEvent event(/*uid=*/0, /*pid=*/0);
-    CreateTwoValueLogEvent(&event, TAG_ID, 0, 2, 3);
-
-    // Test
-    keyValue1->set_eq_int(2);
-    keyValue2->set_eq_int(3);
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    keyValue1->set_eq_int(2);
-    keyValue2->set_eq_int(4);
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    keyValue1->set_eq_int(4);
-    keyValue2->set_eq_int(3);
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-}
-
-TEST(AtomMatcherTest, TestIntComparisonMatcher) {
-    sp<UidMap> uidMap = new UidMap();
-    // Set up the matcher
-    AtomMatcher matcher;
-    auto simpleMatcher = matcher.mutable_simple_atom_matcher();
-
-    simpleMatcher->set_atom_id(TAG_ID);
-    auto keyValue = simpleMatcher->add_field_value_matcher();
-    keyValue->set_field(FIELD_ID_1);
-
-    // Set up the event
-    LogEvent event(/*uid=*/0, /*pid=*/0);
-    makeIntLogEvent(&event, TAG_ID, 0, 11);
-
-    // Test
-
-    // eq_int
-    keyValue->set_eq_int(10);
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-    keyValue->set_eq_int(11);
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    keyValue->set_eq_int(12);
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    // lt_int
-    keyValue->set_lt_int(10);
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-    keyValue->set_lt_int(11);
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-    keyValue->set_lt_int(12);
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    // lte_int
-    keyValue->set_lte_int(10);
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-    keyValue->set_lte_int(11);
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    keyValue->set_lte_int(12);
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    // gt_int
-    keyValue->set_gt_int(10);
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    keyValue->set_gt_int(11);
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-    keyValue->set_gt_int(12);
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-
-    // gte_int
-    keyValue->set_gte_int(10);
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    keyValue->set_gte_int(11);
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
-    keyValue->set_gte_int(12);
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
-}
-
-TEST(AtomMatcherTest, TestFloatComparisonMatcher) {
-    sp<UidMap> uidMap = new UidMap();
-    // Set up the matcher
-    AtomMatcher matcher;
-    auto simpleMatcher = matcher.mutable_simple_atom_matcher();
-    simpleMatcher->set_atom_id(TAG_ID);
-
-    auto keyValue = simpleMatcher->add_field_value_matcher();
-    keyValue->set_field(FIELD_ID_1);
-
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    makeFloatLogEvent(&event1, TAG_ID, 0, 10.1f);
-    keyValue->set_lt_float(10.0);
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event1));
-
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    makeFloatLogEvent(&event2, TAG_ID, 0, 9.9f);
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event2));
-
-    LogEvent event3(/*uid=*/0, /*pid=*/0);
-    makeFloatLogEvent(&event3, TAG_ID, 0, 10.1f);
-    keyValue->set_gt_float(10.0);
-    EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event3));
-
-    LogEvent event4(/*uid=*/0, /*pid=*/0);
-    makeFloatLogEvent(&event4, TAG_ID, 0, 9.9f);
-    EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event4));
-}
-
-// Helper for the composite matchers.
-void addSimpleMatcher(SimpleAtomMatcher* simpleMatcher, int tag, int key, int val) {
-    simpleMatcher->set_atom_id(tag);
-    auto keyValue = simpleMatcher->add_field_value_matcher();
-    keyValue->set_field(key);
-    keyValue->set_eq_int(val);
-}
-
-TEST(AtomMatcherTest, TestAndMatcher) {
-    // Set up the matcher
-    LogicalOperation operation = LogicalOperation::AND;
-
-    vector<int> children;
-    children.push_back(0);
-    children.push_back(1);
-    children.push_back(2);
-
-    vector<MatchingState> matcherResults;
-    matcherResults.push_back(MatchingState::kMatched);
-    matcherResults.push_back(MatchingState::kNotMatched);
-    matcherResults.push_back(MatchingState::kMatched);
-
-    EXPECT_FALSE(combinationMatch(children, operation, matcherResults));
-
-    matcherResults.clear();
-    matcherResults.push_back(MatchingState::kMatched);
-    matcherResults.push_back(MatchingState::kMatched);
-    matcherResults.push_back(MatchingState::kMatched);
-
-    EXPECT_TRUE(combinationMatch(children, operation, matcherResults));
-}
-
-TEST(AtomMatcherTest, TestOrMatcher) {
-    // Set up the matcher
-    LogicalOperation operation = LogicalOperation::OR;
-
-    vector<int> children;
-    children.push_back(0);
-    children.push_back(1);
-    children.push_back(2);
-
-    vector<MatchingState> matcherResults;
-    matcherResults.push_back(MatchingState::kMatched);
-    matcherResults.push_back(MatchingState::kNotMatched);
-    matcherResults.push_back(MatchingState::kMatched);
-
-    EXPECT_TRUE(combinationMatch(children, operation, matcherResults));
-
-    matcherResults.clear();
-    matcherResults.push_back(MatchingState::kNotMatched);
-    matcherResults.push_back(MatchingState::kNotMatched);
-    matcherResults.push_back(MatchingState::kNotMatched);
-
-    EXPECT_FALSE(combinationMatch(children, operation, matcherResults));
-}
-
-TEST(AtomMatcherTest, TestNotMatcher) {
-    // Set up the matcher
-    LogicalOperation operation = LogicalOperation::NOT;
-
-    vector<int> children;
-    children.push_back(0);
-
-    vector<MatchingState> matcherResults;
-    matcherResults.push_back(MatchingState::kMatched);
-
-    EXPECT_FALSE(combinationMatch(children, operation, matcherResults));
-
-    matcherResults.clear();
-    matcherResults.push_back(MatchingState::kNotMatched);
-    EXPECT_TRUE(combinationMatch(children, operation, matcherResults));
-}
-
-TEST(AtomMatcherTest, TestNandMatcher) {
-    // Set up the matcher
-    LogicalOperation operation = LogicalOperation::NAND;
-
-    vector<int> children;
-    children.push_back(0);
-    children.push_back(1);
-
-    vector<MatchingState> matcherResults;
-    matcherResults.push_back(MatchingState::kMatched);
-    matcherResults.push_back(MatchingState::kNotMatched);
-
-    EXPECT_TRUE(combinationMatch(children, operation, matcherResults));
-
-    matcherResults.clear();
-    matcherResults.push_back(MatchingState::kNotMatched);
-    matcherResults.push_back(MatchingState::kNotMatched);
-    EXPECT_TRUE(combinationMatch(children, operation, matcherResults));
-
-    matcherResults.clear();
-    matcherResults.push_back(MatchingState::kMatched);
-    matcherResults.push_back(MatchingState::kMatched);
-    EXPECT_FALSE(combinationMatch(children, operation, matcherResults));
-}
-
-TEST(AtomMatcherTest, TestNorMatcher) {
-    // Set up the matcher
-    LogicalOperation operation = LogicalOperation::NOR;
-
-    vector<int> children;
-    children.push_back(0);
-    children.push_back(1);
-
-    vector<MatchingState> matcherResults;
-    matcherResults.push_back(MatchingState::kMatched);
-    matcherResults.push_back(MatchingState::kNotMatched);
-
-    EXPECT_FALSE(combinationMatch(children, operation, matcherResults));
-
-    matcherResults.clear();
-    matcherResults.push_back(MatchingState::kNotMatched);
-    matcherResults.push_back(MatchingState::kNotMatched);
-    EXPECT_TRUE(combinationMatch(children, operation, matcherResults));
-
-    matcherResults.clear();
-    matcherResults.push_back(MatchingState::kMatched);
-    matcherResults.push_back(MatchingState::kMatched);
-    EXPECT_FALSE(combinationMatch(children, operation, matcherResults));
-}
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp
deleted file mode 100644
index bde59f4..0000000
--- a/cmds/statsd/tests/LogEvent_test.cpp
+++ /dev/null
@@ -1,371 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/logd/LogEvent.h"
-
-#include <gtest/gtest.h>
-
-#include "frameworks/proto_logging/stats/atoms.pb.h"
-#include "frameworks/proto_logging/stats/enums/stats/launcher/launcher.pb.h"
-#include "log/log_event_list.h"
-#include "stats_event.h"
-
-#ifdef __ANDROID__
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using std::string;
-using std::vector;
-using util::ProtoOutputStream;
-using util::ProtoReader;
-
-namespace {
-
-Field getField(int32_t tag, const vector<int32_t>& pos, int32_t depth, const vector<bool>& last) {
-    Field f(tag, (int32_t*)pos.data(), depth);
-
-    // For loop starts at 1 because the last field at depth 0 is not decorated.
-    for (int i = 1; i < depth; i++) {
-        if (last[i]) f.decorateLastPos(i);
-    }
-
-    return f;
-}
-
-void createIntWithBoolAnnotationLogEvent(LogEvent* logEvent, uint8_t annotationId,
-                                         bool annotationValue) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, /*atomId=*/100);
-    AStatsEvent_writeInt32(statsEvent, 10);
-    AStatsEvent_addBoolAnnotation(statsEvent, annotationId, annotationValue);
-    AStatsEvent_build(statsEvent);
-
-    size_t size;
-    uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
-    EXPECT_TRUE(logEvent->parseBuffer(buf, size));
-
-    AStatsEvent_release(statsEvent);
-}
-
-void createIntWithIntAnnotationLogEvent(LogEvent* logEvent, uint8_t annotationId,
-                                        int annotationValue) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, /*atomId=*/100);
-    AStatsEvent_writeInt32(statsEvent, 10);
-    AStatsEvent_addInt32Annotation(statsEvent, annotationId, annotationValue);
-    AStatsEvent_build(statsEvent);
-
-    size_t size;
-    uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
-    EXPECT_TRUE(logEvent->parseBuffer(buf, size));
-
-    AStatsEvent_release(statsEvent);
-}
-
-}  // anonymous namespace
-
-TEST(LogEventTest, TestPrimitiveParsing) {
-    AStatsEvent* event = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(event, 100);
-    AStatsEvent_writeInt32(event, 10);
-    AStatsEvent_writeInt64(event, 0x123456789);
-    AStatsEvent_writeFloat(event, 2.0);
-    AStatsEvent_writeBool(event, true);
-    AStatsEvent_build(event);
-
-    size_t size;
-    uint8_t* buf = AStatsEvent_getBuffer(event, &size);
-
-    LogEvent logEvent(/*uid=*/1000, /*pid=*/1001);
-    EXPECT_TRUE(logEvent.parseBuffer(buf, size));
-
-    EXPECT_EQ(100, logEvent.GetTagId());
-    EXPECT_EQ(1000, logEvent.GetUid());
-    EXPECT_EQ(1001, logEvent.GetPid());
-    EXPECT_FALSE(logEvent.hasAttributionChain());
-
-    const vector<FieldValue>& values = logEvent.getValues();
-    ASSERT_EQ(4, values.size());
-
-    const FieldValue& int32Item = values[0];
-    Field expectedField = getField(100, {1, 1, 1}, 0, {false, false, false});
-    EXPECT_EQ(expectedField, int32Item.mField);
-    EXPECT_EQ(Type::INT, int32Item.mValue.getType());
-    EXPECT_EQ(10, int32Item.mValue.int_value);
-
-    const FieldValue& int64Item = values[1];
-    expectedField = getField(100, {2, 1, 1}, 0, {false, false, false});
-    EXPECT_EQ(expectedField, int64Item.mField);
-    EXPECT_EQ(Type::LONG, int64Item.mValue.getType());
-    EXPECT_EQ(0x123456789, int64Item.mValue.long_value);
-
-    const FieldValue& floatItem = values[2];
-    expectedField = getField(100, {3, 1, 1}, 0, {false, false, false});
-    EXPECT_EQ(expectedField, floatItem.mField);
-    EXPECT_EQ(Type::FLOAT, floatItem.mValue.getType());
-    EXPECT_EQ(2.0, floatItem.mValue.float_value);
-
-    const FieldValue& boolItem = values[3];
-    expectedField = getField(100, {4, 1, 1}, 0, {true, false, false});
-    EXPECT_EQ(expectedField, boolItem.mField);
-    EXPECT_EQ(Type::INT, boolItem.mValue.getType());  // FieldValue does not support boolean type
-    EXPECT_EQ(1, boolItem.mValue.int_value);
-
-    AStatsEvent_release(event);
-}
-
-TEST(LogEventTest, TestStringAndByteArrayParsing) {
-    AStatsEvent* event = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(event, 100);
-    string str = "test";
-    AStatsEvent_writeString(event, str.c_str());
-    AStatsEvent_writeByteArray(event, (uint8_t*)str.c_str(), str.length());
-    AStatsEvent_build(event);
-
-    size_t size;
-    uint8_t* buf = AStatsEvent_getBuffer(event, &size);
-
-    LogEvent logEvent(/*uid=*/1000, /*pid=*/1001);
-    EXPECT_TRUE(logEvent.parseBuffer(buf, size));
-
-    EXPECT_EQ(100, logEvent.GetTagId());
-    EXPECT_EQ(1000, logEvent.GetUid());
-    EXPECT_EQ(1001, logEvent.GetPid());
-    EXPECT_FALSE(logEvent.hasAttributionChain());
-
-    const vector<FieldValue>& values = logEvent.getValues();
-    ASSERT_EQ(2, values.size());
-
-    const FieldValue& stringItem = values[0];
-    Field expectedField = getField(100, {1, 1, 1}, 0, {false, false, false});
-    EXPECT_EQ(expectedField, stringItem.mField);
-    EXPECT_EQ(Type::STRING, stringItem.mValue.getType());
-    EXPECT_EQ(str, stringItem.mValue.str_value);
-
-    const FieldValue& storageItem = values[1];
-    expectedField = getField(100, {2, 1, 1}, 0, {true, false, false});
-    EXPECT_EQ(expectedField, storageItem.mField);
-    EXPECT_EQ(Type::STORAGE, storageItem.mValue.getType());
-    vector<uint8_t> expectedValue = {'t', 'e', 's', 't'};
-    EXPECT_EQ(expectedValue, storageItem.mValue.storage_value);
-
-    AStatsEvent_release(event);
-}
-
-TEST(LogEventTest, TestEmptyString) {
-    AStatsEvent* event = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(event, 100);
-    string empty = "";
-    AStatsEvent_writeString(event, empty.c_str());
-    AStatsEvent_build(event);
-
-    size_t size;
-    uint8_t* buf = AStatsEvent_getBuffer(event, &size);
-
-    LogEvent logEvent(/*uid=*/1000, /*pid=*/1001);
-    EXPECT_TRUE(logEvent.parseBuffer(buf, size));
-
-    EXPECT_EQ(100, logEvent.GetTagId());
-    EXPECT_EQ(1000, logEvent.GetUid());
-    EXPECT_EQ(1001, logEvent.GetPid());
-    EXPECT_FALSE(logEvent.hasAttributionChain());
-
-    const vector<FieldValue>& values = logEvent.getValues();
-    ASSERT_EQ(1, values.size());
-
-    const FieldValue& item = values[0];
-    Field expectedField = getField(100, {1, 1, 1}, 0, {true, false, false});
-    EXPECT_EQ(expectedField, item.mField);
-    EXPECT_EQ(Type::STRING, item.mValue.getType());
-    EXPECT_EQ(empty, item.mValue.str_value);
-
-    AStatsEvent_release(event);
-}
-
-TEST(LogEventTest, TestByteArrayWithNullCharacter) {
-    AStatsEvent* event = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(event, 100);
-    uint8_t message[] = {'\t', 'e', '\0', 's', 't'};
-    AStatsEvent_writeByteArray(event, message, 5);
-    AStatsEvent_build(event);
-
-    size_t size;
-    uint8_t* buf = AStatsEvent_getBuffer(event, &size);
-
-    LogEvent logEvent(/*uid=*/1000, /*pid=*/1001);
-    EXPECT_TRUE(logEvent.parseBuffer(buf, size));
-
-    EXPECT_EQ(100, logEvent.GetTagId());
-    EXPECT_EQ(1000, logEvent.GetUid());
-    EXPECT_EQ(1001, logEvent.GetPid());
-
-    const vector<FieldValue>& values = logEvent.getValues();
-    ASSERT_EQ(1, values.size());
-
-    const FieldValue& item = values[0];
-    Field expectedField = getField(100, {1, 1, 1}, 0, {true, false, false});
-    EXPECT_EQ(expectedField, item.mField);
-    EXPECT_EQ(Type::STORAGE, item.mValue.getType());
-    vector<uint8_t> expectedValue(message, message + 5);
-    EXPECT_EQ(expectedValue, item.mValue.storage_value);
-
-    AStatsEvent_release(event);
-}
-
-TEST(LogEventTest, TestAttributionChain) {
-    AStatsEvent* event = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(event, 100);
-
-    string tag1 = "tag1";
-    string tag2 = "tag2";
-
-    uint32_t uids[] = {1001, 1002};
-    const char* tags[] = {tag1.c_str(), tag2.c_str()};
-
-    AStatsEvent_writeAttributionChain(event, uids, tags, 2);
-    AStatsEvent_build(event);
-
-    size_t size;
-    uint8_t* buf = AStatsEvent_getBuffer(event, &size);
-
-    LogEvent logEvent(/*uid=*/1000, /*pid=*/1001);
-    EXPECT_TRUE(logEvent.parseBuffer(buf, size));
-
-    EXPECT_EQ(100, logEvent.GetTagId());
-    EXPECT_EQ(1000, logEvent.GetUid());
-    EXPECT_EQ(1001, logEvent.GetPid());
-
-    const vector<FieldValue>& values = logEvent.getValues();
-    ASSERT_EQ(4, values.size());  // 2 per attribution node
-
-    std::pair<int, int> attrIndexRange;
-    EXPECT_TRUE(logEvent.hasAttributionChain(&attrIndexRange));
-    EXPECT_EQ(0, attrIndexRange.first);
-    EXPECT_EQ(3, attrIndexRange.second);
-
-    // Check first attribution node
-    const FieldValue& uid1Item = values[0];
-    Field expectedField = getField(100, {1, 1, 1}, 2, {true, false, false});
-    EXPECT_EQ(expectedField, uid1Item.mField);
-    EXPECT_EQ(Type::INT, uid1Item.mValue.getType());
-    EXPECT_EQ(1001, uid1Item.mValue.int_value);
-
-    const FieldValue& tag1Item = values[1];
-    expectedField = getField(100, {1, 1, 2}, 2, {true, false, true});
-    EXPECT_EQ(expectedField, tag1Item.mField);
-    EXPECT_EQ(Type::STRING, tag1Item.mValue.getType());
-    EXPECT_EQ(tag1, tag1Item.mValue.str_value);
-
-    // Check second attribution nodes
-    const FieldValue& uid2Item = values[2];
-    expectedField = getField(100, {1, 2, 1}, 2, {true, true, false});
-    EXPECT_EQ(expectedField, uid2Item.mField);
-    EXPECT_EQ(Type::INT, uid2Item.mValue.getType());
-    EXPECT_EQ(1002, uid2Item.mValue.int_value);
-
-    const FieldValue& tag2Item = values[3];
-    expectedField = getField(100, {1, 2, 2}, 2, {true, true, true});
-    EXPECT_EQ(expectedField, tag2Item.mField);
-    EXPECT_EQ(Type::STRING, tag2Item.mValue.getType());
-    EXPECT_EQ(tag2, tag2Item.mValue.str_value);
-
-    AStatsEvent_release(event);
-}
-
-TEST(LogEventTest, TestAnnotationIdIsUid) {
-    LogEvent event(/*uid=*/0, /*pid=*/0);
-    createIntWithBoolAnnotationLogEvent(&event, ANNOTATION_ID_IS_UID, true);
-
-    const vector<FieldValue>& values = event.getValues();
-    ASSERT_EQ(values.size(), 1);
-    EXPECT_EQ(event.getUidFieldIndex(), 0);
-}
-
-TEST(LogEventTest, TestAnnotationIdStateNested) {
-    LogEvent event(/*uid=*/0, /*pid=*/0);
-    createIntWithBoolAnnotationLogEvent(&event, ANNOTATION_ID_STATE_NESTED, true);
-
-    const vector<FieldValue>& values = event.getValues();
-    ASSERT_EQ(values.size(), 1);
-    EXPECT_TRUE(values[0].mAnnotations.isNested());
-}
-
-TEST(LogEventTest, TestPrimaryFieldAnnotation) {
-    LogEvent event(/*uid=*/0, /*pid=*/0);
-    createIntWithBoolAnnotationLogEvent(&event, ANNOTATION_ID_PRIMARY_FIELD, true);
-
-    const vector<FieldValue>& values = event.getValues();
-    ASSERT_EQ(values.size(), 1);
-    EXPECT_TRUE(values[0].mAnnotations.isPrimaryField());
-}
-
-TEST(LogEventTest, TestExclusiveStateAnnotation) {
-    LogEvent event(/*uid=*/0, /*pid=*/0);
-    createIntWithBoolAnnotationLogEvent(&event, ANNOTATION_ID_EXCLUSIVE_STATE, true);
-
-    const vector<FieldValue>& values = event.getValues();
-    ASSERT_EQ(values.size(), 1);
-    EXPECT_TRUE(values[0].mAnnotations.isExclusiveState());
-}
-
-TEST(LogEventTest, TestPrimaryFieldFirstUidAnnotation) {
-    // Event has 10 ints and then an attribution chain
-    int numInts = 10;
-    int firstUidInChainIndex = numInts;
-    string tag1 = "tag1";
-    string tag2 = "tag2";
-    uint32_t uids[] = {1001, 1002};
-    const char* tags[] = {tag1.c_str(), tag2.c_str()};
-
-    // Construct AStatsEvent
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, 100);
-    for (int i = 0; i < numInts; i++) {
-        AStatsEvent_writeInt32(statsEvent, 10);
-    }
-    AStatsEvent_writeAttributionChain(statsEvent, uids, tags, 2);
-    AStatsEvent_addBoolAnnotation(statsEvent, ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID, true);
-    AStatsEvent_build(statsEvent);
-
-    // Construct LogEvent
-    size_t size;
-    uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
-    LogEvent logEvent(/*uid=*/0, /*pid=*/0);
-    EXPECT_TRUE(logEvent.parseBuffer(buf, size));
-    AStatsEvent_release(statsEvent);
-
-    // Check annotation
-    const vector<FieldValue>& values = logEvent.getValues();
-    ASSERT_EQ(values.size(), numInts + 4);
-    EXPECT_TRUE(values[firstUidInChainIndex].mAnnotations.isPrimaryField());
-}
-
-TEST(LogEventTest, TestResetStateAnnotation) {
-    int32_t resetState = 10;
-    LogEvent event(/*uid=*/0, /*pid=*/0);
-    createIntWithIntAnnotationLogEvent(&event, ANNOTATION_ID_TRIGGER_STATE_RESET, resetState);
-
-    const vector<FieldValue>& values = event.getValues();
-    ASSERT_EQ(values.size(), 1);
-    EXPECT_EQ(event.getResetState(), resetState);
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/LogReader_test.cpp b/cmds/statsd/tests/LogReader_test.cpp
deleted file mode 100644
index 7ce1d6a..0000000
--- a/cmds/statsd/tests/LogReader_test.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <gtest/gtest.h>
-
-#include <stdio.h>
-
-TEST(LogReaderTest, TestNothingAtAll) {
-    printf("yay!");
-}
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
deleted file mode 100644
index f05ec49..0000000
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ /dev/null
@@ -1,325 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <private/android_filesystem_config.h>
-#include <stdio.h>
-
-#include <set>
-#include <unordered_map>
-#include <vector>
-
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "metrics/metrics_test_helper.h"
-#include "src/condition/ConditionTracker.h"
-#include "src/matchers/AtomMatchingTracker.h"
-#include "src/metrics/CountMetricProducer.h"
-#include "src/metrics/GaugeMetricProducer.h"
-#include "src/metrics/MetricProducer.h"
-#include "src/metrics/ValueMetricProducer.h"
-#include "src/metrics/parsing_utils/metrics_manager_util.h"
-#include "src/state/StateManager.h"
-#include "statsd_test_util.h"
-
-using namespace testing;
-using android::sp;
-using android::os::statsd::Predicate;
-using std::map;
-using std::set;
-using std::unordered_map;
-using std::vector;
-
-#ifdef __ANDROID__
-
-namespace android {
-namespace os {
-namespace statsd {
-
-namespace {
-const ConfigKey kConfigKey(0, 12345);
-
-const long timeBaseSec = 1000;
-
-StatsdConfig buildGoodConfig() {
-    StatsdConfig config;
-    config.set_id(12345);
-
-    AtomMatcher* eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
-
-    SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
-    simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
-    simpleAtomMatcher->add_field_value_matcher()->set_field(
-            1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
-    simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int(
-            2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
-
-    eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_id(StringToId("SCREEN_IS_OFF"));
-
-    simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
-    simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
-    simpleAtomMatcher->add_field_value_matcher()->set_field(
-            1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
-    simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int(
-            1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/);
-
-    eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF"));
-
-    AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
-    combination->set_operation(LogicalOperation::OR);
-    combination->add_matcher(StringToId("SCREEN_IS_ON"));
-    combination->add_matcher(StringToId("SCREEN_IS_OFF"));
-
-    CountMetric* metric = config.add_count_metric();
-    metric->set_id(3);
-    metric->set_what(StringToId("SCREEN_IS_ON"));
-    metric->set_bucket(ONE_MINUTE);
-    metric->mutable_dimensions_in_what()->set_field(2 /*SCREEN_STATE_CHANGE*/);
-    metric->mutable_dimensions_in_what()->add_child()->set_field(1);
-    return config;
-}
-
-set<int32_t> unionSet(const vector<set<int32_t>> sets) {
-    set<int32_t> toRet;
-    for (const set<int32_t>& s : sets) {
-        toRet.insert(s.begin(), s.end());
-    }
-    return toRet;
-}
-}  // anonymous namespace
-
-TEST(MetricsManagerTest, TestLogSources) {
-    string app1 = "app1";
-    set<int32_t> app1Uids = {1111, 11111};
-    string app2 = "app2";
-    set<int32_t> app2Uids = {2222};
-    string app3 = "app3";
-    set<int32_t> app3Uids = {3333, 1111};
-
-    map<string, set<int32_t>> pkgToUids;
-    pkgToUids[app1] = app1Uids;
-    pkgToUids[app2] = app2Uids;
-    pkgToUids[app3] = app3Uids;
-
-    int32_t atom1 = 10, atom2 = 20, atom3 = 30;
-    sp<MockUidMap> uidMap = new StrictMock<MockUidMap>();
-    EXPECT_CALL(*uidMap, getAppUid(_))
-            .Times(4)
-            .WillRepeatedly(Invoke([&pkgToUids](const string& pkg) {
-                const auto& it = pkgToUids.find(pkg);
-                if (it != pkgToUids.end()) {
-                    return it->second;
-                }
-                return set<int32_t>();
-            }));
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterPullUidProvider(kConfigKey, _)).Times(1);
-    EXPECT_CALL(*pullerManager, UnregisterPullUidProvider(kConfigKey, _)).Times(1);
-
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> periodicAlarmMonitor;
-
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_SYSTEM");
-    config.add_allowed_log_source(app1);
-    config.add_default_pull_packages("AID_SYSTEM");
-    config.add_default_pull_packages("AID_ROOT");
-
-    const set<int32_t> defaultPullUids = {AID_SYSTEM, AID_ROOT};
-
-    PullAtomPackages* pullAtomPackages = config.add_pull_atom_packages();
-    pullAtomPackages->set_atom_id(atom1);
-    pullAtomPackages->add_packages(app1);
-    pullAtomPackages->add_packages(app3);
-
-    pullAtomPackages = config.add_pull_atom_packages();
-    pullAtomPackages->set_atom_id(atom2);
-    pullAtomPackages->add_packages(app2);
-    pullAtomPackages->add_packages("AID_STATSD");
-
-    MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap,
-                                  pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor);
-    EXPECT_TRUE(metricsManager.isConfigValid());
-
-    EXPECT_THAT(metricsManager.mAllowedUid, ElementsAre(AID_SYSTEM));
-    EXPECT_THAT(metricsManager.mAllowedPkg, ElementsAre(app1));
-    EXPECT_THAT(metricsManager.mAllowedLogSources,
-                ContainerEq(unionSet(vector<set<int32_t>>({app1Uids, {AID_SYSTEM}}))));
-    EXPECT_THAT(metricsManager.mDefaultPullUids, ContainerEq(defaultPullUids));
-
-    vector<int32_t> atom1Uids = metricsManager.getPullAtomUids(atom1);
-    EXPECT_THAT(atom1Uids,
-                UnorderedElementsAreArray(unionSet({defaultPullUids, app1Uids, app3Uids})));
-
-    vector<int32_t> atom2Uids = metricsManager.getPullAtomUids(atom2);
-    EXPECT_THAT(atom2Uids,
-                UnorderedElementsAreArray(unionSet({defaultPullUids, app2Uids, {AID_STATSD}})));
-
-    vector<int32_t> atom3Uids = metricsManager.getPullAtomUids(atom3);
-    EXPECT_THAT(atom3Uids, UnorderedElementsAreArray(defaultPullUids));
-}
-
-TEST(MetricsManagerTest, TestLogSourcesOnConfigUpdate) {
-    string app1 = "app1";
-    set<int32_t> app1Uids = {1111, 11111};
-    string app2 = "app2";
-    set<int32_t> app2Uids = {2222};
-    string app3 = "app3";
-    set<int32_t> app3Uids = {3333, 1111};
-
-    map<string, set<int32_t>> pkgToUids;
-    pkgToUids[app1] = app1Uids;
-    pkgToUids[app2] = app2Uids;
-    pkgToUids[app3] = app3Uids;
-
-    int32_t atom1 = 10, atom2 = 20, atom3 = 30;
-    sp<MockUidMap> uidMap = new StrictMock<MockUidMap>();
-    EXPECT_CALL(*uidMap, getAppUid(_))
-            .Times(8)
-            .WillRepeatedly(Invoke([&pkgToUids](const string& pkg) {
-                const auto& it = pkgToUids.find(pkg);
-                if (it != pkgToUids.end()) {
-                    return it->second;
-                }
-                return set<int32_t>();
-            }));
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterPullUidProvider(kConfigKey, _)).Times(1);
-    EXPECT_CALL(*pullerManager, UnregisterPullUidProvider(kConfigKey, _)).Times(1);
-
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> periodicAlarmMonitor;
-
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_SYSTEM");
-    config.add_allowed_log_source(app1);
-    config.add_default_pull_packages("AID_SYSTEM");
-    config.add_default_pull_packages("AID_ROOT");
-
-    PullAtomPackages* pullAtomPackages = config.add_pull_atom_packages();
-    pullAtomPackages->set_atom_id(atom1);
-    pullAtomPackages->add_packages(app1);
-    pullAtomPackages->add_packages(app3);
-
-    pullAtomPackages = config.add_pull_atom_packages();
-    pullAtomPackages->set_atom_id(atom2);
-    pullAtomPackages->add_packages(app2);
-    pullAtomPackages->add_packages("AID_STATSD");
-
-    MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap,
-                                  pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor);
-    EXPECT_TRUE(metricsManager.isConfigValid());
-
-    // Update with new allowed log sources.
-    StatsdConfig newConfig;
-    newConfig.add_allowed_log_source("AID_ROOT");
-    newConfig.add_allowed_log_source(app2);
-    newConfig.add_default_pull_packages("AID_SYSTEM");
-    newConfig.add_default_pull_packages("AID_STATSD");
-
-    pullAtomPackages = newConfig.add_pull_atom_packages();
-    pullAtomPackages->set_atom_id(atom2);
-    pullAtomPackages->add_packages(app1);
-    pullAtomPackages->add_packages(app3);
-
-    pullAtomPackages = newConfig.add_pull_atom_packages();
-    pullAtomPackages->set_atom_id(atom3);
-    pullAtomPackages->add_packages(app2);
-    pullAtomPackages->add_packages("AID_ADB");
-
-    metricsManager.updateConfig(newConfig, timeBaseSec, timeBaseSec, anomalyAlarmMonitor,
-                                periodicAlarmMonitor);
-    EXPECT_TRUE(metricsManager.isConfigValid());
-
-    EXPECT_THAT(metricsManager.mAllowedUid, ElementsAre(AID_ROOT));
-    EXPECT_THAT(metricsManager.mAllowedPkg, ElementsAre(app2));
-    EXPECT_THAT(metricsManager.mAllowedLogSources,
-                ContainerEq(unionSet(vector<set<int32_t>>({app2Uids, {AID_ROOT}}))));
-    const set<int32_t> defaultPullUids = {AID_SYSTEM, AID_STATSD};
-    EXPECT_THAT(metricsManager.mDefaultPullUids, ContainerEq(defaultPullUids));
-
-    vector<int32_t> atom1Uids = metricsManager.getPullAtomUids(atom1);
-    EXPECT_THAT(atom1Uids, UnorderedElementsAreArray(defaultPullUids));
-
-    vector<int32_t> atom2Uids = metricsManager.getPullAtomUids(atom2);
-    EXPECT_THAT(atom2Uids,
-                UnorderedElementsAreArray(unionSet({defaultPullUids, app1Uids, app3Uids})));
-
-    vector<int32_t> atom3Uids = metricsManager.getPullAtomUids(atom3);
-    EXPECT_THAT(atom3Uids,
-                UnorderedElementsAreArray(unionSet({defaultPullUids, app2Uids, {AID_ADB}})));
-}
-
-TEST(MetricsManagerTest, TestCheckLogCredentialsWhitelistedAtom) {
-    sp<UidMap> uidMap;
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> periodicAlarmMonitor;
-
-    StatsdConfig config;
-    config.add_whitelisted_atom_ids(3);
-    config.add_whitelisted_atom_ids(4);
-
-    MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap,
-                                  pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor);
-
-    LogEvent event(0 /* uid */, 0 /* pid */);
-    CreateNoValuesLogEvent(&event, 10 /* atom id */, 0 /* timestamp */);
-    EXPECT_FALSE(metricsManager.checkLogCredentials(event));
-
-    CreateNoValuesLogEvent(&event, 3 /* atom id */, 0 /* timestamp */);
-    EXPECT_TRUE(metricsManager.checkLogCredentials(event));
-
-    CreateNoValuesLogEvent(&event, 4 /* atom id */, 0 /* timestamp */);
-    EXPECT_TRUE(metricsManager.checkLogCredentials(event));
-}
-
-TEST(MetricsManagerTest, TestWhitelistedAtomStateTracker) {
-    sp<UidMap> uidMap;
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> periodicAlarmMonitor;
-
-    StatsdConfig config = buildGoodConfig();
-    config.add_allowed_log_source("AID_SYSTEM");
-    config.add_whitelisted_atom_ids(3);
-    config.add_whitelisted_atom_ids(4);
-
-    State state;
-    state.set_id(1);
-    state.set_atom_id(3);
-
-    *config.add_state() = state;
-
-    config.mutable_count_metric(0)->add_slice_by_state(state.id());
-
-    StateManager::getInstance().clear();
-
-    MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap,
-                                  pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor);
-
-    EXPECT_EQ(0, StateManager::getInstance().getStateTrackersCount());
-    EXPECT_FALSE(metricsManager.isConfigValid());
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
deleted file mode 100644
index 1409b62..0000000
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ /dev/null
@@ -1,1886 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "StatsLogProcessor.h"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <stdio.h>
-
-#include "StatsService.h"
-#include "config/ConfigKey.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "guardrail/StatsdStats.h"
-#include "logd/LogEvent.h"
-#include "packages/UidMap.h"
-#include "statslog_statsdtest.h"
-#include "storage/StorageManager.h"
-#include "tests/statsd_test_util.h"
-
-using namespace android;
-using namespace testing;
-using ::ndk::SharedRefBase;
-using std::shared_ptr;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using android::util::ProtoOutputStream;
-
-#ifdef __ANDROID__
-
-/**
- * Mock MetricsManager (ByteSize() is called).
- */
-class MockMetricsManager : public MetricsManager {
-public:
-    MockMetricsManager()
-        : MetricsManager(ConfigKey(1, 12345), StatsdConfig(), 1000, 1000, new UidMap(),
-                         new StatsPullerManager(),
-                         new AlarmMonitor(10,
-                                          [](const shared_ptr<IStatsCompanionService>&, int64_t) {},
-                                          [](const shared_ptr<IStatsCompanionService>&) {}),
-                         new AlarmMonitor(10,
-                                          [](const shared_ptr<IStatsCompanionService>&, int64_t) {},
-                                          [](const shared_ptr<IStatsCompanionService>&) {})) {
-    }
-
-    MOCK_METHOD0(byteSize, size_t());
-
-    MOCK_METHOD1(dropData, void(const int64_t dropTimeNs));
-};
-
-TEST(StatsLogProcessorTest, TestRateLimitByteSize) {
-    sp<UidMap> m = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> periodicAlarmMonitor;
-    // Construct the processor with a no-op sendBroadcast function that does nothing.
-    StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor, 0,
-                        [](const ConfigKey& key) { return true; },
-                        [](const int&, const vector<int64_t>&) {return true;});
-
-    MockMetricsManager mockMetricsManager;
-
-    ConfigKey key(100, 12345);
-    // Expect only the first flush to trigger a check for byte size since the last two are
-    // rate-limited.
-    EXPECT_CALL(mockMetricsManager, byteSize()).Times(1);
-    p.flushIfNecessaryLocked(key, mockMetricsManager);
-    p.flushIfNecessaryLocked(key, mockMetricsManager);
-    p.flushIfNecessaryLocked(key, mockMetricsManager);
-}
-
-TEST(StatsLogProcessorTest, TestRateLimitBroadcast) {
-    sp<UidMap> m = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> subscriberAlarmMonitor;
-    int broadcastCount = 0;
-    StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
-                        [&broadcastCount](const ConfigKey& key) {
-                            broadcastCount++;
-                            return true;
-                        },
-                        [](const int&, const vector<int64_t>&) {return true;});
-
-    MockMetricsManager mockMetricsManager;
-
-    ConfigKey key(100, 12345);
-    EXPECT_CALL(mockMetricsManager, byteSize())
-            .Times(1)
-            .WillRepeatedly(::testing::Return(int(
-                    StatsdStats::kMaxMetricsBytesPerConfig * .95)));
-
-    // Expect only one broadcast despite always returning a size that should trigger broadcast.
-    p.flushIfNecessaryLocked(key, mockMetricsManager);
-    EXPECT_EQ(1, broadcastCount);
-
-    // b/73089712
-    // This next call to flush should not trigger a broadcast.
-    // p.mLastByteSizeTimes.clear();  // Force another check for byte size.
-    // p.flushIfNecessaryLocked(2, key, mockMetricsManager);
-    // EXPECT_EQ(1, broadcastCount);
-}
-
-TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge) {
-    sp<UidMap> m = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> subscriberAlarmMonitor;
-    int broadcastCount = 0;
-    StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
-                        [&broadcastCount](const ConfigKey& key) {
-                            broadcastCount++;
-                            return true;
-                        },
-                        [](const int&, const vector<int64_t>&) {return true;});
-
-    MockMetricsManager mockMetricsManager;
-
-    ConfigKey key(100, 12345);
-    EXPECT_CALL(mockMetricsManager, byteSize())
-            .Times(1)
-            .WillRepeatedly(::testing::Return(int(StatsdStats::kMaxMetricsBytesPerConfig * 1.2)));
-
-    EXPECT_CALL(mockMetricsManager, dropData(_)).Times(1);
-
-    // Expect to call the onDumpReport and skip the broadcast.
-    p.flushIfNecessaryLocked(key, mockMetricsManager);
-    EXPECT_EQ(0, broadcastCount);
-}
-
-StatsdConfig MakeConfig(bool includeMetric) {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-
-    if (includeMetric) {
-        auto appCrashMatcher = CreateProcessCrashAtomMatcher();
-        *config.add_atom_matcher() = appCrashMatcher;
-        auto countMetric = config.add_count_metric();
-        countMetric->set_id(StringToId("AppCrashes"));
-        countMetric->set_what(appCrashMatcher.id());
-        countMetric->set_bucket(FIVE_MINUTES);
-    }
-    return config;
-}
-
-TEST(StatsLogProcessorTest, TestUidMapHasSnapshot) {
-    // Setup simple config key corresponding to empty config.
-    sp<UidMap> m = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    m->updateMap(1, {1, 2}, {1, 2}, {String16("v1"), String16("v2")},
-                 {String16("p1"), String16("p2")}, {String16(""), String16("")});
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> subscriberAlarmMonitor;
-    int broadcastCount = 0;
-    StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
-                        [&broadcastCount](const ConfigKey& key) {
-                            broadcastCount++;
-                            return true;
-                        },
-                        [](const int&, const vector<int64_t>&) {return true;});
-    ConfigKey key(3, 4);
-    StatsdConfig config = MakeConfig(true);
-    p.OnConfigUpdated(0, key, config);
-
-    // Expect to get no metrics, but snapshot specified above in uidmap.
-    vector<uint8_t> bytes;
-    p.onDumpReport(key, 1, false, true, ADB_DUMP, FAST, &bytes);
-
-    ConfigMetricsReportList output;
-    output.ParseFromArray(bytes.data(), bytes.size());
-    EXPECT_TRUE(output.reports_size() > 0);
-    auto uidmap = output.reports(0).uid_map();
-    EXPECT_TRUE(uidmap.snapshots_size() > 0);
-    ASSERT_EQ(2, uidmap.snapshots(0).package_info_size());
-}
-
-TEST(StatsLogProcessorTest, TestEmptyConfigHasNoUidMap) {
-    // Setup simple config key corresponding to empty config.
-    sp<UidMap> m = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    m->updateMap(1, {1, 2}, {1, 2}, {String16("v1"), String16("v2")},
-                 {String16("p1"), String16("p2")}, {String16(""), String16("")});
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> subscriberAlarmMonitor;
-    int broadcastCount = 0;
-    StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
-                        [&broadcastCount](const ConfigKey& key) {
-                            broadcastCount++;
-                            return true;
-                        },
-                        [](const int&, const vector<int64_t>&) {return true;});
-    ConfigKey key(3, 4);
-    StatsdConfig config = MakeConfig(false);
-    p.OnConfigUpdated(0, key, config);
-
-    // Expect to get no metrics, but snapshot specified above in uidmap.
-    vector<uint8_t> bytes;
-    p.onDumpReport(key, 1, false, true, ADB_DUMP, FAST, &bytes);
-
-    ConfigMetricsReportList output;
-    output.ParseFromArray(bytes.data(), bytes.size());
-    EXPECT_TRUE(output.reports_size() > 0);
-    EXPECT_FALSE(output.reports(0).has_uid_map());
-}
-
-TEST(StatsLogProcessorTest, TestReportIncludesSubConfig) {
-    // Setup simple config key corresponding to empty config.
-    sp<UidMap> m = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> subscriberAlarmMonitor;
-    int broadcastCount = 0;
-    StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
-                        [&broadcastCount](const ConfigKey& key) {
-                            broadcastCount++;
-                            return true;
-                        },
-                        [](const int&, const vector<int64_t>&) {return true;});
-    ConfigKey key(3, 4);
-    StatsdConfig config;
-    auto annotation = config.add_annotation();
-    annotation->set_field_int64(1);
-    annotation->set_field_int32(2);
-    config.add_allowed_log_source("AID_ROOT");
-    p.OnConfigUpdated(1, key, config);
-
-    // Expect to get no metrics, but snapshot specified above in uidmap.
-    vector<uint8_t> bytes;
-    p.onDumpReport(key, 1, false, true, ADB_DUMP, FAST, &bytes);
-
-    ConfigMetricsReportList output;
-    output.ParseFromArray(bytes.data(), bytes.size());
-    EXPECT_TRUE(output.reports_size() > 0);
-    auto report = output.reports(0);
-    ASSERT_EQ(1, report.annotation_size());
-    EXPECT_EQ(1, report.annotation(0).field_int64());
-    EXPECT_EQ(2, report.annotation(0).field_int32());
-}
-
-TEST(StatsLogProcessorTest, TestOnDumpReportEraseData) {
-    // Setup a simple config.
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-    auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
-    *config.add_atom_matcher() = wakelockAcquireMatcher;
-
-    auto countMetric = config.add_count_metric();
-    countMetric->set_id(123456);
-    countMetric->set_what(wakelockAcquireMatcher.id());
-    countMetric->set_bucket(FIVE_MINUTES);
-
-    ConfigKey cfgKey;
-    sp<StatsLogProcessor> processor = CreateStatsLogProcessor(1, 1, config, cfgKey);
-
-    std::vector<int> attributionUids = {111};
-    std::vector<string> attributionTags = {"App1"};
-    std::unique_ptr<LogEvent> event =
-            CreateAcquireWakelockEvent(2 /*timestamp*/, attributionUids, attributionTags, "wl1");
-    processor->OnLogEvent(event.get());
-
-    vector<uint8_t> bytes;
-    ConfigMetricsReportList output;
-
-    // Dump report WITHOUT erasing data.
-    processor->onDumpReport(cfgKey, 3, true, false /* Do NOT erase data. */, ADB_DUMP, FAST,
-                            &bytes);
-    output.ParseFromArray(bytes.data(), bytes.size());
-    ASSERT_EQ(output.reports_size(), 1);
-    ASSERT_EQ(output.reports(0).metrics_size(), 1);
-    ASSERT_EQ(output.reports(0).metrics(0).count_metrics().data_size(), 1);
-
-    // Dump report WITH erasing data. There should be data since we didn't previously erase it.
-    processor->onDumpReport(cfgKey, 4, true, true /* DO erase data. */, ADB_DUMP, FAST, &bytes);
-    output.ParseFromArray(bytes.data(), bytes.size());
-    ASSERT_EQ(output.reports_size(), 1);
-    ASSERT_EQ(output.reports(0).metrics_size(), 1);
-    ASSERT_EQ(output.reports(0).metrics(0).count_metrics().data_size(), 1);
-
-    // Dump report again. There should be no data since we erased it.
-    processor->onDumpReport(cfgKey, 5, true, true /* DO erase data. */, ADB_DUMP, FAST, &bytes);
-    output.ParseFromArray(bytes.data(), bytes.size());
-    // We don't care whether statsd has a report, as long as it has no count metrics in it.
-    bool noData = output.reports_size() == 0 || output.reports(0).metrics_size() == 0 ||
-                  output.reports(0).metrics(0).count_metrics().data_size() == 0;
-    EXPECT_TRUE(noData);
-}
-
-TEST(StatsLogProcessorTest, TestPullUidProviderSetOnConfigUpdate) {
-    // Setup simple config key corresponding to empty config.
-    sp<UidMap> m = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> subscriberAlarmMonitor;
-    StatsLogProcessor p(
-            m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
-            [](const ConfigKey& key) { return true; },
-            [](const int&, const vector<int64_t>&) { return true; });
-    ConfigKey key(3, 4);
-    StatsdConfig config = MakeConfig(false);
-    p.OnConfigUpdated(0, key, config);
-    EXPECT_NE(pullerManager->mPullUidProviders.find(key), pullerManager->mPullUidProviders.end());
-
-    config.add_default_pull_packages("AID_STATSD");
-    p.OnConfigUpdated(5, key, config);
-    EXPECT_NE(pullerManager->mPullUidProviders.find(key), pullerManager->mPullUidProviders.end());
-
-    p.OnConfigRemoved(key);
-    EXPECT_EQ(pullerManager->mPullUidProviders.find(key), pullerManager->mPullUidProviders.end());
-}
-
-TEST(StatsLogProcessorTest, InvalidConfigRemoved) {
-    // Setup simple config key corresponding to empty config.
-    StatsdStats::getInstance().reset();
-    sp<UidMap> m = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    m->updateMap(1, {1, 2}, {1, 2}, {String16("v1"), String16("v2")},
-                 {String16("p1"), String16("p2")}, {String16(""), String16("")});
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> subscriberAlarmMonitor;
-    StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
-                        [](const ConfigKey& key) { return true; },
-                        [](const int&, const vector<int64_t>&) {return true;});
-    ConfigKey key(3, 4);
-    StatsdConfig config = MakeConfig(true);
-    p.OnConfigUpdated(0, key, config);
-    EXPECT_EQ(1, p.mMetricsManagers.size());
-    EXPECT_NE(p.mMetricsManagers.find(key), p.mMetricsManagers.end());
-    // Cannot assert the size of mConfigStats since it is static and does not get cleared on reset.
-    EXPECT_NE(StatsdStats::getInstance().mConfigStats.end(),
-              StatsdStats::getInstance().mConfigStats.find(key));
-    EXPECT_EQ(0, StatsdStats::getInstance().mIceBox.size());
-
-    StatsdConfig invalidConfig = MakeConfig(true);
-    invalidConfig.clear_allowed_log_source();
-    p.OnConfigUpdated(0, key, invalidConfig);
-    EXPECT_EQ(0, p.mMetricsManagers.size());
-    // The current configs should not contain the invalid config.
-    EXPECT_EQ(StatsdStats::getInstance().mConfigStats.end(),
-              StatsdStats::getInstance().mConfigStats.find(key));
-    // Both "config" and "invalidConfig" should be in the icebox.
-    EXPECT_EQ(2, StatsdStats::getInstance().mIceBox.size());
-
-}
-
-
-TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
-    int uid = 1111;
-
-    // Setup a simple config, no activation
-    StatsdConfig config1;
-    int64_t cfgId1 = 12341;
-    config1.set_id(cfgId1);
-    config1.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-    auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
-    *config1.add_atom_matcher() = wakelockAcquireMatcher;
-
-    long metricId1 = 1234561;
-    long metricId2 = 1234562;
-    auto countMetric1 = config1.add_count_metric();
-    countMetric1->set_id(metricId1);
-    countMetric1->set_what(wakelockAcquireMatcher.id());
-    countMetric1->set_bucket(FIVE_MINUTES);
-
-    auto countMetric2 = config1.add_count_metric();
-    countMetric2->set_id(metricId2);
-    countMetric2->set_what(wakelockAcquireMatcher.id());
-    countMetric2->set_bucket(FIVE_MINUTES);
-
-    ConfigKey cfgKey1(uid, cfgId1);
-
-    // Add another config, with two metrics, one with activation
-    StatsdConfig config2;
-    int64_t cfgId2 = 12342;
-    config2.set_id(cfgId2);
-    config2.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-    *config2.add_atom_matcher() = wakelockAcquireMatcher;
-
-    long metricId3 = 1234561;
-    long metricId4 = 1234562;
-
-    auto countMetric3 = config2.add_count_metric();
-    countMetric3->set_id(metricId3);
-    countMetric3->set_what(wakelockAcquireMatcher.id());
-    countMetric3->set_bucket(FIVE_MINUTES);
-
-    auto countMetric4 = config2.add_count_metric();
-    countMetric4->set_id(metricId4);
-    countMetric4->set_what(wakelockAcquireMatcher.id());
-    countMetric4->set_bucket(FIVE_MINUTES);
-
-    auto metric3Activation = config2.add_metric_activation();
-    metric3Activation->set_metric_id(metricId3);
-    metric3Activation->set_activation_type(ACTIVATE_IMMEDIATELY);
-    auto metric3ActivationTrigger = metric3Activation->add_event_activation();
-    metric3ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
-    metric3ActivationTrigger->set_ttl_seconds(100);
-
-    ConfigKey cfgKey2(uid, cfgId2);
-
-    // Add another config, with two metrics, both with activations
-    StatsdConfig config3;
-    int64_t cfgId3 = 12343;
-    config3.set_id(cfgId3);
-    config3.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-    *config3.add_atom_matcher() = wakelockAcquireMatcher;
-
-    long metricId5 = 1234565;
-    long metricId6 = 1234566;
-    auto countMetric5 = config3.add_count_metric();
-    countMetric5->set_id(metricId5);
-    countMetric5->set_what(wakelockAcquireMatcher.id());
-    countMetric5->set_bucket(FIVE_MINUTES);
-
-    auto countMetric6 = config3.add_count_metric();
-    countMetric6->set_id(metricId6);
-    countMetric6->set_what(wakelockAcquireMatcher.id());
-    countMetric6->set_bucket(FIVE_MINUTES);
-
-    auto metric5Activation = config3.add_metric_activation();
-    metric5Activation->set_metric_id(metricId5);
-    metric5Activation->set_activation_type(ACTIVATE_IMMEDIATELY);
-    auto metric5ActivationTrigger = metric5Activation->add_event_activation();
-    metric5ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
-    metric5ActivationTrigger->set_ttl_seconds(100);
-
-    auto metric6Activation = config3.add_metric_activation();
-    metric6Activation->set_metric_id(metricId6);
-    metric6Activation->set_activation_type(ACTIVATE_IMMEDIATELY);
-    auto metric6ActivationTrigger = metric6Activation->add_event_activation();
-    metric6ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
-    metric6ActivationTrigger->set_ttl_seconds(200);
-
-    ConfigKey cfgKey3(uid, cfgId3);
-
-    sp<UidMap> m = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> subscriberAlarmMonitor;
-    vector<int64_t> activeConfigsBroadcast;
-
-    long timeBase1 = 1;
-    int broadcastCount = 0;
-    StatsLogProcessor processor(
-            m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, timeBase1,
-            [](const ConfigKey& key) { return true; },
-            [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-                                                             const vector<int64_t>& activeConfigs) {
-                broadcastCount++;
-                EXPECT_EQ(broadcastUid, uid);
-                activeConfigsBroadcast.clear();
-                activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
-                                              activeConfigs.end());
-                return true;
-            });
-
-    processor.OnConfigUpdated(1, cfgKey1, config1);
-    processor.OnConfigUpdated(2, cfgKey2, config2);
-    processor.OnConfigUpdated(3, cfgKey3, config3);
-
-    ASSERT_EQ(3, processor.mMetricsManagers.size());
-
-    // Expect the first config and both metrics in it to be active.
-    auto it = processor.mMetricsManagers.find(cfgKey1);
-    EXPECT_TRUE(it != processor.mMetricsManagers.end());
-    auto& metricsManager1 = it->second;
-    EXPECT_TRUE(metricsManager1->isActive());
-
-    auto metricIt = metricsManager1->mAllMetricProducers.begin();
-    for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
-        if ((*metricIt)->getMetricId() == metricId1) {
-            break;
-        }
-    }
-    EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
-    auto& metricProducer1 = *metricIt;
-    EXPECT_TRUE(metricProducer1->isActive());
-
-    metricIt = metricsManager1->mAllMetricProducers.begin();
-    for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
-        if ((*metricIt)->getMetricId() == metricId2) {
-            break;
-        }
-    }
-    EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
-    auto& metricProducer2 = *metricIt;
-    EXPECT_TRUE(metricProducer2->isActive());
-
-    // Expect config 2 to be active. Metric 3 shouldn't be active, metric 4 should be active.
-    it = processor.mMetricsManagers.find(cfgKey2);
-    EXPECT_TRUE(it != processor.mMetricsManagers.end());
-    auto& metricsManager2 = it->second;
-    EXPECT_TRUE(metricsManager2->isActive());
-
-    metricIt = metricsManager2->mAllMetricProducers.begin();
-    for (; metricIt != metricsManager2->mAllMetricProducers.end(); metricIt++) {
-        if ((*metricIt)->getMetricId() == metricId3) {
-            break;
-        }
-    }
-    EXPECT_TRUE(metricIt != metricsManager2->mAllMetricProducers.end());
-    auto& metricProducer3 = *metricIt;
-    EXPECT_FALSE(metricProducer3->isActive());
-
-    metricIt = metricsManager2->mAllMetricProducers.begin();
-    for (; metricIt != metricsManager2->mAllMetricProducers.end(); metricIt++) {
-        if ((*metricIt)->getMetricId() == metricId4) {
-            break;
-        }
-    }
-    EXPECT_TRUE(metricIt != metricsManager2->mAllMetricProducers.end());
-    auto& metricProducer4 = *metricIt;
-    EXPECT_TRUE(metricProducer4->isActive());
-
-    // Expect the third config and both metrics in it to be inactive.
-    it = processor.mMetricsManagers.find(cfgKey3);
-    EXPECT_TRUE(it != processor.mMetricsManagers.end());
-    auto& metricsManager3 = it->second;
-    EXPECT_FALSE(metricsManager3->isActive());
-
-    metricIt = metricsManager3->mAllMetricProducers.begin();
-    for (; metricIt != metricsManager2->mAllMetricProducers.end(); metricIt++) {
-        if ((*metricIt)->getMetricId() == metricId5) {
-            break;
-        }
-    }
-    EXPECT_TRUE(metricIt != metricsManager3->mAllMetricProducers.end());
-    auto& metricProducer5 = *metricIt;
-    EXPECT_FALSE(metricProducer5->isActive());
-
-    metricIt = metricsManager3->mAllMetricProducers.begin();
-    for (; metricIt != metricsManager3->mAllMetricProducers.end(); metricIt++) {
-        if ((*metricIt)->getMetricId() == metricId6) {
-            break;
-        }
-    }
-    EXPECT_TRUE(metricIt != metricsManager3->mAllMetricProducers.end());
-    auto& metricProducer6 = *metricIt;
-    EXPECT_FALSE(metricProducer6->isActive());
-
-    // No broadcast for active configs should have happened yet.
-    EXPECT_EQ(broadcastCount, 0);
-
-    // Activate all 3 metrics that were not active.
-    std::vector<int> attributionUids = {111};
-    std::vector<string> attributionTags = {"App1"};
-    std::unique_ptr<LogEvent> event =
-            CreateAcquireWakelockEvent(timeBase1 + 100, attributionUids, attributionTags, "wl1");
-    processor.OnLogEvent(event.get());
-
-    // Assert that all 3 configs are active.
-    EXPECT_TRUE(metricsManager1->isActive());
-    EXPECT_TRUE(metricsManager2->isActive());
-    EXPECT_TRUE(metricsManager3->isActive());
-
-    // A broadcast should have happened, and all 3 configs should be active in the broadcast.
-    EXPECT_EQ(broadcastCount, 1);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 3);
-    EXPECT_TRUE(std::find(activeConfigsBroadcast.begin(), activeConfigsBroadcast.end(), cfgId1) !=
-                activeConfigsBroadcast.end());
-    EXPECT_TRUE(std::find(activeConfigsBroadcast.begin(), activeConfigsBroadcast.end(), cfgId2) !=
-                activeConfigsBroadcast.end());
-    EXPECT_TRUE(std::find(activeConfigsBroadcast.begin(), activeConfigsBroadcast.end(), cfgId3) !=
-                activeConfigsBroadcast.end());
-
-    // When we shut down, metrics 3 & 5 have 100ns remaining, metric 6 has 100s + 100ns.
-    int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
-    processor.SaveActiveConfigsToDisk(shutDownTime);
-    const int64_t ttl3 = event->GetElapsedTimestampNs() +
-                         metric3ActivationTrigger->ttl_seconds() * NS_PER_SEC - shutDownTime;
-    const int64_t ttl5 = event->GetElapsedTimestampNs() +
-                         metric5ActivationTrigger->ttl_seconds() * NS_PER_SEC - shutDownTime;
-    const int64_t ttl6 = event->GetElapsedTimestampNs() +
-                         metric6ActivationTrigger->ttl_seconds() * NS_PER_SEC - shutDownTime;
-
-    // Create a second StatsLogProcessor and push the same 3 configs.
-    long timeBase2 = 1000;
-    sp<StatsLogProcessor> processor2 =
-            CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
-    processor2->OnConfigUpdated(timeBase2, cfgKey2, config2);
-    processor2->OnConfigUpdated(timeBase2, cfgKey3, config3);
-
-    ASSERT_EQ(3, processor2->mMetricsManagers.size());
-
-    // First config and both metrics are active.
-    it = processor2->mMetricsManagers.find(cfgKey1);
-    EXPECT_TRUE(it != processor2->mMetricsManagers.end());
-    auto& metricsManager1001 = it->second;
-    EXPECT_TRUE(metricsManager1001->isActive());
-
-    metricIt = metricsManager1001->mAllMetricProducers.begin();
-    for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
-        if ((*metricIt)->getMetricId() == metricId1) {
-            break;
-        }
-    }
-    EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
-    auto& metricProducer1001 = *metricIt;
-    EXPECT_TRUE(metricProducer1001->isActive());
-
-    metricIt = metricsManager1001->mAllMetricProducers.begin();
-    for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
-        if ((*metricIt)->getMetricId() == metricId2) {
-            break;
-        }
-    }
-    EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
-    auto& metricProducer1002 = *metricIt;
-    EXPECT_TRUE(metricProducer1002->isActive());
-
-    // Second config is active. Metric 3 is inactive, metric 4 is active.
-    it = processor2->mMetricsManagers.find(cfgKey2);
-    EXPECT_TRUE(it != processor2->mMetricsManagers.end());
-    auto& metricsManager1002 = it->second;
-    EXPECT_TRUE(metricsManager1002->isActive());
-
-    metricIt = metricsManager1002->mAllMetricProducers.begin();
-    for (; metricIt != metricsManager1002->mAllMetricProducers.end(); metricIt++) {
-        if ((*metricIt)->getMetricId() == metricId3) {
-            break;
-        }
-    }
-    EXPECT_TRUE(metricIt != metricsManager1002->mAllMetricProducers.end());
-    auto& metricProducer1003 = *metricIt;
-    EXPECT_FALSE(metricProducer1003->isActive());
-
-    metricIt = metricsManager1002->mAllMetricProducers.begin();
-    for (; metricIt != metricsManager1002->mAllMetricProducers.end(); metricIt++) {
-        if ((*metricIt)->getMetricId() == metricId4) {
-            break;
-        }
-    }
-    EXPECT_TRUE(metricIt != metricsManager1002->mAllMetricProducers.end());
-    auto& metricProducer1004 = *metricIt;
-    EXPECT_TRUE(metricProducer1004->isActive());
-
-    // Config 3 is inactive. both metrics are inactive.
-    it = processor2->mMetricsManagers.find(cfgKey3);
-    EXPECT_TRUE(it != processor2->mMetricsManagers.end());
-    auto& metricsManager1003 = it->second;
-    EXPECT_FALSE(metricsManager1003->isActive());
-    ASSERT_EQ(2, metricsManager1003->mAllMetricProducers.size());
-
-    metricIt = metricsManager1003->mAllMetricProducers.begin();
-    for (; metricIt != metricsManager1002->mAllMetricProducers.end(); metricIt++) {
-        if ((*metricIt)->getMetricId() == metricId5) {
-            break;
-        }
-    }
-    EXPECT_TRUE(metricIt != metricsManager1003->mAllMetricProducers.end());
-    auto& metricProducer1005 = *metricIt;
-    EXPECT_FALSE(metricProducer1005->isActive());
-
-    metricIt = metricsManager1003->mAllMetricProducers.begin();
-    for (; metricIt != metricsManager1003->mAllMetricProducers.end(); metricIt++) {
-        if ((*metricIt)->getMetricId() == metricId6) {
-            break;
-        }
-    }
-    EXPECT_TRUE(metricIt != metricsManager1003->mAllMetricProducers.end());
-    auto& metricProducer1006 = *metricIt;
-    EXPECT_FALSE(metricProducer1006->isActive());
-
-    // Assert that all 3 metrics with activation are inactive and that the ttls were properly set.
-    EXPECT_FALSE(metricProducer1003->isActive());
-    const auto& activation1003 = metricProducer1003->mEventActivationMap.begin()->second;
-    EXPECT_EQ(100 * NS_PER_SEC, activation1003->ttl_ns);
-    EXPECT_EQ(0, activation1003->start_ns);
-    EXPECT_FALSE(metricProducer1005->isActive());
-    const auto& activation1005 = metricProducer1005->mEventActivationMap.begin()->second;
-    EXPECT_EQ(100 * NS_PER_SEC, activation1005->ttl_ns);
-    EXPECT_EQ(0, activation1005->start_ns);
-    EXPECT_FALSE(metricProducer1006->isActive());
-    const auto& activation1006 = metricProducer1006->mEventActivationMap.begin()->second;
-    EXPECT_EQ(200 * NS_PER_SEC, activation1006->ttl_ns);
-    EXPECT_EQ(0, activation1006->start_ns);
-
-    processor2->LoadActiveConfigsFromDisk();
-
-    // After loading activations from disk, assert that all 3 metrics are active.
-    EXPECT_TRUE(metricProducer1003->isActive());
-    EXPECT_EQ(timeBase2 + ttl3 - activation1003->ttl_ns, activation1003->start_ns);
-    EXPECT_TRUE(metricProducer1005->isActive());
-    EXPECT_EQ(timeBase2 + ttl5 - activation1005->ttl_ns, activation1005->start_ns);
-    EXPECT_TRUE(metricProducer1006->isActive());
-    EXPECT_EQ(timeBase2 + ttl6 - activation1006->ttl_ns, activation1003->start_ns);
-
-    // Make sure no more broadcasts have happened.
-    EXPECT_EQ(broadcastCount, 1);
-}
-
-TEST(StatsLogProcessorTest, TestActivationOnBoot) {
-    int uid = 1111;
-
-    StatsdConfig config1;
-    config1.set_id(12341);
-    config1.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-    auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
-    *config1.add_atom_matcher() = wakelockAcquireMatcher;
-
-    long metricId1 = 1234561;
-    long metricId2 = 1234562;
-    auto countMetric1 = config1.add_count_metric();
-    countMetric1->set_id(metricId1);
-    countMetric1->set_what(wakelockAcquireMatcher.id());
-    countMetric1->set_bucket(FIVE_MINUTES);
-
-    auto countMetric2 = config1.add_count_metric();
-    countMetric2->set_id(metricId2);
-    countMetric2->set_what(wakelockAcquireMatcher.id());
-    countMetric2->set_bucket(FIVE_MINUTES);
-
-    auto metric1Activation = config1.add_metric_activation();
-    metric1Activation->set_metric_id(metricId1);
-    metric1Activation->set_activation_type(ACTIVATE_ON_BOOT);
-    auto metric1ActivationTrigger = metric1Activation->add_event_activation();
-    metric1ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
-    metric1ActivationTrigger->set_ttl_seconds(100);
-
-    ConfigKey cfgKey1(uid, 12341);
-    long timeBase1 = 1;
-    sp<StatsLogProcessor> processor =
-            CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
-
-    ASSERT_EQ(1, processor->mMetricsManagers.size());
-    auto it = processor->mMetricsManagers.find(cfgKey1);
-    EXPECT_TRUE(it != processor->mMetricsManagers.end());
-    auto& metricsManager1 = it->second;
-    EXPECT_TRUE(metricsManager1->isActive());
-
-    auto metricIt = metricsManager1->mAllMetricProducers.begin();
-    for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
-        if ((*metricIt)->getMetricId() == metricId1) {
-            break;
-        }
-    }
-    EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
-    auto& metricProducer1 = *metricIt;
-    EXPECT_FALSE(metricProducer1->isActive());
-
-    metricIt = metricsManager1->mAllMetricProducers.begin();
-    for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
-        if ((*metricIt)->getMetricId() == metricId2) {
-            break;
-        }
-    }
-    EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
-    auto& metricProducer2 = *metricIt;
-    EXPECT_TRUE(metricProducer2->isActive());
-
-    const auto& activation1 = metricProducer1->mEventActivationMap.begin()->second;
-    EXPECT_EQ(100 * NS_PER_SEC, activation1->ttl_ns);
-    EXPECT_EQ(0, activation1->start_ns);
-    EXPECT_EQ(kNotActive, activation1->state);
-
-    std::vector<int> attributionUids = {111};
-    std::vector<string> attributionTags = {"App1"};
-    std::unique_ptr<LogEvent> event =
-            CreateAcquireWakelockEvent(timeBase1 + 100, attributionUids, attributionTags, "wl1");
-    processor->OnLogEvent(event.get());
-
-    EXPECT_FALSE(metricProducer1->isActive());
-    EXPECT_EQ(0, activation1->start_ns);
-    EXPECT_EQ(kActiveOnBoot, activation1->state);
-
-    int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
-    processor->SaveActiveConfigsToDisk(shutDownTime);
-    EXPECT_FALSE(metricProducer1->isActive());
-    const int64_t ttl1 = metric1ActivationTrigger->ttl_seconds() * NS_PER_SEC;
-
-    long timeBase2 = 1000;
-    sp<StatsLogProcessor> processor2 =
-            CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
-
-    ASSERT_EQ(1, processor2->mMetricsManagers.size());
-    it = processor2->mMetricsManagers.find(cfgKey1);
-    EXPECT_TRUE(it != processor2->mMetricsManagers.end());
-    auto& metricsManager1001 = it->second;
-    EXPECT_TRUE(metricsManager1001->isActive());
-
-    metricIt = metricsManager1001->mAllMetricProducers.begin();
-    for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
-        if ((*metricIt)->getMetricId() == metricId1) {
-            break;
-        }
-    }
-    EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
-    auto& metricProducer1001 = *metricIt;
-    EXPECT_FALSE(metricProducer1001->isActive());
-
-    metricIt = metricsManager1001->mAllMetricProducers.begin();
-    for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
-        if ((*metricIt)->getMetricId() == metricId2) {
-            break;
-        }
-    }
-    EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
-    auto& metricProducer1002 = *metricIt;
-    EXPECT_TRUE(metricProducer1002->isActive());
-
-    const auto& activation1001 = metricProducer1001->mEventActivationMap.begin()->second;
-    EXPECT_EQ(100 * NS_PER_SEC, activation1001->ttl_ns);
-    EXPECT_EQ(0, activation1001->start_ns);
-    EXPECT_EQ(kNotActive, activation1001->state);
-
-    processor2->LoadActiveConfigsFromDisk();
-
-    EXPECT_TRUE(metricProducer1001->isActive());
-    EXPECT_EQ(timeBase2 + ttl1 - activation1001->ttl_ns, activation1001->start_ns);
-    EXPECT_EQ(kActive, activation1001->state);
-}
-
-TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations) {
-    int uid = 1111;
-
-    // Create config with 2 metrics:
-    // Metric 1: Activate on boot with 2 activations
-    // Metric 2: Always active
-    StatsdConfig config1;
-    config1.set_id(12341);
-    config1.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-    auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
-    auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config1.add_atom_matcher() = wakelockAcquireMatcher;
-    *config1.add_atom_matcher() = screenOnMatcher;
-
-    long metricId1 = 1234561;
-    long metricId2 = 1234562;
-
-    auto countMetric1 = config1.add_count_metric();
-    countMetric1->set_id(metricId1);
-    countMetric1->set_what(wakelockAcquireMatcher.id());
-    countMetric1->set_bucket(FIVE_MINUTES);
-
-    auto countMetric2 = config1.add_count_metric();
-    countMetric2->set_id(metricId2);
-    countMetric2->set_what(wakelockAcquireMatcher.id());
-    countMetric2->set_bucket(FIVE_MINUTES);
-
-    auto metric1Activation = config1.add_metric_activation();
-    metric1Activation->set_metric_id(metricId1);
-    metric1Activation->set_activation_type(ACTIVATE_ON_BOOT);
-    auto metric1ActivationTrigger1 = metric1Activation->add_event_activation();
-    metric1ActivationTrigger1->set_atom_matcher_id(wakelockAcquireMatcher.id());
-    metric1ActivationTrigger1->set_ttl_seconds(100);
-    auto metric1ActivationTrigger2 = metric1Activation->add_event_activation();
-    metric1ActivationTrigger2->set_atom_matcher_id(screenOnMatcher.id());
-    metric1ActivationTrigger2->set_ttl_seconds(200);
-
-    ConfigKey cfgKey1(uid, 12341);
-    long timeBase1 = 1;
-    sp<StatsLogProcessor> processor =
-            CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
-
-    // Metric 1 is not active.
-    // Metric 2 is active.
-    // {{{---------------------------------------------------------------------------
-    ASSERT_EQ(1, processor->mMetricsManagers.size());
-    auto it = processor->mMetricsManagers.find(cfgKey1);
-    EXPECT_TRUE(it != processor->mMetricsManagers.end());
-    auto& metricsManager1 = it->second;
-    EXPECT_TRUE(metricsManager1->isActive());
-
-    auto metricIt = metricsManager1->mAllMetricProducers.begin();
-    for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
-        if ((*metricIt)->getMetricId() == metricId1) {
-            break;
-        }
-    }
-    EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
-    auto& metricProducer1 = *metricIt;
-    EXPECT_FALSE(metricProducer1->isActive());
-
-    metricIt = metricsManager1->mAllMetricProducers.begin();
-    for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
-        if ((*metricIt)->getMetricId() == metricId2) {
-            break;
-        }
-    }
-    EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
-    auto& metricProducer2 = *metricIt;
-    EXPECT_TRUE(metricProducer2->isActive());
-
-    int i = 0;
-    for (; i < metricsManager1->mAllAtomMatchingTrackers.size(); i++) {
-        if (metricsManager1->mAllAtomMatchingTrackers[i]->getId() ==
-            metric1ActivationTrigger1->atom_matcher_id()) {
-            break;
-        }
-    }
-    const auto& activation1 = metricProducer1->mEventActivationMap.at(i);
-    EXPECT_EQ(100 * NS_PER_SEC, activation1->ttl_ns);
-    EXPECT_EQ(0, activation1->start_ns);
-    EXPECT_EQ(kNotActive, activation1->state);
-
-    i = 0;
-    for (; i < metricsManager1->mAllAtomMatchingTrackers.size(); i++) {
-        if (metricsManager1->mAllAtomMatchingTrackers[i]->getId() ==
-            metric1ActivationTrigger2->atom_matcher_id()) {
-            break;
-        }
-    }
-    const auto& activation2 = metricProducer1->mEventActivationMap.at(i);
-    EXPECT_EQ(200 * NS_PER_SEC, activation2->ttl_ns);
-    EXPECT_EQ(0, activation2->start_ns);
-    EXPECT_EQ(kNotActive, activation2->state);
-    // }}}------------------------------------------------------------------------------
-
-    // Trigger Activation 1 for Metric 1
-    std::vector<int> attributionUids = {111};
-    std::vector<string> attributionTags = {"App1"};
-    std::unique_ptr<LogEvent> event =
-            CreateAcquireWakelockEvent(timeBase1 + 100, attributionUids, attributionTags, "wl1");
-    processor->OnLogEvent(event.get());
-
-    // Metric 1 is not active; Activation 1 set to kActiveOnBoot
-    // Metric 2 is active.
-    // {{{---------------------------------------------------------------------------
-    EXPECT_FALSE(metricProducer1->isActive());
-    EXPECT_EQ(0, activation1->start_ns);
-    EXPECT_EQ(kActiveOnBoot, activation1->state);
-    EXPECT_EQ(0, activation2->start_ns);
-    EXPECT_EQ(kNotActive, activation2->state);
-
-    EXPECT_TRUE(metricProducer2->isActive());
-    // }}}-----------------------------------------------------------------------------
-
-    // Simulate shutdown by saving state to disk
-    int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
-    processor->SaveActiveConfigsToDisk(shutDownTime);
-    EXPECT_FALSE(metricProducer1->isActive());
-    int64_t ttl1 = metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC;
-
-    // Simulate device restarted state by creating new instance of StatsLogProcessor with the
-    // same config.
-    long timeBase2 = 1000;
-    sp<StatsLogProcessor> processor2 =
-            CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
-
-    // Metric 1 is not active.
-    // Metric 2 is active.
-    // {{{---------------------------------------------------------------------------
-    ASSERT_EQ(1, processor2->mMetricsManagers.size());
-    it = processor2->mMetricsManagers.find(cfgKey1);
-    EXPECT_TRUE(it != processor2->mMetricsManagers.end());
-    auto& metricsManager1001 = it->second;
-    EXPECT_TRUE(metricsManager1001->isActive());
-
-    metricIt = metricsManager1001->mAllMetricProducers.begin();
-    for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
-        if ((*metricIt)->getMetricId() == metricId1) {
-            break;
-        }
-    }
-    EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
-    auto& metricProducer1001 = *metricIt;
-    EXPECT_FALSE(metricProducer1001->isActive());
-
-    metricIt = metricsManager1001->mAllMetricProducers.begin();
-    for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
-        if ((*metricIt)->getMetricId() == metricId2) {
-            break;
-        }
-    }
-    EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
-    auto& metricProducer1002 = *metricIt;
-    EXPECT_TRUE(metricProducer1002->isActive());
-
-    i = 0;
-    for (; i < metricsManager1001->mAllAtomMatchingTrackers.size(); i++) {
-        if (metricsManager1001->mAllAtomMatchingTrackers[i]->getId() ==
-            metric1ActivationTrigger1->atom_matcher_id()) {
-            break;
-        }
-    }
-    const auto& activation1001_1 = metricProducer1001->mEventActivationMap.at(i);
-    EXPECT_EQ(100 * NS_PER_SEC, activation1001_1->ttl_ns);
-    EXPECT_EQ(0, activation1001_1->start_ns);
-    EXPECT_EQ(kNotActive, activation1001_1->state);
-
-    i = 0;
-    for (; i < metricsManager1001->mAllAtomMatchingTrackers.size(); i++) {
-        if (metricsManager1001->mAllAtomMatchingTrackers[i]->getId() ==
-            metric1ActivationTrigger2->atom_matcher_id()) {
-            break;
-        }
-    }
-
-    const auto& activation1001_2 = metricProducer1001->mEventActivationMap.at(i);
-    EXPECT_EQ(200 * NS_PER_SEC, activation1001_2->ttl_ns);
-    EXPECT_EQ(0, activation1001_2->start_ns);
-    EXPECT_EQ(kNotActive, activation1001_2->state);
-    // }}}-----------------------------------------------------------------------------------
-
-    // Load saved state from disk.
-    processor2->LoadActiveConfigsFromDisk();
-
-    // Metric 1 active; Activation 1 is active, Activation 2 is not active
-    // Metric 2 is active.
-    // {{{---------------------------------------------------------------------------
-    EXPECT_TRUE(metricProducer1001->isActive());
-    EXPECT_EQ(timeBase2 + ttl1 - activation1001_1->ttl_ns, activation1001_1->start_ns);
-    EXPECT_EQ(kActive, activation1001_1->state);
-    EXPECT_EQ(0, activation1001_2->start_ns);
-    EXPECT_EQ(kNotActive, activation1001_2->state);
-
-    EXPECT_TRUE(metricProducer1002->isActive());
-    // }}}--------------------------------------------------------------------------------
-
-    // Trigger Activation 2 for Metric 1.
-    auto screenOnEvent =
-            CreateScreenStateChangedEvent(timeBase2 + 200, android::view::DISPLAY_STATE_ON);
-    processor2->OnLogEvent(screenOnEvent.get());
-
-    // Metric 1 active; Activation 1 is active, Activation 2 is set to kActiveOnBoot
-    // Metric 2 is active.
-    // {{{---------------------------------------------------------------------------
-    EXPECT_TRUE(metricProducer1001->isActive());
-    EXPECT_EQ(timeBase2 + ttl1 - activation1001_1->ttl_ns, activation1001_1->start_ns);
-    EXPECT_EQ(kActive, activation1001_1->state);
-    EXPECT_EQ(0, activation1001_2->start_ns);
-    EXPECT_EQ(kActiveOnBoot, activation1001_2->state);
-
-    EXPECT_TRUE(metricProducer1002->isActive());
-    // }}}---------------------------------------------------------------------------
-
-    // Simulate shutdown by saving state to disk
-    shutDownTime = timeBase2 + 50 * NS_PER_SEC;
-    processor2->SaveActiveConfigsToDisk(shutDownTime);
-    EXPECT_TRUE(metricProducer1001->isActive());
-    EXPECT_TRUE(metricProducer1002->isActive());
-    ttl1 = timeBase2 + metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC - shutDownTime;
-    int64_t ttl2 = metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC;
-
-    // Simulate device restarted state by creating new instance of StatsLogProcessor with the
-    // same config.
-    long timeBase3 = timeBase2 + 120 * NS_PER_SEC;
-    sp<StatsLogProcessor> processor3 =
-            CreateStatsLogProcessor(timeBase3, timeBase3, config1, cfgKey1);
-
-    // Metric 1 is not active.
-    // Metric 2 is active.
-    // {{{---------------------------------------------------------------------------
-    ASSERT_EQ(1, processor3->mMetricsManagers.size());
-    it = processor3->mMetricsManagers.find(cfgKey1);
-    EXPECT_TRUE(it != processor3->mMetricsManagers.end());
-    auto& metricsManagerTimeBase3 = it->second;
-    EXPECT_TRUE(metricsManagerTimeBase3->isActive());
-
-    metricIt = metricsManagerTimeBase3->mAllMetricProducers.begin();
-    for (; metricIt != metricsManagerTimeBase3->mAllMetricProducers.end(); metricIt++) {
-        if ((*metricIt)->getMetricId() == metricId1) {
-            break;
-        }
-    }
-    EXPECT_TRUE(metricIt != metricsManagerTimeBase3->mAllMetricProducers.end());
-    auto& metricProducerTimeBase3_1 = *metricIt;
-    EXPECT_FALSE(metricProducerTimeBase3_1->isActive());
-
-    metricIt = metricsManagerTimeBase3->mAllMetricProducers.begin();
-    for (; metricIt != metricsManagerTimeBase3->mAllMetricProducers.end(); metricIt++) {
-        if ((*metricIt)->getMetricId() == metricId2) {
-            break;
-        }
-    }
-    EXPECT_TRUE(metricIt != metricsManagerTimeBase3->mAllMetricProducers.end());
-    auto& metricProducerTimeBase3_2 = *metricIt;
-    EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
-
-    i = 0;
-    for (; i < metricsManagerTimeBase3->mAllAtomMatchingTrackers.size(); i++) {
-        if (metricsManagerTimeBase3->mAllAtomMatchingTrackers[i]->getId() ==
-            metric1ActivationTrigger1->atom_matcher_id()) {
-            break;
-        }
-    }
-    const auto& activationTimeBase3_1 = metricProducerTimeBase3_1->mEventActivationMap.at(i);
-    EXPECT_EQ(100 * NS_PER_SEC, activationTimeBase3_1->ttl_ns);
-    EXPECT_EQ(0, activationTimeBase3_1->start_ns);
-    EXPECT_EQ(kNotActive, activationTimeBase3_1->state);
-
-    i = 0;
-    for (; i < metricsManagerTimeBase3->mAllAtomMatchingTrackers.size(); i++) {
-        if (metricsManagerTimeBase3->mAllAtomMatchingTrackers[i]->getId() ==
-            metric1ActivationTrigger2->atom_matcher_id()) {
-            break;
-        }
-    }
-
-    const auto& activationTimeBase3_2 = metricProducerTimeBase3_1->mEventActivationMap.at(i);
-    EXPECT_EQ(200 * NS_PER_SEC, activationTimeBase3_2->ttl_ns);
-    EXPECT_EQ(0, activationTimeBase3_2->start_ns);
-    EXPECT_EQ(kNotActive, activationTimeBase3_2->state);
-
-    EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
-    // }}}----------------------------------------------------------------------------------
-
-    // Load saved state from disk.
-    processor3->LoadActiveConfigsFromDisk();
-
-    // Metric 1 active: Activation 1 is active, Activation 2 is active
-    // Metric 2 is active.
-    // {{{---------------------------------------------------------------------------
-    EXPECT_TRUE(metricProducerTimeBase3_1->isActive());
-    EXPECT_EQ(timeBase3 + ttl1 - activationTimeBase3_1->ttl_ns, activationTimeBase3_1->start_ns);
-    EXPECT_EQ(kActive, activationTimeBase3_1->state);
-    EXPECT_EQ(timeBase3 + ttl2 - activationTimeBase3_2->ttl_ns, activationTimeBase3_2->start_ns);
-    EXPECT_EQ(kActive, activationTimeBase3_2->state);
-
-    EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
-    // }}}-------------------------------------------------------------------------------
-
-    // Trigger Activation 2 for Metric 1 again.
-    screenOnEvent = CreateScreenStateChangedEvent(timeBase3 + 100 * NS_PER_SEC,
-                                                  android::view::DISPLAY_STATE_ON);
-    processor3->OnLogEvent(screenOnEvent.get());
-
-    // Metric 1 active; Activation 1 is not active, Activation 2 is set to active
-    // Metric 2 is active.
-    // {{{---------------------------------------------------------------------------
-    EXPECT_TRUE(metricProducerTimeBase3_1->isActive());
-    EXPECT_EQ(kNotActive, activationTimeBase3_1->state);
-    EXPECT_EQ(timeBase3 + ttl2 - activationTimeBase3_2->ttl_ns, activationTimeBase3_2->start_ns);
-    EXPECT_EQ(kActive, activationTimeBase3_2->state);
-
-    EXPECT_TRUE(metricProducerTimeBase3_2->isActive());
-    // }}}---------------------------------------------------------------------------
-
-    // Simulate shutdown by saving state to disk.
-    shutDownTime = timeBase3 + 500 * NS_PER_SEC;
-    processor3->SaveActiveConfigsToDisk(shutDownTime);
-    EXPECT_TRUE(metricProducer1001->isActive());
-    EXPECT_TRUE(metricProducer1002->isActive());
-    ttl1 = timeBase3 + ttl1 - shutDownTime;
-    ttl2 = timeBase3 + metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC - shutDownTime;
-
-    // Simulate device restarted state by creating new instance of StatsLogProcessor with the
-    // same config.
-    long timeBase4 = timeBase3 + 600 * NS_PER_SEC;
-    sp<StatsLogProcessor> processor4 =
-            CreateStatsLogProcessor(timeBase4, timeBase4, config1, cfgKey1);
-
-    // Metric 1 is not active.
-    // Metric 2 is active.
-    // {{{---------------------------------------------------------------------------
-    ASSERT_EQ(1, processor4->mMetricsManagers.size());
-    it = processor4->mMetricsManagers.find(cfgKey1);
-    EXPECT_TRUE(it != processor4->mMetricsManagers.end());
-    auto& metricsManagerTimeBase4 = it->second;
-    EXPECT_TRUE(metricsManagerTimeBase4->isActive());
-
-    metricIt = metricsManagerTimeBase4->mAllMetricProducers.begin();
-    for (; metricIt != metricsManagerTimeBase4->mAllMetricProducers.end(); metricIt++) {
-        if ((*metricIt)->getMetricId() == metricId1) {
-            break;
-        }
-    }
-    EXPECT_TRUE(metricIt != metricsManagerTimeBase4->mAllMetricProducers.end());
-    auto& metricProducerTimeBase4_1 = *metricIt;
-    EXPECT_FALSE(metricProducerTimeBase4_1->isActive());
-
-    metricIt = metricsManagerTimeBase4->mAllMetricProducers.begin();
-    for (; metricIt != metricsManagerTimeBase4->mAllMetricProducers.end(); metricIt++) {
-        if ((*metricIt)->getMetricId() == metricId2) {
-            break;
-        }
-    }
-    EXPECT_TRUE(metricIt != metricsManagerTimeBase4->mAllMetricProducers.end());
-    auto& metricProducerTimeBase4_2 = *metricIt;
-    EXPECT_TRUE(metricProducerTimeBase4_2->isActive());
-
-    i = 0;
-    for (; i < metricsManagerTimeBase4->mAllAtomMatchingTrackers.size(); i++) {
-        if (metricsManagerTimeBase4->mAllAtomMatchingTrackers[i]->getId() ==
-            metric1ActivationTrigger1->atom_matcher_id()) {
-            break;
-        }
-    }
-    const auto& activationTimeBase4_1 = metricProducerTimeBase4_1->mEventActivationMap.at(i);
-    EXPECT_EQ(100 * NS_PER_SEC, activationTimeBase4_1->ttl_ns);
-    EXPECT_EQ(0, activationTimeBase4_1->start_ns);
-    EXPECT_EQ(kNotActive, activationTimeBase4_1->state);
-
-    i = 0;
-    for (; i < metricsManagerTimeBase4->mAllAtomMatchingTrackers.size(); i++) {
-        if (metricsManagerTimeBase4->mAllAtomMatchingTrackers[i]->getId() ==
-            metric1ActivationTrigger2->atom_matcher_id()) {
-            break;
-        }
-    }
-
-    const auto& activationTimeBase4_2 = metricProducerTimeBase4_1->mEventActivationMap.at(i);
-    EXPECT_EQ(200 * NS_PER_SEC, activationTimeBase4_2->ttl_ns);
-    EXPECT_EQ(0, activationTimeBase4_2->start_ns);
-    EXPECT_EQ(kNotActive, activationTimeBase4_2->state);
-
-    EXPECT_TRUE(metricProducerTimeBase4_2->isActive());
-    // }}}----------------------------------------------------------------------------------
-
-    // Load saved state from disk.
-    processor4->LoadActiveConfigsFromDisk();
-
-    // Metric 1 active: Activation 1 is not active, Activation 2 is not active
-    // Metric 2 is active.
-    // {{{---------------------------------------------------------------------------
-    EXPECT_FALSE(metricProducerTimeBase4_1->isActive());
-    EXPECT_EQ(kNotActive, activationTimeBase4_1->state);
-    EXPECT_EQ(kNotActive, activationTimeBase4_2->state);
-
-    EXPECT_TRUE(metricProducerTimeBase4_2->isActive());
-    // }}}-------------------------------------------------------------------------------
-}
-
-TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivationsDifferentActivationTypes) {
-    int uid = 1111;
-
-    // Create config with 2 metrics:
-    // Metric 1: Activate on boot with 2 activations
-    // Metric 2: Always active
-    StatsdConfig config1;
-    config1.set_id(12341);
-    config1.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-    auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
-    auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config1.add_atom_matcher() = wakelockAcquireMatcher;
-    *config1.add_atom_matcher() = screenOnMatcher;
-
-    long metricId1 = 1234561;
-    long metricId2 = 1234562;
-
-    auto countMetric1 = config1.add_count_metric();
-    countMetric1->set_id(metricId1);
-    countMetric1->set_what(wakelockAcquireMatcher.id());
-    countMetric1->set_bucket(FIVE_MINUTES);
-
-    auto countMetric2 = config1.add_count_metric();
-    countMetric2->set_id(metricId2);
-    countMetric2->set_what(wakelockAcquireMatcher.id());
-    countMetric2->set_bucket(FIVE_MINUTES);
-
-    auto metric1Activation = config1.add_metric_activation();
-    metric1Activation->set_metric_id(metricId1);
-    metric1Activation->set_activation_type(ACTIVATE_ON_BOOT);
-    auto metric1ActivationTrigger1 = metric1Activation->add_event_activation();
-    metric1ActivationTrigger1->set_atom_matcher_id(wakelockAcquireMatcher.id());
-    metric1ActivationTrigger1->set_ttl_seconds(100);
-    auto metric1ActivationTrigger2 = metric1Activation->add_event_activation();
-    metric1ActivationTrigger2->set_atom_matcher_id(screenOnMatcher.id());
-    metric1ActivationTrigger2->set_ttl_seconds(200);
-    metric1ActivationTrigger2->set_activation_type(ACTIVATE_IMMEDIATELY);
-
-    ConfigKey cfgKey1(uid, 12341);
-    long timeBase1 = 1;
-    sp<StatsLogProcessor> processor1 =
-            CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
-
-    // Metric 1 is not active.
-    // Metric 2 is active.
-    // {{{---------------------------------------------------------------------------
-    ASSERT_EQ(1, processor1->mMetricsManagers.size());
-    auto it = processor1->mMetricsManagers.find(cfgKey1);
-    EXPECT_TRUE(it != processor1->mMetricsManagers.end());
-    auto& metricsManager1 = it->second;
-    EXPECT_TRUE(metricsManager1->isActive());
-
-    ASSERT_EQ(metricsManager1->mAllMetricProducers.size(), 2);
-    // We assume that the index of a MetricProducer within the mAllMetricProducers
-    // array follows the order in which metrics are added to the config.
-    auto& metricProducer1_1 = metricsManager1->mAllMetricProducers[0];
-    EXPECT_EQ(metricProducer1_1->getMetricId(), metricId1);
-    EXPECT_FALSE(metricProducer1_1->isActive());  // inactive due to associated MetricActivation
-
-    auto& metricProducer1_2 = metricsManager1->mAllMetricProducers[1];
-    EXPECT_EQ(metricProducer1_2->getMetricId(), metricId2);
-    EXPECT_TRUE(metricProducer1_2->isActive());
-
-    ASSERT_EQ(metricProducer1_1->mEventActivationMap.size(), 2);
-    // The key in mEventActivationMap is the index of the associated atom matcher. We assume
-    // that matchers are indexed in the order that they are added to the config.
-    const auto& activation1_1_1 = metricProducer1_1->mEventActivationMap.at(0);
-    EXPECT_EQ(100 * NS_PER_SEC, activation1_1_1->ttl_ns);
-    EXPECT_EQ(0, activation1_1_1->start_ns);
-    EXPECT_EQ(kNotActive, activation1_1_1->state);
-    EXPECT_EQ(ACTIVATE_ON_BOOT, activation1_1_1->activationType);
-
-    const auto& activation1_1_2 = metricProducer1_1->mEventActivationMap.at(1);
-    EXPECT_EQ(200 * NS_PER_SEC, activation1_1_2->ttl_ns);
-    EXPECT_EQ(0, activation1_1_2->start_ns);
-    EXPECT_EQ(kNotActive, activation1_1_2->state);
-    EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1_1_2->activationType);
-    // }}}------------------------------------------------------------------------------
-
-    // Trigger Activation 1 for Metric 1
-    std::vector<int> attributionUids = {111};
-    std::vector<string> attributionTags = {"App1"};
-    std::unique_ptr<LogEvent> event =
-            CreateAcquireWakelockEvent(timeBase1 + 100, attributionUids, attributionTags, "wl1");
-    processor1->OnLogEvent(event.get());
-
-    // Metric 1 is not active; Activation 1 set to kActiveOnBoot
-    // Metric 2 is active.
-    // {{{---------------------------------------------------------------------------
-    EXPECT_FALSE(metricProducer1_1->isActive());
-    EXPECT_EQ(0, activation1_1_1->start_ns);
-    EXPECT_EQ(kActiveOnBoot, activation1_1_1->state);
-    EXPECT_EQ(0, activation1_1_2->start_ns);
-    EXPECT_EQ(kNotActive, activation1_1_2->state);
-
-    EXPECT_TRUE(metricProducer1_2->isActive());
-    // }}}-----------------------------------------------------------------------------
-
-    // Simulate shutdown by saving state to disk
-    int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
-    processor1->SaveActiveConfigsToDisk(shutDownTime);
-    EXPECT_FALSE(metricProducer1_1->isActive());
-
-    // Simulate device restarted state by creating new instance of StatsLogProcessor with the
-    // same config.
-    long timeBase2 = 1000;
-    sp<StatsLogProcessor> processor2 =
-            CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
-
-    // Metric 1 is not active.
-    // Metric 2 is active.
-    // {{{---------------------------------------------------------------------------
-    ASSERT_EQ(1, processor2->mMetricsManagers.size());
-    it = processor2->mMetricsManagers.find(cfgKey1);
-    EXPECT_TRUE(it != processor2->mMetricsManagers.end());
-    auto& metricsManager2 = it->second;
-    EXPECT_TRUE(metricsManager2->isActive());
-
-    ASSERT_EQ(metricsManager2->mAllMetricProducers.size(), 2);
-    // We assume that the index of a MetricProducer within the mAllMetricProducers
-    // array follows the order in which metrics are added to the config.
-    auto& metricProducer2_1 = metricsManager2->mAllMetricProducers[0];
-    EXPECT_EQ(metricProducer2_1->getMetricId(), metricId1);
-    EXPECT_FALSE(metricProducer2_1->isActive());
-
-    auto& metricProducer2_2 = metricsManager2->mAllMetricProducers[1];
-    EXPECT_EQ(metricProducer2_2->getMetricId(), metricId2);
-    EXPECT_TRUE(metricProducer2_2->isActive());
-
-    ASSERT_EQ(metricProducer2_1->mEventActivationMap.size(), 2);
-    // The key in mEventActivationMap is the index of the associated atom matcher. We assume
-    // that matchers are indexed in the order that they are added to the config.
-    const auto& activation2_1_1 = metricProducer2_1->mEventActivationMap.at(0);
-    EXPECT_EQ(100 * NS_PER_SEC, activation2_1_1->ttl_ns);
-    EXPECT_EQ(0, activation2_1_1->start_ns);
-    EXPECT_EQ(kNotActive, activation2_1_1->state);
-    EXPECT_EQ(ACTIVATE_ON_BOOT, activation2_1_1->activationType);
-
-    const auto& activation2_1_2 = metricProducer2_1->mEventActivationMap.at(1);
-    EXPECT_EQ(200 * NS_PER_SEC, activation2_1_2->ttl_ns);
-    EXPECT_EQ(0, activation2_1_2->start_ns);
-    EXPECT_EQ(kNotActive, activation2_1_2->state);
-    EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation2_1_2->activationType);
-    // }}}-----------------------------------------------------------------------------------
-
-    // Load saved state from disk.
-    processor2->LoadActiveConfigsFromDisk();
-
-    // Metric 1 active; Activation 1 is active, Activation 2 is not active
-    // Metric 2 is active.
-    // {{{---------------------------------------------------------------------------
-    EXPECT_TRUE(metricProducer2_1->isActive());
-    int64_t ttl1 = metric1ActivationTrigger1->ttl_seconds() * NS_PER_SEC;
-    EXPECT_EQ(timeBase2 + ttl1 - activation2_1_1->ttl_ns, activation2_1_1->start_ns);
-    EXPECT_EQ(kActive, activation2_1_1->state);
-    EXPECT_EQ(0, activation2_1_2->start_ns);
-    EXPECT_EQ(kNotActive, activation2_1_2->state);
-
-    EXPECT_TRUE(metricProducer2_2->isActive());
-    // }}}--------------------------------------------------------------------------------
-
-    // Trigger Activation 2 for Metric 1.
-    auto screenOnEvent =
-            CreateScreenStateChangedEvent(timeBase2 + 200, android::view::DISPLAY_STATE_ON);
-    processor2->OnLogEvent(screenOnEvent.get());
-
-    // Metric 1 active; Activation 1 is active, Activation 2 is active
-    // Metric 2 is active.
-    // {{{---------------------------------------------------------------------------
-    EXPECT_TRUE(metricProducer2_1->isActive());
-    EXPECT_EQ(timeBase2 + ttl1 - activation2_1_1->ttl_ns, activation2_1_1->start_ns);
-    EXPECT_EQ(kActive, activation2_1_1->state);
-    EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activation2_1_2->start_ns);
-    EXPECT_EQ(kActive, activation2_1_2->state);
-
-    EXPECT_TRUE(metricProducer2_2->isActive());
-    // }}}---------------------------------------------------------------------------
-
-    // Simulate shutdown by saving state to disk
-    shutDownTime = timeBase2 + 50 * NS_PER_SEC;
-    processor2->SaveActiveConfigsToDisk(shutDownTime);
-    EXPECT_TRUE(metricProducer2_1->isActive());
-    EXPECT_TRUE(metricProducer2_2->isActive());
-    ttl1 -= shutDownTime - timeBase2;
-    int64_t ttl2 = metric1ActivationTrigger2->ttl_seconds() * NS_PER_SEC -
-                   (shutDownTime - screenOnEvent->GetElapsedTimestampNs());
-
-    // Simulate device restarted state by creating new instance of StatsLogProcessor with the
-    // same config.
-    long timeBase3 = timeBase2 + 120 * NS_PER_SEC;
-    sp<StatsLogProcessor> processor3 =
-            CreateStatsLogProcessor(timeBase3, timeBase3, config1, cfgKey1);
-
-    // Metric 1 is not active.
-    // Metric 2 is active.
-    // {{{---------------------------------------------------------------------------
-    ASSERT_EQ(1, processor3->mMetricsManagers.size());
-    it = processor3->mMetricsManagers.find(cfgKey1);
-    EXPECT_TRUE(it != processor3->mMetricsManagers.end());
-    auto& metricsManager3 = it->second;
-    EXPECT_TRUE(metricsManager3->isActive());
-
-    ASSERT_EQ(metricsManager3->mAllMetricProducers.size(), 2);
-    // We assume that the index of a MetricProducer within the mAllMetricProducers
-    // array follows the order in which metrics are added to the config.
-    auto& metricProducer3_1 = metricsManager3->mAllMetricProducers[0];
-    EXPECT_EQ(metricProducer3_1->getMetricId(), metricId1);
-    EXPECT_FALSE(metricProducer3_1->isActive());
-
-    auto& metricProducer3_2 = metricsManager3->mAllMetricProducers[1];
-    EXPECT_EQ(metricProducer3_2->getMetricId(), metricId2);
-    EXPECT_TRUE(metricProducer3_2->isActive());
-
-    ASSERT_EQ(metricProducer3_1->mEventActivationMap.size(), 2);
-    // The key in mEventActivationMap is the index of the associated atom matcher. We assume
-    // that matchers are indexed in the order that they are added to the config.
-    const auto& activation3_1_1 = metricProducer3_1->mEventActivationMap.at(0);
-    EXPECT_EQ(100 * NS_PER_SEC, activation3_1_1->ttl_ns);
-    EXPECT_EQ(0, activation3_1_1->start_ns);
-    EXPECT_EQ(kNotActive, activation3_1_1->state);
-    EXPECT_EQ(ACTIVATE_ON_BOOT, activation3_1_1->activationType);
-
-    const auto& activation3_1_2 = metricProducer3_1->mEventActivationMap.at(1);
-    EXPECT_EQ(200 * NS_PER_SEC, activation3_1_2->ttl_ns);
-    EXPECT_EQ(0, activation3_1_2->start_ns);
-    EXPECT_EQ(kNotActive, activation3_1_2->state);
-    EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation3_1_2->activationType);
-    // }}}----------------------------------------------------------------------------------
-
-    // Load saved state from disk.
-    processor3->LoadActiveConfigsFromDisk();
-
-    // Metric 1 active: Activation 1 is active, Activation 2 is active
-    // Metric 2 is active.
-    // {{{---------------------------------------------------------------------------
-    EXPECT_TRUE(metricProducer3_1->isActive());
-    EXPECT_EQ(timeBase3 + ttl1 - activation3_1_1->ttl_ns, activation3_1_1->start_ns);
-    EXPECT_EQ(kActive, activation3_1_1->state);
-    EXPECT_EQ(timeBase3 + ttl2 - activation3_1_2->ttl_ns, activation3_1_2->start_ns);
-    EXPECT_EQ(kActive, activation3_1_2->state);
-
-    EXPECT_TRUE(metricProducer3_2->isActive());
-    // }}}-------------------------------------------------------------------------------
-
-    // Trigger Activation 2 for Metric 1 again.
-    screenOnEvent = CreateScreenStateChangedEvent(timeBase3 + 100 * NS_PER_SEC,
-                                                  android::view::DISPLAY_STATE_ON);
-    processor3->OnLogEvent(screenOnEvent.get());
-
-    // Metric 1 active; Activation 1 is inactive (above screenOnEvent causes ttl1 to expire),
-    //                  Activation 2 is set to active
-    // Metric 2 is active.
-    // {{{---------------------------------------------------------------------------
-    EXPECT_TRUE(metricProducer3_1->isActive());
-    EXPECT_EQ(kNotActive, activation3_1_1->state);
-    EXPECT_EQ(screenOnEvent->GetElapsedTimestampNs(), activation3_1_2->start_ns);
-    EXPECT_EQ(kActive, activation3_1_2->state);
-
-    EXPECT_TRUE(metricProducer3_2->isActive());
-    // }}}---------------------------------------------------------------------------
-}
-
-TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart) {
-    int uid = 9876;
-    long configId = 12341;
-
-    // Create config with 3 metrics:
-    // Metric 1: Activate on 2 activations, 1 on boot, 1 immediate.
-    // Metric 2: Activate on 2 activations, 1 on boot, 1 immediate.
-    // Metric 3: Always active
-    StatsdConfig config1;
-    config1.set_id(configId);
-    config1.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-    auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
-    auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-    auto jobStartMatcher = CreateStartScheduledJobAtomMatcher();
-    auto jobFinishMatcher = CreateFinishScheduledJobAtomMatcher();
-    *config1.add_atom_matcher() = wakelockAcquireMatcher;
-    *config1.add_atom_matcher() = screenOnMatcher;
-    *config1.add_atom_matcher() = jobStartMatcher;
-    *config1.add_atom_matcher() = jobFinishMatcher;
-
-    long metricId1 = 1234561;
-    long metricId2 = 1234562;
-    long metricId3 = 1234563;
-
-    auto countMetric1 = config1.add_count_metric();
-    countMetric1->set_id(metricId1);
-    countMetric1->set_what(wakelockAcquireMatcher.id());
-    countMetric1->set_bucket(FIVE_MINUTES);
-
-    auto countMetric2 = config1.add_count_metric();
-    countMetric2->set_id(metricId2);
-    countMetric2->set_what(wakelockAcquireMatcher.id());
-    countMetric2->set_bucket(FIVE_MINUTES);
-
-    auto countMetric3 = config1.add_count_metric();
-    countMetric3->set_id(metricId3);
-    countMetric3->set_what(wakelockAcquireMatcher.id());
-    countMetric3->set_bucket(FIVE_MINUTES);
-
-    // Metric 1 activates on boot for wakelock acquire, immediately for screen on.
-    auto metric1Activation = config1.add_metric_activation();
-    metric1Activation->set_metric_id(metricId1);
-    auto metric1ActivationTrigger1 = metric1Activation->add_event_activation();
-    metric1ActivationTrigger1->set_atom_matcher_id(wakelockAcquireMatcher.id());
-    metric1ActivationTrigger1->set_ttl_seconds(100);
-    metric1ActivationTrigger1->set_activation_type(ACTIVATE_ON_BOOT);
-    auto metric1ActivationTrigger2 = metric1Activation->add_event_activation();
-    metric1ActivationTrigger2->set_atom_matcher_id(screenOnMatcher.id());
-    metric1ActivationTrigger2->set_ttl_seconds(200);
-    metric1ActivationTrigger2->set_activation_type(ACTIVATE_IMMEDIATELY);
-
-    // Metric 2 activates on boot for scheduled job start, immediately for scheduled job finish.
-    auto metric2Activation = config1.add_metric_activation();
-    metric2Activation->set_metric_id(metricId2);
-    auto metric2ActivationTrigger1 = metric2Activation->add_event_activation();
-    metric2ActivationTrigger1->set_atom_matcher_id(jobStartMatcher.id());
-    metric2ActivationTrigger1->set_ttl_seconds(100);
-    metric2ActivationTrigger1->set_activation_type(ACTIVATE_ON_BOOT);
-    auto metric2ActivationTrigger2 = metric2Activation->add_event_activation();
-    metric2ActivationTrigger2->set_atom_matcher_id(jobFinishMatcher.id());
-    metric2ActivationTrigger2->set_ttl_seconds(200);
-    metric2ActivationTrigger2->set_activation_type(ACTIVATE_IMMEDIATELY);
-
-    // Send the config.
-    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-    string serialized = config1.SerializeAsString();
-    service->addConfigurationChecked(uid, configId, {serialized.begin(), serialized.end()});
-
-    // Make sure the config is stored on disk. Otherwise, we will not reset on system server death.
-    StatsdConfig tmpConfig;
-    ConfigKey cfgKey1(uid, configId);
-    EXPECT_TRUE(StorageManager::readConfigFromDisk(cfgKey1, &tmpConfig));
-
-    // Metric 1 is not active.
-    // Metric 2 is not active.
-    // Metric 3 is active.
-    // {{{---------------------------------------------------------------------------
-    sp<StatsLogProcessor> processor = service->mProcessor;
-    ASSERT_EQ(1, processor->mMetricsManagers.size());
-    auto it = processor->mMetricsManagers.find(cfgKey1);
-    EXPECT_TRUE(it != processor->mMetricsManagers.end());
-    auto& metricsManager1 = it->second;
-    EXPECT_TRUE(metricsManager1->isActive());
-    ASSERT_EQ(3, metricsManager1->mAllMetricProducers.size());
-
-    auto& metricProducer1 = metricsManager1->mAllMetricProducers[0];
-    EXPECT_EQ(metricId1, metricProducer1->getMetricId());
-    EXPECT_FALSE(metricProducer1->isActive());
-
-    auto& metricProducer2 = metricsManager1->mAllMetricProducers[1];
-    EXPECT_EQ(metricId2, metricProducer2->getMetricId());
-    EXPECT_FALSE(metricProducer2->isActive());
-
-    auto& metricProducer3 = metricsManager1->mAllMetricProducers[2];
-    EXPECT_EQ(metricId3, metricProducer3->getMetricId());
-    EXPECT_TRUE(metricProducer3->isActive());
-
-    // Check event activations.
-    ASSERT_EQ(metricsManager1->mAllAtomMatchingTrackers.size(), 4);
-    EXPECT_EQ(metricsManager1->mAllAtomMatchingTrackers[0]->getId(),
-              metric1ActivationTrigger1->atom_matcher_id());
-    const auto& activation1 = metricProducer1->mEventActivationMap.at(0);
-    EXPECT_EQ(100 * NS_PER_SEC, activation1->ttl_ns);
-    EXPECT_EQ(0, activation1->start_ns);
-    EXPECT_EQ(kNotActive, activation1->state);
-    EXPECT_EQ(ACTIVATE_ON_BOOT, activation1->activationType);
-
-    EXPECT_EQ(metricsManager1->mAllAtomMatchingTrackers[1]->getId(),
-              metric1ActivationTrigger2->atom_matcher_id());
-    const auto& activation2 = metricProducer1->mEventActivationMap.at(1);
-    EXPECT_EQ(200 * NS_PER_SEC, activation2->ttl_ns);
-    EXPECT_EQ(0, activation2->start_ns);
-    EXPECT_EQ(kNotActive, activation2->state);
-    EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation2->activationType);
-
-    EXPECT_EQ(metricsManager1->mAllAtomMatchingTrackers[2]->getId(),
-              metric2ActivationTrigger1->atom_matcher_id());
-    const auto& activation3 = metricProducer2->mEventActivationMap.at(2);
-    EXPECT_EQ(100 * NS_PER_SEC, activation3->ttl_ns);
-    EXPECT_EQ(0, activation3->start_ns);
-    EXPECT_EQ(kNotActive, activation3->state);
-    EXPECT_EQ(ACTIVATE_ON_BOOT, activation3->activationType);
-
-    EXPECT_EQ(metricsManager1->mAllAtomMatchingTrackers[3]->getId(),
-              metric2ActivationTrigger2->atom_matcher_id());
-    const auto& activation4 = metricProducer2->mEventActivationMap.at(3);
-    EXPECT_EQ(200 * NS_PER_SEC, activation4->ttl_ns);
-    EXPECT_EQ(0, activation4->start_ns);
-    EXPECT_EQ(kNotActive, activation4->state);
-    EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation4->activationType);
-    // }}}------------------------------------------------------------------------------
-
-    // Trigger Activation 1 for Metric 1. Should activate on boot.
-    // Trigger Activation 4 for Metric 2. Should activate immediately.
-    int64_t configAddedTimeNs = metricsManager1->mLastReportTimeNs;
-    std::vector<int> attributionUids = {111};
-    std::vector<string> attributionTags = {"App1"};
-    std::unique_ptr<LogEvent> event1 = CreateAcquireWakelockEvent(
-            1 + configAddedTimeNs, attributionUids, attributionTags, "wl1");
-    processor->OnLogEvent(event1.get());
-
-    std::unique_ptr<LogEvent> event2 = CreateFinishScheduledJobEvent(
-            2 + configAddedTimeNs, attributionUids, attributionTags, "finish1");
-    processor->OnLogEvent(event2.get());
-
-    // Metric 1 is not active; Activation 1 set to kActiveOnBoot
-    // Metric 2 is active. Activation 4 set to kActive
-    // Metric 3 is active.
-    // {{{---------------------------------------------------------------------------
-    EXPECT_FALSE(metricProducer1->isActive());
-    EXPECT_EQ(0, activation1->start_ns);
-    EXPECT_EQ(kActiveOnBoot, activation1->state);
-    EXPECT_EQ(0, activation2->start_ns);
-    EXPECT_EQ(kNotActive, activation2->state);
-
-    EXPECT_TRUE(metricProducer2->isActive());
-    EXPECT_EQ(0, activation3->start_ns);
-    EXPECT_EQ(kNotActive, activation3->state);
-    EXPECT_EQ(2 + configAddedTimeNs, activation4->start_ns);
-    EXPECT_EQ(kActive, activation4->state);
-
-    EXPECT_TRUE(metricProducer3->isActive());
-    // }}}-----------------------------------------------------------------------------
-
-    // Can't fake time with StatsService.
-    // Lets get a time close to the system server death time and make sure it's sane.
-    int64_t approximateSystemServerDeath = getElapsedRealtimeNs();
-    EXPECT_TRUE(approximateSystemServerDeath > 2 + configAddedTimeNs);
-    EXPECT_TRUE(approximateSystemServerDeath < NS_PER_SEC + configAddedTimeNs);
-
-    // System server dies.
-    service->statsCompanionServiceDiedImpl();
-
-    // We should have a new metrics manager. Lets get it and ensure activation status is restored.
-    // {{{---------------------------------------------------------------------------
-    ASSERT_EQ(1, processor->mMetricsManagers.size());
-    it = processor->mMetricsManagers.find(cfgKey1);
-    EXPECT_TRUE(it != processor->mMetricsManagers.end());
-    auto& metricsManager2 = it->second;
-    EXPECT_TRUE(metricsManager2->isActive());
-    ASSERT_EQ(3, metricsManager2->mAllMetricProducers.size());
-
-    auto& metricProducer1001 = metricsManager2->mAllMetricProducers[0];
-    EXPECT_EQ(metricId1, metricProducer1001->getMetricId());
-    EXPECT_FALSE(metricProducer1001->isActive());
-
-    auto& metricProducer1002 = metricsManager2->mAllMetricProducers[1];
-    EXPECT_EQ(metricId2, metricProducer1002->getMetricId());
-    EXPECT_TRUE(metricProducer1002->isActive());
-
-    auto& metricProducer1003 = metricsManager2->mAllMetricProducers[2];
-    EXPECT_EQ(metricId3, metricProducer1003->getMetricId());
-    EXPECT_TRUE(metricProducer1003->isActive());
-
-    // Check event activations.
-    // Activation 1 is kActiveOnBoot.
-    // Activation 2 and 3 are not active.
-    // Activation 4 is active.
-    ASSERT_EQ(metricsManager2->mAllAtomMatchingTrackers.size(), 4);
-    EXPECT_EQ(metricsManager2->mAllAtomMatchingTrackers[0]->getId(),
-              metric1ActivationTrigger1->atom_matcher_id());
-    const auto& activation1001 = metricProducer1001->mEventActivationMap.at(0);
-    EXPECT_EQ(100 * NS_PER_SEC, activation1001->ttl_ns);
-    EXPECT_EQ(0, activation1001->start_ns);
-    EXPECT_EQ(kActiveOnBoot, activation1001->state);
-    EXPECT_EQ(ACTIVATE_ON_BOOT, activation1001->activationType);
-
-    EXPECT_EQ(metricsManager2->mAllAtomMatchingTrackers[1]->getId(),
-              metric1ActivationTrigger2->atom_matcher_id());
-    const auto& activation1002 = metricProducer1001->mEventActivationMap.at(1);
-    EXPECT_EQ(200 * NS_PER_SEC, activation1002->ttl_ns);
-    EXPECT_EQ(0, activation1002->start_ns);
-    EXPECT_EQ(kNotActive, activation1002->state);
-    EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1002->activationType);
-
-    EXPECT_EQ(metricsManager2->mAllAtomMatchingTrackers[2]->getId(),
-              metric2ActivationTrigger1->atom_matcher_id());
-    const auto& activation1003 = metricProducer1002->mEventActivationMap.at(2);
-    EXPECT_EQ(100 * NS_PER_SEC, activation1003->ttl_ns);
-    EXPECT_EQ(0, activation1003->start_ns);
-    EXPECT_EQ(kNotActive, activation1003->state);
-    EXPECT_EQ(ACTIVATE_ON_BOOT, activation1003->activationType);
-
-    EXPECT_EQ(metricsManager2->mAllAtomMatchingTrackers[3]->getId(),
-              metric2ActivationTrigger2->atom_matcher_id());
-    const auto& activation1004 = metricProducer1002->mEventActivationMap.at(3);
-    EXPECT_EQ(200 * NS_PER_SEC, activation1004->ttl_ns);
-    EXPECT_EQ(2 + configAddedTimeNs, activation1004->start_ns);
-    EXPECT_EQ(kActive, activation1004->state);
-    EXPECT_EQ(ACTIVATE_IMMEDIATELY, activation1004->activationType);
-    // }}}------------------------------------------------------------------------------
-
-    // Clear the data stored on disk as a result of the system server death.
-    vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey1, configAddedTimeNs + NS_PER_SEC, false, true, ADB_DUMP, FAST,
-                            &buffer);
-}
-
-TEST(StatsLogProcessorTest_mapIsolatedUidToHostUid, LogHostUid) {
-    int hostUid = 20;
-    int isolatedUid = 30;
-    uint64_t eventTimeNs = 12355;
-    int atomId = 89;
-    int field1 = 90;
-    int field2 = 28;
-    sp<MockUidMap> mockUidMap = makeMockUidMapForOneHost(hostUid, {isolatedUid});
-    ConfigKey cfgKey;
-    StatsdConfig config = MakeConfig(false);
-    sp<StatsLogProcessor> processor =
-            CreateStatsLogProcessor(1, 1, config, cfgKey, nullptr, 0, mockUidMap);
-
-    shared_ptr<LogEvent> logEvent = makeUidLogEvent(atomId, eventTimeNs, hostUid, field1, field2);
-
-    processor->OnLogEvent(logEvent.get());
-
-    const vector<FieldValue>* actualFieldValues = &logEvent->getValues();
-    ASSERT_EQ(3, actualFieldValues->size());
-    EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
-    EXPECT_EQ(field1, actualFieldValues->at(1).mValue.int_value);
-    EXPECT_EQ(field2, actualFieldValues->at(2).mValue.int_value);
-}
-
-TEST(StatsLogProcessorTest_mapIsolatedUidToHostUid, LogIsolatedUid) {
-    int hostUid = 20;
-    int isolatedUid = 30;
-    uint64_t eventTimeNs = 12355;
-    int atomId = 89;
-    int field1 = 90;
-    int field2 = 28;
-    sp<MockUidMap> mockUidMap = makeMockUidMapForOneHost(hostUid, {isolatedUid});
-    ConfigKey cfgKey;
-    StatsdConfig config = MakeConfig(false);
-    sp<StatsLogProcessor> processor =
-            CreateStatsLogProcessor(1, 1, config, cfgKey, nullptr, 0, mockUidMap);
-
-    shared_ptr<LogEvent> logEvent =
-            makeUidLogEvent(atomId, eventTimeNs, isolatedUid, field1, field2);
-
-    processor->OnLogEvent(logEvent.get());
-
-    const vector<FieldValue>* actualFieldValues = &logEvent->getValues();
-    ASSERT_EQ(3, actualFieldValues->size());
-    EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
-    EXPECT_EQ(field1, actualFieldValues->at(1).mValue.int_value);
-    EXPECT_EQ(field2, actualFieldValues->at(2).mValue.int_value);
-}
-
-TEST(StatsLogProcessorTest_mapIsolatedUidToHostUid, LogHostUidAttributionChain) {
-    int hostUid = 20;
-    int isolatedUid = 30;
-    uint64_t eventTimeNs = 12355;
-    int atomId = 89;
-    int field1 = 90;
-    int field2 = 28;
-    sp<MockUidMap> mockUidMap = makeMockUidMapForOneHost(hostUid, {isolatedUid});
-    ConfigKey cfgKey;
-    StatsdConfig config = MakeConfig(false);
-    sp<StatsLogProcessor> processor =
-            CreateStatsLogProcessor(1, 1, config, cfgKey, nullptr, 0, mockUidMap);
-
-    shared_ptr<LogEvent> logEvent = makeAttributionLogEvent(atomId, eventTimeNs, {hostUid, 200},
-                                                            {"tag1", "tag2"}, field1, field2);
-
-    processor->OnLogEvent(logEvent.get());
-
-    const vector<FieldValue>* actualFieldValues = &logEvent->getValues();
-    ASSERT_EQ(6, actualFieldValues->size());
-    EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
-    EXPECT_EQ("tag1", actualFieldValues->at(1).mValue.str_value);
-    EXPECT_EQ(200, actualFieldValues->at(2).mValue.int_value);
-    EXPECT_EQ("tag2", actualFieldValues->at(3).mValue.str_value);
-    EXPECT_EQ(field1, actualFieldValues->at(4).mValue.int_value);
-    EXPECT_EQ(field2, actualFieldValues->at(5).mValue.int_value);
-}
-
-TEST(StatsLogProcessorTest_mapIsolatedUidToHostUid, LogIsolatedUidAttributionChain) {
-    int hostUid = 20;
-    int isolatedUid = 30;
-    uint64_t eventTimeNs = 12355;
-    int atomId = 89;
-    int field1 = 90;
-    int field2 = 28;
-    sp<MockUidMap> mockUidMap = makeMockUidMapForOneHost(hostUid, {isolatedUid});
-    ConfigKey cfgKey;
-    StatsdConfig config = MakeConfig(false);
-    sp<StatsLogProcessor> processor =
-            CreateStatsLogProcessor(1, 1, config, cfgKey, nullptr, 0, mockUidMap);
-
-    shared_ptr<LogEvent> logEvent = makeAttributionLogEvent(atomId, eventTimeNs, {isolatedUid, 200},
-                                                            {"tag1", "tag2"}, field1, field2);
-
-    processor->OnLogEvent(logEvent.get());
-
-    const vector<FieldValue>* actualFieldValues = &logEvent->getValues();
-    ASSERT_EQ(6, actualFieldValues->size());
-    EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
-    EXPECT_EQ("tag1", actualFieldValues->at(1).mValue.str_value);
-    EXPECT_EQ(200, actualFieldValues->at(2).mValue.int_value);
-    EXPECT_EQ("tag2", actualFieldValues->at(3).mValue.str_value);
-    EXPECT_EQ(field1, actualFieldValues->at(4).mValue.int_value);
-    EXPECT_EQ(field2, actualFieldValues->at(5).mValue.int_value);
-}
-
-TEST(StatsLogProcessorTest, TestDumpReportWithoutErasingDataDoesNotUpdateTimestamp) {
-    int hostUid = 20;
-    int isolatedUid = 30;
-    sp<MockUidMap> mockUidMap = makeMockUidMapForOneHost(hostUid, {isolatedUid});
-    ConfigKey key(3, 4);
-
-    // TODO: All tests should not persist state on disk. This removes any reports that were present.
-    ProtoOutputStream proto;
-    StorageManager::appendConfigMetricsReport(key, &proto, /*erase data=*/true, /*isAdb=*/false);
-
-    StatsdConfig config = MakeConfig(false);
-    sp<StatsLogProcessor> processor =
-            CreateStatsLogProcessor(1, 1, config, key, nullptr, 0, mockUidMap);
-    vector<uint8_t> bytes;
-
-    int64_t dumpTime1Ns = 1 * NS_PER_SEC;
-    processor->onDumpReport(key, dumpTime1Ns, false /* include_current_bucket */,
-            true /* erase_data */, ADB_DUMP, FAST, &bytes);
-
-    ConfigMetricsReportList output;
-    output.ParseFromArray(bytes.data(), bytes.size());
-    EXPECT_EQ(output.reports_size(), 1);
-    EXPECT_EQ(output.reports(0).current_report_elapsed_nanos(), dumpTime1Ns);
-
-    int64_t dumpTime2Ns = 5 * NS_PER_SEC;
-    processor->onDumpReport(key, dumpTime2Ns, false /* include_current_bucket */,
-            false /* erase_data */, ADB_DUMP, FAST, &bytes);
-
-    // Check that the dump report without clearing data is successful.
-    output.ParseFromArray(bytes.data(), bytes.size());
-    EXPECT_EQ(output.reports_size(), 1);
-    EXPECT_EQ(output.reports(0).current_report_elapsed_nanos(), dumpTime2Ns);
-    EXPECT_EQ(output.reports(0).last_report_elapsed_nanos(), dumpTime1Ns);
-
-    int64_t dumpTime3Ns = 10 * NS_PER_SEC;
-    processor->onDumpReport(key, dumpTime3Ns, false /* include_current_bucket */,
-            true /* erase_data */, ADB_DUMP, FAST, &bytes);
-
-    // Check that the previous dump report that didn't clear data did not overwrite the first dump's
-    // timestamps.
-    output.ParseFromArray(bytes.data(), bytes.size());
-    EXPECT_EQ(output.reports_size(), 1);
-    EXPECT_EQ(output.reports(0).current_report_elapsed_nanos(), dumpTime3Ns);
-    EXPECT_EQ(output.reports(0).last_report_elapsed_nanos(), dumpTime1Ns);
-
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/tests/StatsService_test.cpp b/cmds/statsd/tests/StatsService_test.cpp
deleted file mode 100644
index cc38c4a..0000000
--- a/cmds/statsd/tests/StatsService_test.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "StatsService.h"
-#include "config/ConfigKey.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-
-#include <android/binder_interface_utils.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include <stdio.h>
-
-using namespace android;
-using namespace testing;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using android::util::ProtoOutputStream;
-using ::ndk::SharedRefBase;
-
-#ifdef __ANDROID__
-
-TEST(StatsServiceTest, TestAddConfig_simple) {
-    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-    StatsdConfig config;
-    config.set_id(12345);
-    string serialized = config.SerializeAsString();
-
-    EXPECT_TRUE(
-            service->addConfigurationChecked(123, 12345, {serialized.begin(), serialized.end()}));
-}
-
-TEST(StatsServiceTest, TestAddConfig_empty) {
-    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-    string serialized = "";
-
-    EXPECT_TRUE(
-            service->addConfigurationChecked(123, 12345, {serialized.begin(), serialized.end()}));
-}
-
-TEST(StatsServiceTest, TestAddConfig_invalid) {
-    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-    string serialized = "Invalid config!";
-
-    EXPECT_FALSE(
-            service->addConfigurationChecked(123, 12345, {serialized.begin(), serialized.end()}));
-}
-
-TEST(StatsServiceTest, TestGetUidFromArgs) {
-    Vector<String8> args;
-    args.push(String8("-1"));
-    args.push(String8("0"));
-    args.push(String8("1"));
-    args.push(String8("a1"));
-    args.push(String8(""));
-
-    int32_t uid;
-
-    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-    service->mEngBuild = true;
-
-    // "-1"
-    EXPECT_FALSE(service->getUidFromArgs(args, 0, uid));
-
-    // "0"
-    EXPECT_TRUE(service->getUidFromArgs(args, 1, uid));
-    EXPECT_EQ(0, uid);
-
-    // "1"
-    EXPECT_TRUE(service->getUidFromArgs(args, 2, uid));
-    EXPECT_EQ(1, uid);
-
-    // "a1"
-    EXPECT_FALSE(service->getUidFromArgs(args, 3, uid));
-
-    // ""
-    EXPECT_FALSE(service->getUidFromArgs(args, 4, uid));
-
-    // For a non-userdebug, uid "1" cannot be impersonated.
-    service->mEngBuild = false;
-    EXPECT_FALSE(service->getUidFromArgs(args, 2, uid));
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
deleted file mode 100644
index 33bdc64..0000000
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ /dev/null
@@ -1,426 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "packages/UidMap.h"
-#include "StatsLogProcessor.h"
-#include "config/ConfigKey.h"
-#include "guardrail/StatsdStats.h"
-#include "logd/LogEvent.h"
-#include "hash.h"
-#include "statslog_statsdtest.h"
-#include "statsd_test_util.h"
-
-#include <android/util/ProtoOutputStream.h>
-#include <gtest/gtest.h>
-
-#include <stdio.h>
-
-using namespace android;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using android::util::ProtoOutputStream;
-using android::util::ProtoReader;
-
-#ifdef __ANDROID__
-const string kApp1 = "app1.sharing.1";
-const string kApp2 = "app2.sharing.1";
-
-TEST(UidMapTest, TestIsolatedUID) {
-    sp<UidMap> m = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> subscriberAlarmMonitor;
-    // Construct the processor with a no-op sendBroadcast function that does nothing.
-    StatsLogProcessor p(
-            m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
-            [](const ConfigKey& key) { return true; },
-            [](const int&, const vector<int64_t>&) { return true; });
-
-    std::unique_ptr<LogEvent> addEvent = CreateIsolatedUidChangedEvent(
-            1 /*timestamp*/, 100 /*hostUid*/, 101 /*isolatedUid*/, 1 /*is_create*/);
-    EXPECT_EQ(101, m->getHostUidOrSelf(101));
-    p.OnLogEvent(addEvent.get());
-    EXPECT_EQ(100, m->getHostUidOrSelf(101));
-
-    std::unique_ptr<LogEvent> removeEvent = CreateIsolatedUidChangedEvent(
-            1 /*timestamp*/, 100 /*hostUid*/, 101 /*isolatedUid*/, 0 /*is_create*/);
-    p.OnLogEvent(removeEvent.get());
-    EXPECT_EQ(101, m->getHostUidOrSelf(101));
-}
-
-TEST(UidMapTest, TestMatching) {
-    UidMap m;
-    vector<int32_t> uids;
-    vector<int64_t> versions;
-    vector<String16> apps;
-    vector<String16> versionStrings;
-    vector<String16> installers;
-
-    uids.push_back(1000);
-    uids.push_back(1000);
-    versionStrings.push_back(String16("v1"));
-    versionStrings.push_back(String16("v1"));
-    installers.push_back(String16(""));
-    installers.push_back(String16(""));
-    apps.push_back(String16(kApp1.c_str()));
-    apps.push_back(String16(kApp2.c_str()));
-    versions.push_back(4);
-    versions.push_back(5);
-    m.updateMap(1, uids, versions, versionStrings, apps, installers);
-    EXPECT_TRUE(m.hasApp(1000, kApp1));
-    EXPECT_TRUE(m.hasApp(1000, kApp2));
-    EXPECT_FALSE(m.hasApp(1000, "not.app"));
-
-    std::set<string> name_set = m.getAppNamesFromUid(1000u, true /* returnNormalized */);
-    ASSERT_EQ(name_set.size(), 2u);
-    EXPECT_TRUE(name_set.find(kApp1) != name_set.end());
-    EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
-
-    name_set = m.getAppNamesFromUid(12345, true /* returnNormalized */);
-    EXPECT_TRUE(name_set.empty());
-}
-
-TEST(UidMapTest, TestAddAndRemove) {
-    UidMap m;
-    vector<int32_t> uids;
-    vector<int64_t> versions;
-    vector<String16> apps;
-    vector<String16> versionStrings;
-    vector<String16> installers;
-
-    uids.push_back(1000);
-    uids.push_back(1000);
-    versionStrings.push_back(String16("v1"));
-    versionStrings.push_back(String16("v1"));
-    installers.push_back(String16(""));
-    installers.push_back(String16(""));
-    apps.push_back(String16(kApp1.c_str()));
-    apps.push_back(String16(kApp2.c_str()));
-    versions.push_back(4);
-    versions.push_back(5);
-    m.updateMap(1, uids, versions, versionStrings, apps, installers);
-
-    std::set<string> name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
-    ASSERT_EQ(name_set.size(), 2u);
-    EXPECT_TRUE(name_set.find(kApp1) != name_set.end());
-    EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
-
-    // Update the app1 version.
-    m.updateApp(2, String16(kApp1.c_str()), 1000, 40, String16("v40"), String16(""));
-    EXPECT_EQ(40, m.getAppVersion(1000, kApp1));
-
-    name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
-    ASSERT_EQ(name_set.size(), 2u);
-    EXPECT_TRUE(name_set.find(kApp1) != name_set.end());
-    EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
-
-    m.removeApp(3, String16(kApp1.c_str()), 1000);
-    EXPECT_FALSE(m.hasApp(1000, kApp1));
-    EXPECT_TRUE(m.hasApp(1000, kApp2));
-    name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
-    ASSERT_EQ(name_set.size(), 1u);
-    EXPECT_TRUE(name_set.find(kApp1) == name_set.end());
-    EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
-
-    // Remove app2.
-    m.removeApp(4, String16(kApp2.c_str()), 1000);
-    EXPECT_FALSE(m.hasApp(1000, kApp1));
-    EXPECT_FALSE(m.hasApp(1000, kApp2));
-    name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
-    EXPECT_TRUE(name_set.empty());
-}
-
-TEST(UidMapTest, TestUpdateApp) {
-    UidMap m;
-    m.updateMap(1, {1000, 1000}, {4, 5}, {String16("v4"), String16("v5")},
-                {String16(kApp1.c_str()), String16(kApp2.c_str())}, {String16(""), String16("")});
-    std::set<string> name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
-    ASSERT_EQ(name_set.size(), 2u);
-    EXPECT_TRUE(name_set.find(kApp1) != name_set.end());
-    EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
-
-    // Adds a new name for uid 1000.
-    m.updateApp(2, String16("NeW_aPP1_NAmE"), 1000, 40, String16("v40"), String16(""));
-    name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
-    ASSERT_EQ(name_set.size(), 3u);
-    EXPECT_TRUE(name_set.find(kApp1) != name_set.end());
-    EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
-    EXPECT_TRUE(name_set.find("NeW_aPP1_NAmE") == name_set.end());
-    EXPECT_TRUE(name_set.find("new_app1_name") != name_set.end());
-
-    // This name is also reused by another uid 2000.
-    m.updateApp(3, String16("NeW_aPP1_NAmE"), 2000, 1, String16("v1"), String16(""));
-    name_set = m.getAppNamesFromUid(2000, true /* returnNormalized */);
-    ASSERT_EQ(name_set.size(), 1u);
-    EXPECT_TRUE(name_set.find("NeW_aPP1_NAmE") == name_set.end());
-    EXPECT_TRUE(name_set.find("new_app1_name") != name_set.end());
-}
-
-static void protoOutputStreamToUidMapping(ProtoOutputStream* proto, UidMapping* results) {
-    vector<uint8_t> bytes;
-    bytes.resize(proto->size());
-    size_t pos = 0;
-    sp<ProtoReader> reader = proto->data();
-    while (reader->readBuffer() != NULL) {
-        size_t toRead = reader->currentToRead();
-        std::memcpy(&((bytes)[pos]), reader->readBuffer(), toRead);
-        pos += toRead;
-        reader->move(toRead);
-    }
-    results->ParseFromArray(bytes.data(), bytes.size());
-}
-
-// Test that uid map returns at least one snapshot even if we already obtained
-// this snapshot from a previous call to getData.
-TEST(UidMapTest, TestOutputIncludesAtLeastOneSnapshot) {
-    UidMap m;
-    // Initialize single config key.
-    ConfigKey config1(1, StringToId("config1"));
-    m.OnConfigUpdated(config1);
-    vector<int32_t> uids;
-    vector<int64_t> versions;
-    vector<String16> apps;
-    vector<String16> versionStrings;
-    vector<String16> installers;
-    uids.push_back(1000);
-    apps.push_back(String16(kApp2.c_str()));
-    versionStrings.push_back(String16("v1"));
-    installers.push_back(String16(""));
-    versions.push_back(5);
-    m.updateMap(1, uids, versions, versionStrings, apps, installers);
-
-    // Set the last timestamp for this config key to be newer.
-    m.mLastUpdatePerConfigKey[config1] = 2;
-
-    ProtoOutputStream proto;
-    m.appendUidMap(3, config1, nullptr, true, true, &proto);
-
-    // Check there's still a uidmap attached this one.
-    UidMapping results;
-    protoOutputStreamToUidMapping(&proto, &results);
-    ASSERT_EQ(1, results.snapshots_size());
-    EXPECT_EQ("v1", results.snapshots(0).package_info(0).version_string());
-}
-
-TEST(UidMapTest, TestRemovedAppRetained) {
-    UidMap m;
-    // Initialize single config key.
-    ConfigKey config1(1, StringToId("config1"));
-    m.OnConfigUpdated(config1);
-    vector<int32_t> uids;
-    vector<int64_t> versions;
-    vector<String16> versionStrings;
-    vector<String16> installers;
-    vector<String16> apps;
-    uids.push_back(1000);
-    apps.push_back(String16(kApp2.c_str()));
-    versions.push_back(5);
-    versionStrings.push_back(String16("v5"));
-    installers.push_back(String16(""));
-    m.updateMap(1, uids, versions, versionStrings, apps, installers);
-    m.removeApp(2, String16(kApp2.c_str()), 1000);
-
-    ProtoOutputStream proto;
-    m.appendUidMap(3, config1, nullptr, true, true, &proto);
-
-    // Snapshot should still contain this item as deleted.
-    UidMapping results;
-    protoOutputStreamToUidMapping(&proto, &results);
-    ASSERT_EQ(1, results.snapshots(0).package_info_size());
-    EXPECT_EQ(true, results.snapshots(0).package_info(0).deleted());
-}
-
-TEST(UidMapTest, TestRemovedAppOverGuardrail) {
-    UidMap m;
-    // Initialize single config key.
-    ConfigKey config1(1, StringToId("config1"));
-    m.OnConfigUpdated(config1);
-    vector<int32_t> uids;
-    vector<int64_t> versions;
-    vector<String16> versionStrings;
-    vector<String16> installers;
-    vector<String16> apps;
-    const int maxDeletedApps = StatsdStats::kMaxDeletedAppsInUidMap;
-    for (int j = 0; j < maxDeletedApps + 10; j++) {
-        uids.push_back(j);
-        apps.push_back(String16(kApp1.c_str()));
-        versions.push_back(j);
-        versionStrings.push_back(String16("v"));
-        installers.push_back(String16(""));
-    }
-    m.updateMap(1, uids, versions, versionStrings, apps, installers);
-
-    // First, verify that we have the expected number of items.
-    UidMapping results;
-    ProtoOutputStream proto;
-    m.appendUidMap(3, config1, nullptr, true, true, &proto);
-    protoOutputStreamToUidMapping(&proto, &results);
-    ASSERT_EQ(maxDeletedApps + 10, results.snapshots(0).package_info_size());
-
-    // Now remove all the apps.
-    m.updateMap(1, uids, versions, versionStrings, apps, installers);
-    for (int j = 0; j < maxDeletedApps + 10; j++) {
-        m.removeApp(4, String16(kApp1.c_str()), j);
-    }
-
-    proto.clear();
-    m.appendUidMap(5, config1, nullptr, true, true, &proto);
-    // Snapshot drops the first nine items.
-    protoOutputStreamToUidMapping(&proto, &results);
-    ASSERT_EQ(maxDeletedApps, results.snapshots(0).package_info_size());
-}
-
-TEST(UidMapTest, TestClearingOutput) {
-    UidMap m;
-
-    ConfigKey config1(1, StringToId("config1"));
-    ConfigKey config2(1, StringToId("config2"));
-
-    m.OnConfigUpdated(config1);
-
-    vector<int32_t> uids;
-    vector<int64_t> versions;
-    vector<String16> versionStrings;
-    vector<String16> installers;
-    vector<String16> apps;
-    uids.push_back(1000);
-    uids.push_back(1000);
-    apps.push_back(String16(kApp1.c_str()));
-    apps.push_back(String16(kApp2.c_str()));
-    versions.push_back(4);
-    versions.push_back(5);
-    versionStrings.push_back(String16("v4"));
-    versionStrings.push_back(String16("v5"));
-    installers.push_back(String16(""));
-    installers.push_back(String16(""));
-    m.updateMap(1, uids, versions, versionStrings, apps, installers);
-
-    ProtoOutputStream proto;
-    m.appendUidMap(2, config1, nullptr, true, true, &proto);
-    UidMapping results;
-    protoOutputStreamToUidMapping(&proto, &results);
-    ASSERT_EQ(1, results.snapshots_size());
-
-    // We have to keep at least one snapshot in memory at all times.
-    proto.clear();
-    m.appendUidMap(2, config1, nullptr, true, true, &proto);
-    protoOutputStreamToUidMapping(&proto, &results);
-    ASSERT_EQ(1, results.snapshots_size());
-
-    // Now add another configuration.
-    m.OnConfigUpdated(config2);
-    m.updateApp(5, String16(kApp1.c_str()), 1000, 40, String16("v40"), String16(""));
-    ASSERT_EQ(1U, m.mChanges.size());
-    proto.clear();
-    m.appendUidMap(6, config1, nullptr, true, true, &proto);
-    protoOutputStreamToUidMapping(&proto, &results);
-    ASSERT_EQ(1, results.snapshots_size());
-    ASSERT_EQ(1, results.changes_size());
-    ASSERT_EQ(1U, m.mChanges.size());
-
-    // Add another delta update.
-    m.updateApp(7, String16(kApp2.c_str()), 1001, 41, String16("v41"), String16(""));
-    ASSERT_EQ(2U, m.mChanges.size());
-
-    // We still can't remove anything.
-    proto.clear();
-    m.appendUidMap(8, config1, nullptr, true, true, &proto);
-    protoOutputStreamToUidMapping(&proto, &results);
-    ASSERT_EQ(1, results.snapshots_size());
-    ASSERT_EQ(1, results.changes_size());
-    ASSERT_EQ(2U, m.mChanges.size());
-
-    proto.clear();
-    m.appendUidMap(9, config2, nullptr, true, true, &proto);
-    protoOutputStreamToUidMapping(&proto, &results);
-    ASSERT_EQ(1, results.snapshots_size());
-    ASSERT_EQ(2, results.changes_size());
-    // At this point both should be cleared.
-    ASSERT_EQ(0U, m.mChanges.size());
-}
-
-TEST(UidMapTest, TestMemoryComputed) {
-    UidMap m;
-
-    ConfigKey config1(1, StringToId("config1"));
-    m.OnConfigUpdated(config1);
-
-    size_t startBytes = m.mBytesUsed;
-    vector<int32_t> uids;
-    vector<int64_t> versions;
-    vector<String16> apps;
-    vector<String16> versionStrings;
-    vector<String16> installers;
-    uids.push_back(1000);
-    apps.push_back(String16(kApp1.c_str()));
-    versions.push_back(1);
-    versionStrings.push_back(String16("v1"));
-    installers.push_back(String16(""));
-    m.updateMap(1, uids, versions, versionStrings, apps, installers);
-
-    m.updateApp(3, String16(kApp1.c_str()), 1000, 40, String16("v40"), String16(""));
-
-    ProtoOutputStream proto;
-    vector<uint8_t> bytes;
-    m.appendUidMap(2, config1, nullptr, true, true, &proto);
-    size_t prevBytes = m.mBytesUsed;
-
-    m.appendUidMap(4, config1, nullptr, true, true, &proto);
-    EXPECT_TRUE(m.mBytesUsed < prevBytes);
-}
-
-TEST(UidMapTest, TestMemoryGuardrail) {
-    UidMap m;
-    string buf;
-
-    ConfigKey config1(1, StringToId("config1"));
-    m.OnConfigUpdated(config1);
-
-    size_t startBytes = m.mBytesUsed;
-    vector<int32_t> uids;
-    vector<int64_t> versions;
-    vector<String16> versionStrings;
-    vector<String16> installers;
-    vector<String16> apps;
-    for (int i = 0; i < 100; i++) {
-        uids.push_back(1);
-        buf = "EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY." + to_string(i);
-        apps.push_back(String16(buf.c_str()));
-        versions.push_back(1);
-        versionStrings.push_back(String16("v1"));
-        installers.push_back(String16(""));
-    }
-    m.updateMap(1, uids, versions, versionStrings, apps, installers);
-
-    m.updateApp(3, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 2,
-                String16("v2"), String16(""));
-    ASSERT_EQ(1U, m.mChanges.size());
-
-    // Now force deletion by limiting the memory to hold one delta change.
-    m.maxBytesOverride = 120; // Since the app string alone requires >45 characters.
-    m.updateApp(5, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 4,
-                String16("v4"), String16(""));
-    ASSERT_EQ(1U, m.mChanges.size());
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp b/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp
deleted file mode 100644
index 64ea219..0000000
--- a/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/anomaly/AlarmTracker.h"
-
-#include <gtest/gtest.h>
-#include <log/log_time.h>
-#include <stdio.h>
-#include <vector>
-
-using namespace testing;
-using android::sp;
-using std::set;
-using std::shared_ptr;
-using std::unordered_map;
-using std::vector;
-
-#ifdef __ANDROID__
-
-namespace android {
-namespace os {
-namespace statsd {
-
-const ConfigKey kConfigKey(0, 12345);
-
-TEST(AlarmTrackerTest, TestTriggerTimestamp) {
-    sp<AlarmMonitor> subscriberAlarmMonitor =
-        new AlarmMonitor(100,
-                         [](const shared_ptr<IStatsCompanionService>&, int64_t){},
-                         [](const shared_ptr<IStatsCompanionService>&){});
-    Alarm alarm;
-    alarm.set_offset_millis(15 * MS_PER_SEC);
-    alarm.set_period_millis(60 * 60 * MS_PER_SEC);  // 1hr
-    int64_t startMillis = 100000000 * MS_PER_SEC;
-    int64_t nextAlarmTime = startMillis / MS_PER_SEC + 15;
-    AlarmTracker tracker(startMillis, startMillis, alarm, kConfigKey, subscriberAlarmMonitor);
-
-    EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime);
-
-    uint64_t currentTimeSec = startMillis / MS_PER_SEC + 10;
-    std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> firedAlarmSet =
-        subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
-    EXPECT_TRUE(firedAlarmSet.empty());
-    tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
-    EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime);
-    EXPECT_EQ(tracker.getAlarmTimestampSec(), nextAlarmTime);
-
-    currentTimeSec = startMillis / MS_PER_SEC + 7000;
-    nextAlarmTime = startMillis / MS_PER_SEC + 15 + 2 * 60 * 60;
-    firedAlarmSet = subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
-    ASSERT_EQ(firedAlarmSet.size(), 1u);
-    tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
-    EXPECT_TRUE(firedAlarmSet.empty());
-    EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime);
-    EXPECT_EQ(tracker.getAlarmTimestampSec(), nextAlarmTime);
-
-    // Alarm fires exactly on time.
-    currentTimeSec = startMillis / MS_PER_SEC + 15 + 2 * 60 * 60;
-    nextAlarmTime = startMillis / MS_PER_SEC + 15 + 3 * 60 * 60;
-    firedAlarmSet = subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
-    ASSERT_EQ(firedAlarmSet.size(), 1u);
-    tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
-    EXPECT_TRUE(firedAlarmSet.empty());
-    EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime);
-    EXPECT_EQ(tracker.getAlarmTimestampSec(), nextAlarmTime);
-
-    // Alarm fires exactly 1 period late.
-    currentTimeSec = startMillis / MS_PER_SEC + 15 + 4 * 60 * 60;
-    nextAlarmTime = startMillis / MS_PER_SEC + 15 + 5 * 60 * 60;
-    firedAlarmSet = subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
-    ASSERT_EQ(firedAlarmSet.size(), 1u);
-    tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
-    EXPECT_TRUE(firedAlarmSet.empty());
-    EXPECT_EQ(tracker.mAlarmSec, nextAlarmTime);
-    EXPECT_EQ(tracker.getAlarmTimestampSec(), nextAlarmTime);
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
deleted file mode 100644
index 0cc8af1..0000000
--- a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
+++ /dev/null
@@ -1,408 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/anomaly/AnomalyTracker.h"
-
-#include <gtest/gtest.h>
-#include <math.h>
-#include <stdio.h>
-
-#include <vector>
-
-#include "tests/statsd_test_util.h"
-
-using namespace testing;
-using android::sp;
-using std::set;
-using std::unordered_map;
-using std::vector;
-
-#ifdef __ANDROID__
-
-namespace android {
-namespace os {
-namespace statsd {
-
-const ConfigKey kConfigKey(0, 12345);
-
-MetricDimensionKey getMockMetricDimensionKey(int key, string value) {
-    int pos[] = {key, 0, 0};
-    HashableDimensionKey dim;
-    dim.addValue(FieldValue(Field(1, pos, 0), Value(value)));
-    return MetricDimensionKey(dim, DEFAULT_DIMENSION_KEY);
-}
-
-void AddValueToBucket(const std::vector<std::pair<MetricDimensionKey, long>>& key_value_pair_list,
-                      std::shared_ptr<DimToValMap> bucket) {
-    for (auto itr = key_value_pair_list.begin(); itr != key_value_pair_list.end(); itr++) {
-        (*bucket)[itr->first] += itr->second;
-    }
-}
-
-std::shared_ptr<DimToValMap> MockBucket(
-        const std::vector<std::pair<MetricDimensionKey, long>>& key_value_pair_list) {
-    std::shared_ptr<DimToValMap> bucket = std::make_shared<DimToValMap>();
-    AddValueToBucket(key_value_pair_list, bucket);
-    return bucket;
-}
-
-// Returns the value, for the given key, in that bucket, or 0 if not present.
-int64_t getBucketValue(const std::shared_ptr<DimToValMap>& bucket,
-                       const MetricDimensionKey& key) {
-    const auto& itr = bucket->find(key);
-    if (itr != bucket->end()) {
-        return itr->second;
-    }
-    return 0;
-}
-
-// Returns true if keys in trueList are detected as anomalies and keys in falseList are not.
-bool detectAnomaliesPass(AnomalyTracker& tracker,
-                         const int64_t& bucketNum,
-                         const std::shared_ptr<DimToValMap>& currentBucket,
-                         const std::set<const MetricDimensionKey>& trueList,
-                         const std::set<const MetricDimensionKey>& falseList) {
-    for (const MetricDimensionKey& key : trueList) {
-        if (!tracker.detectAnomaly(bucketNum, key, getBucketValue(currentBucket, key))) {
-            return false;
-        }
-    }
-    for (const MetricDimensionKey& key : falseList) {
-        if (tracker.detectAnomaly(bucketNum, key, getBucketValue(currentBucket, key))) {
-            return false;
-        }
-    }
-    return true;
-}
-
-// Calls tracker.detectAndDeclareAnomaly on each key in the bucket.
-void detectAndDeclareAnomalies(AnomalyTracker& tracker,
-                               const int64_t& bucketNum,
-                               const std::shared_ptr<DimToValMap>& bucket,
-                               const int64_t& eventTimestamp) {
-    for (const auto& kv : *bucket) {
-        tracker.detectAndDeclareAnomaly(eventTimestamp, bucketNum, 0 /*metric_id*/, kv.first,
-                                        kv.second);
-    }
-}
-
-// Asserts that the refractory time for each key in timestamps is the corresponding
-// timestamp (in ns) + refractoryPeriodSec.
-// If a timestamp value is negative, instead asserts that the refractory period is inapplicable
-// (either non-existant or already past).
-void checkRefractoryTimes(AnomalyTracker& tracker,
-                          const int64_t& currTimestampNs,
-                          const int32_t& refractoryPeriodSec,
-                          const std::unordered_map<MetricDimensionKey, int64_t>& timestamps) {
-    for (const auto& kv : timestamps) {
-        if (kv.second < 0) {
-            // Make sure that, if there is a refractory period, it is already past.
-            EXPECT_LT(tracker.getRefractoryPeriodEndsSec(kv.first) * NS_PER_SEC,
-                    (uint64_t)currTimestampNs)
-                    << "Failure was at currTimestampNs " << currTimestampNs;
-        } else {
-            EXPECT_EQ(tracker.getRefractoryPeriodEndsSec(kv.first),
-                      std::ceil(1.0 * kv.second / NS_PER_SEC) + refractoryPeriodSec)
-                      << "Failure was at currTimestampNs " << currTimestampNs;
-        }
-    }
-}
-
-TEST(AnomalyTrackerTest, TestConsecutiveBuckets) {
-    const int64_t bucketSizeNs = 30 * NS_PER_SEC;
-    const int32_t refractoryPeriodSec = 2 * bucketSizeNs / NS_PER_SEC;
-    Alert alert;
-    alert.set_num_buckets(3);
-    alert.set_refractory_period_secs(refractoryPeriodSec);
-    alert.set_trigger_if_sum_gt(2);
-
-    AnomalyTracker anomalyTracker(alert, kConfigKey);
-    MetricDimensionKey keyA = getMockMetricDimensionKey(1, "a");
-    MetricDimensionKey keyB = getMockMetricDimensionKey(1, "b");
-    MetricDimensionKey keyC = getMockMetricDimensionKey(1, "c");
-
-    int64_t eventTimestamp0 = 10 * NS_PER_SEC;
-    int64_t eventTimestamp1 = bucketSizeNs + 11 * NS_PER_SEC;
-    int64_t eventTimestamp2 = 2 * bucketSizeNs + 12 * NS_PER_SEC;
-    int64_t eventTimestamp3 = 3 * bucketSizeNs + 13 * NS_PER_SEC;
-    int64_t eventTimestamp4 = 4 * bucketSizeNs + 14 * NS_PER_SEC;
-    int64_t eventTimestamp5 = 5 * bucketSizeNs + 5 * NS_PER_SEC;
-    int64_t eventTimestamp6 = 6 * bucketSizeNs + 16 * NS_PER_SEC;
-
-    std::shared_ptr<DimToValMap> bucket0 = MockBucket({{keyA, 1}, {keyB, 2}, {keyC, 1}});
-    std::shared_ptr<DimToValMap> bucket1 = MockBucket({{keyA, 1}});
-    std::shared_ptr<DimToValMap> bucket2 = MockBucket({{keyB, 1}});
-    std::shared_ptr<DimToValMap> bucket3 = MockBucket({{keyA, 2}});
-    std::shared_ptr<DimToValMap> bucket4 = MockBucket({{keyB, 5}});
-    std::shared_ptr<DimToValMap> bucket5 = MockBucket({{keyA, 2}});
-    std::shared_ptr<DimToValMap> bucket6 = MockBucket({{keyA, 2}});
-
-    // Start time with no events.
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0u);
-    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, -1LL);
-
-    // Event from bucket #0 occurs.
-    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 0, bucket0, {}, {keyA, keyB, keyC}));
-    detectAndDeclareAnomalies(anomalyTracker, 0, bucket0, eventTimestamp1);
-    checkRefractoryTimes(anomalyTracker, eventTimestamp0, refractoryPeriodSec,
-            {{keyA, -1}, {keyB, -1}, {keyC, -1}});
-
-    // Adds past bucket #0
-    anomalyTracker.addPastBucket(bucket0, 0);
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3u);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
-    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 0LL);
-
-    // Event from bucket #1 occurs.
-    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 1, bucket1, {}, {keyA, keyB, keyC}));
-    detectAndDeclareAnomalies(anomalyTracker, 1, bucket1, eventTimestamp1);
-    checkRefractoryTimes(anomalyTracker, eventTimestamp1, refractoryPeriodSec,
-            {{keyA, -1}, {keyB, -1}, {keyC, -1}});
-
-    // Adds past bucket #0 again. The sum does not change.
-    anomalyTracker.addPastBucket(bucket0, 0);
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3u);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
-    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 0LL);
-    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 1, bucket1, {}, {keyA, keyB, keyC}));
-    detectAndDeclareAnomalies(anomalyTracker, 1, bucket1, eventTimestamp1 + 1);
-    checkRefractoryTimes(anomalyTracker, eventTimestamp1, refractoryPeriodSec,
-            {{keyA, -1}, {keyB, -1}, {keyC, -1}});
-
-    // Adds past bucket #1.
-    anomalyTracker.addPastBucket(bucket1, 1);
-    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 1L);
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3UL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
-
-    // Event from bucket #2 occurs. New anomaly on keyB.
-    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 2, bucket2, {keyB}, {keyA, keyC}));
-    detectAndDeclareAnomalies(anomalyTracker, 2, bucket2, eventTimestamp2);
-    checkRefractoryTimes(anomalyTracker, eventTimestamp2, refractoryPeriodSec,
-            {{keyA, -1}, {keyB, eventTimestamp2}, {keyC, -1}});
-
-    // Adds past bucket #1 again. Nothing changes.
-    anomalyTracker.addPastBucket(bucket1, 1);
-    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 1L);
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3UL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
-    // Event from bucket #2 occurs (again).
-    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 2, bucket2, {keyB}, {keyA, keyC}));
-    detectAndDeclareAnomalies(anomalyTracker, 2, bucket2, eventTimestamp2 + 1);
-    checkRefractoryTimes(anomalyTracker, eventTimestamp2, refractoryPeriodSec,
-            {{keyA, -1}, {keyB, eventTimestamp2}, {keyC, -1}});
-
-    // Adds past bucket #2.
-    anomalyTracker.addPastBucket(bucket2, 2);
-    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 2L);
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
-
-    // Event from bucket #3 occurs. New anomaly on keyA.
-    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 3, bucket3, {keyA}, {keyB, keyC}));
-    detectAndDeclareAnomalies(anomalyTracker, 3, bucket3, eventTimestamp3);
-    checkRefractoryTimes(anomalyTracker, eventTimestamp3, refractoryPeriodSec,
-            {{keyA, eventTimestamp3}, {keyB, eventTimestamp2}, {keyC, -1}});
-
-    // Adds bucket #3.
-    anomalyTracker.addPastBucket(bucket3, 3L);
-    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 3L);
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
-
-    // Event from bucket #4 occurs. New anomaly on keyB.
-    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 4, bucket4, {keyB}, {keyA, keyC}));
-    detectAndDeclareAnomalies(anomalyTracker, 4, bucket4, eventTimestamp4);
-    checkRefractoryTimes(anomalyTracker, eventTimestamp4, refractoryPeriodSec,
-            {{keyA, eventTimestamp3}, {keyB, eventTimestamp4}, {keyC, -1}});
-
-    // Adds bucket #4.
-    anomalyTracker.addPastBucket(bucket4, 4);
-    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 4L);
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 5LL);
-
-    // Event from bucket #5 occurs. New anomaly on keyA, which is still in refractory.
-    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 5, bucket5, {keyA, keyB}, {keyC}));
-    detectAndDeclareAnomalies(anomalyTracker, 5, bucket5, eventTimestamp5);
-    checkRefractoryTimes(anomalyTracker, eventTimestamp5, refractoryPeriodSec,
-            {{keyA, eventTimestamp3}, {keyB, eventTimestamp4}, {keyC, -1}});
-
-    // Adds bucket #5.
-    anomalyTracker.addPastBucket(bucket5, 5);
-    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 5L);
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 2LL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 5LL);
-
-    // Event from bucket #6 occurs. New anomaly on keyA, which is now out of refractory.
-    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 6, bucket6, {keyA, keyB}, {keyC}));
-    detectAndDeclareAnomalies(anomalyTracker, 6, bucket6, eventTimestamp6);
-    checkRefractoryTimes(anomalyTracker, eventTimestamp6, refractoryPeriodSec,
-            {{keyA, eventTimestamp6}, {keyB, eventTimestamp4}, {keyC, -1}});
-}
-
-TEST(AnomalyTrackerTest, TestSparseBuckets) {
-    const int64_t bucketSizeNs = 30 * NS_PER_SEC;
-    const int32_t refractoryPeriodSec = 2 * bucketSizeNs / NS_PER_SEC;
-    Alert alert;
-    alert.set_num_buckets(3);
-    alert.set_refractory_period_secs(refractoryPeriodSec);
-    alert.set_trigger_if_sum_gt(2);
-
-    AnomalyTracker anomalyTracker(alert, kConfigKey);
-    MetricDimensionKey keyA = getMockMetricDimensionKey(1, "a");
-    MetricDimensionKey keyB = getMockMetricDimensionKey(1, "b");
-    MetricDimensionKey keyC = getMockMetricDimensionKey(1, "c");
-    MetricDimensionKey keyD = getMockMetricDimensionKey(1, "d");
-    MetricDimensionKey keyE = getMockMetricDimensionKey(1, "e");
-
-    std::shared_ptr<DimToValMap> bucket9 = MockBucket({{keyA, 1}, {keyB, 2}, {keyC, 1}});
-    std::shared_ptr<DimToValMap> bucket16 = MockBucket({{keyB, 4}});
-    std::shared_ptr<DimToValMap> bucket18 = MockBucket({{keyB, 1}, {keyC, 1}});
-    std::shared_ptr<DimToValMap> bucket20 = MockBucket({{keyB, 3}, {keyC, 1}});
-    std::shared_ptr<DimToValMap> bucket25 = MockBucket({{keyD, 1}});
-    std::shared_ptr<DimToValMap> bucket28 = MockBucket({{keyE, 2}});
-
-    int64_t eventTimestamp1 = bucketSizeNs * 8 + 1;
-    int64_t eventTimestamp2 = bucketSizeNs * 15 + 11;
-    int64_t eventTimestamp3 = bucketSizeNs * 17 + 1;
-    int64_t eventTimestamp4 = bucketSizeNs * 19 + 2;
-    int64_t eventTimestamp5 = bucketSizeNs * 24 + 3;
-    int64_t eventTimestamp6 = bucketSizeNs * 27 + 3;
-
-    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, -1LL);
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
-    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 9, bucket9, {}, {keyA, keyB, keyC, keyD}));
-    detectAndDeclareAnomalies(anomalyTracker, 9, bucket9, eventTimestamp1);
-    checkRefractoryTimes(anomalyTracker, eventTimestamp1, refractoryPeriodSec,
-            {{keyA, -1}, {keyB, -1}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
-
-    // Add past bucket #9
-    anomalyTracker.addPastBucket(bucket9, 9);
-    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 9L);
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 3UL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyA), 1LL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
-    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 16, bucket16, {keyB}, {keyA, keyC, keyD}));
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
-    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 15L);
-    detectAndDeclareAnomalies(anomalyTracker, 16, bucket16, eventTimestamp2);
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
-    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 15L);
-    checkRefractoryTimes(anomalyTracker, eventTimestamp2, refractoryPeriodSec,
-            {{keyA, -1}, {keyB, eventTimestamp2}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
-
-    // Add past bucket #16
-    anomalyTracker.addPastBucket(bucket16, 16);
-    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 16L);
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 4LL);
-    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 18, bucket18, {keyB}, {keyA, keyC, keyD}));
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 4LL);
-    // Within refractory period.
-    detectAndDeclareAnomalies(anomalyTracker, 18, bucket18, eventTimestamp3);
-    checkRefractoryTimes(anomalyTracker, eventTimestamp3, refractoryPeriodSec,
-            {{keyA, -1}, {keyB, eventTimestamp2}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 4LL);
-
-    // Add past bucket #18
-    anomalyTracker.addPastBucket(bucket18, 18);
-    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 18L);
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
-    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 20, bucket20, {keyB}, {keyA, keyC, keyD}));
-    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 19L);
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
-    detectAndDeclareAnomalies(anomalyTracker, 20, bucket20, eventTimestamp4);
-    checkRefractoryTimes(anomalyTracker, eventTimestamp4, refractoryPeriodSec,
-            {{keyA, -1}, {keyB, eventTimestamp4}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
-
-    // Add bucket #18 again. Nothing changes.
-    anomalyTracker.addPastBucket(bucket18, 18);
-    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 19L);
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
-    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 20, bucket20, {keyB}, {keyA, keyC, keyD}));
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 1LL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
-    detectAndDeclareAnomalies(anomalyTracker, 20, bucket20, eventTimestamp4 + 1);
-    // Within refractory period.
-    checkRefractoryTimes(anomalyTracker, eventTimestamp4 + 1, refractoryPeriodSec,
-            {{keyA, -1}, {keyB, eventTimestamp4}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
-
-    // Add past bucket #20
-    anomalyTracker.addPastBucket(bucket20, 20);
-    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 20L);
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 2UL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 3LL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
-    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 25, bucket25, {}, {keyA, keyB, keyC, keyD}));
-    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 24L);
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
-    detectAndDeclareAnomalies(anomalyTracker, 25, bucket25, eventTimestamp5);
-    checkRefractoryTimes(anomalyTracker, eventTimestamp5, refractoryPeriodSec,
-            {{keyA, -1}, {keyB, eventTimestamp4}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
-
-    // Add past bucket #25
-    anomalyTracker.addPastBucket(bucket25, 25);
-    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 25L);
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
-    EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyD), 1LL);
-    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 28, bucket28, {},
-            {keyA, keyB, keyC, keyD, keyE}));
-    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 27L);
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
-    detectAndDeclareAnomalies(anomalyTracker, 28, bucket28, eventTimestamp6);
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
-    checkRefractoryTimes(anomalyTracker, eventTimestamp6, refractoryPeriodSec,
-            {{keyA, -1}, {keyB, -1}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
-
-    // Updates current bucket #28.
-    (*bucket28)[keyE] = 5;
-    EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 28, bucket28, {keyE},
-            {keyA, keyB, keyC, keyD}));
-    EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 27L);
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
-    detectAndDeclareAnomalies(anomalyTracker, 28, bucket28, eventTimestamp6 + 7);
-    ASSERT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
-    checkRefractoryTimes(anomalyTracker, eventTimestamp6, refractoryPeriodSec,
-            {{keyA, -1}, {keyB, -1}, {keyC, -1}, {keyD, -1}, {keyE, eventTimestamp6 + 7}});
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/condition/CombinationConditionTracker_test.cpp b/cmds/statsd/tests/condition/CombinationConditionTracker_test.cpp
deleted file mode 100644
index 1d501fd..0000000
--- a/cmds/statsd/tests/condition/CombinationConditionTracker_test.cpp
+++ /dev/null
@@ -1,167 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "condition/condition_util.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-
-#include <gtest/gtest.h>
-
-#include <stdio.h>
-#include <vector>
-
-using namespace android::os::statsd;
-using std::vector;
-
-#ifdef __ANDROID__
-
-TEST(ConditionTrackerTest, TestUnknownCondition) {
-    LogicalOperation operation = LogicalOperation::AND;
-
-    vector<int> children;
-    children.push_back(0);
-    children.push_back(1);
-    children.push_back(2);
-
-    vector<ConditionState> conditionResults;
-    conditionResults.push_back(ConditionState::kUnknown);
-    conditionResults.push_back(ConditionState::kFalse);
-    conditionResults.push_back(ConditionState::kTrue);
-
-    EXPECT_EQ(evaluateCombinationCondition(children, operation, conditionResults),
-              ConditionState::kUnknown);
-}
-
-TEST(ConditionTrackerTest, TestAndCondition) {
-    // Set up the matcher
-    LogicalOperation operation = LogicalOperation::AND;
-
-    vector<int> children;
-    children.push_back(0);
-    children.push_back(1);
-    children.push_back(2);
-
-    vector<ConditionState> conditionResults;
-    conditionResults.push_back(ConditionState::kTrue);
-    conditionResults.push_back(ConditionState::kFalse);
-    conditionResults.push_back(ConditionState::kTrue);
-
-    EXPECT_FALSE(evaluateCombinationCondition(children, operation, conditionResults));
-
-    conditionResults.clear();
-    conditionResults.push_back(ConditionState::kTrue);
-    conditionResults.push_back(ConditionState::kTrue);
-    conditionResults.push_back(ConditionState::kTrue);
-
-    EXPECT_TRUE(evaluateCombinationCondition(children, operation, conditionResults));
-}
-
-TEST(ConditionTrackerTest, TestOrCondition) {
-    // Set up the matcher
-    LogicalOperation operation = LogicalOperation::OR;
-
-    vector<int> children;
-    children.push_back(0);
-    children.push_back(1);
-    children.push_back(2);
-
-    vector<ConditionState> conditionResults;
-    conditionResults.push_back(ConditionState::kTrue);
-    conditionResults.push_back(ConditionState::kFalse);
-    conditionResults.push_back(ConditionState::kTrue);
-
-    EXPECT_TRUE(evaluateCombinationCondition(children, operation, conditionResults));
-
-    conditionResults.clear();
-    conditionResults.push_back(ConditionState::kFalse);
-    conditionResults.push_back(ConditionState::kFalse);
-    conditionResults.push_back(ConditionState::kFalse);
-
-    EXPECT_FALSE(evaluateCombinationCondition(children, operation, conditionResults));
-}
-
-TEST(ConditionTrackerTest, TestNotCondition) {
-    // Set up the matcher
-    LogicalOperation operation = LogicalOperation::NOT;
-
-    vector<int> children;
-    children.push_back(0);
-
-    vector<ConditionState> conditionResults;
-    conditionResults.push_back(ConditionState::kTrue);
-
-    EXPECT_FALSE(evaluateCombinationCondition(children, operation, conditionResults));
-
-    conditionResults.clear();
-    conditionResults.push_back(ConditionState::kFalse);
-    EXPECT_TRUE(evaluateCombinationCondition(children, operation, conditionResults));
-
-    children.clear();
-    conditionResults.clear();
-    EXPECT_EQ(evaluateCombinationCondition(children, operation, conditionResults),
-              ConditionState::kUnknown);
-}
-
-TEST(ConditionTrackerTest, TestNandCondition) {
-    // Set up the matcher
-    LogicalOperation operation = LogicalOperation::NAND;
-
-    vector<int> children;
-    children.push_back(0);
-    children.push_back(1);
-
-    vector<ConditionState> conditionResults;
-    conditionResults.push_back(ConditionState::kTrue);
-    conditionResults.push_back(ConditionState::kFalse);
-
-    EXPECT_TRUE(evaluateCombinationCondition(children, operation, conditionResults));
-
-    conditionResults.clear();
-    conditionResults.push_back(ConditionState::kFalse);
-    conditionResults.push_back(ConditionState::kFalse);
-    EXPECT_TRUE(evaluateCombinationCondition(children, operation, conditionResults));
-
-    conditionResults.clear();
-    conditionResults.push_back(ConditionState::kTrue);
-    conditionResults.push_back(ConditionState::kTrue);
-    EXPECT_FALSE(evaluateCombinationCondition(children, operation, conditionResults));
-}
-
-TEST(ConditionTrackerTest, TestNorCondition) {
-    // Set up the matcher
-    LogicalOperation operation = LogicalOperation::NOR;
-
-    vector<int> children;
-    children.push_back(0);
-    children.push_back(1);
-
-    vector<ConditionState> conditionResults;
-    conditionResults.push_back(ConditionState::kTrue);
-    conditionResults.push_back(ConditionState::kFalse);
-
-    EXPECT_FALSE(evaluateCombinationCondition(children, operation, conditionResults));
-
-    conditionResults.clear();
-    conditionResults.push_back(ConditionState::kFalse);
-    conditionResults.push_back(ConditionState::kFalse);
-    EXPECT_TRUE(evaluateCombinationCondition(children, operation, conditionResults));
-
-    conditionResults.clear();
-    conditionResults.push_back(ConditionState::kTrue);
-    conditionResults.push_back(ConditionState::kTrue);
-    EXPECT_FALSE(evaluateCombinationCondition(children, operation, conditionResults));
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/condition/ConditionTimer_test.cpp b/cmds/statsd/tests/condition/ConditionTimer_test.cpp
deleted file mode 100644
index 46dc9a9..0000000
--- a/cmds/statsd/tests/condition/ConditionTimer_test.cpp
+++ /dev/null
@@ -1,68 +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.
-
-#include "src/condition/ConditionTimer.h"
-
-#include <gtest/gtest.h>
-#include <stdio.h>
-
-#ifdef __ANDROID__
-
-namespace android {
-namespace os {
-namespace statsd {
-
-static int64_t time_base = 10;
-static int64_t ct_start_time = 200;
-
-TEST(ConditionTimerTest, TestTimer_Inital_False) {
-    ConditionTimer timer(false, time_base);
-    EXPECT_EQ(false, timer.mCondition);
-    EXPECT_EQ(0, timer.mTimerNs);
-
-    EXPECT_EQ(0, timer.newBucketStart(ct_start_time));
-    EXPECT_EQ(0, timer.mTimerNs);
-
-    timer.onConditionChanged(true, ct_start_time + 5);
-    EXPECT_EQ(ct_start_time + 5, timer.mLastConditionChangeTimestampNs);
-    EXPECT_EQ(true, timer.mCondition);
-
-    EXPECT_EQ(95, timer.newBucketStart(ct_start_time + 100));
-    EXPECT_EQ(ct_start_time + 100, timer.mLastConditionChangeTimestampNs);
-    EXPECT_EQ(true, timer.mCondition);
-}
-
-TEST(ConditionTimerTest, TestTimer_Inital_True) {
-    ConditionTimer timer(true, time_base);
-    EXPECT_EQ(true, timer.mCondition);
-    EXPECT_EQ(0, timer.mTimerNs);
-
-    EXPECT_EQ(ct_start_time - time_base, timer.newBucketStart(ct_start_time));
-    EXPECT_EQ(true, timer.mCondition);
-    EXPECT_EQ(0, timer.mTimerNs);
-    EXPECT_EQ(ct_start_time, timer.mLastConditionChangeTimestampNs);
-
-    timer.onConditionChanged(false, ct_start_time + 5);
-    EXPECT_EQ(5, timer.mTimerNs);
-
-    EXPECT_EQ(5, timer.newBucketStart(ct_start_time + 100));
-    EXPECT_EQ(0, timer.mTimerNs);
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
deleted file mode 100644
index 8998b5f..0000000
--- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
+++ /dev/null
@@ -1,741 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/condition/SimpleConditionTracker.h"
-#include "stats_event.h"
-#include "tests/statsd_test_util.h"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <stdio.h>
-#include <vector>
-#include <numeric>
-
-using std::map;
-using std::unordered_map;
-using std::vector;
-
-#ifdef __ANDROID__
-
-namespace android {
-namespace os {
-namespace statsd {
-
-namespace {
-
-const ConfigKey kConfigKey(0, 12345);
-
-const int ATTRIBUTION_NODE_FIELD_ID = 1;
-const int ATTRIBUTION_UID_FIELD_ID = 1;
-const int TAG_ID = 1;
-const uint64_t protoHash = 0x123456789;
-
-SimplePredicate getWakeLockHeldCondition(bool countNesting, bool defaultFalse,
-                                         bool outputSlicedUid, Position position) {
-    SimplePredicate simplePredicate;
-    simplePredicate.set_start(StringToId("WAKE_LOCK_ACQUIRE"));
-    simplePredicate.set_stop(StringToId("WAKE_LOCK_RELEASE"));
-    simplePredicate.set_stop_all(StringToId("RELEASE_ALL"));
-    if (outputSlicedUid) {
-        simplePredicate.mutable_dimensions()->set_field(TAG_ID);
-        simplePredicate.mutable_dimensions()->add_child()->set_field(ATTRIBUTION_NODE_FIELD_ID);
-        simplePredicate.mutable_dimensions()->mutable_child(0)->set_position(position);
-        simplePredicate.mutable_dimensions()->mutable_child(0)->add_child()->set_field(
-            ATTRIBUTION_UID_FIELD_ID);
-    }
-
-    simplePredicate.set_count_nesting(countNesting);
-    simplePredicate.set_initial_value(defaultFalse ? SimplePredicate_InitialValue_FALSE
-                                                       : SimplePredicate_InitialValue_UNKNOWN);
-    return simplePredicate;
-}
-
-void makeWakeLockEvent(LogEvent* logEvent, uint32_t atomId, uint64_t timestamp,
-                       const vector<int>& uids, const string& wl, int acquire) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, atomId);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestamp);
-
-    vector<std::string> tags(uids.size()); // vector of empty strings
-    writeAttribution(statsEvent, uids, tags);
-
-    AStatsEvent_writeString(statsEvent, wl.c_str());
-    AStatsEvent_writeInt32(statsEvent, acquire);
-
-    parseStatsEventToLogEvent(statsEvent, logEvent);
-}
-
-} // anonymous namespace
-
-
-std::map<int64_t, HashableDimensionKey> getWakeLockQueryKey(
-    const Position position,
-    const std::vector<int> &uids, const string& conditionName) {
-    std::map<int64_t, HashableDimensionKey> outputKeyMap;
-    std::vector<int> uid_indexes;
-    int pos[] = {1, 1, 1};
-    int depth = 2;
-    Field field(1, pos, depth);
-    switch(position) {
-        case Position::FIRST:
-            uid_indexes.push_back(0);
-            break;
-        case Position::LAST:
-            uid_indexes.push_back(uids.size() - 1);
-            field.setField(0x02018001);
-            break;
-        case Position::ANY:
-            uid_indexes.resize(uids.size());
-            std::iota(uid_indexes.begin(), uid_indexes.end(), 0);
-            field.setField(0x02010001);
-            break;
-        default:
-            break;
-    }
-
-    for (const int idx : uid_indexes) {
-        Value value((int32_t)uids[idx]);
-        HashableDimensionKey dim;
-        dim.addValue(FieldValue(field, value));
-        outputKeyMap[StringToId(conditionName)] = dim;
-    }
-    return outputKeyMap;
-}
-
-TEST(SimpleConditionTrackerTest, TestNonSlicedInitialValueFalse) {
-    SimplePredicate simplePredicate;
-    simplePredicate.set_start(StringToId("SCREEN_TURNED_ON"));
-    simplePredicate.set_stop(StringToId("SCREEN_TURNED_OFF"));
-    simplePredicate.set_count_nesting(false);
-    simplePredicate.set_initial_value(SimplePredicate_InitialValue_FALSE);
-
-    unordered_map<int64_t, int> trackerNameIndexMap;
-    trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
-    trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
-
-    SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), protoHash,
-                                            0 /*tracker index*/, simplePredicate,
-                                            trackerNameIndexMap);
-
-    ConditionKey queryKey;
-    vector<sp<ConditionTracker>> allPredicates;
-    vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
-
-    // Check that initial condition is false.
-    conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
-    EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
-
-    vector<MatchingState> matcherState;
-    vector<bool> changedCache(1, false);
-
-    // Matched stop event.
-    // Check that condition is still false.
-    unique_ptr<LogEvent> screenOffEvent =
-            CreateScreenStateChangedEvent(/*timestamp=*/50, android::view::DISPLAY_STATE_OFF);
-    matcherState.clear();
-    matcherState.push_back(MatchingState::kNotMatched);  // On matcher not matched
-    matcherState.push_back(MatchingState::kMatched);     // Off matcher matched
-    conditionCache[0] = ConditionState::kNotEvaluated;
-    conditionTracker.evaluateCondition(*screenOffEvent, matcherState, allPredicates, conditionCache,
-                                       changedCache);
-    EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
-    EXPECT_FALSE(changedCache[0]);
-
-    // Matched start event.
-    // Check that condition has changed to true.
-    unique_ptr<LogEvent> screenOnEvent =
-            CreateScreenStateChangedEvent(/*timestamp=*/100, android::view::DISPLAY_STATE_ON);
-    matcherState.clear();
-    matcherState.push_back(MatchingState::kMatched);     // On matcher matched
-    matcherState.push_back(MatchingState::kNotMatched);  // Off matcher not matched
-    conditionCache[0] = ConditionState::kNotEvaluated;
-    changedCache[0] = false;
-    conditionTracker.evaluateCondition(*screenOnEvent, matcherState, allPredicates, conditionCache,
-                                       changedCache);
-    EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
-    EXPECT_TRUE(changedCache[0]);
-}
-
-TEST(SimpleConditionTrackerTest, TestNonSlicedInitialValueUnknown) {
-    SimplePredicate simplePredicate;
-    simplePredicate.set_start(StringToId("SCREEN_TURNED_ON"));
-    simplePredicate.set_stop(StringToId("SCREEN_TURNED_OFF"));
-    simplePredicate.set_count_nesting(false);
-    simplePredicate.set_initial_value(SimplePredicate_InitialValue_UNKNOWN);
-
-    unordered_map<int64_t, int> trackerNameIndexMap;
-    trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
-    trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
-
-    SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), protoHash,
-                                            0 /*tracker index*/, simplePredicate,
-                                            trackerNameIndexMap);
-
-    ConditionKey queryKey;
-    vector<sp<ConditionTracker>> allPredicates;
-    vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
-
-    // Check that initial condition is unknown.
-    conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
-    EXPECT_EQ(ConditionState::kUnknown, conditionCache[0]);
-
-    vector<MatchingState> matcherState;
-    vector<bool> changedCache(1, false);
-
-    // Matched stop event.
-    // Check that condition is changed to false.
-    unique_ptr<LogEvent> screenOffEvent =
-            CreateScreenStateChangedEvent(/*timestamp=*/50, android::view::DISPLAY_STATE_OFF);
-    matcherState.clear();
-    matcherState.push_back(MatchingState::kNotMatched);  // On matcher not matched
-    matcherState.push_back(MatchingState::kMatched);     // Off matcher matched
-    conditionCache[0] = ConditionState::kNotEvaluated;
-    conditionTracker.evaluateCondition(*screenOffEvent, matcherState, allPredicates, conditionCache,
-                                       changedCache);
-    EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
-    EXPECT_TRUE(changedCache[0]);
-
-    // Matched start event.
-    // Check that condition has changed to true.
-    unique_ptr<LogEvent> screenOnEvent =
-            CreateScreenStateChangedEvent(/*timestamp=*/100, android::view::DISPLAY_STATE_ON);
-    matcherState.clear();
-    matcherState.push_back(MatchingState::kMatched);     // On matcher matched
-    matcherState.push_back(MatchingState::kNotMatched);  // Off matcher not matched
-    conditionCache[0] = ConditionState::kNotEvaluated;
-    changedCache[0] = false;
-    conditionTracker.evaluateCondition(*screenOnEvent, matcherState, allPredicates, conditionCache,
-                                       changedCache);
-    EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
-    EXPECT_TRUE(changedCache[0]);
-}
-
-TEST(SimpleConditionTrackerTest, TestNonSlicedCondition) {
-    SimplePredicate simplePredicate;
-    simplePredicate.set_start(StringToId("SCREEN_TURNED_ON"));
-    simplePredicate.set_stop(StringToId("SCREEN_TURNED_OFF"));
-    simplePredicate.set_count_nesting(false);
-    simplePredicate.set_initial_value(SimplePredicate_InitialValue_UNKNOWN);
-
-    unordered_map<int64_t, int> trackerNameIndexMap;
-    trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
-    trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
-
-    SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), protoHash,
-                                            0 /*tracker index*/, simplePredicate,
-                                            trackerNameIndexMap);
-    EXPECT_FALSE(conditionTracker.isSliced());
-
-    // This event is not accessed in this test besides dimensions which is why this is okay.
-    // This is technically an invalid LogEvent because we do not call parseBuffer.
-    LogEvent event(/*uid=*/0, /*pid=*/0);
-
-    vector<MatchingState> matcherState;
-    matcherState.push_back(MatchingState::kNotMatched);
-    matcherState.push_back(MatchingState::kNotMatched);
-
-    vector<sp<ConditionTracker>> allPredicates;
-    vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
-    vector<bool> changedCache(1, false);
-
-    conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
-                                       changedCache);
-    // not matched start or stop. condition doesn't change
-    EXPECT_EQ(ConditionState::kUnknown, conditionCache[0]);
-    EXPECT_FALSE(changedCache[0]);
-
-    // prepare a case for match start.
-    matcherState.clear();
-    matcherState.push_back(MatchingState::kMatched);
-    matcherState.push_back(MatchingState::kNotMatched);
-    conditionCache[0] = ConditionState::kNotEvaluated;
-    changedCache[0] = false;
-
-    conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
-                                       changedCache);
-    // now condition should change to true.
-    EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
-    EXPECT_TRUE(changedCache[0]);
-
-    // match nothing.
-    matcherState.clear();
-    matcherState.push_back(MatchingState::kNotMatched);
-    matcherState.push_back(MatchingState::kNotMatched);
-    conditionCache[0] = ConditionState::kNotEvaluated;
-    changedCache[0] = false;
-
-    conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
-                                       changedCache);
-    EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
-    EXPECT_FALSE(changedCache[0]);
-
-    // the case for match stop.
-    matcherState.clear();
-    matcherState.push_back(MatchingState::kNotMatched);
-    matcherState.push_back(MatchingState::kMatched);
-    conditionCache[0] = ConditionState::kNotEvaluated;
-    changedCache[0] = false;
-
-    conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
-                                       changedCache);
-
-    // condition changes to false.
-    EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
-    EXPECT_TRUE(changedCache[0]);
-
-    // match stop again.
-    matcherState.clear();
-    matcherState.push_back(MatchingState::kNotMatched);
-    matcherState.push_back(MatchingState::kMatched);
-    conditionCache[0] = ConditionState::kNotEvaluated;
-    changedCache[0] = false;
-
-    conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
-                                       changedCache);
-    // condition should still be false. not changed.
-    EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
-    EXPECT_FALSE(changedCache[0]);
-}
-
-TEST(SimpleConditionTrackerTest, TestNonSlicedConditionNestCounting) {
-    std::vector<sp<ConditionTracker>> allConditions;
-    SimplePredicate simplePredicate;
-    simplePredicate.set_start(StringToId("SCREEN_TURNED_ON"));
-    simplePredicate.set_stop(StringToId("SCREEN_TURNED_OFF"));
-    simplePredicate.set_count_nesting(true);
-
-    unordered_map<int64_t, int> trackerNameIndexMap;
-    trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
-    trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
-
-    SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), protoHash,
-                                            0 /*condition tracker index*/, simplePredicate,
-                                            trackerNameIndexMap);
-    EXPECT_FALSE(conditionTracker.isSliced());
-
-    // This event is not accessed in this test besides dimensions which is why this is okay.
-    // This is technically an invalid LogEvent because we do not call parseBuffer.
-    LogEvent event(/*uid=*/0, /*pid=*/0);
-
-    // one matched start
-    vector<MatchingState> matcherState;
-    matcherState.push_back(MatchingState::kMatched);
-    matcherState.push_back(MatchingState::kNotMatched);
-    vector<sp<ConditionTracker>> allPredicates;
-    vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
-    vector<bool> changedCache(1, false);
-
-    conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
-                                       changedCache);
-
-    EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
-    EXPECT_TRUE(changedCache[0]);
-
-    // prepare for another matched start.
-    matcherState.clear();
-    matcherState.push_back(MatchingState::kMatched);
-    matcherState.push_back(MatchingState::kNotMatched);
-    conditionCache[0] = ConditionState::kNotEvaluated;
-    changedCache[0] = false;
-
-    conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
-                                       changedCache);
-
-    EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
-    EXPECT_FALSE(changedCache[0]);
-
-    // ONE MATCHED STOP
-    matcherState.clear();
-    matcherState.push_back(MatchingState::kNotMatched);
-    matcherState.push_back(MatchingState::kMatched);
-    conditionCache[0] = ConditionState::kNotEvaluated;
-    changedCache[0] = false;
-
-    conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
-                                       changedCache);
-    // result should still be true
-    EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
-    EXPECT_FALSE(changedCache[0]);
-
-    // ANOTHER MATCHED STOP
-    matcherState.clear();
-    matcherState.push_back(MatchingState::kNotMatched);
-    matcherState.push_back(MatchingState::kMatched);
-    conditionCache[0] = ConditionState::kNotEvaluated;
-    changedCache[0] = false;
-
-    conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
-                                       changedCache);
-    EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
-    EXPECT_TRUE(changedCache[0]);
-}
-
-TEST(SimpleConditionTrackerTest, TestSlicedCondition) {
-    std::vector<sp<ConditionTracker>> allConditions;
-    for (Position position : {Position::FIRST, Position::LAST}) {
-        SimplePredicate simplePredicate = getWakeLockHeldCondition(
-                true /*nesting*/, true /*default to false*/, true /*output slice by uid*/,
-                position);
-        string conditionName = "WL_HELD_BY_UID2";
-
-        unordered_map<int64_t, int> trackerNameIndexMap;
-        trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0;
-        trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
-        trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
-
-        SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), protoHash,
-                                                0 /*condition tracker index*/, simplePredicate,
-                                                trackerNameIndexMap);
-
-        std::vector<int> uids = {111, 222, 333};
-
-        LogEvent event1(/*uid=*/0, /*pid=*/0);
-        makeWakeLockEvent(&event1, /*atomId=*/1, /*timestamp=*/0, uids, "wl1", /*acquire=*/1);
-
-        // one matched start
-        vector<MatchingState> matcherState;
-        matcherState.push_back(MatchingState::kMatched);
-        matcherState.push_back(MatchingState::kNotMatched);
-        matcherState.push_back(MatchingState::kNotMatched);
-        vector<sp<ConditionTracker>> allPredicates;
-        vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
-        vector<bool> changedCache(1, false);
-
-        conditionTracker.evaluateCondition(event1, matcherState, allPredicates, conditionCache,
-                                           changedCache);
-
-        if (position == Position::FIRST || position == Position::LAST) {
-            ASSERT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
-        } else {
-            ASSERT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size());
-        }
-        EXPECT_TRUE(changedCache[0]);
-        if (position == Position::FIRST || position == Position::LAST) {
-            ASSERT_EQ(conditionTracker.getChangedToTrueDimensions(allConditions)->size(), 1u);
-            EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
-        } else {
-            EXPECT_EQ(conditionTracker.getChangedToTrueDimensions(allConditions)->size(),
-                      uids.size());
-        }
-
-        // Now test query
-        const auto queryKey = getWakeLockQueryKey(position, uids, conditionName);
-        conditionCache[0] = ConditionState::kNotEvaluated;
-
-        conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
-        EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
-
-        // another wake lock acquired by this uid
-        LogEvent event2(/*uid=*/0, /*pid=*/0);
-        makeWakeLockEvent(&event2, /*atomId=*/1, /*timestamp=*/0, uids, "wl2", /*acquire=*/1);
-        matcherState.clear();
-        matcherState.push_back(MatchingState::kMatched);
-        matcherState.push_back(MatchingState::kNotMatched);
-        conditionCache[0] = ConditionState::kNotEvaluated;
-        changedCache[0] = false;
-        conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
-                                           changedCache);
-        EXPECT_FALSE(changedCache[0]);
-        if (position == Position::FIRST || position == Position::LAST) {
-            ASSERT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
-        } else {
-            ASSERT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size());
-        }
-        EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
-        EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
-
-
-        // wake lock 1 release
-        LogEvent event3(/*uid=*/0, /*pid=*/0);
-        makeWakeLockEvent(&event3, /*atomId=*/1, /*timestamp=*/0, uids, "wl1", /*acquire=*/0);
-        matcherState.clear();
-        matcherState.push_back(MatchingState::kNotMatched);
-        matcherState.push_back(MatchingState::kMatched);
-        conditionCache[0] = ConditionState::kNotEvaluated;
-        changedCache[0] = false;
-        conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
-                                           changedCache);
-        // nothing changes, because wake lock 2 is still held for this uid
-        EXPECT_FALSE(changedCache[0]);
-        if (position == Position::FIRST || position == Position::LAST) {
-            ASSERT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
-        } else {
-            ASSERT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size());
-        }
-        EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
-        EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
-
-        LogEvent event4(/*uid=*/0, /*pid=*/0);
-        makeWakeLockEvent(&event4, /*atomId=*/1, /*timestamp=*/0, uids, "wl2", /*acquire=*/0);
-        matcherState.clear();
-        matcherState.push_back(MatchingState::kNotMatched);
-        matcherState.push_back(MatchingState::kMatched);
-        conditionCache[0] = ConditionState::kNotEvaluated;
-        changedCache[0] = false;
-        conditionTracker.evaluateCondition(event4, matcherState, allPredicates, conditionCache,
-                                           changedCache);
-        ASSERT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
-        EXPECT_TRUE(changedCache[0]);
-        if (position == Position::FIRST || position == Position::LAST) {
-            ASSERT_EQ(conditionTracker.getChangedToFalseDimensions(allConditions)->size(), 1u);
-            EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
-        } else {
-            EXPECT_EQ(conditionTracker.getChangedToFalseDimensions(allConditions)->size(),
-                      uids.size());
-        }
-
-        // query again
-        conditionCache[0] = ConditionState::kNotEvaluated;
-        conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
-        EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
-    }
-
-}
-
-TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
-    std::vector<sp<ConditionTracker>> allConditions;
-
-    SimplePredicate simplePredicate =
-            getWakeLockHeldCondition(true /*nesting*/, true /*default to false*/,
-                                     false /*slice output by uid*/, Position::ANY /* position */);
-    string conditionName = "WL_HELD";
-
-    unordered_map<int64_t, int> trackerNameIndexMap;
-    trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0;
-    trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
-    trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
-
-    SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), protoHash,
-                                            0 /*condition tracker index*/, simplePredicate,
-                                            trackerNameIndexMap);
-
-    EXPECT_FALSE(conditionTracker.isSliced());
-
-    std::vector<int> uids1 = {111, 1111, 11111};
-    string uid1_wl1 = "wl1_1";
-    std::vector<int> uids2 = {222, 2222, 22222};
-    string uid2_wl1 = "wl2_1";
-
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    makeWakeLockEvent(&event1, /*atomId=*/1, /*timestamp=*/0, uids1, uid1_wl1, /*acquire=*/1);
-
-    // one matched start for uid1
-    vector<MatchingState> matcherState;
-    matcherState.push_back(MatchingState::kMatched);
-    matcherState.push_back(MatchingState::kNotMatched);
-    matcherState.push_back(MatchingState::kNotMatched);
-    vector<sp<ConditionTracker>> allPredicates;
-    vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
-    vector<bool> changedCache(1, false);
-
-    conditionTracker.evaluateCondition(event1, matcherState, allPredicates, conditionCache,
-                                       changedCache);
-
-    ASSERT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
-    EXPECT_TRUE(changedCache[0]);
-
-    // Now test query
-    ConditionKey queryKey;
-    conditionCache[0] = ConditionState::kNotEvaluated;
-
-    conditionTracker.isConditionMet(queryKey, allPredicates, true, conditionCache);
-    EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
-
-    // another wake lock acquired by this uid
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    makeWakeLockEvent(&event2, /*atomId=*/1, /*timestamp=*/0, uids2, uid2_wl1, /*acquire=*/1);
-
-    matcherState.clear();
-    matcherState.push_back(MatchingState::kMatched);
-    matcherState.push_back(MatchingState::kNotMatched);
-    conditionCache[0] = ConditionState::kNotEvaluated;
-    changedCache[0] = false;
-    conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
-                                       changedCache);
-    EXPECT_FALSE(changedCache[0]);
-
-    // uid1 wake lock 1 release
-    LogEvent event3(/*uid=*/0, /*pid=*/0);
-    makeWakeLockEvent(&event3, /*atomId=*/1, /*timestamp=*/0, uids1, uid1_wl1,
-                      /*release=*/0);  // now release it.
-
-    matcherState.clear();
-    matcherState.push_back(MatchingState::kNotMatched);
-    matcherState.push_back(MatchingState::kMatched);
-    conditionCache[0] = ConditionState::kNotEvaluated;
-    changedCache[0] = false;
-    conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
-                                       changedCache);
-    // nothing changes, because uid2 is still holding wl.
-    EXPECT_FALSE(changedCache[0]);
-
-    LogEvent event4(/*uid=*/0, /*pid=*/0);
-    makeWakeLockEvent(&event4, /*atomId=*/1, /*timestamp=*/0, uids2, uid2_wl1,
-                      /*acquire=*/0);  // now release it.
-    matcherState.clear();
-    matcherState.push_back(MatchingState::kNotMatched);
-    matcherState.push_back(MatchingState::kMatched);
-    conditionCache[0] = ConditionState::kNotEvaluated;
-    changedCache[0] = false;
-    conditionTracker.evaluateCondition(event4, matcherState, allPredicates, conditionCache,
-                                       changedCache);
-    ASSERT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
-    EXPECT_TRUE(changedCache[0]);
-
-    // query again
-    conditionCache[0] = ConditionState::kNotEvaluated;
-    conditionTracker.isConditionMet(queryKey, allPredicates, true, conditionCache);
-    EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
-}
-
-TEST(SimpleConditionTrackerTest, TestStopAll) {
-    std::vector<sp<ConditionTracker>> allConditions;
-    for (Position position : {Position::FIRST, Position::LAST}) {
-        SimplePredicate simplePredicate =
-                getWakeLockHeldCondition(true /*nesting*/, true /*default to false*/,
-                                         true /*output slice by uid*/, position);
-        string conditionName = "WL_HELD_BY_UID3";
-
-        unordered_map<int64_t, int> trackerNameIndexMap;
-        trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0;
-        trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
-        trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
-
-        SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), protoHash,
-                                                0 /*condition tracker index*/, simplePredicate,
-                                                trackerNameIndexMap);
-
-        std::vector<int> uids1 = {111, 1111, 11111};
-        std::vector<int> uids2 = {222, 2222, 22222};
-
-        LogEvent event1(/*uid=*/0, /*pid=*/0);
-        makeWakeLockEvent(&event1, /*atomId=*/1, /*timestamp=*/0, uids1, "wl1", /*acquire=*/1);
-
-        // one matched start
-        vector<MatchingState> matcherState;
-        matcherState.push_back(MatchingState::kMatched);
-        matcherState.push_back(MatchingState::kNotMatched);
-        matcherState.push_back(MatchingState::kNotMatched);
-        vector<sp<ConditionTracker>> allPredicates;
-        vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
-        vector<bool> changedCache(1, false);
-
-        conditionTracker.evaluateCondition(event1, matcherState, allPredicates, conditionCache,
-                                           changedCache);
-        if (position == Position::FIRST || position == Position::LAST) {
-            ASSERT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
-        } else {
-            ASSERT_EQ(uids1.size(), conditionTracker.mSlicedConditionState.size());
-        }
-        EXPECT_TRUE(changedCache[0]);
-        {
-            if (position == Position::FIRST || position == Position::LAST) {
-                ASSERT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size());
-                EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
-            } else {
-                EXPECT_EQ(uids1.size(),
-                          conditionTracker.getChangedToTrueDimensions(allConditions)->size());
-                EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
-            }
-        }
-
-        // Now test query
-        const auto queryKey = getWakeLockQueryKey(position, uids1, conditionName);
-        conditionCache[0] = ConditionState::kNotEvaluated;
-
-        conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
-        EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
-
-        // another wake lock acquired by uid2
-        LogEvent event2(/*uid=*/0, /*pid=*/0);
-        makeWakeLockEvent(&event2, /*atomId=*/1, /*timestamp=*/0, uids2, "wl2", /*acquire=*/1);
-
-        matcherState.clear();
-        matcherState.push_back(MatchingState::kMatched);
-        matcherState.push_back(MatchingState::kNotMatched);
-        matcherState.push_back(MatchingState::kNotMatched);
-        conditionCache[0] = ConditionState::kNotEvaluated;
-        changedCache[0] = false;
-        conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
-                                           changedCache);
-        if (position == Position::FIRST || position == Position::LAST) {
-            ASSERT_EQ(2UL, conditionTracker.mSlicedConditionState.size());
-        } else {
-            ASSERT_EQ(uids1.size() + uids2.size(), conditionTracker.mSlicedConditionState.size());
-        }
-        EXPECT_TRUE(changedCache[0]);
-        {
-            if (position == Position::FIRST || position == Position::LAST) {
-                ASSERT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size());
-                EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
-            } else {
-                EXPECT_EQ(uids2.size(),
-                          conditionTracker.getChangedToTrueDimensions(allConditions)->size());
-                EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
-            }
-        }
-
-        // TEST QUERY
-        const auto queryKey2 = getWakeLockQueryKey(position, uids2, conditionName);
-        conditionCache[0] = ConditionState::kNotEvaluated;
-        conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
-
-        EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
-
-        // stop all event
-        LogEvent event3(/*uid=*/0, /*pid=*/0);
-        makeWakeLockEvent(&event3, /*atomId=*/1, /*timestamp=*/0, uids2, "wl2", /*acquire=*/1);
-
-        matcherState.clear();
-        matcherState.push_back(MatchingState::kNotMatched);
-        matcherState.push_back(MatchingState::kNotMatched);
-        matcherState.push_back(MatchingState::kMatched);
-
-        conditionCache[0] = ConditionState::kNotEvaluated;
-        changedCache[0] = false;
-        conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
-                                           changedCache);
-        EXPECT_TRUE(changedCache[0]);
-        ASSERT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
-        {
-            if (position == Position::FIRST || position == Position::LAST) {
-                ASSERT_EQ(2UL, conditionTracker.getChangedToFalseDimensions(allConditions)->size());
-                EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
-            } else {
-                EXPECT_EQ(uids1.size() + uids2.size(),
-                          conditionTracker.getChangedToFalseDimensions(allConditions)->size());
-                EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
-            }
-        }
-
-        // TEST QUERY
-        const auto queryKey3 = getWakeLockQueryKey(position, uids1, conditionName);
-        conditionCache[0] = ConditionState::kNotEvaluated;
-        conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
-        EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
-
-        // TEST QUERY
-        const auto queryKey4 = getWakeLockQueryKey(position, uids2, conditionName);
-        conditionCache[0] = ConditionState::kNotEvaluated;
-        conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
-        EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
-    }
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/e2e/Alarm_e2e_test.cpp b/cmds/statsd/tests/e2e/Alarm_e2e_test.cpp
deleted file mode 100644
index 93b2783..0000000
--- a/cmds/statsd/tests/e2e/Alarm_e2e_test.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <gtest/gtest.h>
-
-#include "src/StatsLogProcessor.h"
-#include "src/stats_log_util.h"
-#include "tests/statsd_test_util.h"
-
-#include <vector>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-#ifdef __ANDROID__
-
-namespace {
-
-StatsdConfig CreateStatsdConfig() {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-
-    auto alarm = config.add_alarm();
-    alarm->set_id(123456);
-    alarm->set_offset_millis(TimeUnitToBucketSizeInMillis(TEN_MINUTES));
-    alarm->set_period_millis(TimeUnitToBucketSizeInMillis(ONE_HOUR));
-
-    alarm = config.add_alarm();
-    alarm->set_id(654321);
-    alarm->set_offset_millis(TimeUnitToBucketSizeInMillis(FIVE_MINUTES));
-    alarm->set_period_millis(TimeUnitToBucketSizeInMillis(THIRTY_MINUTES));
-    return config;
-}
-
-}  // namespace
-
-TEST(AlarmE2eTest, TestMultipleAlarms) {
-    auto config = CreateStatsdConfig();
-    int64_t bucketStartTimeNs = 10000000000;
-
-    ConfigKey cfgKey;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-    ASSERT_EQ(2u, processor->mMetricsManagers.begin()->second->mAllPeriodicAlarmTrackers.size());
-
-    auto alarmTracker1 = processor->mMetricsManagers.begin()->second->mAllPeriodicAlarmTrackers[0];
-    auto alarmTracker2 = processor->mMetricsManagers.begin()->second->mAllPeriodicAlarmTrackers[1];
-
-    int64_t alarmTimestampSec0 = bucketStartTimeNs / NS_PER_SEC + 10 * 60;
-    int64_t alarmTimestampSec1 = bucketStartTimeNs / NS_PER_SEC + 5 * 60;
-    EXPECT_EQ(alarmTimestampSec0, alarmTracker1->getAlarmTimestampSec());
-    EXPECT_EQ(alarmTimestampSec1, alarmTracker2->getAlarmTimestampSec());
-
-    // Alarm fired.
-    const int64_t alarmFiredTimestampSec0 = alarmTimestampSec1 + 5;
-    auto alarmSet = processor->getPeriodicAlarmMonitor()->popSoonerThan(
-            static_cast<uint32_t>(alarmFiredTimestampSec0));
-    ASSERT_EQ(1u, alarmSet.size());
-    processor->onPeriodicAlarmFired(alarmFiredTimestampSec0 * NS_PER_SEC, alarmSet);
-    EXPECT_EQ(alarmTimestampSec0, alarmTracker1->getAlarmTimestampSec());
-    EXPECT_EQ(alarmTimestampSec1 + 30 * 60, alarmTracker2->getAlarmTimestampSec());
-
-    // Alarms fired very late.
-    const int64_t alarmFiredTimestampSec1 = alarmTimestampSec0 + 2 * 60 * 60 + 125;
-    alarmSet = processor->getPeriodicAlarmMonitor()->popSoonerThan(
-            static_cast<uint32_t>(alarmFiredTimestampSec1));
-    ASSERT_EQ(2u, alarmSet.size());
-    processor->onPeriodicAlarmFired(alarmFiredTimestampSec1 * NS_PER_SEC, alarmSet);
-    EXPECT_EQ(alarmTimestampSec0 + 60 * 60 * 3, alarmTracker1->getAlarmTimestampSec());
-    EXPECT_EQ(alarmTimestampSec1 + 30 * 60 * 5, alarmTracker2->getAlarmTimestampSec());
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp b/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
deleted file mode 100644
index af9436b..0000000
--- a/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
+++ /dev/null
@@ -1,390 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <gtest/gtest.h>
-
-#include "frameworks/base/cmds/statsd/src/statsd_metadata.pb.h"
-#include "src/StatsLogProcessor.h"
-#include "src/stats_log_util.h"
-#include "tests/statsd_test_util.h"
-
-#include <vector>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-#ifdef __ANDROID__
-
-namespace {
-
-StatsdConfig CreateStatsdConfig(int num_buckets, int threshold, int refractory_period_sec) {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-    auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
-
-    *config.add_atom_matcher() = wakelockAcquireMatcher;
-
-    auto countMetric = config.add_count_metric();
-    countMetric->set_id(123456);
-    countMetric->set_what(wakelockAcquireMatcher.id());
-    *countMetric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
-            util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-    countMetric->set_bucket(FIVE_MINUTES);
-
-    auto alert = config.add_alert();
-    alert->set_id(StringToId("alert"));
-    alert->set_metric_id(123456);
-    alert->set_num_buckets(num_buckets);
-    alert->set_refractory_period_secs(refractory_period_sec);
-    alert->set_trigger_if_sum_gt(threshold);
-    return config;
-}
-
-}  // namespace
-
-TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_single_bucket) {
-    const int num_buckets = 1;
-    const int threshold = 3;
-    const int refractory_period_sec = 10;
-    auto config = CreateStatsdConfig(num_buckets, threshold, refractory_period_sec);
-    const uint64_t alert_id = config.alert(0).id();
-
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
-
-    ConfigKey cfgKey;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-    ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
-
-    sp<AnomalyTracker> anomalyTracker =
-            processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
-
-    std::vector<int> attributionUids1 = {111};
-    std::vector<string> attributionTags1 = {"App1"};
-    std::vector<int> attributionUids2 = {111, 222};
-    std::vector<string> attributionTags2 = {"App1", "GMSCoreModule1"};
-    std::vector<int> attributionUids3 = {111, 333};
-    std::vector<string> attributionTags3 = {"App1", "App3"};
-    std::vector<int> attributionUids4 = {222, 333};
-    std::vector<string> attributionTags4 = {"GMSCoreModule1", "App3"};
-    std::vector<int> attributionUids5 = {222};
-    std::vector<string> attributionTags5 = {"GMSCoreModule1"};
-
-    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(util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
-                           Value((int32_t)222));
-    HashableDimensionKey whatKey2({fieldValue2});
-    MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY);
-
-    auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
-                                            attributionTags1, "wl1");
-    processor->OnLogEvent(event.get());
-    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids4, attributionTags4,
-                                       "wl2");
-    processor->OnLogEvent(event.get());
-    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3, attributionUids2, attributionTags2,
-                                       "wl1");
-    processor->OnLogEvent(event.get());
-    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3, attributionUids5, attributionTags5,
-                                       "wl2");
-    processor->OnLogEvent(event.get());
-    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 4, attributionUids3, attributionTags3,
-                                       "wl1");
-    processor->OnLogEvent(event.get());
-    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 4, attributionUids5, attributionTags5,
-                                       "wl2");
-    processor->OnLogEvent(event.get());
-    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-
-    // Fired alarm and refractory period end timestamp updated.
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 5, attributionUids1, attributionTags1,
-                                       "wl1");
-    processor->OnLogEvent(event.get());
-    EXPECT_EQ(refractory_period_sec + bucketStartTimeNs / NS_PER_SEC + 1,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 100, attributionUids1, attributionTags1,
-                                       "wl1");
-    processor->OnLogEvent(event.get());
-    EXPECT_EQ(refractory_period_sec + bucketStartTimeNs / NS_PER_SEC + 1,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1, attributionUids1,
-                                       attributionTags1, "wl1");
-    processor->OnLogEvent(event.get());
-    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs - 1) / NS_PER_SEC + 1,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1, attributionUids1,
-                                       attributionTags1, "wl1");
-    processor->OnLogEvent(event.get());
-    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs - 1) / NS_PER_SEC + 1,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1, attributionUids4,
-                                       attributionTags4, "wl2");
-    processor->OnLogEvent(event.get());
-    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2, attributionUids5,
-                                       attributionTags5, "wl2");
-    processor->OnLogEvent(event.get());
-    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 3, attributionUids5,
-                                       attributionTags5, "wl2");
-    processor->OnLogEvent(event.get());
-    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 4, attributionUids5,
-                                       attributionTags5, "wl2");
-    processor->OnLogEvent(event.get());
-    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 4) / NS_PER_SEC + 1,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-}
-
-TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_multiple_buckets) {
-    const int num_buckets = 3;
-    const int threshold = 3;
-    const int refractory_period_sec = 10;
-    auto config = CreateStatsdConfig(num_buckets, threshold, refractory_period_sec);
-    const uint64_t alert_id = config.alert(0).id();
-
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
-
-    ConfigKey cfgKey;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-    ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
-
-    sp<AnomalyTracker> anomalyTracker =
-            processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
-
-    std::vector<int> attributionUids1 = {111};
-    std::vector<string> attributionTags1 = {"App1"};
-    std::vector<int> attributionUids2 = {111, 222};
-    std::vector<string> attributionTags2 = {"App1", "GMSCoreModule1"};
-
-    FieldValue fieldValue1(Field(util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
-                           Value((int32_t)111));
-    HashableDimensionKey whatKey1({fieldValue1});
-    MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
-
-    auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
-                                            attributionTags1, "wl1");
-    processor->OnLogEvent(event.get());
-    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3, attributionUids2, attributionTags2,
-                                       "wl1");
-    processor->OnLogEvent(event.get());
-    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    // Fired alarm and refractory period end timestamp updated.
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 4, attributionUids1, attributionTags1,
-                                       "wl1");
-    processor->OnLogEvent(event.get());
-    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1, attributionUids1,
-                                       attributionTags1, "wl1");
-    processor->OnLogEvent(event.get());
-    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2, attributionUids2,
-                                       attributionTags2, "wl1");
-    processor->OnLogEvent(event.get());
-    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 1, attributionUids2,
-                                       attributionTags2, "wl1");
-    processor->OnLogEvent(event.get());
-    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 2, attributionUids2,
-                                       attributionTags2, "wl1");
-    processor->OnLogEvent(event.get());
-    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + 3 * bucketSizeNs + 2) / NS_PER_SEC + 1,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-}
-
-TEST(AnomalyDetectionE2eTest, TestCountMetric_save_refractory_to_disk_no_data_written) {
-    const int num_buckets = 1;
-    const int threshold = 0;
-    const int refractory_period_sec = 86400 * 365; // 1 year
-    auto config = CreateStatsdConfig(num_buckets, threshold, refractory_period_sec);
-    const int64_t alert_id = config.alert(0).id();
-
-    int64_t bucketStartTimeNs = 10000000000;
-
-    int configUid = 2000;
-    int64_t configId = 1000;
-    ConfigKey cfgKey(configUid, configId);
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-    ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
-
-    metadata::StatsMetadataList result;
-    int64_t mockWallClockNs = 1584991200 * NS_PER_SEC;
-    int64_t mockElapsedTimeNs = bucketStartTimeNs + 5000 * NS_PER_SEC;
-    processor->WriteMetadataToProto(mockWallClockNs, mockElapsedTimeNs, &result);
-
-    ASSERT_EQ(result.stats_metadata_size(), 0);
-}
-
-TEST(AnomalyDetectionE2eTest, TestCountMetric_save_refractory_to_disk) {
-    const int num_buckets = 1;
-    const int threshold = 0;
-    const int refractory_period_sec = 86400 * 365; // 1 year
-    auto config = CreateStatsdConfig(num_buckets, threshold, refractory_period_sec);
-    const int64_t alert_id = config.alert(0).id();
-
-    int64_t bucketStartTimeNs = 10000000000;
-
-    int configUid = 2000;
-    int64_t configId = 1000;
-    ConfigKey cfgKey(configUid, configId);
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-    ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
-
-    sp<AnomalyTracker> anomalyTracker =
-            processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
-
-    std::vector<int> attributionUids1 = {111};
-    std::vector<string> attributionTags1 = {"App1"};
-    std::vector<int> attributionUids2 = {111, 222};
-    std::vector<string> attributionTags2 = {"App1", "GMSCoreModule1"};
-
-    FieldValue fieldValue1(Field(util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
-                           Value((int32_t)111));
-    HashableDimensionKey whatKey1({fieldValue1});
-    MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
-
-    auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
-                                            attributionTags1, "wl1");
-    processor->OnLogEvent(event.get());
-    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + 2) / NS_PER_SEC + 1,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    metadata::StatsMetadataList result;
-    int64_t mockWallClockNs = 1584991200 * NS_PER_SEC;
-    int64_t mockElapsedTimeNs = bucketStartTimeNs + 5000 * NS_PER_SEC;
-    processor->WriteMetadataToProto(mockWallClockNs, mockElapsedTimeNs, &result);
-
-    metadata::StatsMetadata statsMetadata = result.stats_metadata(0);
-    ASSERT_EQ(result.stats_metadata_size(), 1);
-    EXPECT_EQ(statsMetadata.config_key().config_id(), configId);
-    EXPECT_EQ(statsMetadata.config_key().uid(), configUid);
-
-    metadata::AlertMetadata alertMetadata = statsMetadata.alert_metadata(0);
-    ASSERT_EQ(statsMetadata.alert_metadata_size(), 1);
-    EXPECT_EQ(alertMetadata.alert_id(), alert_id);
-    metadata::AlertDimensionKeyedData keyedData = alertMetadata.alert_dim_keyed_data(0);
-    ASSERT_EQ(alertMetadata.alert_dim_keyed_data_size(), 1);
-    EXPECT_EQ(keyedData.last_refractory_ends_sec(),
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1) -
-              mockElapsedTimeNs / NS_PER_SEC +
-              mockWallClockNs / NS_PER_SEC);
-
-    metadata::MetricDimensionKey metadataDimKey = keyedData.dimension_key();
-    metadata::FieldValue dimKeyInWhat = metadataDimKey.dimension_key_in_what(0);
-    EXPECT_EQ(dimKeyInWhat.field().tag(), fieldValue1.mField.getTag());
-    EXPECT_EQ(dimKeyInWhat.field().field(), fieldValue1.mField.getField());
-    EXPECT_EQ(dimKeyInWhat.value_int(), fieldValue1.mValue.int_value);
-}
-
-TEST(AnomalyDetectionE2eTest, TestCountMetric_load_refractory_from_disk) {
-    const int num_buckets = 1;
-    const int threshold = 0;
-    const int refractory_period_sec = 86400 * 365; // 1 year
-    auto config = CreateStatsdConfig(num_buckets, threshold, refractory_period_sec);
-    const int64_t alert_id = config.alert(0).id();
-
-    int64_t bucketStartTimeNs = 10000000000;
-
-    int configUid = 2000;
-    int64_t configId = 1000;
-    ConfigKey cfgKey(configUid, configId);
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-    ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
-
-    sp<AnomalyTracker> anomalyTracker =
-            processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
-
-    std::vector<int> attributionUids1 = {111};
-    std::vector<string> attributionTags1 = {"App1"};
-    std::vector<int> attributionUids2 = {111, 222};
-    std::vector<string> attributionTags2 = {"App1", "GMSCoreModule1"};
-
-    FieldValue fieldValue1(Field(util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
-                           Value((int32_t)111));
-    HashableDimensionKey whatKey1({fieldValue1});
-    MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
-
-    auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
-                                            attributionTags1, "wl1");
-    processor->OnLogEvent(event.get());
-    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + 2) / NS_PER_SEC + 1,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    int64_t mockWallClockNs = 1584991200 * NS_PER_SEC;
-    int64_t mockElapsedTimeNs = bucketStartTimeNs + 5000 * NS_PER_SEC;
-    processor->SaveMetadataToDisk(mockWallClockNs, mockElapsedTimeNs);
-
-    auto processor2 = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-    int64_t mockElapsedTimeSinceBoot = 10 * NS_PER_SEC;
-    processor2->LoadMetadataFromDisk(mockWallClockNs, mockElapsedTimeSinceBoot);
-
-    sp<AnomalyTracker> anomalyTracker2 =
-                processor2->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
-    EXPECT_EQ(anomalyTracker2->getRefractoryPeriodEndsSec(dimensionKey1) -
-              mockElapsedTimeSinceBoot / NS_PER_SEC,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1) -
-              mockElapsedTimeNs / NS_PER_SEC);
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
deleted file mode 100644
index 70e7365..0000000
--- a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
+++ /dev/null
@@ -1,527 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <android/binder_ibinder.h>
-#include <android/binder_interface_utils.h>
-#include <gtest/gtest.h>
-
-#include <vector>
-
-#include "src/StatsLogProcessor.h"
-#include "src/StatsService.h"
-#include "src/anomaly/DurationAnomalyTracker.h"
-#include "src/stats_log_util.h"
-#include "tests/statsd_test_util.h"
-
-using ::ndk::SharedRefBase;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-#ifdef __ANDROID__
-
-namespace {
-
-const int kConfigKey = 789130124;
-const int kCallingUid = 0;
-
-StatsdConfig CreateStatsdConfig(int num_buckets,
-                                uint64_t threshold_ns,
-                                DurationMetric::AggregationType aggregationType,
-                                bool nesting) {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-    *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
-    *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
-
-    auto screenIsOffPredicate = CreateScreenIsOffPredicate();
-    *config.add_predicate() = screenIsOffPredicate;
-
-    auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
-    FieldMatcher dimensions = CreateAttributionUidDimensions(
-            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);
-    *config.add_predicate() = holdingWakelockPredicate;
-
-    auto durationMetric = config.add_duration_metric();
-    durationMetric->set_id(StringToId("WakelockDuration"));
-    durationMetric->set_what(holdingWakelockPredicate.id());
-    durationMetric->set_condition(screenIsOffPredicate.id());
-    durationMetric->set_aggregation_type(aggregationType);
-    *durationMetric->mutable_dimensions_in_what() =
-        CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-    durationMetric->set_bucket(FIVE_MINUTES);
-
-    auto alert = config.add_alert();
-    alert->set_id(StringToId("alert"));
-    alert->set_metric_id(StringToId("WakelockDuration"));
-    alert->set_num_buckets(num_buckets);
-    alert->set_refractory_period_secs(2);
-    alert->set_trigger_if_sum_gt(threshold_ns);
-    return config;
-}
-
-std::vector<int> attributionUids1 = {111, 222};
-std::vector<string> attributionTags1 = {"App1", "GMSCoreModule1"};
-
-std::vector<int> attributionUids2 = {111, 222};
-std::vector<string> attributionTags2 = {"App2", "GMSCoreModule1"};
-
-std::vector<int> attributionUids3 = {222};
-std::vector<string> attributionTags3 = {"GMSCoreModule1"};
-
-MetricDimensionKey dimensionKey1(
-        HashableDimensionKey({FieldValue(Field(util::WAKELOCK_STATE_CHANGED,
-                                               (int32_t)0x02010101),
-                                         Value((int32_t)111))}),
-        DEFAULT_DIMENSION_KEY);
-
-MetricDimensionKey dimensionKey2(
-    HashableDimensionKey({FieldValue(Field(util::WAKELOCK_STATE_CHANGED,
-                                           (int32_t)0x02010101), Value((int32_t)222))}),
-    DEFAULT_DIMENSION_KEY);
-
-void sendConfig(shared_ptr<StatsService>& service, const StatsdConfig& config) {
-    string str;
-    config.SerializeToString(&str);
-    std::vector<uint8_t> configAsVec(str.begin(), str.end());
-    service->addConfiguration(kConfigKey, configAsVec, kCallingUid);
-}
-
-}  // namespace
-
-TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) {
-    const int num_buckets = 1;
-    const uint64_t threshold_ns = NS_PER_SEC;
-    auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true);
-    const uint64_t alert_id = config.alert(0).id();
-    const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
-
-    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-    sendConfig(service, config);
-
-    auto processor = service->mProcessor;
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-    ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
-
-    int64_t bucketStartTimeNs = processor->mTimeBaseNs;
-    int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6;
-
-    sp<AnomalyTracker> anomalyTracker =
-            processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
-
-    auto screen_on_event = CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-    auto screen_off_event = CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 10, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
-    processor->OnLogEvent(screen_on_event.get());
-    processor->OnLogEvent(screen_off_event.get());
-
-    // Acquire wakelock wl1.
-    auto acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 11, attributionUids1,
-                                                    attributionTags1, "wl1");
-    processor->OnLogEvent(acquire_event.get());
-    EXPECT_EQ((bucketStartTimeNs + 11 + threshold_ns) / NS_PER_SEC + 1,
-              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    // Release wakelock wl1. No anomaly detected. Alarm cancelled at the "release" event.
-    auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 101, attributionUids1,
-                                                    attributionTags1, "wl1");
-    processor->OnLogEvent(release_event.get());
-    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    // Acquire wakelock wl1 within bucket #0.
-    acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 110, attributionUids2,
-                                               attributionTags2, "wl1");
-    processor->OnLogEvent(acquire_event.get());
-    EXPECT_EQ((bucketStartTimeNs + 110 + threshold_ns - 90) / NS_PER_SEC + 1,
-              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    // Release wakelock wl1. One anomaly detected.
-    release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + NS_PER_SEC + 109,
-                                               attributionUids2, attributionTags2, "wl1");
-    processor->OnLogEvent(release_event.get());
-    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    // Acquire wakelock wl1.
-    acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + NS_PER_SEC + 112,
-                                               attributionUids1, attributionTags1, "wl1");
-    processor->OnLogEvent(acquire_event.get());
-    // Wakelock has been hold longer than the threshold in bucket #0. The alarm is set at the
-    // end of the refractory period.
-    const int64_t alarmFiredTimestampSec0 = anomalyTracker->getAlarmTimestampSec(dimensionKey1);
-    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
-              (uint32_t)alarmFiredTimestampSec0);
-    EXPECT_EQ(alarmFiredTimestampSec0,
-              processor->getAnomalyAlarmMonitor()->getRegisteredAlarmTimeSec());
-
-    // Anomaly alarm fired.
-    auto alarmTriggerEvent = CreateBatterySaverOnEvent(alarmFiredTimestampSec0 * NS_PER_SEC);
-    processor->OnLogEvent(alarmTriggerEvent.get(), alarmFiredTimestampSec0 * NS_PER_SEC);
-
-    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-    EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    // Release wakelock wl1.
-    release_event =
-            CreateReleaseWakelockEvent(alarmFiredTimestampSec0 * NS_PER_SEC + NS_PER_SEC + 1,
-                                       attributionUids1, attributionTags1, "wl1");
-    processor->OnLogEvent(release_event.get());
-    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-    // Within refractory period. No more anomaly detected.
-    EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    // Acquire wakelock wl1.
-    acquire_event = CreateAcquireWakelockEvent(
-            roundedBucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC - 11, attributionUids2,
-            attributionTags2, "wl1");
-    processor->OnLogEvent(acquire_event.get());
-    const int64_t alarmFiredTimestampSec1 = anomalyTracker->getAlarmTimestampSec(dimensionKey1);
-    EXPECT_EQ((bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC) / NS_PER_SEC,
-              (uint64_t)alarmFiredTimestampSec1);
-
-    // Release wakelock wl1.
-    int64_t release_event_time = roundedBucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10;
-    release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2,
-                                               attributionTags2, "wl1");
-    processor->OnLogEvent(release_event.get(), release_event_time);
-    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-    EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC + 1,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
-            static_cast<uint32_t>(alarmFiredTimestampSec1));
-    ASSERT_EQ(0u, alarmSet.size());
-
-    // Acquire wakelock wl1 near the end of bucket #0.
-    acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs - 2,
-                                               attributionUids1, attributionTags1, "wl1");
-    processor->OnLogEvent(acquire_event.get());
-    EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC,
-              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-
-    // Release the event at early bucket #1.
-    release_event_time = roundedBucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1;
-    release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1,
-                                               attributionTags1, "wl1");
-    processor->OnLogEvent(release_event.get(), release_event_time);
-    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-    // Anomaly detected when stopping the alarm. The refractory period does not change.
-    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    // Condition changes to false.
-    screen_on_event =
-            CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 20,
-                                          android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-    processor->OnLogEvent(screen_on_event.get());
-    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-
-    acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 30,
-                                               attributionUids2, attributionTags2, "wl1");
-    processor->OnLogEvent(acquire_event.get());
-    // The condition is false. Do not start the alarm.
-    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    // Condition turns true.
-    screen_off_event =
-            CreateScreenStateChangedEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC,
-                                          android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
-    processor->OnLogEvent(screen_off_event.get());
-    EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + threshold_ns) / NS_PER_SEC,
-              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-
-    // Condition turns to false.
-    int64_t condition_false_time = bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1;
-    screen_on_event = CreateScreenStateChangedEvent(
-            condition_false_time, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-    processor->OnLogEvent(screen_on_event.get(), condition_false_time);
-    // Condition turns to false. Cancelled the alarm.
-    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-    //  Detected one anomaly.
-    EXPECT_EQ(refractory_period_sec +
-                      (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1) / NS_PER_SEC + 1,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    // Condition turns to true again.
-    screen_off_event =
-            CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 2,
-                                          android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
-    processor->OnLogEvent(screen_off_event.get());
-    EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 2 + 1,
-              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-
-    release_event_time = roundedBucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC;
-    release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2,
-                                               attributionTags2, "wl1");
-    processor->OnLogEvent(release_event.get());
-    EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-}
-
-TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets) {
-    const int num_buckets = 3;
-    const uint64_t threshold_ns = NS_PER_SEC;
-    auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true);
-    const uint64_t alert_id = config.alert(0).id();
-    const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
-
-    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-    sendConfig(service, config);
-
-    auto processor = service->mProcessor;
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-    ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
-
-    int64_t bucketStartTimeNs = processor->mTimeBaseNs;
-    int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6;
-
-    sp<AnomalyTracker> anomalyTracker =
-            processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
-
-    auto screen_off_event = CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
-    processor->OnLogEvent(screen_off_event.get());
-
-    // Acquire wakelock "wc1" in bucket #0.
-    auto acquire_event =
-            CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs - NS_PER_SEC / 2 - 1,
-                                       attributionUids1, attributionTags1, "wl1");
-    processor->OnLogEvent(acquire_event.get());
-    EXPECT_EQ((roundedBucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
-              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    // Release wakelock "wc1" in bucket #0.
-    int64_t release_event_time = roundedBucketStartTimeNs + bucketSizeNs - 1;
-    auto release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1,
-                                                    attributionTags1, "wl1");
-    processor->OnLogEvent(release_event.get(), release_event_time);
-    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    // Acquire wakelock "wc1" in bucket #1.
-    acquire_event =
-            CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs + NS_PER_SEC + 1,
-                                       attributionUids2, attributionTags2, "wl1");
-    processor->OnLogEvent(acquire_event.get());
-    EXPECT_EQ((bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC + 1,
-              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    release_event_time = roundedBucketStartTimeNs + bucketSizeNs + NS_PER_SEC + 100;
-    release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2,
-                                               attributionTags2, "wl1");
-    processor->OnLogEvent(release_event.get(), release_event_time);
-    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    // Acquire wakelock "wc2" in bucket #2.
-    acquire_event =
-            CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + 1,
-                                       attributionUids3, attributionTags3, "wl2");
-    processor->OnLogEvent(acquire_event.get());
-    EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 3,
-              anomalyTracker->getAlarmTimestampSec(dimensionKey2));
-    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-
-    // Release wakelock "wc2" in bucket #2.
-    release_event_time = roundedBucketStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC;
-    release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids3,
-                                               attributionTags3, "wl2");
-    processor->OnLogEvent(release_event.get(), release_event_time);
-    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
-    EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-
-    // Acquire wakelock "wc1" in bucket #2.
-    acquire_event =
-            CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC,
-                                       attributionUids2, attributionTags2, "wl1");
-    processor->OnLogEvent(acquire_event.get());
-    EXPECT_EQ((roundedBucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 3 + 1,
-              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    // Release wakelock "wc1" in bucket #2.
-    release_event_time = roundedBucketStartTimeNs + 2 * bucketSizeNs + 3.5 * NS_PER_SEC;
-    release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2,
-                                               attributionTags2, "wl1");
-    processor->OnLogEvent(release_event.get(), release_event_time);
-    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-    EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC + 1,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 6 * bucketSizeNs + 4,
-                                               attributionUids3, attributionTags3, "wl2");
-    processor->OnLogEvent(acquire_event.get());
-    acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 6 * bucketSizeNs + 5,
-                                               attributionUids1, attributionTags1, "wl1");
-    processor->OnLogEvent(acquire_event.get());
-    EXPECT_EQ((roundedBucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 2,
-              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-    EXPECT_EQ((roundedBucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 2,
-              anomalyTracker->getAlarmTimestampSec(dimensionKey2));
-
-    release_event_time = roundedBucketStartTimeNs + 6 * bucketSizeNs + NS_PER_SEC + 2;
-    release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids3,
-                                               attributionTags3, "wl2");
-    processor->OnLogEvent(release_event.get(), release_event_time);
-    release_event = CreateReleaseWakelockEvent(release_event_time + 4, attributionUids1,
-                                               attributionTags1, "wl1");
-    processor->OnLogEvent(release_event.get(), release_event_time + 4);
-    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
-    // The buckets are not messed up across dimensions. Only one dimension has anomaly triggered.
-    EXPECT_EQ(refractory_period_sec +
-                      (int64_t)(roundedBucketStartTimeNs + 6 * bucketSizeNs + NS_PER_SEC) /
-                              NS_PER_SEC +
-                      1,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-}
-
-TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period) {
-    const int num_buckets = 2;
-    const uint64_t threshold_ns = 3 * NS_PER_SEC;
-    auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, false);
-    const uint64_t alert_id = config.alert(0).id();
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6;
-    const uint32_t refractory_period_sec = 3 * bucketSizeNs / NS_PER_SEC;
-    config.mutable_alert(0)->set_refractory_period_secs(refractory_period_sec);
-
-    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-    sendConfig(service, config);
-
-    auto processor = service->mProcessor;
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-    ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
-
-    int64_t bucketStartTimeNs = processor->mTimeBaseNs;
-    int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC;
-
-    sp<AnomalyTracker> anomalyTracker =
-            processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
-
-    auto screen_off_event = CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
-    processor->OnLogEvent(screen_off_event.get());
-
-    // Acquire wakelock "wc1" in bucket #0.
-    auto acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs - 100,
-                                                    attributionUids1, attributionTags1, "wl1");
-    processor->OnLogEvent(acquire_event.get());
-    EXPECT_EQ((roundedBucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
-              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    // Acquire the wakelock "wc1" again.
-    acquire_event =
-            CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1,
-                                       attributionUids1, attributionTags1, "wl1");
-    processor->OnLogEvent(acquire_event.get());
-    // The alarm does not change.
-    EXPECT_EQ((roundedBucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
-              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    // Anomaly alarm fired late.
-    const int64_t firedAlarmTimestampNs = roundedBucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC;
-    auto alarmTriggerEvent = CreateBatterySaverOnEvent(firedAlarmTimestampNs);
-    processor->OnLogEvent(alarmTriggerEvent.get(), firedAlarmTimestampNs);
-    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-    EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs - 100,
-                                               attributionUids1, attributionTags1, "wl1");
-    processor->OnLogEvent(acquire_event.get());
-    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-    EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    int64_t release_event_time = bucketStartTimeNs + 2 * bucketSizeNs + 1;
-    auto release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1,
-                                                    attributionTags1, "wl1");
-    processor->OnLogEvent(release_event.get(), release_event_time);
-    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-    // Within the refractory period. No anomaly.
-    EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    // A new wakelock, but still within refractory period.
-    acquire_event = CreateAcquireWakelockEvent(
-            roundedBucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC, attributionUids1,
-            attributionTags1, "wl1");
-    processor->OnLogEvent(acquire_event.get());
-    EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
-              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-
-    release_event =
-            CreateReleaseWakelockEvent(roundedBucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC,
-                                       attributionUids1, attributionTags1, "wl1");
-    // Still in the refractory period. No anomaly.
-    processor->OnLogEvent(release_event.get());
-    EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
-              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-
-    acquire_event = CreateAcquireWakelockEvent(
-            roundedBucketStartTimeNs + 5 * bucketSizeNs - 2 * NS_PER_SEC - 5, attributionUids1,
-            attributionTags1, "wl1");
-    processor->OnLogEvent(acquire_event.get());
-    EXPECT_EQ((roundedBucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC + 1,
-              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-
-    release_event_time = roundedBucketStartTimeNs + 5 * bucketSizeNs - 2 * NS_PER_SEC - 4;
-    release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1,
-                                               attributionTags1, "wl1");
-    processor->OnLogEvent(release_event.get(), release_event_time);
-    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-
-    acquire_event = CreateAcquireWakelockEvent(
-            roundedBucketStartTimeNs + 5 * bucketSizeNs - 2 * NS_PER_SEC - 3, attributionUids1,
-            attributionTags1, "wl1");
-    processor->OnLogEvent(acquire_event.get());
-    EXPECT_EQ((roundedBucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC + 1,
-              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
deleted file mode 100644
index 4c2caa9..0000000
--- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
+++ /dev/null
@@ -1,375 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <gtest/gtest.h>
-
-#include "src/StatsLogProcessor.h"
-#include "src/stats_log_util.h"
-#include "tests/statsd_test_util.h"
-
-#include <iostream>
-#include <vector>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-#ifdef __ANDROID__
-
-namespace {
-
-StatsdConfig CreateStatsdConfig(const Position position) {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-    auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
-    auto attributionNodeMatcher =
-        wakelockAcquireMatcher.mutable_simple_atom_matcher()->add_field_value_matcher();
-    attributionNodeMatcher->set_field(1);
-    attributionNodeMatcher->set_position(Position::ANY);
-    auto uidMatcher = attributionNodeMatcher->mutable_matches_tuple()->add_field_value_matcher();
-    uidMatcher->set_field(1);  // uid field.
-    uidMatcher->set_eq_string("com.android.gmscore");
-
-    *config.add_atom_matcher() = wakelockAcquireMatcher;
-
-    auto countMetric = config.add_count_metric();
-    countMetric->set_id(123456);
-    countMetric->set_what(wakelockAcquireMatcher.id());
-    *countMetric->mutable_dimensions_in_what() =
-        CreateAttributionUidAndTagDimensions(
-            util::WAKELOCK_STATE_CHANGED, {position});
-    countMetric->set_bucket(FIVE_MINUTES);
-    return config;
-}
-
-// GMS core node is in the middle.
-std::vector<int> attributionUids1 = {111, 222, 333};
-std::vector<string> attributionTags1 = {"App1", "GMSCoreModule1", "App3"};
-
-// GMS core node is the last one.
-std::vector<int> attributionUids2 = {111, 333, 222};
-std::vector<string> attributionTags2 = {"App1", "App3", "GMSCoreModule1"};
-
-// GMS core node is the first one.
-std::vector<int> attributionUids3 = {222, 333};
-std::vector<string> attributionTags3 = {"GMSCoreModule1", "App3"};
-
-// Single GMS core node.
-std::vector<int> attributionUids4 = {222};
-std::vector<string> attributionTags4 = {"GMSCoreModule1"};
-
-// GMS core has another uid.
-std::vector<int> attributionUids5 = {111, 444, 333};
-std::vector<string> attributionTags5 = {"App1", "GMSCoreModule2", "App3"};
-
-// Multiple GMS core nodes.
-std::vector<int> attributionUids6 = {444, 222};
-std::vector<string> attributionTags6 = {"GMSCoreModule2", "GMSCoreModule1"};
-
-// No GMS core nodes
-std::vector<int> attributionUids7 = {111, 333};
-std::vector<string> attributionTags7 = {"App1", "App3"};
-
-std::vector<int> attributionUids8 = {111};
-std::vector<string> attributionTags8 = {"App1"};
-
-// GMS core node with isolated uid.
-const int isolatedUid = 666;
-std::vector<int> attributionUids9 = {isolatedUid};
-std::vector<string> attributionTags9 = {"GMSCoreModule3"};
-
-std::vector<int> attributionUids10 = {isolatedUid};
-std::vector<string> attributionTags10 = {"GMSCoreModule1"};
-
-}  // namespace
-
-TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid) {
-    auto config = CreateStatsdConfig(Position::FIRST);
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
-
-    ConfigKey cfgKey;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-
-    // Here it assumes that GMS core has two uids.
-    processor->getUidMap()->updateMap(
-            1, {222, 444, 111, 333}, {1, 1, 2, 2},
-            {String16("v1"), String16("v1"), String16("v2"), String16("v2")},
-            {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"),
-             String16("APP3")},
-            {String16(""), String16(""), String16(""), String16("")});
-
-    std::vector<std::unique_ptr<LogEvent>> events;
-    // Events 1~4 are in the 1st bucket.
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
-                                                attributionTags1, "wl1"));
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 200, attributionUids2,
-                                                attributionTags2, "wl1"));
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1,
-                                                attributionUids3, attributionTags3, "wl1"));
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs, attributionUids4,
-                                                attributionTags4, "wl1"));
-
-    // Events 5~8 are in the 3rd bucket.
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1,
-                                                attributionUids5, attributionTags5, "wl2"));
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100,
-                                                attributionUids6, attributionTags6, "wl2"));
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs - 2,
-                                                attributionUids7, attributionTags7, "wl2"));
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs,
-                                                attributionUids8, attributionTags8, "wl2"));
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 1,
-                                                attributionUids9, attributionTags9, "wl2"));
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 100,
-                                                attributionUids9, attributionTags9, "wl2"));
-    events.push_back(CreateIsolatedUidChangedEvent(bucketStartTimeNs + 3 * bucketSizeNs - 1, 222,
-                                                   isolatedUid, true /*is_create*/));
-    events.push_back(CreateIsolatedUidChangedEvent(bucketStartTimeNs + 3 * bucketSizeNs + 10, 222,
-                                                   isolatedUid, false /*is_create*/));
-
-    sortLogEventsByTimestamp(&events);
-
-    for (const auto& event : events) {
-        processor->OnLogEvent(event.get());
-    }
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true, ADB_DUMP,
-                            FAST, &buffer);
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(reports.reports_size(), 1);
-    ASSERT_EQ(reports.reports(0).metrics_size(), 1);
-
-    StatsLogReport::CountMetricDataWrapper countMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-    ASSERT_EQ(countMetrics.data_size(), 4);
-
-    auto data = countMetrics.data(0);
-    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
-                                          util::WAKELOCK_STATE_CHANGED, 111, "App1");
-    ASSERT_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);
-    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
-    EXPECT_EQ(data.bucket_info(1).count(), 1);
-    EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
-              bucketStartTimeNs + 2 * bucketSizeNs);
-    EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
-
-    data = countMetrics.data(1);
-    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
-                                          util::WAKELOCK_STATE_CHANGED, 222,
-                                          "GMSCoreModule1");
-    ASSERT_EQ(data.bucket_info_size(), 2);
-    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);
-    EXPECT_EQ(data.bucket_info(1).count(), 1);
-    EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
-    EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
-
-    data = countMetrics.data(2);
-    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
-                                          util::WAKELOCK_STATE_CHANGED, 222,
-                                          "GMSCoreModule3");
-    ASSERT_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 + 3 * bucketSizeNs);
-    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 4 * bucketSizeNs);
-
-    data = countMetrics.data(3);
-    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
-                                          util::WAKELOCK_STATE_CHANGED, 444,
-                                          "GMSCoreModule2");
-    ASSERT_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 + 2 * bucketSizeNs);
-    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
-}
-
-TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain) {
-    auto config = CreateStatsdConfig(Position::ALL);
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
-
-    ConfigKey cfgKey;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-
-    // Here it assumes that GMS core has two uids.
-    processor->getUidMap()->updateMap(
-            1, {222, 444, 111, 333}, {1, 1, 2, 2},
-            {String16("v1"), String16("v1"), String16("v2"), String16("v2")},
-            {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"),
-             String16("APP3")},
-            {String16(""), String16(""), String16(""), String16("")});
-
-    std::vector<std::unique_ptr<LogEvent>> events;
-    // Events 1~4 are in the 1st bucket.
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
-                                                attributionTags1, "wl1"));
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 200, attributionUids2,
-                                                attributionTags2, "wl1"));
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1,
-                                                attributionUids3, attributionTags3, "wl1"));
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs, attributionUids4,
-                                                attributionTags4, "wl1"));
-
-    // Events 5~8 are in the 3rd bucket.
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1,
-                                                attributionUids5, attributionTags5, "wl2"));
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100,
-                                                attributionUids6, attributionTags6, "wl2"));
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs - 2,
-                                                attributionUids7, attributionTags7, "wl2"));
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs,
-                                                attributionUids8, attributionTags8, "wl2"));
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 1,
-                                                attributionUids10, attributionTags10, "wl2"));
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 100,
-                                                attributionUids10, attributionTags10, "wl2"));
-    events.push_back(CreateIsolatedUidChangedEvent(bucketStartTimeNs + 3 * bucketSizeNs - 1, 222,
-                                                   isolatedUid, true /*is_create*/));
-    events.push_back(CreateIsolatedUidChangedEvent(bucketStartTimeNs + 3 * bucketSizeNs + 10, 222,
-                                                   isolatedUid, false /*is_create*/));
-
-    sortLogEventsByTimestamp(&events);
-
-    for (const auto& event : events) {
-        processor->OnLogEvent(event.get());
-    }
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true, ADB_DUMP,
-                            FAST, &buffer);
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(reports.reports_size(), 1);
-    ASSERT_EQ(reports.reports(0).metrics_size(), 1);
-
-    StatsLogReport::CountMetricDataWrapper countMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-    ASSERT_EQ(countMetrics.data_size(), 6);
-
-    auto data = countMetrics.data(0);
-    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
-                                          util::WAKELOCK_STATE_CHANGED, 222,
-                                          "GMSCoreModule1");
-    ASSERT_EQ(2, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-    EXPECT_EQ(1, data.bucket_info(1).count());
-    EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-              data.bucket_info(1).start_bucket_elapsed_nanos());
-    EXPECT_EQ(bucketStartTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
-
-    data = countMetrics.data(1);
-    ValidateUidDimension(data.dimensions_in_what(), 0, util::WAKELOCK_STATE_CHANGED, 222);
-    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
-                                          util::WAKELOCK_STATE_CHANGED, 222,
-                                          "GMSCoreModule1");
-    ValidateUidDimension(data.dimensions_in_what(), 1, util::WAKELOCK_STATE_CHANGED, 333);
-    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
-                                          util::WAKELOCK_STATE_CHANGED, 333, "App3");
-    ASSERT_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, util::WAKELOCK_STATE_CHANGED, 444);
-    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
-                                          util::WAKELOCK_STATE_CHANGED, 444,
-                                          "GMSCoreModule2");
-    ValidateUidDimension(data.dimensions_in_what(), 1, util::WAKELOCK_STATE_CHANGED, 222);
-    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
-                                          util::WAKELOCK_STATE_CHANGED, 222,
-                                          "GMSCoreModule1");
-    ASSERT_EQ(data.bucket_info_size(), 1);
-    EXPECT_EQ(data.bucket_info(0).count(), 1);
-    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-              data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-
-    data = countMetrics.data(3);
-    ValidateUidDimension(data.dimensions_in_what(), 0, util::WAKELOCK_STATE_CHANGED, 111);
-    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
-                                          util::WAKELOCK_STATE_CHANGED, 111, "App1");
-    ValidateUidDimension(data.dimensions_in_what(), 1, util::WAKELOCK_STATE_CHANGED, 222);
-    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
-                                          util::WAKELOCK_STATE_CHANGED, 222,
-                                          "GMSCoreModule1");
-    ValidateUidDimension(data.dimensions_in_what(), 2, util::WAKELOCK_STATE_CHANGED, 333);
-    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 2,
-                                          util::WAKELOCK_STATE_CHANGED, 333, "App3");
-    ASSERT_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, util::WAKELOCK_STATE_CHANGED, 111);
-    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
-                                          util::WAKELOCK_STATE_CHANGED, 111, "App1");
-    ValidateUidDimension(data.dimensions_in_what(), 1, util::WAKELOCK_STATE_CHANGED, 333);
-    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
-                                          util::WAKELOCK_STATE_CHANGED, 333, "App3");
-    ValidateUidDimension(data.dimensions_in_what(), 2, util::WAKELOCK_STATE_CHANGED, 222);
-    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 2,
-                                          util::WAKELOCK_STATE_CHANGED, 222,
-                                          "GMSCoreModule1");
-    ASSERT_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(5);
-    ValidateUidDimension(data.dimensions_in_what(), 0, util::WAKELOCK_STATE_CHANGED, 111);
-    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
-                                          util::WAKELOCK_STATE_CHANGED, 111, "App1");
-    ValidateUidDimension(data.dimensions_in_what(), 1, util::WAKELOCK_STATE_CHANGED, 444);
-    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
-                                          util::WAKELOCK_STATE_CHANGED, 444,
-                                          "GMSCoreModule2");
-    ValidateUidDimension(data.dimensions_in_what(), 2, util::WAKELOCK_STATE_CHANGED, 333);
-    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 2,
-                                          util::WAKELOCK_STATE_CHANGED, 333, "App3");
-    ASSERT_EQ(data.bucket_info_size(), 1);
-    EXPECT_EQ(data.bucket_info(0).count(), 1);
-    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-              data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp b/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
deleted file mode 100644
index 0bce0ba..0000000
--- a/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <gtest/gtest.h>
-
-#include "src/StatsLogProcessor.h"
-#include "src/stats_log_util.h"
-#include "tests/statsd_test_util.h"
-
-#include <vector>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-#ifdef __ANDROID__
-
-namespace {
-
-StatsdConfig CreateStatsdConfig(int num_buckets, int threshold) {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-    auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
-
-    *config.add_atom_matcher() = wakelockAcquireMatcher;
-
-    auto countMetric = config.add_count_metric();
-    countMetric->set_id(123456);
-    countMetric->set_what(wakelockAcquireMatcher.id());
-    *countMetric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
-            util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-    countMetric->set_bucket(FIVE_MINUTES);
-
-    auto alert = config.add_alert();
-    alert->set_id(StringToId("alert"));
-    alert->set_metric_id(123456);
-    alert->set_num_buckets(num_buckets);
-    alert->set_refractory_period_secs(10);
-    alert->set_trigger_if_sum_gt(threshold);
-
-    // Two hours
-    config.set_ttl_in_seconds(2 * 3600);
-    return config;
-}
-
-}  // namespace
-
-TEST(ConfigTtlE2eTest, TestCountMetric) {
-    const int num_buckets = 1;
-    const int threshold = 3;
-    auto config = CreateStatsdConfig(num_buckets, threshold);
-    const uint64_t alert_id = config.alert(0).id();
-    const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
-
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
-
-    ConfigKey cfgKey;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-
-    std::vector<int> attributionUids1 = {111};
-    std::vector<string> attributionTags1 = {"App1"};
-
-    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(util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
-                           Value((int32_t)222));
-    HashableDimensionKey whatKey2({fieldValue2});
-    MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY);
-
-    auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
-                                            attributionTags1, "wl1");
-    processor->OnLogEvent(event.get());
-
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2, attributionUids1,
-                                       attributionTags1, "wl2");
-    processor->OnLogEvent(event.get());
-
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 25 * bucketSizeNs + 2, attributionUids1,
-                                       attributionTags1, "wl1");
-    processor->OnLogEvent(event.get());
-
-    EXPECT_EQ((int64_t)(bucketStartTimeNs + 25 * bucketSizeNs + 2 + 2 * 3600 * NS_PER_SEC),
-              processor->mMetricsManagers.begin()->second->getTtlEndNs());
-
-    // Clear the data stored on disk as a result of the ttl.
-    vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 25 * bucketSizeNs + 3, false, true,
-                            ADB_DUMP, FAST, &buffer);
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/tests/e2e/ConfigUpdate_e2e_ab_test.cpp b/cmds/statsd/tests/e2e/ConfigUpdate_e2e_ab_test.cpp
deleted file mode 100644
index 098f284..0000000
--- a/cmds/statsd/tests/e2e/ConfigUpdate_e2e_ab_test.cpp
+++ /dev/null
@@ -1,328 +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.
-
-#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
-#include <gtest/gtest.h>
-
-#include "flags/flags.h"
-#include "src/StatsLogProcessor.h"
-#include "src/storage/StorageManager.h"
-#include "tests/statsd_test_util.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-#ifdef __ANDROID__
-#define STATS_DATA_DIR "/data/misc/stats-data"
-
-using android::base::SetProperty;
-using android::base::StringPrintf;
-using namespace std;
-
-namespace {
-
-StatsdConfig CreateSimpleConfig() {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_STATSD");
-    config.set_hash_strings_in_metric_report(false);
-
-    *config.add_atom_matcher() = CreateBatteryStateUsbMatcher();
-    // Simple count metric so the config isn't empty.
-    CountMetric* countMetric1 = config.add_count_metric();
-    countMetric1->set_id(StringToId("Count1"));
-    countMetric1->set_what(config.atom_matcher(0).id());
-    countMetric1->set_bucket(FIVE_MINUTES);
-    return config;
-}
-}  // namespace
-
-// Setup for parameterized tests.
-class ConfigUpdateE2eAbTest : public TestWithParam<bool> {
-private:
-    string originalFlagValue;
-
-public:
-    void SetUp() override {
-        originalFlagValue = getFlagBool(PARTIAL_CONFIG_UPDATE_FLAG, "");
-        string rawFlagName =
-                StringPrintf("persist.device_config.%s.%s", STATSD_NATIVE_NAMESPACE.c_str(),
-                             PARTIAL_CONFIG_UPDATE_FLAG.c_str());
-        SetProperty(rawFlagName, GetParam() ? "true" : "false");
-    }
-
-    void TearDown() override {
-        string rawFlagName =
-                StringPrintf("persist.device_config.%s.%s", STATSD_NATIVE_NAMESPACE.c_str(),
-                             PARTIAL_CONFIG_UPDATE_FLAG.c_str());
-        SetProperty(rawFlagName, originalFlagValue);
-    }
-};
-
-INSTANTIATE_TEST_SUITE_P(ConfigUpdateE2eAbTest, ConfigUpdateE2eAbTest, testing::Bool());
-
-TEST_P(ConfigUpdateE2eAbTest, TestUidMapVersionStringInstaller) {
-    sp<UidMap> uidMap = new UidMap();
-    vector<int32_t> uids({1000});
-    vector<int64_t> versions({1});
-    vector<String16> apps({String16("app1")});
-    vector<String16> versionStrings({String16("v1")});
-    vector<String16> installers({String16("installer1")});
-    uidMap->updateMap(1, uids, versions, versionStrings, apps, installers);
-
-    StatsdConfig config = CreateSimpleConfig();
-    config.set_version_strings_in_metric_report(true);
-    config.set_installer_in_metric_report(false);
-    int64_t baseTimeNs = getElapsedRealtimeNs();
-
-    ConfigKey cfgKey(0, 12345);
-    sp<StatsLogProcessor> processor =
-            CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey, nullptr, 0, uidMap);
-    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-
-    // Now update.
-    config.set_version_strings_in_metric_report(false);
-    config.set_installer_in_metric_report(true);
-    processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config);
-    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_EQ(metricsManager == processor->mMetricsManagers.begin()->second, GetParam());
-    EXPECT_TRUE(metricsManager->isConfigValid());
-
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    // First report is written to disk when the update happens.
-    ASSERT_EQ(reports.reports_size(), 2);
-    UidMapping uidMapping = reports.reports(1).uid_map();
-    ASSERT_EQ(uidMapping.snapshots_size(), 1);
-    ASSERT_EQ(uidMapping.snapshots(0).package_info_size(), 1);
-    EXPECT_FALSE(uidMapping.snapshots(0).package_info(0).has_version_string());
-    EXPECT_EQ(uidMapping.snapshots(0).package_info(0).installer(), "installer1");
-}
-
-TEST_P(ConfigUpdateE2eAbTest, TestHashStrings) {
-    sp<UidMap> uidMap = new UidMap();
-    vector<int32_t> uids({1000});
-    vector<int64_t> versions({1});
-    vector<String16> apps({String16("app1")});
-    vector<String16> versionStrings({String16("v1")});
-    vector<String16> installers({String16("installer1")});
-    uidMap->updateMap(1, uids, versions, versionStrings, apps, installers);
-
-    StatsdConfig config = CreateSimpleConfig();
-    config.set_version_strings_in_metric_report(true);
-    config.set_hash_strings_in_metric_report(true);
-    int64_t baseTimeNs = getElapsedRealtimeNs();
-
-    ConfigKey cfgKey(0, 12345);
-    sp<StatsLogProcessor> processor =
-            CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey, nullptr, 0, uidMap);
-    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-
-    // Now update.
-    config.set_hash_strings_in_metric_report(false);
-    processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config);
-    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_EQ(metricsManager == processor->mMetricsManagers.begin()->second, GetParam());
-    EXPECT_TRUE(metricsManager->isConfigValid());
-
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    // First report is written to disk when the update happens.
-    ASSERT_EQ(reports.reports_size(), 2);
-    UidMapping uidMapping = reports.reports(1).uid_map();
-    ASSERT_EQ(uidMapping.snapshots_size(), 1);
-    ASSERT_EQ(uidMapping.snapshots(0).package_info_size(), 1);
-    EXPECT_TRUE(uidMapping.snapshots(0).package_info(0).has_version_string());
-    EXPECT_FALSE(uidMapping.snapshots(0).package_info(0).has_version_string_hash());
-}
-
-TEST_P(ConfigUpdateE2eAbTest, TestAnnotations) {
-    StatsdConfig config = CreateSimpleConfig();
-    StatsdConfig_Annotation* annotation = config.add_annotation();
-    annotation->set_field_int64(11);
-    annotation->set_field_int32(1);
-    int64_t baseTimeNs = getElapsedRealtimeNs();
-    ConfigKey cfgKey(0, 12345);
-    sp<StatsLogProcessor> processor =
-            CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
-
-    // Now update
-    config.clear_annotation();
-    annotation = config.add_annotation();
-    annotation->set_field_int64(22);
-    annotation->set_field_int32(2);
-    processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config);
-
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    // First report is written to disk when the update happens.
-    ASSERT_EQ(reports.reports_size(), 2);
-    ConfigMetricsReport report = reports.reports(1);
-    EXPECT_EQ(report.annotation_size(), 1);
-    EXPECT_EQ(report.annotation(0).field_int64(), 22);
-    EXPECT_EQ(report.annotation(0).field_int32(), 2);
-}
-
-TEST_P(ConfigUpdateE2eAbTest, TestPersistLocally) {
-    StatsdConfig config = CreateSimpleConfig();
-    config.set_persist_locally(false);
-    int64_t baseTimeNs = getElapsedRealtimeNs();
-    ConfigKey cfgKey(0, 12345);
-    sp<StatsLogProcessor> processor =
-            CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    ASSERT_EQ(reports.reports_size(), 1);
-    // Number of reports should still be 1 since persist_locally is false.
-    reports.Clear();
-    buffer.clear();
-    processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    ASSERT_EQ(reports.reports_size(), 1);
-
-    // Now update.
-    config.set_persist_locally(true);
-    processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config);
-
-    // Should get 2: 1 in memory + 1 on disk. Both should be saved on disk.
-    reports.Clear();
-    buffer.clear();
-    processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    ASSERT_EQ(reports.reports_size(), 2);
-    // Should get 3, 2 on disk + 1 in memory.
-    reports.Clear();
-    buffer.clear();
-    processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    ASSERT_EQ(reports.reports_size(), 3);
-    string suffix = StringPrintf("%d_%lld", cfgKey.GetUid(), (long long)cfgKey.GetId());
-    StorageManager::deleteSuffixedFiles(STATS_DATA_DIR, suffix.c_str());
-    string historySuffix =
-            StringPrintf("%d_%lld_history", cfgKey.GetUid(), (long long)cfgKey.GetId());
-    StorageManager::deleteSuffixedFiles(STATS_DATA_DIR, historySuffix.c_str());
-}
-
-TEST_P(ConfigUpdateE2eAbTest, TestNoReportMetrics) {
-    StatsdConfig config = CreateSimpleConfig();
-    // Second simple count metric.
-    CountMetric* countMetric = config.add_count_metric();
-    countMetric->set_id(StringToId("Count2"));
-    countMetric->set_what(config.atom_matcher(0).id());
-    countMetric->set_bucket(FIVE_MINUTES);
-    config.add_no_report_metric(config.count_metric(0).id());
-    int64_t baseTimeNs = getElapsedRealtimeNs();
-    ConfigKey cfgKey(0, 12345);
-    sp<StatsLogProcessor> processor =
-            CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
-
-    // Now update.
-    config.clear_no_report_metric();
-    config.add_no_report_metric(config.count_metric(1).id());
-    processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config);
-
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    // First report is written to disk when the update happens.
-    ASSERT_EQ(reports.reports_size(), 2);
-    // First report (before update) has the first count metric.
-    ASSERT_EQ(reports.reports(0).metrics_size(), 1);
-    EXPECT_EQ(reports.reports(0).metrics(0).metric_id(), config.count_metric(1).id());
-    // Second report (after update) has the first count metric.
-    ASSERT_EQ(reports.reports(1).metrics_size(), 1);
-    EXPECT_EQ(reports.reports(1).metrics(0).metric_id(), config.count_metric(0).id());
-}
-
-TEST_P(ConfigUpdateE2eAbTest, TestAtomsAllowedFromAnyUid) {
-    StatsdConfig config = CreateSimpleConfig();
-    int64_t baseTimeNs = getElapsedRealtimeNs();
-    ConfigKey cfgKey(0, 12345);
-    sp<StatsLogProcessor> processor =
-            CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
-    // Uses AID_ROOT, which isn't in allowed log sources.
-    unique_ptr<LogEvent> event = CreateBatteryStateChangedEvent(
-            baseTimeNs + 2, BatteryPluggedStateEnum::BATTERY_PLUGGED_USB);
-    processor->OnLogEvent(event.get());
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, baseTimeNs + 1001, true, true, ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    ASSERT_EQ(reports.reports_size(), 1);
-    // Check the metric and make sure it has 0 count.
-    ASSERT_EQ(reports.reports(0).metrics_size(), 1);
-    EXPECT_FALSE(reports.reports(0).metrics(0).has_count_metrics());
-
-    // Now update. Allow plugged state to be logged from any uid, so the atom will be counted.
-    config.add_whitelisted_atom_ids(util::PLUGGED_STATE_CHANGED);
-    processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config);
-    unique_ptr<LogEvent> event2 = CreateBatteryStateChangedEvent(
-            baseTimeNs + 2000, BatteryPluggedStateEnum::BATTERY_PLUGGED_USB);
-    processor->OnLogEvent(event.get());
-    reports.Clear();
-    buffer.clear();
-    processor->onDumpReport(cfgKey, baseTimeNs + 3000, true, true, ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    ASSERT_EQ(reports.reports_size(), 2);
-    // Check the metric and make sure it has 0 count.
-    ASSERT_EQ(reports.reports(1).metrics_size(), 1);
-    EXPECT_TRUE(reports.reports(1).metrics(0).has_count_metrics());
-    ASSERT_EQ(reports.reports(1).metrics(0).count_metrics().data_size(), 1);
-    ASSERT_EQ(reports.reports(1).metrics(0).count_metrics().data(0).bucket_info_size(), 1);
-    EXPECT_EQ(reports.reports(1).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
-}
-
-TEST_P(ConfigUpdateE2eAbTest, TestConfigTtl) {
-    StatsdConfig config = CreateSimpleConfig();
-    config.set_ttl_in_seconds(1);
-    int64_t baseTimeNs = getElapsedRealtimeNs();
-    ConfigKey cfgKey(0, 12345);
-    sp<StatsLogProcessor> processor =
-            CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
-    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-    EXPECT_EQ(metricsManager->getTtlEndNs(), baseTimeNs + NS_PER_SEC);
-
-    config.set_ttl_in_seconds(5);
-    processor->OnConfigUpdated(baseTimeNs + 2 * NS_PER_SEC, cfgKey, config);
-    metricsManager = processor->mMetricsManagers.begin()->second;
-    EXPECT_EQ(metricsManager->getTtlEndNs(), baseTimeNs + 7 * NS_PER_SEC);
-
-    // Clear the data stored on disk as a result of the update.
-    vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, baseTimeNs + 3 * NS_PER_SEC, false, true, ADB_DUMP, FAST,
-                            &buffer);
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/tests/e2e/ConfigUpdate_e2e_test.cpp b/cmds/statsd/tests/e2e/ConfigUpdate_e2e_test.cpp
deleted file mode 100644
index 94b778c..0000000
--- a/cmds/statsd/tests/e2e/ConfigUpdate_e2e_test.cpp
+++ /dev/null
@@ -1,358 +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.
-
-#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
-#include <gtest/gtest.h>
-
-#include "flags/flags.h"
-#include "src/StatsLogProcessor.h"
-#include "src/storage/StorageManager.h"
-#include "tests/statsd_test_util.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-#ifdef __ANDROID__
-
-using android::base::SetProperty;
-using android::base::StringPrintf;
-using namespace std;
-
-// Tests that only run with the partial config update feature turned on.
-namespace {
-// Setup for test fixture.
-class ConfigUpdateE2eTest : public ::testing::Test {
-private:
-    string originalFlagValue;
-public:
-    void SetUp() override {
-        originalFlagValue = getFlagBool(PARTIAL_CONFIG_UPDATE_FLAG, "");
-        string rawFlagName =
-                StringPrintf("persist.device_config.%s.%s", STATSD_NATIVE_NAMESPACE.c_str(),
-                             PARTIAL_CONFIG_UPDATE_FLAG.c_str());
-        SetProperty(rawFlagName, "true");
-    }
-
-    void TearDown() override {
-        string rawFlagName =
-                StringPrintf("persist.device_config.%s.%s", STATSD_NATIVE_NAMESPACE.c_str(),
-                             PARTIAL_CONFIG_UPDATE_FLAG.c_str());
-        SetProperty(rawFlagName, originalFlagValue);
-    }
-};
-}  // Anonymous namespace.
-
-TEST_F(ConfigUpdateE2eTest, TestNewDurationExistingWhat) {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");
-    *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
-    *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
-
-    Predicate holdingWakelockPredicate = CreateHoldingWakelockPredicate();
-    *config.add_predicate() = holdingWakelockPredicate;
-
-    ConfigKey key(123, 987);
-    uint64_t bucketStartTimeNs = 10000000000;  // 0:10
-    uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(FIVE_MINUTES) * 1000000LL;
-    sp<StatsLogProcessor> processor =
-            CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, key);
-
-    int app1Uid = 123;
-    vector<int> attributionUids1 = {app1Uid};
-    vector<string> attributionTags1 = {"App1"};
-    // Create a wakelock acquire, causing the condition to be true.
-    unique_ptr<LogEvent> event = CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC,
-                                                            attributionUids1, attributionTags1,
-                                                            "wl1");  // 0:10
-    processor->OnLogEvent(event.get());
-
-    // Add metric.
-    DurationMetric* durationMetric = config.add_duration_metric();
-    durationMetric->set_id(StringToId("WakelockDuration"));
-    durationMetric->set_what(holdingWakelockPredicate.id());
-    durationMetric->set_aggregation_type(DurationMetric::SUM);
-    durationMetric->set_bucket(FIVE_MINUTES);
-
-    uint64_t updateTimeNs = bucketStartTimeNs + 60 * NS_PER_SEC;  // 1:00
-    processor->OnConfigUpdated(updateTimeNs, key, config);
-
-    event = CreateReleaseWakelockEvent(bucketStartTimeNs + 80 * NS_PER_SEC, attributionUids1,
-                                       attributionTags1,
-                                       "wl1");  // 1:20
-    processor->OnLogEvent(event.get());
-    uint64_t dumpTimeNs = bucketStartTimeNs + 90 * NS_PER_SEC;  // 1:30
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor->onDumpReport(key, dumpTimeNs, true, true, ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(reports.reports_size(), 1);
-    ASSERT_EQ(reports.reports(0).metrics_size(), 1);
-    EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
-
-    StatsLogReport::DurationMetricDataWrapper metricData;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), &metricData);
-    ASSERT_EQ(metricData.data_size(), 1);
-    DurationMetricData data = metricData.data(0);
-    ASSERT_EQ(data.bucket_info_size(), 1);
-
-    DurationBucketInfo bucketInfo = data.bucket_info(0);
-    EXPECT_EQ(bucketInfo.start_bucket_elapsed_nanos(), updateTimeNs);
-    EXPECT_EQ(bucketInfo.end_bucket_elapsed_nanos(), dumpTimeNs);
-    EXPECT_EQ(bucketInfo.duration_nanos(), 20 * NS_PER_SEC);
-}
-
-TEST_F(ConfigUpdateE2eTest, TestNewDurationExistingWhatSlicedCondition) {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");
-    *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
-    *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
-    *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
-    *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
-
-    Predicate holdingWakelockPredicate = CreateHoldingWakelockPredicate();
-    // The predicate is dimensioning by first attribution node by uid.
-    *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() =
-            CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-    *config.add_predicate() = holdingWakelockPredicate;
-
-    Predicate isInBackgroundPredicate = CreateIsInBackgroundPredicate();
-    *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
-            CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /*uid*/});
-    *config.add_predicate() = isInBackgroundPredicate;
-
-    ConfigKey key(123, 987);
-    uint64_t bucketStartTimeNs = 10000000000;  // 0:10
-    uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(FIVE_MINUTES) * 1000000LL;
-    sp<StatsLogProcessor> processor =
-            CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, key);
-
-    int app1Uid = 123, app2Uid = 456;
-    vector<int> attributionUids1 = {app1Uid};
-    vector<string> attributionTags1 = {"App1"};
-    vector<int> attributionUids2 = {app2Uid};
-    vector<string> attributionTags2 = {"App2"};
-    unique_ptr<LogEvent> event = CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC,
-                                                            attributionUids1, attributionTags1,
-                                                            "wl1");  // 0:10
-    processor->OnLogEvent(event.get());
-    event = CreateMoveToBackgroundEvent(bucketStartTimeNs + 22 * NS_PER_SEC, app1Uid);  // 0:22
-    processor->OnLogEvent(event.get());
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 35 * NS_PER_SEC, attributionUids2,
-                                       attributionTags2,
-                                       "wl1");  // 0:35
-    processor->OnLogEvent(event.get());
-
-    // Add metric.
-    DurationMetric* durationMetric = config.add_duration_metric();
-    durationMetric->set_id(StringToId("WakelockDuration"));
-    durationMetric->set_what(holdingWakelockPredicate.id());
-    durationMetric->set_condition(isInBackgroundPredicate.id());
-    durationMetric->set_aggregation_type(DurationMetric::SUM);
-    // The metric is dimensioning by first attribution node and only by uid.
-    *durationMetric->mutable_dimensions_in_what() =
-            CreateAttributionUidDimensions(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());
-    *links->mutable_fields_in_what() =
-            CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-    *links->mutable_fields_in_condition() =
-            CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /*uid*/});
-
-    uint64_t updateTimeNs = bucketStartTimeNs + 60 * NS_PER_SEC;  // 1:00
-    processor->OnConfigUpdated(updateTimeNs, key, config);
-
-    event = CreateMoveToBackgroundEvent(bucketStartTimeNs + 73 * NS_PER_SEC, app2Uid);  // 1:13
-    processor->OnLogEvent(event.get());
-    event = CreateReleaseWakelockEvent(bucketStartTimeNs + 84 * NS_PER_SEC, attributionUids1,
-                                       attributionTags1, "wl1");  // 1:24
-    processor->OnLogEvent(event.get());
-
-    uint64_t dumpTimeNs = bucketStartTimeNs + 90 * NS_PER_SEC;  //  1:30
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor->onDumpReport(key, dumpTimeNs, true, true, ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(reports.reports_size(), 1);
-    ASSERT_EQ(reports.reports(0).metrics_size(), 1);
-    EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
-
-    StatsLogReport::DurationMetricDataWrapper metricData;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), &metricData);
-    ASSERT_EQ(metricData.data_size(), 2);
-
-    DurationMetricData data = metricData.data(0);
-    ValidateAttributionUidDimension(data.dimensions_in_what(), util::WAKELOCK_STATE_CHANGED,
-                                    app1Uid);
-    ASSERT_EQ(data.bucket_info_size(), 1);
-    DurationBucketInfo bucketInfo = data.bucket_info(0);
-    EXPECT_EQ(bucketInfo.duration_nanos(), 24 * NS_PER_SEC);
-
-    data = metricData.data(1);
-    ValidateAttributionUidDimension(data.dimensions_in_what(), util::WAKELOCK_STATE_CHANGED,
-                                    app2Uid);
-    ASSERT_EQ(data.bucket_info_size(), 1);
-    bucketInfo = data.bucket_info(0);
-    EXPECT_EQ(bucketInfo.duration_nanos(), 17 * NS_PER_SEC);
-}
-
-TEST_F(ConfigUpdateE2eTest, TestNewDurationExistingWhatSlicedState) {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");
-    *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
-    *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
-
-    Predicate holdingWakelockPredicate = CreateHoldingWakelockPredicate();
-    // The predicate is dimensioning by first attribution node by uid.
-    *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() =
-            CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-    *config.add_predicate() = holdingWakelockPredicate;
-
-    auto uidProcessState = CreateUidProcessState();
-    *config.add_state() = uidProcessState;
-
-    // Count metric. We don't care about this one. Only use it so the StateTracker gets persisted.
-    CountMetric* countMetric = config.add_count_metric();
-    countMetric->set_id(StringToId("Tmp"));
-    countMetric->set_what(config.atom_matcher(0).id());
-    countMetric->add_slice_by_state(uidProcessState.id());
-    // The metric is dimensioning by first attribution node and only by uid.
-    *countMetric->mutable_dimensions_in_what() =
-            CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-    countMetric->set_bucket(FIVE_MINUTES);
-    auto stateLink = countMetric->add_state_link();
-    stateLink->set_state_atom_id(util::UID_PROCESS_STATE_CHANGED);
-    *stateLink->mutable_fields_in_what() =
-            CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-    *stateLink->mutable_fields_in_state() =
-            CreateDimensions(util::UID_PROCESS_STATE_CHANGED, {1 /*uid*/});
-    config.add_no_report_metric(countMetric->id());
-
-    ConfigKey key(123, 987);
-    uint64_t bucketStartTimeNs = 10000000000;  // 0:10
-    uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(FIVE_MINUTES) * 1000000LL;
-    sp<StatsLogProcessor> processor =
-            CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, key);
-
-    int app1Uid = 123, app2Uid = 456;
-    vector<int> attributionUids1 = {app1Uid};
-    vector<string> attributionTags1 = {"App1"};
-    vector<int> attributionUids2 = {app2Uid};
-    vector<string> attributionTags2 = {"App2"};
-    unique_ptr<LogEvent> event = CreateUidProcessStateChangedEvent(
-            bucketStartTimeNs + 10 * NS_PER_SEC, app1Uid,
-            android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND);  // 0:10
-    processor->OnLogEvent(event.get());
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 22 * NS_PER_SEC, attributionUids1,
-                                       attributionTags1,
-                                       "wl1");  // 0:22
-    processor->OnLogEvent(event.get());
-    event = CreateUidProcessStateChangedEvent(
-            bucketStartTimeNs + 30 * NS_PER_SEC, app2Uid,
-            android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND);  // 0:30
-    processor->OnLogEvent(event.get());
-
-    // Add metric.
-    DurationMetric* durationMetric = config.add_duration_metric();
-    durationMetric->set_id(StringToId("WakelockDuration"));
-    durationMetric->set_what(holdingWakelockPredicate.id());
-    durationMetric->add_slice_by_state(uidProcessState.id());
-    durationMetric->set_aggregation_type(DurationMetric::SUM);
-    // The metric is dimensioning by first attribution node and only by uid.
-    *durationMetric->mutable_dimensions_in_what() =
-            CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-    durationMetric->set_bucket(FIVE_MINUTES);
-    // Links between wakelock state atom and condition of app is in background.
-    stateLink = durationMetric->add_state_link();
-    stateLink->set_state_atom_id(util::UID_PROCESS_STATE_CHANGED);
-    *stateLink->mutable_fields_in_what() =
-            CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-    *stateLink->mutable_fields_in_state() =
-            CreateDimensions(util::UID_PROCESS_STATE_CHANGED, {1 /*uid*/});
-
-    uint64_t updateTimeNs = bucketStartTimeNs + 60 * NS_PER_SEC;  // 1:00
-    processor->OnConfigUpdated(updateTimeNs, key, config);
-
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 72 * NS_PER_SEC, attributionUids2,
-                                       attributionTags2,
-                                       "wl1");  // 1:13
-    processor->OnLogEvent(event.get());
-    event = CreateUidProcessStateChangedEvent(
-            bucketStartTimeNs + 75 * NS_PER_SEC, app1Uid,
-            android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND);  // 1:15
-    processor->OnLogEvent(event.get());
-    event = CreateReleaseWakelockEvent(bucketStartTimeNs + 84 * NS_PER_SEC, attributionUids1,
-                                       attributionTags1, "wl1");  // 1:24
-    processor->OnLogEvent(event.get());
-
-    uint64_t dumpTimeNs = bucketStartTimeNs + 90 * NS_PER_SEC;  //  1:30
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor->onDumpReport(key, dumpTimeNs, true, true, ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(reports.reports_size(), 1);
-    ASSERT_EQ(reports.reports(0).metrics_size(), 1);
-    EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
-
-    StatsLogReport::DurationMetricDataWrapper metricData;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), &metricData);
-    ASSERT_EQ(metricData.data_size(), 3);
-
-    DurationMetricData data = metricData.data(0);
-    ValidateAttributionUidDimension(data.dimensions_in_what(), util::WAKELOCK_STATE_CHANGED,
-                                    app1Uid);
-    ValidateStateValue(data.slice_by_state(), util::UID_PROCESS_STATE_CHANGED,
-                       android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND);
-    ASSERT_EQ(data.bucket_info_size(), 1);
-    DurationBucketInfo bucketInfo = data.bucket_info(0);
-    EXPECT_EQ(bucketInfo.duration_nanos(), 15 * NS_PER_SEC);
-
-    data = metricData.data(1);
-    ValidateAttributionUidDimension(data.dimensions_in_what(), util::WAKELOCK_STATE_CHANGED,
-                                    app1Uid);
-    ValidateStateValue(data.slice_by_state(), util::UID_PROCESS_STATE_CHANGED,
-                       android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND);
-    ASSERT_EQ(data.bucket_info_size(), 1);
-    bucketInfo = data.bucket_info(0);
-    EXPECT_EQ(bucketInfo.duration_nanos(), 9 * NS_PER_SEC);
-
-    data = metricData.data(2);
-    ValidateAttributionUidDimension(data.dimensions_in_what(), util::WAKELOCK_STATE_CHANGED,
-                                    app2Uid);
-    ValidateStateValue(data.slice_by_state(), util::UID_PROCESS_STATE_CHANGED,
-                       android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND);
-    ASSERT_EQ(data.bucket_info_size(), 1);
-    bucketInfo = data.bucket_info(0);
-    EXPECT_EQ(bucketInfo.duration_nanos(), 18 * NS_PER_SEC);
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
deleted file mode 100644
index 04eb400..0000000
--- a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
+++ /dev/null
@@ -1,901 +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.
- */
-
-#include <gtest/gtest.h>
-
-#include "src/StatsLogProcessor.h"
-#include "src/state/StateManager.h"
-#include "src/state/StateTracker.h"
-#include "tests/statsd_test_util.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-#ifdef __ANDROID__
-
-/**
- * Tests the initial condition and condition after the first log events for
- * count metrics with either a combination condition or simple condition.
- *
- * Metrics should be initialized with condition kUnknown (given that the
- * predicate is using the default InitialValue of UNKNOWN). The condition should
- * be updated to either kFalse or kTrue if a condition event is logged for all
- * children conditions.
- */
-TEST(CountMetricE2eTest, TestInitialConditionChanges) {
-    // Initialize config.
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");     // LogEvent defaults to UID of root.
-    config.add_default_pull_packages("AID_ROOT");  // Fake puller is registered with root.
-
-    auto syncStartMatcher = CreateSyncStartAtomMatcher();
-    *config.add_atom_matcher() = syncStartMatcher;
-    *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = CreateBatteryStateNoneMatcher();
-    *config.add_atom_matcher() = CreateBatteryStateUsbMatcher();
-
-    auto screenOnPredicate = CreateScreenIsOnPredicate();
-    *config.add_predicate() = screenOnPredicate;
-
-    auto deviceUnpluggedPredicate = CreateDeviceUnpluggedPredicate();
-    *config.add_predicate() = deviceUnpluggedPredicate;
-
-    auto screenOnOnBatteryPredicate = config.add_predicate();
-    screenOnOnBatteryPredicate->set_id(StringToId("screenOnOnBatteryPredicate"));
-    screenOnOnBatteryPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
-    addPredicateToPredicateCombination(screenOnPredicate, screenOnOnBatteryPredicate);
-    addPredicateToPredicateCombination(deviceUnpluggedPredicate, screenOnOnBatteryPredicate);
-
-    // CountSyncStartWhileScreenOnOnBattery (CombinationCondition)
-    CountMetric* countMetric1 = config.add_count_metric();
-    countMetric1->set_id(StringToId("CountSyncStartWhileScreenOnOnBattery"));
-    countMetric1->set_what(syncStartMatcher.id());
-    countMetric1->set_condition(screenOnOnBatteryPredicate->id());
-    countMetric1->set_bucket(FIVE_MINUTES);
-
-    // CountSyncStartWhileOnBattery (SimpleCondition)
-    CountMetric* countMetric2 = config.add_count_metric();
-    countMetric2->set_id(StringToId("CountSyncStartWhileOnBatterySliceScreen"));
-    countMetric2->set_what(syncStartMatcher.id());
-    countMetric2->set_condition(deviceUnpluggedPredicate.id());
-    countMetric2->set_bucket(FIVE_MINUTES);
-
-    const uint64_t bucketStartTimeNs = 10000000000;  // 0:10
-    const uint64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-    int uid = 12345;
-    int64_t cfgId = 98765;
-    ConfigKey cfgKey(uid, cfgId);
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-
-    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-    EXPECT_EQ(2, metricsManager->mAllMetricProducers.size());
-
-    sp<MetricProducer> metricProducer1 = metricsManager->mAllMetricProducers[0];
-    sp<MetricProducer> metricProducer2 = metricsManager->mAllMetricProducers[1];
-
-    EXPECT_EQ(ConditionState::kUnknown, metricProducer1->mCondition);
-    EXPECT_EQ(ConditionState::kUnknown, metricProducer2->mCondition);
-
-    auto screenOnEvent =
-            CreateScreenStateChangedEvent(bucketStartTimeNs + 30, android::view::DISPLAY_STATE_ON);
-    processor->OnLogEvent(screenOnEvent.get());
-    EXPECT_EQ(ConditionState::kUnknown, metricProducer1->mCondition);
-    EXPECT_EQ(ConditionState::kUnknown, metricProducer2->mCondition);
-
-    auto pluggedUsbEvent = CreateBatteryStateChangedEvent(
-            bucketStartTimeNs + 50, BatteryPluggedStateEnum::BATTERY_PLUGGED_USB);
-    processor->OnLogEvent(pluggedUsbEvent.get());
-    EXPECT_EQ(ConditionState::kFalse, metricProducer1->mCondition);
-    EXPECT_EQ(ConditionState::kFalse, metricProducer2->mCondition);
-
-    auto pluggedNoneEvent = CreateBatteryStateChangedEvent(
-            bucketStartTimeNs + 70, BatteryPluggedStateEnum::BATTERY_PLUGGED_NONE);
-    processor->OnLogEvent(pluggedNoneEvent.get());
-    EXPECT_EQ(ConditionState::kTrue, metricProducer1->mCondition);
-    EXPECT_EQ(ConditionState::kTrue, metricProducer2->mCondition);
-}
-
-/**
-* Test a count metric that has one slice_by_state with no primary fields.
-*
-* Once the CountMetricProducer is initialized, it has one atom id in
-* mSlicedStateAtoms and no entries in mStateGroupMap.
-
-* One StateTracker tracks the state atom, and it has one listener which is the
-* CountMetricProducer that was initialized.
-*/
-TEST(CountMetricE2eTest, TestSlicedState) {
-    // Initialize config.
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-
-    auto syncStartMatcher = CreateSyncStartAtomMatcher();
-    *config.add_atom_matcher() = syncStartMatcher;
-
-    auto state = CreateScreenState();
-    *config.add_state() = state;
-
-    // Create count metric that slices by screen state.
-    int64_t metricId = 123456;
-    auto countMetric = config.add_count_metric();
-    countMetric->set_id(metricId);
-    countMetric->set_what(syncStartMatcher.id());
-    countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
-    countMetric->add_slice_by_state(state.id());
-
-    // Initialize StatsLogProcessor.
-    const uint64_t bucketStartTimeNs = 10000000000;  // 0:10
-    const uint64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-    int uid = 12345;
-    int64_t cfgId = 98765;
-    ConfigKey cfgKey(uid, cfgId);
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-
-    // Check that CountMetricProducer was initialized correctly.
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-    ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-    ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
-    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
-    ASSERT_EQ(metricProducer->mStateGroupMap.size(), 0);
-
-    // Check that StateTrackers were initialized correctly.
-    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
-
-    /*
-               bucket #1                      bucket #2
-    |     1     2     3     4     5     6     7     8     9     10 (minutes)
-    |-----------------------------|-----------------------------|--
-            x                x         x    x        x      x       (syncStartEvents)
-          |                                       |                 (ScreenIsOnEvent)
-                   |     |                                          (ScreenIsOffEvent)
-                                                        |           (ScreenDozeEvent)
-    */
-    // Initialize log events - first bucket.
-    std::vector<int> attributionUids1 = {123};
-    std::vector<string> attributionTags1 = {"App1"};
-
-    std::vector<std::unique_ptr<LogEvent>> events;
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 50 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_ON));  // 1:00
-    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 75 * NS_PER_SEC, attributionUids1,
-                                          attributionTags1, "sync_name"));  // 1:25
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 150 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_OFF));  // 2:40
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 200 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_OFF));  // 3:30
-    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 250 * NS_PER_SEC, attributionUids1,
-                                          attributionTags1, "sync_name"));  // 4:20
-
-    // Initialize log events - second bucket.
-    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 350 * NS_PER_SEC, attributionUids1,
-                                          attributionTags1, "sync_name"));  // 6:00
-    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 400 * NS_PER_SEC, attributionUids1,
-                                          attributionTags1, "sync_name"));  // 6:50
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 450 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_ON));  // 7:40
-    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 475 * NS_PER_SEC, attributionUids1,
-                                          attributionTags1, "sync_name"));  // 8:05
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 500 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN));  // 8:30
-    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 520 * NS_PER_SEC, attributionUids1,
-                                          attributionTags1, "sync_name"));  // 8:50
-
-    // Send log events to StatsLogProcessor.
-    for (auto& event : events) {
-        processor->OnLogEvent(event.get());
-    }
-
-    // Check dump report.
-    vector<uint8_t> buffer;
-    ConfigMetricsReportList reports;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
-                            FAST, &buffer);
-    ASSERT_GT(buffer.size(), 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-    EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
-    StatsLogReport::CountMetricDataWrapper countMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-    ASSERT_EQ(3, countMetrics.data_size());
-
-    // For each CountMetricData, check StateValue info is correct and buckets
-    // have correct counts.
-    auto data = countMetrics.data(0);
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN,
-              data.slice_by_state(0).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-
-    data = countMetrics.data(1);
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value());
-    ASSERT_EQ(2, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    EXPECT_EQ(2, data.bucket_info(1).count());
-
-    data = countMetrics.data(2);
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value());
-    ASSERT_EQ(2, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    EXPECT_EQ(1, data.bucket_info(1).count());
-}
-
-/**
- * Test a count metric that has one slice_by_state with a mapping and no
- * primary fields.
- *
- * Once the CountMetricProducer is initialized, it has one atom id in
- * mSlicedStateAtoms and has one entry per state value in mStateGroupMap.
- *
- * One StateTracker tracks the state atom, and it has one listener which is the
- * CountMetricProducer that was initialized.
- */
-TEST(CountMetricE2eTest, TestSlicedStateWithMap) {
-    // Initialize config.
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-
-    auto syncStartMatcher = CreateSyncStartAtomMatcher();
-    *config.add_atom_matcher() = syncStartMatcher;
-
-    int64_t screenOnId = 4444;
-    int64_t screenOffId = 9876;
-    auto state = CreateScreenStateWithOnOffMap(screenOnId, screenOffId);
-    *config.add_state() = state;
-
-    // Create count metric that slices by screen state with on/off map.
-    int64_t metricId = 123456;
-    auto countMetric = config.add_count_metric();
-    countMetric->set_id(metricId);
-    countMetric->set_what(syncStartMatcher.id());
-    countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
-    countMetric->add_slice_by_state(state.id());
-
-    // Initialize StatsLogProcessor.
-    const uint64_t bucketStartTimeNs = 10000000000;  // 0:10
-    const uint64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-    int uid = 12345;
-    int64_t cfgId = 98765;
-    ConfigKey cfgKey(uid, cfgId);
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-
-    // Check that StateTrackers were initialized correctly.
-    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
-
-    // Check that CountMetricProducer was initialized correctly.
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-    ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-    ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
-    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
-    ASSERT_EQ(metricProducer->mStateGroupMap.size(), 1);
-
-    StateMap map = state.map();
-    for (auto group : map.group()) {
-        for (auto value : group.value()) {
-            EXPECT_EQ(metricProducer->mStateGroupMap.at(SCREEN_STATE_ATOM_ID).at(value),
-                      group.group_id());
-        }
-    }
-
-    /*
-               bucket #1                      bucket #2
-    |     1     2     3     4     5     6     7     8     9     10 (minutes)
-    |-----------------------------|-----------------------------|--
-      x   x     x       x    x   x      x         x         x       (syncStartEvents)
-     -----------------------------------------------------------SCREEN_OFF events
-             |                  |                                   (ScreenStateOffEvent = 1)
-       |                  |                                         (ScreenStateDozeEvent = 3)
-                                                |                   (ScreenStateDozeSuspendEvent =
-    4)
-     -----------------------------------------------------------SCREEN_ON events
-                   |                                       |        (ScreenStateOnEvent = 2)
-                      |                                             (ScreenStateVrEvent = 5)
-                                            |                       (ScreenStateOnSuspendEvent = 6)
-    */
-    // Initialize log events - first bucket.
-    std::vector<int> attributionUids1 = {123};
-    std::vector<string> attributionTags1 = {"App1"};
-
-    std::vector<std::unique_ptr<LogEvent>> events;
-    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 20 * NS_PER_SEC, attributionUids1,
-                                          attributionTags1, "sync_name"));  // 0:30
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 30 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_DOZE));  // 0:40
-    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 60 * NS_PER_SEC, attributionUids1,
-                                          attributionTags1, "sync_name"));  // 1:10
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 90 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_OFF));  // 1:40
-    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 120 * NS_PER_SEC, attributionUids1,
-                                          attributionTags1, "sync_name"));  // 2:10
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 150 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_ON));  // 2:40
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 180 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_VR));  // 3:10
-    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 200 * NS_PER_SEC, attributionUids1,
-                                          attributionTags1, "sync_name"));  // 3:30
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 210 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_DOZE));  // 3:40
-    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 250 * NS_PER_SEC, attributionUids1,
-                                          attributionTags1, "sync_name"));  // 4:20
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 280 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_OFF));  // 4:50
-    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 285 * NS_PER_SEC, attributionUids1,
-                                          attributionTags1, "sync_name"));  // 4:55
-
-    // Initialize log events - second bucket.
-    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 360 * NS_PER_SEC, attributionUids1,
-                                          attributionTags1, "sync_name"));  // 6:10
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 390 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND));  // 6:40
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 430 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_DOZE_SUSPEND));  // 7:20
-    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 440 * NS_PER_SEC, attributionUids1,
-                                          attributionTags1, "sync_name"));  // 7:30
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 540 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_ON));  // 9:10
-    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 570 * NS_PER_SEC, attributionUids1,
-                                          attributionTags1, "sync_name"));  // 9:40
-
-    // Send log events to StatsLogProcessor.
-    for (auto& event : events) {
-        processor->OnLogEvent(event.get());
-    }
-
-    // Check dump report.
-    vector<uint8_t> buffer;
-    ConfigMetricsReportList reports;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
-                            FAST, &buffer);
-    ASSERT_GT(buffer.size(), 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-    EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
-    StatsLogReport::CountMetricDataWrapper countMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-    ASSERT_EQ(3, countMetrics.data_size());
-
-    // For each CountMetricData, check StateValue info is correct and buckets
-    // have correct counts.
-    auto data = countMetrics.data(0);
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-
-    data = countMetrics.data(1);
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-    EXPECT_EQ(screenOnId, data.slice_by_state(0).group_id());
-    ASSERT_EQ(2, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    EXPECT_EQ(1, data.bucket_info(1).count());
-
-    data = countMetrics.data(2);
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-    EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id());
-    ASSERT_EQ(2, data.bucket_info_size());
-    EXPECT_EQ(4, data.bucket_info(0).count());
-    EXPECT_EQ(2, data.bucket_info(1).count());
-}
-
-/**
-* Test a count metric that has one slice_by_state with a primary field.
-
-* Once the CountMetricProducer is initialized, it should have one
-* MetricStateLink stored. State querying using a non-empty primary key
-* should also work as intended.
-*/
-TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields) {
-    // Initialize config.
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-
-    auto appCrashMatcher =
-            CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", util::APP_CRASH_OCCURRED);
-    *config.add_atom_matcher() = appCrashMatcher;
-
-    auto state = CreateUidProcessState();
-    *config.add_state() = state;
-
-    // Create count metric that slices by uid process state.
-    int64_t metricId = 123456;
-    auto countMetric = config.add_count_metric();
-    countMetric->set_id(metricId);
-    countMetric->set_what(appCrashMatcher.id());
-    countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
-    countMetric->add_slice_by_state(state.id());
-    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(util::APP_CRASH_OCCURRED, {1 /*uid*/});
-    auto fieldsInState = stateLink->mutable_fields_in_state();
-    *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /*uid*/});
-
-    // Initialize StatsLogProcessor.
-    const uint64_t bucketStartTimeNs = 10000000000;  // 0:10
-    const uint64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-    int uid = 12345;
-    int64_t cfgId = 98765;
-    ConfigKey cfgKey(uid, cfgId);
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-
-    // Check that StateTrackers were initialized correctly.
-    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
-
-    // Check that CountMetricProducer was initialized correctly.
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-    ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-    ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
-    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), UID_PROCESS_STATE_ATOM_ID);
-    ASSERT_EQ(metricProducer->mStateGroupMap.size(), 0);
-    ASSERT_EQ(metricProducer->mMetric2StateLinks.size(), 1);
-
-    /*
-    NOTE: "1" or "2" represents the uid associated with the state/app crash event
-               bucket #1               bucket #2
-    |    1    2    3    4    5    6    7    8    9    10
-    |------------------------|-------------------------|--
-      1  1    1      1   1  2     1        1        2    (AppCrashEvents)
-     -----------------------------------------------------PROCESS STATE events
-           1               2                             (TopEvent = 1002)
-                       1             1                   (ForegroundServiceEvent = 1003)
-                                         2               (ImportantBackgroundEvent = 1006)
-       1          1                               1      (ImportantForegroundEvent = 1005)
-
-    Based on the diagram above, an AppCrashEvent querying for process state value would return:
-    - StateTracker::kStateUnknown
-    - Important foreground
-    - Top
-    - Important foreground
-    - Foreground service
-    - Top (both the app crash and state still have matching uid = 2)
-
-    - Foreground service
-    - Foreground service
-    - Important background
-    */
-    // Initialize log events - first bucket.
-    std::vector<std::unique_ptr<LogEvent>> events;
-    events.push_back(
-            CreateAppCrashOccurredEvent(bucketStartTimeNs + 20 * NS_PER_SEC, 1 /*uid*/));  // 0:30
-    events.push_back(CreateUidProcessStateChangedEvent(
-            bucketStartTimeNs + 30 * NS_PER_SEC, 1 /*uid*/,
-            android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND));  // 0:40
-    events.push_back(
-            CreateAppCrashOccurredEvent(bucketStartTimeNs + 60 * NS_PER_SEC, 1 /*uid*/));  // 1:10
-    events.push_back(CreateUidProcessStateChangedEvent(
-            bucketStartTimeNs + 90 * NS_PER_SEC, 1 /*uid*/,
-            android::app::ProcessStateEnum::PROCESS_STATE_TOP));  // 1:40
-    events.push_back(
-            CreateAppCrashOccurredEvent(bucketStartTimeNs + 120 * NS_PER_SEC, 1 /*uid*/));  // 2:10
-    events.push_back(CreateUidProcessStateChangedEvent(
-            bucketStartTimeNs + 150 * NS_PER_SEC, 1 /*uid*/,
-            android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND));  // 2:40
-    events.push_back(
-            CreateAppCrashOccurredEvent(bucketStartTimeNs + 200 * NS_PER_SEC, 1 /*uid*/));  // 3:30
-    events.push_back(CreateUidProcessStateChangedEvent(
-            bucketStartTimeNs + 210 * NS_PER_SEC, 1 /*uid*/,
-            android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE));  // 3:40
-    events.push_back(
-            CreateAppCrashOccurredEvent(bucketStartTimeNs + 250 * NS_PER_SEC, 1 /*uid*/));  // 4:20
-    events.push_back(CreateUidProcessStateChangedEvent(
-            bucketStartTimeNs + 280 * NS_PER_SEC, 2 /*uid*/,
-            android::app::ProcessStateEnum::PROCESS_STATE_TOP));  // 4:50
-    events.push_back(
-            CreateAppCrashOccurredEvent(bucketStartTimeNs + 285 * NS_PER_SEC, 2 /*uid*/));  // 4:55
-
-    // Initialize log events - second bucket.
-    events.push_back(
-            CreateAppCrashOccurredEvent(bucketStartTimeNs + 360 * NS_PER_SEC, 1 /*uid*/));  // 6:10
-    events.push_back(CreateUidProcessStateChangedEvent(
-            bucketStartTimeNs + 390 * NS_PER_SEC, 1 /*uid*/,
-            android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE));  // 6:40
-    events.push_back(CreateUidProcessStateChangedEvent(
-            bucketStartTimeNs + 430 * NS_PER_SEC, 2 /*uid*/,
-            android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND));  // 7:20
-    events.push_back(
-            CreateAppCrashOccurredEvent(bucketStartTimeNs + 440 * NS_PER_SEC, 1 /*uid*/));  // 7:30
-    events.push_back(CreateUidProcessStateChangedEvent(
-            bucketStartTimeNs + 540 * NS_PER_SEC, 1 /*uid*/,
-            android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND));  // 9:10
-    events.push_back(
-            CreateAppCrashOccurredEvent(bucketStartTimeNs + 570 * NS_PER_SEC, 2 /*uid*/));  // 9:40
-
-    // Send log events to StatsLogProcessor.
-    for (auto& event : events) {
-        processor->OnLogEvent(event.get());
-    }
-
-    // Check dump report.
-    vector<uint8_t> buffer;
-    ConfigMetricsReportList reports;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
-                            FAST, &buffer);
-    ASSERT_GT(buffer.size(), 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-    EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
-    StatsLogReport::CountMetricDataWrapper countMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-    ASSERT_EQ(5, countMetrics.data_size());
-
-    // For each CountMetricData, check StateValue info is correct and buckets
-    // have correct counts.
-    auto data = countMetrics.data(0);
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-
-    data = countMetrics.data(1);
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(0).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(2, data.bucket_info(0).count());
-
-    data = countMetrics.data(2);
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(0).value());
-    ASSERT_EQ(2, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    EXPECT_EQ(2, data.bucket_info(1).count());
-
-    data = countMetrics.data(3);
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(0).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(2, data.bucket_info(0).count());
-
-    data = countMetrics.data(4);
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-}
-
-TEST(CountMetricE2eTest, TestMultipleSlicedStates) {
-    // Initialize config.
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-
-    auto appCrashMatcher =
-            CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", util::APP_CRASH_OCCURRED);
-    *config.add_atom_matcher() = appCrashMatcher;
-
-    int64_t screenOnId = 4444;
-    int64_t screenOffId = 9876;
-    auto state1 = CreateScreenStateWithOnOffMap(screenOnId, screenOffId);
-    *config.add_state() = state1;
-    auto state2 = CreateUidProcessState();
-    *config.add_state() = state2;
-
-    // Create count metric that slices by screen state with on/off map and
-    // slices by uid process state.
-    int64_t metricId = 123456;
-    auto countMetric = config.add_count_metric();
-    countMetric->set_id(metricId);
-    countMetric->set_what(appCrashMatcher.id());
-    countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
-    countMetric->add_slice_by_state(state1.id());
-    countMetric->add_slice_by_state(state2.id());
-    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(util::APP_CRASH_OCCURRED, {1 /*uid*/});
-    auto fieldsInState = stateLink->mutable_fields_in_state();
-    *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /*uid*/});
-
-    // Initialize StatsLogProcessor.
-    const uint64_t bucketStartTimeNs = 10000000000;  // 0:10
-    const uint64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-    int uid = 12345;
-    int64_t cfgId = 98765;
-    ConfigKey cfgKey(uid, cfgId);
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-
-    // Check that StateTrackers were properly initialized.
-    EXPECT_EQ(2, StateManager::getInstance().getStateTrackersCount());
-    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
-    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
-
-    // Check that CountMetricProducer was initialized correctly.
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-    ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-    ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 2);
-    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
-    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(1), UID_PROCESS_STATE_ATOM_ID);
-    ASSERT_EQ(metricProducer->mStateGroupMap.size(), 1);
-    ASSERT_EQ(metricProducer->mMetric2StateLinks.size(), 1);
-
-    StateMap map = state1.map();
-    for (auto group : map.group()) {
-        for (auto value : group.value()) {
-            EXPECT_EQ(metricProducer->mStateGroupMap.at(SCREEN_STATE_ATOM_ID).at(value),
-                      group.group_id());
-        }
-    }
-
-    /*
-                 bucket #1                      bucket #2
-      |    1    2    3    4    5    6    7    8    9    10 (minutes)
-      |------------------------|------------------------|--
-        1  1    1     1    1  2     1        1         2   (AppCrashEvents)
-       ---------------------------------------------------SCREEN_OFF events
-             |                              |              (ScreenOffEvent = 1)
-         |              |                                  (ScreenDozeEvent = 3)
-       ---------------------------------------------------SCREEN_ON events
-                   |                              |        (ScreenOnEvent = 2)
-                                        |                  (ScreenOnSuspendEvent = 6)
-       ---------------------------------------------------PROCESS STATE events
-             1               2                             (TopEvent = 1002)
-                                      1                    (ForegroundServiceEvent = 1003)
-                                            2              (ImportantBackgroundEvent = 1006)
-       1          1                                   1    (ImportantForegroundEvent = 1005)
-
-       Based on the diagram above, Screen State / Process State pairs for each
-       AppCrashEvent are:
-       - StateTracker::kStateUnknown / important foreground
-       - off / important foreground
-       - off / Top
-       - on / important foreground
-       - off / important foreground
-       - off / top
-
-       - off / important foreground
-       - off / foreground service
-       - on / important background
-
-      */
-    // Initialize log events - first bucket.
-    std::vector<std::unique_ptr<LogEvent>> events;
-    events.push_back(CreateUidProcessStateChangedEvent(
-            bucketStartTimeNs + 5 * NS_PER_SEC, 1 /*uid*/,
-            android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND));  // 0:15
-    events.push_back(
-            CreateAppCrashOccurredEvent(bucketStartTimeNs + 20 * NS_PER_SEC, 1 /*uid*/));  // 0:30
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 30 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_DOZE));  // 0:40
-    events.push_back(
-            CreateAppCrashOccurredEvent(bucketStartTimeNs + 60 * NS_PER_SEC, 1 /*uid*/));  // 1:10
-    events.push_back(CreateUidProcessStateChangedEvent(
-            bucketStartTimeNs + 90 * NS_PER_SEC, 1 /*uid*/,
-            android::app::ProcessStateEnum::PROCESS_STATE_TOP));  // 1:40
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 90 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_OFF));  // 1:40
-    events.push_back(
-            CreateAppCrashOccurredEvent(bucketStartTimeNs + 120 * NS_PER_SEC, 1 /*uid*/));  // 2:10
-    events.push_back(CreateUidProcessStateChangedEvent(
-            bucketStartTimeNs + 150 * NS_PER_SEC, 1 /*uid*/,
-            android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND));  // 2:40
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 160 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_ON));  // 2:50
-    events.push_back(
-            CreateAppCrashOccurredEvent(bucketStartTimeNs + 200 * NS_PER_SEC, 1 /*uid*/));  // 3:30
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 210 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_DOZE));  // 3:40
-    events.push_back(
-            CreateAppCrashOccurredEvent(bucketStartTimeNs + 250 * NS_PER_SEC, 1 /*uid*/));  // 4:20
-    events.push_back(CreateUidProcessStateChangedEvent(
-            bucketStartTimeNs + 280 * NS_PER_SEC, 2 /*uid*/,
-            android::app::ProcessStateEnum::PROCESS_STATE_TOP));  // 4:50
-    events.push_back(
-            CreateAppCrashOccurredEvent(bucketStartTimeNs + 285 * NS_PER_SEC, 2 /*uid*/));  // 4:55
-
-    // Initialize log events - second bucket.
-    events.push_back(
-            CreateAppCrashOccurredEvent(bucketStartTimeNs + 360 * NS_PER_SEC, 1 /*uid*/));  // 6:10
-    events.push_back(CreateUidProcessStateChangedEvent(
-            bucketStartTimeNs + 380 * NS_PER_SEC, 1 /*uid*/,
-            android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE));  // 6:30
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 390 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND));  // 6:40
-    events.push_back(CreateUidProcessStateChangedEvent(
-            bucketStartTimeNs + 420 * NS_PER_SEC, 2 /*uid*/,
-            android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND));  // 7:10
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 440 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_OFF));  // 7:30
-    events.push_back(
-            CreateAppCrashOccurredEvent(bucketStartTimeNs + 450 * NS_PER_SEC, 1 /*uid*/));  // 7:40
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 520 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_ON));  // 8:50
-    events.push_back(CreateUidProcessStateChangedEvent(
-            bucketStartTimeNs + 540 * NS_PER_SEC, 1 /*uid*/,
-            android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND));  // 9:10
-    events.push_back(
-            CreateAppCrashOccurredEvent(bucketStartTimeNs + 570 * NS_PER_SEC, 2 /*uid*/));  // 9:40
-
-    // Send log events to StatsLogProcessor.
-    for (auto& event : events) {
-        processor->OnLogEvent(event.get());
-    }
-
-    // Check dump report.
-    vector<uint8_t> buffer;
-    ConfigMetricsReportList reports;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
-                            FAST, &buffer);
-    ASSERT_GT(buffer.size(), 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-    EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
-    StatsLogReport::CountMetricDataWrapper countMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-    ASSERT_EQ(6, countMetrics.data_size());
-
-    // For each CountMetricData, check StateValue info is correct and buckets
-    // have correct counts.
-    auto data = countMetrics.data(0);
-    ASSERT_EQ(2, data.slice_by_state_size());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(-1, data.slice_by_state(0).value());
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
-    EXPECT_TRUE(data.slice_by_state(1).has_value());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-
-    data = countMetrics.data(1);
-    ASSERT_EQ(2, data.slice_by_state_size());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-    EXPECT_EQ(screenOnId, data.slice_by_state(0).group_id());
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
-    EXPECT_TRUE(data.slice_by_state(1).has_value());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-
-    data = countMetrics.data(2);
-    ASSERT_EQ(2, data.slice_by_state_size());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-    EXPECT_EQ(screenOnId, data.slice_by_state(0).group_id());
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
-    EXPECT_TRUE(data.slice_by_state(1).has_value());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(1).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-
-    data = countMetrics.data(3);
-    ASSERT_EQ(2, data.slice_by_state_size());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-    EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id());
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
-    EXPECT_TRUE(data.slice_by_state(1).has_value());
-    EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(1).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(2, data.bucket_info(0).count());
-
-    data = countMetrics.data(4);
-    ASSERT_EQ(2, data.slice_by_state_size());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-    EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id());
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
-    EXPECT_TRUE(data.slice_by_state(1).has_value());
-    EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(1).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-
-    data = countMetrics.data(5);
-    ASSERT_EQ(2, data.slice_by_state_size());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-    EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id());
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
-    EXPECT_TRUE(data.slice_by_state(1).has_value());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
-    ASSERT_EQ(2, data.bucket_info_size());
-    EXPECT_EQ(2, data.bucket_info(0).count());
-    EXPECT_EQ(1, data.bucket_info(1).count());
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
deleted file mode 100644
index 2473c1c..0000000
--- a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
+++ /dev/null
@@ -1,1476 +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.
-
-#include <gtest/gtest.h>
-
-#include <vector>
-
-#include "src/StatsLogProcessor.h"
-#include "src/state/StateTracker.h"
-#include "src/stats_log_util.h"
-#include "tests/statsd_test_util.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-#ifdef __ANDROID__
-
-TEST(DurationMetricE2eTest, TestOneBucket) {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-
-    auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-    auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = screenOnMatcher;
-    *config.add_atom_matcher() = screenOffMatcher;
-
-    auto durationPredicate = CreateScreenIsOnPredicate();
-    *config.add_predicate() = durationPredicate;
-
-    int64_t metricId = 123456;
-    auto durationMetric = config.add_duration_metric();
-    durationMetric->set_id(metricId);
-    durationMetric->set_what(durationPredicate.id());
-    durationMetric->set_bucket(FIVE_MINUTES);
-    durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
-
-    const int64_t baseTimeNs = 0;                                   // 0:00
-    const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC;  // 0:01
-    const int64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
-
-    int uid = 12345;
-    int64_t cfgId = 98765;
-    ConfigKey cfgKey(uid, cfgId);
-
-    auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
-
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-    ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-
-    std::unique_ptr<LogEvent> event;
-
-    // Screen is off at start of bucket.
-    event = CreateScreenStateChangedEvent(configAddedTimeNs,
-                                          android::view::DISPLAY_STATE_OFF);  // 0:01
-    processor->OnLogEvent(event.get());
-
-    // Turn screen on.
-    const int64_t durationStartNs = configAddedTimeNs + 10 * NS_PER_SEC;  // 0:11
-    event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON);
-    processor->OnLogEvent(event.get());
-
-    // Turn off screen 30 seconds after turning on.
-    const int64_t durationEndNs = durationStartNs + 30 * NS_PER_SEC;  // 0:41
-    event = CreateScreenStateChangedEvent(durationEndNs, android::view::DISPLAY_STATE_OFF);
-    processor->OnLogEvent(event.get());
-
-    event = CreateScreenBrightnessChangedEvent(durationEndNs + 1 * NS_PER_SEC, 64);  // 0:42
-    processor->OnLogEvent(event.get());
-
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, configAddedTimeNs + bucketSizeNs + 1 * NS_PER_SEC, false, true,
-                            ADB_DUMP, FAST, &buffer);  // 5:01
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-    EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
-    EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
-
-    StatsLogReport::DurationMetricDataWrapper durationMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
-                                    &durationMetrics);
-    ASSERT_EQ(1, durationMetrics.data_size());
-
-    DurationMetricData data = durationMetrics.data(0);
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(durationEndNs - durationStartNs, data.bucket_info(0).duration_nanos());
-    EXPECT_EQ(configAddedTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-}
-
-TEST(DurationMetricE2eTest, TestTwoBuckets) {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-
-    auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-    auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = screenOnMatcher;
-    *config.add_atom_matcher() = screenOffMatcher;
-
-    auto durationPredicate = CreateScreenIsOnPredicate();
-    *config.add_predicate() = durationPredicate;
-
-    int64_t metricId = 123456;
-    auto durationMetric = config.add_duration_metric();
-    durationMetric->set_id(metricId);
-    durationMetric->set_what(durationPredicate.id());
-    durationMetric->set_bucket(FIVE_MINUTES);
-    durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
-
-    const int64_t baseTimeNs = 0;                                   // 0:00
-    const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC;  // 0:01
-    const int64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
-
-    int uid = 12345;
-    int64_t cfgId = 98765;
-    ConfigKey cfgKey(uid, cfgId);
-
-    auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
-
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-    ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-
-    std::unique_ptr<LogEvent> event;
-
-    // Screen is off at start of bucket.
-    event = CreateScreenStateChangedEvent(configAddedTimeNs,
-                                          android::view::DISPLAY_STATE_OFF);  // 0:01
-    processor->OnLogEvent(event.get());
-
-    // Turn screen on.
-    const int64_t durationStartNs = configAddedTimeNs + 10 * NS_PER_SEC;  // 0:11
-    event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON);
-    processor->OnLogEvent(event.get());
-
-    // Turn off screen 30 seconds after turning on.
-    const int64_t durationEndNs = durationStartNs + 30 * NS_PER_SEC;  // 0:41
-    event = CreateScreenStateChangedEvent(durationEndNs, android::view::DISPLAY_STATE_OFF);
-    processor->OnLogEvent(event.get());
-
-    event = CreateScreenBrightnessChangedEvent(durationEndNs + 1 * NS_PER_SEC, 64);  // 0:42
-    processor->OnLogEvent(event.get());
-
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, configAddedTimeNs + 2 * bucketSizeNs + 1 * NS_PER_SEC, false,
-                            true, ADB_DUMP, FAST, &buffer);  // 10:01
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-    EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
-    EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
-
-    StatsLogReport::DurationMetricDataWrapper durationMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
-                                    &durationMetrics);
-    ASSERT_EQ(1, durationMetrics.data_size());
-
-    DurationMetricData data = durationMetrics.data(0);
-    ASSERT_EQ(1, data.bucket_info_size());
-
-    auto bucketInfo = data.bucket_info(0);
-    EXPECT_EQ(0, bucketInfo.bucket_num());
-    EXPECT_EQ(durationEndNs - durationStartNs, bucketInfo.duration_nanos());
-    EXPECT_EQ(configAddedTimeNs, bucketInfo.start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-}
-
-TEST(DurationMetricE2eTest, TestWithActivation) {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-
-    auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-    auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
-    auto crashMatcher = CreateProcessCrashAtomMatcher();
-    *config.add_atom_matcher() = screenOnMatcher;
-    *config.add_atom_matcher() = screenOffMatcher;
-    *config.add_atom_matcher() = crashMatcher;
-
-    auto durationPredicate = CreateScreenIsOnPredicate();
-    *config.add_predicate() = durationPredicate;
-
-    int64_t metricId = 123456;
-    auto durationMetric = config.add_duration_metric();
-    durationMetric->set_id(metricId);
-    durationMetric->set_what(durationPredicate.id());
-    durationMetric->set_bucket(FIVE_MINUTES);
-    durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
-
-    auto metric_activation1 = config.add_metric_activation();
-    metric_activation1->set_metric_id(metricId);
-    auto event_activation1 = metric_activation1->add_event_activation();
-    event_activation1->set_atom_matcher_id(crashMatcher.id());
-    event_activation1->set_ttl_seconds(30);  // 30 secs.
-
-    const int64_t bucketStartTimeNs = 10000000000;
-    const int64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
-
-    int uid = 12345;
-    int64_t cfgId = 98765;
-    ConfigKey cfgKey(uid, cfgId);
-
-    sp<UidMap> m = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> subscriberAlarmMonitor;
-    vector<int64_t> activeConfigsBroadcast;
-
-    int broadcastCount = 0;
-    StatsLogProcessor processor(
-            m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
-            [](const ConfigKey& key) { return true; },
-            [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-                                                             const vector<int64_t>& activeConfigs) {
-                broadcastCount++;
-                EXPECT_EQ(broadcastUid, uid);
-                activeConfigsBroadcast.clear();
-                activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
-                                              activeConfigs.end());
-                return true;
-            });
-
-    processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);  // 0:00
-
-    ASSERT_EQ(processor.mMetricsManagers.size(), 1u);
-    sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-    ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-    auto& eventActivationMap = metricProducer->mEventActivationMap;
-
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    ASSERT_EQ(eventActivationMap.size(), 1u);
-    EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-
-    std::unique_ptr<LogEvent> event;
-
-    // Turn screen off.
-    event = CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * NS_PER_SEC,
-                                          android::view::DISPLAY_STATE_OFF);  // 0:02
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + 2 * NS_PER_SEC);
-
-    // Turn screen on.
-    const int64_t durationStartNs = bucketStartTimeNs + 5 * NS_PER_SEC;  // 0:05
-    event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON);
-    processor.OnLogEvent(event.get(), durationStartNs);
-
-    // Activate metric.
-    const int64_t activationStartNs = bucketStartTimeNs + 5 * NS_PER_SEC;  // 0:10
-    const int64_t activationEndNs =
-            activationStartNs + event_activation1->ttl_seconds() * NS_PER_SEC;  // 0:40
-    event = CreateAppCrashEvent(activationStartNs, 111);
-    processor.OnLogEvent(event.get(), activationStartNs);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(broadcastCount, 1);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 1);
-    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, activationStartNs);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-
-    // Expire activation.
-    const int64_t expirationNs = activationEndNs + 7 * NS_PER_SEC;
-    event = CreateScreenBrightnessChangedEvent(expirationNs, 64);  // 0:47
-    processor.OnLogEvent(event.get(), expirationNs);
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    EXPECT_EQ(broadcastCount, 2);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 0);
-    ASSERT_EQ(eventActivationMap.size(), 1u);
-    EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, activationStartNs);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-
-    // Turn off screen 10 seconds after activation expiration.
-    const int64_t durationEndNs = activationEndNs + 10 * NS_PER_SEC;  // 0:50
-    event = CreateScreenStateChangedEvent(durationEndNs, android::view::DISPLAY_STATE_OFF);
-    processor.OnLogEvent(event.get(), durationEndNs);
-
-    // Turn screen on.
-    const int64_t duration2StartNs = durationEndNs + 5 * NS_PER_SEC;  // 0:55
-    event = CreateScreenStateChangedEvent(duration2StartNs, android::view::DISPLAY_STATE_ON);
-    processor.OnLogEvent(event.get(), duration2StartNs);
-
-    // Turn off screen.
-    const int64_t duration2EndNs = duration2StartNs + 10 * NS_PER_SEC;  // 1:05
-    event = CreateScreenStateChangedEvent(duration2EndNs, android::view::DISPLAY_STATE_OFF);
-    processor.OnLogEvent(event.get(), duration2EndNs);
-
-    // Activate metric.
-    const int64_t activation2StartNs = duration2EndNs + 5 * NS_PER_SEC;  // 1:10
-    const int64_t activation2EndNs =
-            activation2StartNs + event_activation1->ttl_seconds() * NS_PER_SEC;  // 1:40
-    event = CreateAppCrashEvent(activation2StartNs, 211);
-    processor.OnLogEvent(event.get(), activation2StartNs);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(broadcastCount, 3);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 1);
-    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, activation2StartNs);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor.onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1 * NS_PER_SEC, false, true,
-                           ADB_DUMP, FAST, &buffer);  // 5:01
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-    EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
-    EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
-
-    StatsLogReport::DurationMetricDataWrapper durationMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
-                                    &durationMetrics);
-    ASSERT_EQ(1, durationMetrics.data_size());
-
-    DurationMetricData data = durationMetrics.data(0);
-    ASSERT_EQ(1, data.bucket_info_size());
-
-    auto bucketInfo = data.bucket_info(0);
-    EXPECT_EQ(0, bucketInfo.bucket_num());
-    EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
-    EXPECT_EQ(expirationNs, bucketInfo.end_bucket_elapsed_nanos());
-    EXPECT_EQ(expirationNs - durationStartNs, bucketInfo.duration_nanos());
-}
-
-TEST(DurationMetricE2eTest, TestWithCondition) {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-    *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
-    *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
-    *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
-    *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
-
-    auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
-    *config.add_predicate() = holdingWakelockPredicate;
-
-    auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
-    *config.add_predicate() = isInBackgroundPredicate;
-
-    auto durationMetric = config.add_duration_metric();
-    durationMetric->set_id(StringToId("WakelockDuration"));
-    durationMetric->set_what(holdingWakelockPredicate.id());
-    durationMetric->set_condition(isInBackgroundPredicate.id());
-    durationMetric->set_aggregation_type(DurationMetric::SUM);
-    durationMetric->set_bucket(FIVE_MINUTES);
-
-    ConfigKey cfgKey;
-    uint64_t bucketStartTimeNs = 10000000000;
-    uint64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-    ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-    auto& eventActivationMap = metricProducer->mEventActivationMap;
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_TRUE(eventActivationMap.empty());
-
-    int appUid = 123;
-    vector<int> attributionUids1 = {appUid};
-    vector<string> attributionTags1 = {"App1"};
-
-    auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC, attributionUids1,
-                                            attributionTags1,
-                                            "wl1");  // 0:10
-    processor->OnLogEvent(event.get());
-
-    event = CreateMoveToBackgroundEvent(bucketStartTimeNs + 22 * NS_PER_SEC, appUid);  // 0:22
-    processor->OnLogEvent(event.get());
-
-    event = CreateMoveToForegroundEvent(bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC,
-                                        appUid);  // 3:15
-    processor->OnLogEvent(event.get());
-
-    event = CreateReleaseWakelockEvent(bucketStartTimeNs + 4 * 60 * NS_PER_SEC, attributionUids1,
-                                       attributionTags1,
-                                       "wl1");  // 4:00
-    processor->OnLogEvent(event.get());
-
-    vector<uint8_t> buffer;
-    ConfigMetricsReportList reports;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
-                            FAST, &buffer);
-    ASSERT_GT(buffer.size(), 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-    StatsLogReport::DurationMetricDataWrapper durationMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
-                                    &durationMetrics);
-    ASSERT_EQ(1, durationMetrics.data_size());
-
-    DurationMetricData data = durationMetrics.data(0);
-
-    // Validate bucket info.
-    ASSERT_EQ(1, data.bucket_info_size());
-
-    auto bucketInfo = data.bucket_info(0);
-    EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-    EXPECT_EQ((2 * 60 + 53) * NS_PER_SEC, bucketInfo.duration_nanos());
-}
-
-TEST(DurationMetricE2eTest, TestWithSlicedCondition) {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-    auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
-    *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
-    *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
-    *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
-
-    auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
-    // The predicate is dimensioning by first attribution node by uid.
-    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(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
-    *config.add_predicate() = isInBackgroundPredicate;
-
-    auto durationMetric = config.add_duration_metric();
-    durationMetric->set_id(StringToId("WakelockDuration"));
-    durationMetric->set_what(holdingWakelockPredicate.id());
-    durationMetric->set_condition(isInBackgroundPredicate.id());
-    durationMetric->set_aggregation_type(DurationMetric::SUM);
-    // The metric is dimensioning by first attribution node and only by uid.
-    *durationMetric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
-            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());
-    *links->mutable_fields_in_what() =
-            CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-    auto dimensionCondition = links->mutable_fields_in_condition();
-    dimensionCondition->set_field(util::ACTIVITY_FOREGROUND_STATE_CHANGED);
-    dimensionCondition->add_child()->set_field(1);  // uid field.
-
-    ConfigKey cfgKey;
-    uint64_t bucketStartTimeNs = 10000000000;
-    uint64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-    ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-    auto& eventActivationMap = metricProducer->mEventActivationMap;
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_TRUE(eventActivationMap.empty());
-
-    int appUid = 123;
-    std::vector<int> attributionUids1 = {appUid};
-    std::vector<string> attributionTags1 = {"App1"};
-
-    auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC, attributionUids1,
-                                            attributionTags1, "wl1");  // 0:10
-    processor->OnLogEvent(event.get());
-
-    event = CreateMoveToBackgroundEvent(bucketStartTimeNs + 22 * NS_PER_SEC, appUid);  // 0:22
-    processor->OnLogEvent(event.get());
-
-    event = CreateReleaseWakelockEvent(bucketStartTimeNs + 60 * NS_PER_SEC, attributionUids1,
-                                       attributionTags1, "wl1");  // 1:00
-    processor->OnLogEvent(event.get());
-
-    event = CreateMoveToForegroundEvent(bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC,
-                                        appUid);  // 3:15
-    processor->OnLogEvent(event.get());
-
-    vector<uint8_t> buffer;
-    ConfigMetricsReportList reports;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
-                            FAST, &buffer);
-    ASSERT_GT(buffer.size(), 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-    StatsLogReport::DurationMetricDataWrapper durationMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
-                                    &durationMetrics);
-    ASSERT_EQ(1, durationMetrics.data_size());
-
-    DurationMetricData data = durationMetrics.data(0);
-    // Validate dimension value.
-    ValidateAttributionUidDimension(data.dimensions_in_what(),
-                                    util::WAKELOCK_STATE_CHANGED, appUid);
-    // Validate bucket info.
-    ASSERT_EQ(1, data.bucket_info_size());
-
-    auto bucketInfo = data.bucket_info(0);
-    EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-    EXPECT_EQ(38 * NS_PER_SEC, bucketInfo.duration_nanos());
-}
-
-TEST(DurationMetricE2eTest, TestWithActivationAndSlicedCondition) {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-    auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
-    *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
-    *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
-    *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
-    *config.add_atom_matcher() = screenOnMatcher;
-
-    auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
-    // The predicate is dimensioning by first attribution node by uid.
-    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(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
-    *config.add_predicate() = isInBackgroundPredicate;
-
-    auto durationMetric = config.add_duration_metric();
-    durationMetric->set_id(StringToId("WakelockDuration"));
-    durationMetric->set_what(holdingWakelockPredicate.id());
-    durationMetric->set_condition(isInBackgroundPredicate.id());
-    durationMetric->set_aggregation_type(DurationMetric::SUM);
-    // The metric is dimensioning by first attribution node and only by uid.
-    *durationMetric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
-            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());
-    *links->mutable_fields_in_what() =
-            CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-    auto dimensionCondition = links->mutable_fields_in_condition();
-    dimensionCondition->set_field(util::ACTIVITY_FOREGROUND_STATE_CHANGED);
-    dimensionCondition->add_child()->set_field(1);  // uid field.
-
-    auto metric_activation1 = config.add_metric_activation();
-    metric_activation1->set_metric_id(durationMetric->id());
-    auto event_activation1 = metric_activation1->add_event_activation();
-    event_activation1->set_atom_matcher_id(screenOnMatcher.id());
-    event_activation1->set_ttl_seconds(60 * 2);  // 2 minutes.
-
-    ConfigKey cfgKey;
-    uint64_t bucketStartTimeNs = 10000000000;
-    uint64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-    ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-    auto& eventActivationMap = metricProducer->mEventActivationMap;
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    ASSERT_EQ(eventActivationMap.size(), 1u);
-    EXPECT_TRUE(eventActivationMap.find(4) != eventActivationMap.end());
-    EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
-    EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-
-    int appUid = 123;
-    std::vector<int> attributionUids1 = {appUid};
-    std::vector<string> attributionTags1 = {"App1"};
-
-    auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC, attributionUids1,
-                                            attributionTags1, "wl1");  // 0:10
-    processor->OnLogEvent(event.get());
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
-    EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-
-    event = CreateMoveToBackgroundEvent(bucketStartTimeNs + 22 * NS_PER_SEC, appUid);  // 0:22
-    processor->OnLogEvent(event.get());
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
-    EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-
-    const int64_t durationStartNs = bucketStartTimeNs + 30 * NS_PER_SEC;  // 0:30
-    event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON);
-    processor->OnLogEvent(event.get());
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[4]->start_ns, durationStartNs);
-    EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-
-    const int64_t durationEndNs =
-            durationStartNs + (event_activation1->ttl_seconds() + 30) * NS_PER_SEC;  // 3:00
-    event = CreateAppCrashEvent(durationEndNs, 333);
-    processor->OnLogEvent(event.get());
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[4]->start_ns, durationStartNs);
-    EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-
-    event = CreateMoveToForegroundEvent(bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC,
-                                        appUid);  // 3:15
-    processor->OnLogEvent(event.get());
-
-    event = CreateReleaseWakelockEvent(bucketStartTimeNs + (4 * 60 + 17) * NS_PER_SEC,
-                                       attributionUids1, attributionTags1, "wl1");  // 4:17
-    processor->OnLogEvent(event.get());
-
-    event = CreateMoveToBackgroundEvent(bucketStartTimeNs + (4 * 60 + 20) * NS_PER_SEC,
-                                        appUid);  // 4:20
-    processor->OnLogEvent(event.get());
-
-    event = CreateAcquireWakelockEvent(bucketStartTimeNs + (4 * 60 + 25) * NS_PER_SEC,
-                                       attributionUids1, attributionTags1, "wl1");  // 4:25
-    processor->OnLogEvent(event.get());
-
-    const int64_t duration2StartNs = bucketStartTimeNs + (4 * 60 + 30) * NS_PER_SEC;  // 4:30
-    event = CreateScreenStateChangedEvent(duration2StartNs, android::view::DISPLAY_STATE_ON);
-    processor->OnLogEvent(event.get());
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[4]->start_ns, duration2StartNs);
-    EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-
-    vector<uint8_t> buffer;
-    ConfigMetricsReportList reports;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
-                            FAST, &buffer);
-    ASSERT_GT(buffer.size(), 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-    StatsLogReport::DurationMetricDataWrapper durationMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
-                                    &durationMetrics);
-    ASSERT_EQ(1, durationMetrics.data_size());
-
-    DurationMetricData data = durationMetrics.data(0);
-    // Validate dimension value.
-    ValidateAttributionUidDimension(data.dimensions_in_what(),
-                                    util::WAKELOCK_STATE_CHANGED, appUid);
-    // Validate bucket info.
-    ASSERT_EQ(2, data.bucket_info_size());
-
-    auto bucketInfo = data.bucket_info(0);
-    EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
-    EXPECT_EQ(durationEndNs, bucketInfo.end_bucket_elapsed_nanos());
-    EXPECT_EQ(durationEndNs - durationStartNs, bucketInfo.duration_nanos());
-
-    bucketInfo = data.bucket_info(1);
-    EXPECT_EQ(durationEndNs, bucketInfo.start_bucket_elapsed_nanos());
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - duration2StartNs, bucketInfo.duration_nanos());
-}
-
-TEST(DurationMetricE2eTest, TestWithSlicedState) {
-    // Initialize config.
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-
-    *config.add_atom_matcher() = CreateBatterySaverModeStartAtomMatcher();
-    *config.add_atom_matcher() = CreateBatterySaverModeStopAtomMatcher();
-
-    auto batterySaverModePredicate = CreateBatterySaverModePredicate();
-    *config.add_predicate() = batterySaverModePredicate;
-
-    auto screenState = CreateScreenState();
-    *config.add_state() = screenState;
-
-    // Create duration metric that slices by screen state.
-    auto durationMetric = config.add_duration_metric();
-    durationMetric->set_id(StringToId("DurationBatterySaverModeSliceScreen"));
-    durationMetric->set_what(batterySaverModePredicate.id());
-    durationMetric->add_slice_by_state(screenState.id());
-    durationMetric->set_aggregation_type(DurationMetric::SUM);
-    durationMetric->set_bucket(FIVE_MINUTES);
-
-    // Initialize StatsLogProcessor.
-    int uid = 12345;
-    int64_t cfgId = 98765;
-    ConfigKey cfgKey(uid, cfgId);
-    uint64_t bucketStartTimeNs = 10000000000;  // 0:10
-    uint64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-    ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-    EXPECT_TRUE(metricsManager->isActive());
-    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-    EXPECT_TRUE(metricProducer->mIsActive);
-    ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
-    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
-    ASSERT_EQ(metricProducer->mStateGroupMap.size(), 0);
-
-    // Check that StateTrackers were initialized correctly.
-    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
-
-    /*
-               bucket #1                      bucket #2
-    |     1     2     3     4     5     6     7     8     9     10 (minutes)
-    |-----------------------------|-----------------------------|--
-        ON              OFF     ON                                  (BatterySaverMode)
-      |          |                   |                              (ScreenIsOnEvent)
-           |                  |                                     (ScreenIsOffEvent)
-              |                                                     (ScreenDozeEvent)
-    */
-    // Initialize log events.
-    std::vector<std::unique_ptr<LogEvent>> events;
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 10 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_ON));                       // 0:20
-    events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + 20 * NS_PER_SEC));  // 0:30
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 50 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_OFF));  // 1:00
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 80 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_DOZE));  // 1:30
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 120 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_ON));                         // 2:10
-    events.push_back(CreateBatterySaverOffEvent(bucketStartTimeNs + 200 * NS_PER_SEC));  // 3:30
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 250 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_OFF));                       // 4:20
-    events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + 280 * NS_PER_SEC));  // 4:50
-
-    // Bucket boundary.
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 310 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_ON));  // 5:20
-
-    // Send log events to StatsLogProcessor.
-    for (auto& event : events) {
-        processor->OnLogEvent(event.get());
-    }
-
-    // Check dump report.
-    vector<uint8_t> buffer;
-    ConfigMetricsReportList reports;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 360 * NS_PER_SEC,
-                            true /* include current partial bucket */, true, ADB_DUMP, FAST,
-                            &buffer);  // 6:10
-    ASSERT_GT(buffer.size(), 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-    EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
-    StatsLogReport::DurationMetricDataWrapper durationMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
-                                    &durationMetrics);
-    ASSERT_EQ(3, durationMetrics.data_size());
-
-    DurationMetricData data = durationMetrics.data(0);
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value());
-    ASSERT_EQ(2, data.bucket_info_size());
-    EXPECT_EQ(50 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(1).duration_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos());
-    EXPECT_EQ(370 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos());
-
-    data = durationMetrics.data(1);
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value());
-    ASSERT_EQ(2, data.bucket_info_size());
-    EXPECT_EQ(110 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
-    EXPECT_EQ(50 * NS_PER_SEC, data.bucket_info(1).duration_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos());
-    EXPECT_EQ(370 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos());
-
-    data = durationMetrics.data(2);
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_DOZE, data.slice_by_state(0).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(40 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
-}
-
-TEST(DurationMetricE2eTest, TestWithConditionAndSlicedState) {
-    // Initialize config.
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-
-    *config.add_atom_matcher() = CreateBatterySaverModeStartAtomMatcher();
-    *config.add_atom_matcher() = CreateBatterySaverModeStopAtomMatcher();
-    *config.add_atom_matcher() = CreateBatteryStateNoneMatcher();
-    *config.add_atom_matcher() = CreateBatteryStateUsbMatcher();
-
-    auto batterySaverModePredicate = CreateBatterySaverModePredicate();
-    *config.add_predicate() = batterySaverModePredicate;
-
-    auto deviceUnpluggedPredicate = CreateDeviceUnpluggedPredicate();
-    *config.add_predicate() = deviceUnpluggedPredicate;
-
-    auto screenState = CreateScreenState();
-    *config.add_state() = screenState;
-
-    // Create duration metric that has a condition and slices by screen state.
-    auto durationMetric = config.add_duration_metric();
-    durationMetric->set_id(StringToId("DurationBatterySaverModeOnBatterySliceScreen"));
-    durationMetric->set_what(batterySaverModePredicate.id());
-    durationMetric->set_condition(deviceUnpluggedPredicate.id());
-    durationMetric->add_slice_by_state(screenState.id());
-    durationMetric->set_aggregation_type(DurationMetric::SUM);
-    durationMetric->set_bucket(FIVE_MINUTES);
-
-    // Initialize StatsLogProcessor.
-    int uid = 12345;
-    int64_t cfgId = 98765;
-    ConfigKey cfgKey(uid, cfgId);
-    uint64_t bucketStartTimeNs = 10000000000;  // 0:10
-    uint64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-    ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-    EXPECT_TRUE(metricsManager->isActive());
-    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-    EXPECT_TRUE(metricProducer->mIsActive);
-    ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
-    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
-    ASSERT_EQ(metricProducer->mStateGroupMap.size(), 0);
-
-    // Check that StateTrackers were initialized correctly.
-    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
-
-    /*
-               bucket #1                      bucket #2
-    |       1       2       3       4       5     6     7     8  (minutes)
-    |---------------------------------------|------------------
-             ON                          OFF    ON             (BatterySaverMode)
-                  T            F    T                          (DeviceUnpluggedPredicate)
-         |              |              |                       (ScreenIsOnEvent)
-                |           |                       |          (ScreenIsOffEvent)
-                                |                              (ScreenDozeEvent)
-    */
-    // Initialize log events.
-    std::vector<std::unique_ptr<LogEvent>> events;
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 20 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_ON));                       // 0:30
-    events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + 60 * NS_PER_SEC));  // 1:10
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 80 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_OFF));  // 1:30
-    events.push_back(
-            CreateBatteryStateChangedEvent(bucketStartTimeNs + 110 * NS_PER_SEC,
-                                           BatteryPluggedStateEnum::BATTERY_PLUGGED_NONE));  // 2:00
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 145 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_ON));  // 2:35
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 170 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_OFF));  // 3:00
-    events.push_back(
-            CreateBatteryStateChangedEvent(bucketStartTimeNs + 180 * NS_PER_SEC,
-                                           BatteryPluggedStateEnum::BATTERY_PLUGGED_USB));  // 3:10
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 200 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_DOZE));  // 3:30
-    events.push_back(
-            CreateBatteryStateChangedEvent(bucketStartTimeNs + 230 * NS_PER_SEC,
-                                           BatteryPluggedStateEnum::BATTERY_PLUGGED_NONE));  // 4:00
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 260 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_ON));                         // 4:30
-    events.push_back(CreateBatterySaverOffEvent(bucketStartTimeNs + 280 * NS_PER_SEC));  // 4:50
-
-    // Bucket boundary.
-    events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + 320 * NS_PER_SEC));  // 5:30
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 380 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_OFF));  // 6:30
-
-    // Send log events to StatsLogProcessor.
-    for (auto& event : events) {
-        processor->OnLogEvent(event.get());
-    }
-
-    // Check dump report.
-    vector<uint8_t> buffer;
-    ConfigMetricsReportList reports;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 410 * NS_PER_SEC,
-                            true /* include current partial bucket */, true, ADB_DUMP, FAST,
-                            &buffer);
-    ASSERT_GT(buffer.size(), 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-    EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
-    StatsLogReport::DurationMetricDataWrapper durationMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
-                                    &durationMetrics);
-    ASSERT_EQ(3, durationMetrics.data_size());
-
-    DurationMetricData data = durationMetrics.data(0);
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value());
-    ASSERT_EQ(2, data.bucket_info_size());
-    EXPECT_EQ(45 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
-    EXPECT_EQ(30 * NS_PER_SEC, data.bucket_info(1).duration_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos());
-    EXPECT_EQ(420 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos());
-
-    data = durationMetrics.data(1);
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value());
-    ASSERT_EQ(2, data.bucket_info_size());
-    EXPECT_EQ(45 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
-    EXPECT_EQ(60 * NS_PER_SEC, data.bucket_info(1).duration_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos());
-    EXPECT_EQ(420 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos());
-
-    data = durationMetrics.data(2);
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_DOZE, data.slice_by_state(0).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(30 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
-}
-
-TEST(DurationMetricE2eTest, TestWithSlicedStateMapped) {
-    // Initialize config.
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-
-    *config.add_atom_matcher() = CreateBatterySaverModeStartAtomMatcher();
-    *config.add_atom_matcher() = CreateBatterySaverModeStopAtomMatcher();
-
-    auto batterySaverModePredicate = CreateBatterySaverModePredicate();
-    *config.add_predicate() = batterySaverModePredicate;
-
-    int64_t screenOnId = 4444;
-    int64_t screenOffId = 9876;
-    auto screenStateWithMap = CreateScreenStateWithOnOffMap(screenOnId, screenOffId);
-    *config.add_state() = screenStateWithMap;
-
-    // Create duration metric that slices by mapped screen state.
-    auto durationMetric = config.add_duration_metric();
-    durationMetric->set_id(StringToId("DurationBatterySaverModeSliceScreenMapped"));
-    durationMetric->set_what(batterySaverModePredicate.id());
-    durationMetric->add_slice_by_state(screenStateWithMap.id());
-    durationMetric->set_aggregation_type(DurationMetric::SUM);
-    durationMetric->set_bucket(FIVE_MINUTES);
-
-    // Initialize StatsLogProcessor.
-    int uid = 12345;
-    int64_t cfgId = 98765;
-    ConfigKey cfgKey(uid, cfgId);
-    uint64_t bucketStartTimeNs = 10000000000;  // 0:10
-    uint64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-    ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-    EXPECT_TRUE(metricsManager->isActive());
-    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-    EXPECT_TRUE(metricProducer->mIsActive);
-    ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
-    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
-    ASSERT_EQ(metricProducer->mStateGroupMap.size(), 1);
-
-    // Check that StateTrackers were initialized correctly.
-    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
-
-    /*
-               bucket #1                      bucket #2
-    |     1     2     3     4     5     6     7     8     9     10 (minutes)
-    |-----------------------------|-----------------------------|--
-        ON              OFF     ON                                  (BatterySaverMode)
-     ---------------------------------------------------------SCREEN_OFF events
-           |                  |                                  (ScreenStateOffEvent = 1)
-              |                                                  (ScreenStateDozeEvent = 3)
-                                                |                (ScreenStateDozeSuspendEvent = 4)
-     ---------------------------------------------------------SCREEN_ON events
-      |          |                   |                           (ScreenStateOnEvent = 2)
-                      |                                          (ScreenStateVrEvent = 5)
-                                            |                    (ScreenStateOnSuspendEvent = 6)
-    */
-    // Initialize log events.
-    std::vector<std::unique_ptr<LogEvent>> events;
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 10 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_ON));                       // 0:20
-    events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + 20 * NS_PER_SEC));  // 0:30
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 70 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_OFF));  // 1:20
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 100 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_DOZE));  // 1:50
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 120 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_ON));  // 2:10
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 170 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_VR));                         // 3:00
-    events.push_back(CreateBatterySaverOffEvent(bucketStartTimeNs + 200 * NS_PER_SEC));  // 3:30
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 250 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_OFF));                       // 4:20
-    events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + 280 * NS_PER_SEC));  // 4:50
-
-    // Bucket boundary 5:10.
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 320 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_ON));  // 5:30
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 390 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND));  // 6:40
-    events.push_back(CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 430 * NS_PER_SEC,
-            android::view::DisplayStateEnum::DISPLAY_STATE_DOZE_SUSPEND));  // 7:20
-    // Send log events to StatsLogProcessor.
-    for (auto& event : events) {
-        processor->OnLogEvent(event.get());
-    }
-
-    // Check dump report.
-    vector<uint8_t> buffer;
-    ConfigMetricsReportList reports;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 490 * NS_PER_SEC,
-                            true /* include current partial bucket */, true, ADB_DUMP, FAST,
-                            &buffer);
-    ASSERT_GT(buffer.size(), 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-    EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
-    StatsLogReport::DurationMetricDataWrapper durationMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
-                                    &durationMetrics);
-    ASSERT_EQ(2, durationMetrics.data_size());
-
-    DurationMetricData data = durationMetrics.data(0);
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-    EXPECT_EQ(screenOnId, data.slice_by_state(0).group_id());
-    ASSERT_EQ(2, data.bucket_info_size());
-    EXPECT_EQ(130 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
-    EXPECT_EQ(110 * NS_PER_SEC, data.bucket_info(1).duration_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos());
-    EXPECT_EQ(500 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos());
-
-    data = durationMetrics.data(1);
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-    EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id());
-    ASSERT_EQ(2, data.bucket_info_size());
-    EXPECT_EQ(70 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
-    EXPECT_EQ(80 * NS_PER_SEC, data.bucket_info(1).duration_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos());
-    EXPECT_EQ(500 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos());
-}
-
-TEST(DurationMetricE2eTest, TestSlicedStatePrimaryFieldsNotSubsetDimInWhat) {
-    // Initialize config.
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-
-    *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
-    *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
-
-    auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
-    *config.add_predicate() = holdingWakelockPredicate;
-
-    auto uidProcessState = CreateUidProcessState();
-    *config.add_state() = uidProcessState;
-
-    // Create duration metric that slices by uid process state.
-    auto durationMetric = config.add_duration_metric();
-    durationMetric->set_id(StringToId("DurationHoldingWakelockSliceUidProcessState"));
-    durationMetric->set_what(holdingWakelockPredicate.id());
-    durationMetric->add_slice_by_state(uidProcessState.id());
-    durationMetric->set_aggregation_type(DurationMetric::SUM);
-    durationMetric->set_bucket(FIVE_MINUTES);
-
-    // The state has only one primary field (uid).
-    auto stateLink = durationMetric->add_state_link();
-    stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
-    auto fieldsInWhat = stateLink->mutable_fields_in_what();
-    *fieldsInWhat = CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-    auto fieldsInState = stateLink->mutable_fields_in_state();
-    *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
-
-    // Initialize StatsLogProcessor.
-    int uid = 12345;
-    int64_t cfgId = 98765;
-    ConfigKey cfgKey(uid, cfgId);
-    uint64_t bucketStartTimeNs = 10000000000;  // 0:10
-    uint64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-
-    // This config is rejected because the dimension in what fields are not a superset of the sliced
-    // state primary fields.
-    ASSERT_EQ(processor->mMetricsManagers.size(), 0);
-}
-
-TEST(DurationMetricE2eTest, TestWithSlicedStatePrimaryFieldsSubset) {
-    // Initialize config.
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-
-    *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
-    *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
-
-    auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
-    *(holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions()) =
-            CreateAttributionUidAndOtherDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST},
-                                                   {3 /* tag */});
-    *config.add_predicate() = holdingWakelockPredicate;
-
-    auto uidProcessState = CreateUidProcessState();
-    *config.add_state() = uidProcessState;
-
-    // Create duration metric that slices by uid process state.
-    auto durationMetric = config.add_duration_metric();
-    durationMetric->set_id(StringToId("DurationPartialWakelockPerTagUidSliceProcessState"));
-    durationMetric->set_what(holdingWakelockPredicate.id());
-    durationMetric->add_slice_by_state(uidProcessState.id());
-    durationMetric->set_aggregation_type(DurationMetric::SUM);
-    durationMetric->set_bucket(FIVE_MINUTES);
-
-    // The metric is dimensioning by first uid of attribution node and tag.
-    *durationMetric->mutable_dimensions_in_what() = CreateAttributionUidAndOtherDimensions(
-            util::WAKELOCK_STATE_CHANGED, {Position::FIRST}, {3 /* tag */});
-    // The state has only one primary field (uid).
-    auto stateLink = durationMetric->add_state_link();
-    stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
-    auto fieldsInWhat = stateLink->mutable_fields_in_what();
-    *fieldsInWhat = CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-    auto fieldsInState = stateLink->mutable_fields_in_state();
-    *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
-
-    // Initialize StatsLogProcessor.
-    int uid = 12345;
-    int64_t cfgId = 98765;
-    ConfigKey cfgKey(uid, cfgId);
-    uint64_t bucketStartTimeNs = 10000000000;  // 0:10
-    uint64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-    ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-    EXPECT_TRUE(metricsManager->isActive());
-    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-    EXPECT_TRUE(metricProducer->mIsActive);
-    ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
-    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), UID_PROCESS_STATE_ATOM_ID);
-    ASSERT_EQ(metricProducer->mStateGroupMap.size(), 0);
-
-    // Check that StateTrackers were initialized correctly.
-    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
-
-    // Initialize log events.
-    int appUid1 = 1001;
-    int appUid2 = 1002;
-    std::vector<int> attributionUids1 = {appUid1};
-    std::vector<string> attributionTags1 = {"App1"};
-
-    std::vector<int> attributionUids2 = {appUid2};
-    std::vector<string> attributionTags2 = {"App2"};
-
-    std::vector<std::unique_ptr<LogEvent>> events;
-    events.push_back(CreateUidProcessStateChangedEvent(
-            bucketStartTimeNs + 10 * NS_PER_SEC, appUid1,
-            android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND));  // 0:20
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 20 * NS_PER_SEC,
-                                                attributionUids1, attributionTags1,
-                                                "wakelock1"));  // 0:30
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 25 * NS_PER_SEC,
-                                                attributionUids1, attributionTags1,
-                                                "wakelock2"));  // 0:35
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 30 * NS_PER_SEC,
-                                                attributionUids2, attributionTags2,
-                                                "wakelock1"));  // 0:40
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 35 * NS_PER_SEC,
-                                                attributionUids2, attributionTags2,
-                                                "wakelock2"));  // 0:45
-    events.push_back(CreateUidProcessStateChangedEvent(
-            bucketStartTimeNs + 50 * NS_PER_SEC, appUid2,
-            android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND));  // 1:00
-    events.push_back(CreateUidProcessStateChangedEvent(
-            bucketStartTimeNs + 60 * NS_PER_SEC, appUid1,
-            android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND));  // 1:10
-    events.push_back(CreateReleaseWakelockEvent(bucketStartTimeNs + 100 * NS_PER_SEC,
-                                                attributionUids2, attributionTags2,
-                                                "wakelock1"));  // 1:50
-    events.push_back(CreateUidProcessStateChangedEvent(
-            bucketStartTimeNs + 120 * NS_PER_SEC, appUid2,
-            android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE));  // 2:10
-    events.push_back(CreateReleaseWakelockEvent(bucketStartTimeNs + 200 * NS_PER_SEC,
-                                                attributionUids1, attributionTags1,
-                                                "wakelock2"));  // 3:30
-
-    // Send log events to StatsLogProcessor.
-    for (auto& event : events) {
-        processor->OnLogEvent(event.get());
-    }
-
-    // Check dump report.
-    vector<uint8_t> buffer;
-    ConfigMetricsReportList reports;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 320 * NS_PER_SEC,
-                            true /* include current partial bucket */, true, ADB_DUMP, FAST,
-                            &buffer);
-    ASSERT_GT(buffer.size(), 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-    EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
-    StatsLogReport::DurationMetricDataWrapper durationMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
-                                    &durationMetrics);
-    ASSERT_EQ(9, durationMetrics.data_size());
-
-    DurationMetricData data = durationMetrics.data(0);
-    ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid1,
-                                                  "wakelock1");
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              data.slice_by_state(0).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(40 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
-
-    data = durationMetrics.data(1);
-    ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid1,
-                                                  "wakelock1");
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              data.slice_by_state(0).value());
-    ASSERT_EQ(2, data.bucket_info_size());
-    EXPECT_EQ(240 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
-    EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(1).duration_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos());
-    EXPECT_EQ(330 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos());
-
-    data = durationMetrics.data(2);
-    ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid1,
-                                                  "wakelock2");
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              data.slice_by_state(0).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(35 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
-
-    data = durationMetrics.data(3);
-    ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid1,
-                                                  "wakelock2");
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              data.slice_by_state(0).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(140 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
-
-    data = durationMetrics.data(4);
-    ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2,
-                                                  "wakelock1");
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(-1 /* StateTracker:: kStateUnknown */, data.slice_by_state(0).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
-
-    data = durationMetrics.data(5);
-    ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2,
-                                                  "wakelock1");
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              data.slice_by_state(0).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(50 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
-
-    data = durationMetrics.data(6);
-    ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2,
-                                                  "wakelock2");
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(-1 /* StateTracker:: kStateUnknown */, data.slice_by_state(0).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(15 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
-
-    data = durationMetrics.data(7);
-    ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2,
-                                                  "wakelock2");
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE,
-              data.slice_by_state(0).value());
-    ASSERT_EQ(2, data.bucket_info_size());
-    EXPECT_EQ(180 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
-    EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(1).duration_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos());
-    EXPECT_EQ(330 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos());
-
-    data = durationMetrics.data(8);
-    ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2,
-                                                  "wakelock2");
-    ASSERT_EQ(1, data.slice_by_state_size());
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              data.slice_by_state(0).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(70 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
deleted file mode 100644
index 1be2612..0000000
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
+++ /dev/null
@@ -1,624 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <android/binder_interface_utils.h>
-#include <gtest/gtest.h>
-
-#include <vector>
-
-#include "src/StatsLogProcessor.h"
-#include "src/stats_log_util.h"
-#include "tests/statsd_test_util.h"
-
-using ::ndk::SharedRefBase;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-#ifdef __ANDROID__
-
-namespace {
-
-const int64_t metricId = 123456;
-const int32_t ATOM_TAG = util::SUBSYSTEM_SLEEP_STATE;
-
-StatsdConfig CreateStatsdConfig(const GaugeMetric::SamplingType sampling_type,
-                                bool useCondition = true) {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-    config.add_default_pull_packages("AID_ROOT");  // Fake puller is registered with root.
-    auto atomMatcher = CreateSimpleAtomMatcher("TestMatcher", ATOM_TAG);
-    *config.add_atom_matcher() = atomMatcher;
-    *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
-
-    auto screenIsOffPredicate = CreateScreenIsOffPredicate();
-    *config.add_predicate() = screenIsOffPredicate;
-
-    auto gaugeMetric = config.add_gauge_metric();
-    gaugeMetric->set_id(metricId);
-    gaugeMetric->set_what(atomMatcher.id());
-    if (useCondition) {
-        gaugeMetric->set_condition(screenIsOffPredicate.id());
-    }
-    gaugeMetric->set_sampling_type(sampling_type);
-    gaugeMetric->mutable_gauge_fields_filter()->set_include_all(true);
-    *gaugeMetric->mutable_dimensions_in_what() =
-            CreateDimensions(ATOM_TAG, {1 /* subsystem name */});
-    gaugeMetric->set_bucket(FIVE_MINUTES);
-    gaugeMetric->set_max_pull_delay_sec(INT_MAX);
-    config.set_hash_strings_in_metric_report(false);
-
-    return config;
-}
-
-}  // namespaces
-
-TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) {
-    auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE);
-    int64_t baseTimeNs = getElapsedRealtimeNs();
-    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
-
-    ConfigKey cfgKey;
-    auto processor =
-            CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-                                    SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-    processor->mPullerManager->ForceClearPullerCache();
-
-    int startBucketNum = processor->mMetricsManagers.begin()
-                                 ->second->mAllMetricProducers[0]
-                                 ->getCurrentBucketNum();
-    EXPECT_GT(startBucketNum, (int64_t)0);
-
-    // When creating the config, the gauge metric producer should register the alarm at the
-    // end of the current bucket.
-    ASSERT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-    EXPECT_EQ(bucketSizeNs,
-              processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-    int64_t& nextPullTimeNs =
-            processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
-
-    auto screenOffEvent =
-            CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF);
-    processor->OnLogEvent(screenOffEvent.get());
-
-    // Pulling alarm arrives on time and reset the sequential pulling alarm.
-    processor->informPullAlarmFired(nextPullTimeNs + 1);
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, nextPullTimeNs);
-
-    auto screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 10,
-                                                       android::view::DISPLAY_STATE_ON);
-    processor->OnLogEvent(screenOnEvent.get());
-
-    screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 100,
-                                                   android::view::DISPLAY_STATE_OFF);
-    processor->OnLogEvent(screenOffEvent.get());
-
-    processor->informPullAlarmFired(nextPullTimeNs + 1);
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, nextPullTimeNs);
-
-    processor->informPullAlarmFired(nextPullTimeNs + 1);
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, nextPullTimeNs);
-
-    screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 3 * bucketSizeNs + 2,
-                                                  android::view::DISPLAY_STATE_ON);
-    processor->OnLogEvent(screenOnEvent.get());
-
-    processor->informPullAlarmFired(nextPullTimeNs + 3);
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs);
-
-    screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 5 * bucketSizeNs + 1,
-                                                   android::view::DISPLAY_STATE_OFF);
-    processor->OnLogEvent(screenOffEvent.get());
-
-    processor->informPullAlarmFired(nextPullTimeNs + 2);
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, nextPullTimeNs);
-
-    processor->informPullAlarmFired(nextPullTimeNs + 2);
-
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
-                            ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-    StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
-    ASSERT_GT((int)gaugeMetrics.data_size(), 1);
-
-    auto data = gaugeMetrics.data(0);
-    EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-    ASSERT_EQ(6, data.bucket_info_size());
-
-    ASSERT_EQ(1, data.bucket_info(0).atom_size());
-    ASSERT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-    EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-    ASSERT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
-    EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-    EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
-    EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
-
-    ASSERT_EQ(1, data.bucket_info(1).atom_size());
-    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1, data.bucket_info(1).elapsed_timestamp_nanos(0));
-    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1, data.bucket_info(1).elapsed_timestamp_nanos(0));
-    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
-    EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
-    EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
-
-    ASSERT_EQ(1, data.bucket_info(2).atom_size());
-    ASSERT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
-    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 1, data.bucket_info(2).elapsed_timestamp_nanos(0));
-    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
-    EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
-    EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
-
-    ASSERT_EQ(1, data.bucket_info(3).atom_size());
-    ASSERT_EQ(1, data.bucket_info(3).elapsed_timestamp_nanos_size());
-    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs + 1, data.bucket_info(3).elapsed_timestamp_nanos(0));
-    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos());
-    EXPECT_TRUE(data.bucket_info(3).atom(0).subsystem_sleep_state().subsystem_name().empty());
-    EXPECT_GT(data.bucket_info(3).atom(0).subsystem_sleep_state().time_millis(), 0);
-
-    ASSERT_EQ(1, data.bucket_info(4).atom_size());
-    ASSERT_EQ(1, data.bucket_info(4).elapsed_timestamp_nanos_size());
-    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 1, data.bucket_info(4).elapsed_timestamp_nanos(0));
-    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(4).start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(4).end_bucket_elapsed_nanos());
-    EXPECT_TRUE(data.bucket_info(4).atom(0).subsystem_sleep_state().subsystem_name().empty());
-    EXPECT_GT(data.bucket_info(4).atom(0).subsystem_sleep_state().time_millis(), 0);
-
-    ASSERT_EQ(1, data.bucket_info(5).atom_size());
-    ASSERT_EQ(1, data.bucket_info(5).elapsed_timestamp_nanos_size());
-    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs + 2, data.bucket_info(5).elapsed_timestamp_nanos(0));
-    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(5).start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(5).end_bucket_elapsed_nanos());
-    EXPECT_TRUE(data.bucket_info(5).atom(0).subsystem_sleep_state().subsystem_name().empty());
-    EXPECT_GT(data.bucket_info(5).atom(0).subsystem_sleep_state().time_millis(), 0);
-}
-
-TEST(GaugeMetricE2eTest, TestConditionChangeToTrueSamplePulledEvents) {
-    auto config = CreateStatsdConfig(GaugeMetric::CONDITION_CHANGE_TO_TRUE);
-    int64_t baseTimeNs = getElapsedRealtimeNs();
-    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
-
-    ConfigKey cfgKey;
-    auto processor =
-            CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-                                    SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-    processor->mPullerManager->ForceClearPullerCache();
-
-    int startBucketNum = processor->mMetricsManagers.begin()
-                                 ->second->mAllMetricProducers[0]
-                                 ->getCurrentBucketNum();
-    EXPECT_GT(startBucketNum, (int64_t)0);
-
-    auto screenOffEvent =
-            CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF);
-    processor->OnLogEvent(screenOffEvent.get());
-
-    auto screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 10,
-                                                       android::view::DISPLAY_STATE_ON);
-    processor->OnLogEvent(screenOnEvent.get());
-
-    screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 100,
-                                                   android::view::DISPLAY_STATE_OFF);
-    processor->OnLogEvent(screenOffEvent.get());
-
-    screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 3 * bucketSizeNs + 2,
-                                                  android::view::DISPLAY_STATE_ON);
-    processor->OnLogEvent(screenOnEvent.get());
-
-    screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 5 * bucketSizeNs + 1,
-                                                   android::view::DISPLAY_STATE_OFF);
-    processor->OnLogEvent(screenOffEvent.get());
-    screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 5 * bucketSizeNs + 3,
-                                                  android::view::DISPLAY_STATE_ON);
-    processor->OnLogEvent(screenOnEvent.get());
-    screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 5 * bucketSizeNs + 10,
-                                                   android::view::DISPLAY_STATE_OFF);
-    processor->OnLogEvent(screenOffEvent.get());
-
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, configAddedTimeNs + 8 * bucketSizeNs + 10, false, true,
-                            ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-    StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
-    ASSERT_GT((int)gaugeMetrics.data_size(), 1);
-
-    auto data = gaugeMetrics.data(0);
-    EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-    ASSERT_EQ(3, data.bucket_info_size());
-
-    ASSERT_EQ(1, data.bucket_info(0).atom_size());
-    ASSERT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-    EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-    ASSERT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
-    EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-    EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
-    EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
-
-    ASSERT_EQ(1, data.bucket_info(1).atom_size());
-    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 100, data.bucket_info(1).elapsed_timestamp_nanos(0));
-    EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
-    EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
-    EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
-
-    ASSERT_EQ(2, data.bucket_info(2).atom_size());
-    ASSERT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
-    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 1, data.bucket_info(2).elapsed_timestamp_nanos(0));
-    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 10, data.bucket_info(2).elapsed_timestamp_nanos(1));
-    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
-    EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
-    EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
-    EXPECT_TRUE(data.bucket_info(2).atom(1).subsystem_sleep_state().subsystem_name().empty());
-    EXPECT_GT(data.bucket_info(2).atom(1).subsystem_sleep_state().time_millis(), 0);
-}
-
-TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm) {
-    auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE);
-    int64_t baseTimeNs = getElapsedRealtimeNs();
-    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
-
-    ConfigKey cfgKey;
-    auto processor =
-            CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-                                    SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-    processor->mPullerManager->ForceClearPullerCache();
-
-    int startBucketNum = processor->mMetricsManagers.begin()
-                                 ->second->mAllMetricProducers[0]
-                                 ->getCurrentBucketNum();
-    EXPECT_GT(startBucketNum, (int64_t)0);
-
-    // When creating the config, the gauge metric producer should register the alarm at the
-    // end of the current bucket.
-    ASSERT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-    EXPECT_EQ(bucketSizeNs,
-              processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-    int64_t& nextPullTimeNs =
-            processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
-
-    auto screenOffEvent =
-            CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF);
-    processor->OnLogEvent(screenOffEvent.get());
-
-    auto screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 10,
-                                                       android::view::DISPLAY_STATE_ON);
-    processor->OnLogEvent(screenOnEvent.get());
-
-    // Pulling alarm arrives one bucket size late.
-    processor->informPullAlarmFired(nextPullTimeNs + bucketSizeNs);
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, nextPullTimeNs);
-
-    screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 3 * bucketSizeNs + 11,
-                                                   android::view::DISPLAY_STATE_OFF);
-    processor->OnLogEvent(screenOffEvent.get());
-
-    // Pulling alarm arrives more than one bucket size late.
-    processor->informPullAlarmFired(nextPullTimeNs + bucketSizeNs + 12);
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs);
-
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
-                            ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-    StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
-    ASSERT_GT((int)gaugeMetrics.data_size(), 1);
-
-    auto data = gaugeMetrics.data(0);
-    EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-    ASSERT_EQ(3, data.bucket_info_size());
-
-    ASSERT_EQ(1, data.bucket_info(0).atom_size());
-    ASSERT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-    EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-    EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-    EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
-    EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
-
-    ASSERT_EQ(1, data.bucket_info(1).atom_size());
-    EXPECT_EQ(configAddedTimeNs + 3 * bucketSizeNs + 11,
-              data.bucket_info(1).elapsed_timestamp_nanos(0));
-    EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
-    EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
-    EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
-
-    ASSERT_EQ(1, data.bucket_info(2).atom_size());
-    ASSERT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
-    EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs + 12, data.bucket_info(2).elapsed_timestamp_nanos(0));
-    EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
-    EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
-    EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
-}
-
-TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsWithActivation) {
-    auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE, /*useCondition=*/false);
-
-    int64_t baseTimeNs = getElapsedRealtimeNs();
-    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
-
-    auto batterySaverStartMatcher = CreateBatterySaverModeStartAtomMatcher();
-    *config.add_atom_matcher() = batterySaverStartMatcher;
-    const int64_t ttlNs = 2 * bucketSizeNs;  // Two buckets.
-    auto metric_activation = config.add_metric_activation();
-    metric_activation->set_metric_id(metricId);
-    metric_activation->set_activation_type(ACTIVATE_IMMEDIATELY);
-    auto event_activation = metric_activation->add_event_activation();
-    event_activation->set_atom_matcher_id(batterySaverStartMatcher.id());
-    event_activation->set_ttl_seconds(ttlNs / 1000000000);
-
-    ConfigKey cfgKey;
-    auto processor =
-            CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-                                    SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-    processor->mPullerManager->ForceClearPullerCache();
-
-    int startBucketNum = processor->mMetricsManagers.begin()
-                                 ->second->mAllMetricProducers[0]
-                                 ->getCurrentBucketNum();
-    EXPECT_GT(startBucketNum, (int64_t)0);
-    EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-
-    // When creating the config, the gauge metric producer should register the alarm at the
-    // end of the current bucket.
-    ASSERT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-    EXPECT_EQ(bucketSizeNs,
-              processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-    int64_t& nextPullTimeNs =
-            processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
-
-    // Pulling alarm arrives on time and reset the sequential pulling alarm.
-    // Event should not be kept.
-    processor->informPullAlarmFired(nextPullTimeNs + 1);  // 15 mins + 1 ns.
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, nextPullTimeNs);
-    EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-
-    // Activate the metric. A pull occurs upon activation.
-    const int64_t activationNs = configAddedTimeNs + bucketSizeNs + (2 * 1000 * 1000);  // 2 millis.
-    auto batterySaverOnEvent = CreateBatterySaverOnEvent(activationNs);
-    processor->OnLogEvent(batterySaverOnEvent.get());  // 15 mins + 2 ms.
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-
-    // This event should be kept. 2 total.
-    processor->informPullAlarmFired(nextPullTimeNs + 1);  // 20 mins + 1 ns.
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, nextPullTimeNs);
-
-    // This event should be kept. 3 total.
-    processor->informPullAlarmFired(nextPullTimeNs + 2);  // 25 mins + 2 ns.
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, nextPullTimeNs);
-
-    // Create random event to deactivate metric.
-    auto deactivationEvent = CreateScreenBrightnessChangedEvent(activationNs + ttlNs + 1, 50);
-    processor->OnLogEvent(deactivationEvent.get());
-    EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-
-    // Event should not be kept. 3 total.
-    processor->informPullAlarmFired(nextPullTimeNs + 3);
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs);
-
-    processor->informPullAlarmFired(nextPullTimeNs + 2);
-
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
-                            ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-    StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
-    ASSERT_GT((int)gaugeMetrics.data_size(), 0);
-
-    auto data = gaugeMetrics.data(0);
-    EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-    ASSERT_EQ(3, data.bucket_info_size());
-
-    auto bucketInfo = data.bucket_info(0);
-    ASSERT_EQ(1, bucketInfo.atom_size());
-    ASSERT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
-    EXPECT_EQ(activationNs, bucketInfo.elapsed_timestamp_nanos(0));
-    ASSERT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
-    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-    EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty());
-    EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0);
-
-    bucketInfo = data.bucket_info(1);
-    ASSERT_EQ(1, bucketInfo.atom_size());
-    ASSERT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
-    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 1, bucketInfo.elapsed_timestamp_nanos(0));
-    ASSERT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
-    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-    EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty());
-    EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0);
-
-    bucketInfo = data.bucket_info(2);
-    ASSERT_EQ(1, bucketInfo.atom_size());
-    ASSERT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
-    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs + 2, bucketInfo.elapsed_timestamp_nanos(0));
-    ASSERT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
-    EXPECT_EQ(MillisToNano(NanoToMillis(baseTimeNs + 5 * bucketSizeNs)),
-              bucketInfo.start_bucket_elapsed_nanos());
-    EXPECT_EQ(MillisToNano(NanoToMillis(activationNs + ttlNs + 1)),
-              bucketInfo.end_bucket_elapsed_nanos());
-    EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty());
-    EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0);
-}
-
-TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsNoCondition) {
-    auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE, /*useCondition=*/false);
-
-    int64_t baseTimeNs = getElapsedRealtimeNs();
-    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-    int64_t bucketSizeNs =
-        TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
-
-    ConfigKey cfgKey;
-    auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-                                             SharedRefBase::make<FakeSubsystemSleepCallback>(),
-                                             ATOM_TAG);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-    processor->mPullerManager->ForceClearPullerCache();
-
-    int startBucketNum = processor->mMetricsManagers.begin()->second->
-            mAllMetricProducers[0]->getCurrentBucketNum();
-    EXPECT_GT(startBucketNum, (int64_t)0);
-
-    // When creating the config, the gauge metric producer should register the alarm at the
-    // end of the current bucket.
-    ASSERT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-    EXPECT_EQ(bucketSizeNs,
-              processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-    int64_t& nextPullTimeNs =
-            processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
-
-    // Pulling alarm arrives on time and reset the sequential pulling alarm.
-    processor->informPullAlarmFired(nextPullTimeNs + 1);
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, nextPullTimeNs);
-
-    processor->informPullAlarmFired(nextPullTimeNs + 4);
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs,
-              nextPullTimeNs);
-
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
-                            ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-    StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
-    sortMetricDataByDimensionsValue(
-            reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
-    ASSERT_GT((int)gaugeMetrics.data_size(), 0);
-
-    auto data = gaugeMetrics.data(0);
-    EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-    ASSERT_EQ(3, data.bucket_info_size());
-
-    ASSERT_EQ(1, data.bucket_info(0).atom_size());
-    ASSERT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-    EXPECT_EQ(configAddedTimeNs, data.bucket_info(0).elapsed_timestamp_nanos(0));
-    ASSERT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
-    EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-    EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
-    EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
-
-    ASSERT_EQ(1, data.bucket_info(1).atom_size());
-    ASSERT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
-    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1, data.bucket_info(1).elapsed_timestamp_nanos(0));
-    ASSERT_EQ(0, data.bucket_info(1).wall_clock_timestamp_nanos_size());
-    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
-    EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
-    EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
-
-    ASSERT_EQ(1, data.bucket_info(2).atom_size());
-    ASSERT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
-    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 4, data.bucket_info(2).elapsed_timestamp_nanos(0));
-    ASSERT_EQ(0, data.bucket_info(2).wall_clock_timestamp_nanos_size());
-    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
-    EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
-    EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
deleted file mode 100644
index a40a948..0000000
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
+++ /dev/null
@@ -1,295 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <gtest/gtest.h>
-
-#include <vector>
-
-#include "src/StatsLogProcessor.h"
-#include "src/stats_log_util.h"
-#include "stats_event.h"
-#include "tests/statsd_test_util.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-#ifdef __ANDROID__
-
-namespace {
-
-StatsdConfig CreateStatsdConfigForPushedEvent(const GaugeMetric::SamplingType sampling_type) {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-    *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
-    *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
-
-    auto atomMatcher = CreateSimpleAtomMatcher("", util::APP_START_OCCURRED);
-    *config.add_atom_matcher() = atomMatcher;
-
-    auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
-    *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
-        CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */ });
-    *config.add_predicate() = isInBackgroundPredicate;
-
-    auto gaugeMetric = config.add_gauge_metric();
-    gaugeMetric->set_id(123456);
-    gaugeMetric->set_what(atomMatcher.id());
-    gaugeMetric->set_condition(isInBackgroundPredicate.id());
-    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(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(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(util::APP_START_OCCURRED);
-    dimensionWhat->add_child()->set_field(1);  // uid field.
-    auto dimensionCondition = links->mutable_fields_in_condition();
-    dimensionCondition->set_field(util::ACTIVITY_FOREGROUND_STATE_CHANGED);
-    dimensionCondition->add_child()->set_field(1);  // uid field.
-    return config;
-}
-
-std::unique_ptr<LogEvent> CreateAppStartOccurredEvent(
-        uint64_t timestampNs, const int uid, const string& pkg_name,
-        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, util::APP_START_OCCURRED);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-
-    AStatsEvent_writeInt32(statsEvent, uid);
-    AStatsEvent_writeString(statsEvent, pkg_name.c_str());
-    AStatsEvent_writeInt32(statsEvent, type);
-    AStatsEvent_writeString(statsEvent, activity_name.c_str());
-    AStatsEvent_writeString(statsEvent, calling_pkg_name.c_str());
-    AStatsEvent_writeInt32(statsEvent, is_instant_app);
-    AStatsEvent_writeInt32(statsEvent, activity_start_msec);
-
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-}  // namespace
-
-TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) {
-    for (const auto& sampling_type :
-         {GaugeMetric::FIRST_N_SAMPLES, GaugeMetric::RANDOM_ONE_SAMPLE}) {
-        auto config = CreateStatsdConfigForPushedEvent(sampling_type);
-        int64_t bucketStartTimeNs = 10000000000;
-        int64_t bucketSizeNs =
-                TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
-
-        ConfigKey cfgKey;
-        auto processor =
-                CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-        ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-        EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-
-        int appUid1 = 123;
-        int appUid2 = 456;
-        std::vector<std::unique_ptr<LogEvent>> events;
-        events.push_back(CreateMoveToBackgroundEvent(bucketStartTimeNs + 15, appUid1));
-        events.push_back(
-                CreateMoveToForegroundEvent(bucketStartTimeNs + bucketSizeNs + 250, appUid1));
-        events.push_back(
-                CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 350, appUid1));
-        events.push_back(
-                CreateMoveToForegroundEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100, appUid1));
-
-        events.push_back(CreateAppStartOccurredEvent(
-                bucketStartTimeNs + 10, appUid1, "app1", AppStartOccurred::WARM, "activity_name1",
-                "calling_pkg_name1", true /*is_instant_app*/, 101 /*activity_start_msec*/));
-        events.push_back(CreateAppStartOccurredEvent(
-                bucketStartTimeNs + 20, appUid1, "app1", AppStartOccurred::HOT, "activity_name2",
-                "calling_pkg_name2", true /*is_instant_app*/, 102 /*activity_start_msec*/));
-        events.push_back(CreateAppStartOccurredEvent(
-                bucketStartTimeNs + 30, appUid1, "app1", AppStartOccurred::COLD, "activity_name3",
-                "calling_pkg_name3", true /*is_instant_app*/, 103 /*activity_start_msec*/));
-        events.push_back(CreateAppStartOccurredEvent(
-                bucketStartTimeNs + bucketSizeNs + 30, appUid1, "app1", AppStartOccurred::WARM,
-                "activity_name4", "calling_pkg_name4", true /*is_instant_app*/,
-                104 /*activity_start_msec*/));
-        events.push_back(CreateAppStartOccurredEvent(
-                bucketStartTimeNs + 2 * bucketSizeNs, appUid1, "app1", AppStartOccurred::COLD,
-                "activity_name5", "calling_pkg_name5", true /*is_instant_app*/,
-                105 /*activity_start_msec*/));
-        events.push_back(CreateAppStartOccurredEvent(
-                bucketStartTimeNs + 2 * bucketSizeNs + 10, appUid1, "app1", AppStartOccurred::HOT,
-                "activity_name6", "calling_pkg_name6", false /*is_instant_app*/,
-                106 /*activity_start_msec*/));
-
-        events.push_back(
-                CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 10, appUid2));
-        events.push_back(CreateAppStartOccurredEvent(
-                bucketStartTimeNs + 2 * bucketSizeNs + 10, appUid2, "app2", AppStartOccurred::COLD,
-                "activity_name7", "calling_pkg_name7", true /*is_instant_app*/,
-                201 /*activity_start_msec*/));
-
-        sortLogEventsByTimestamp(&events);
-
-        for (const auto& event : events) {
-            processor->OnLogEvent(event.get());
-        }
-        ConfigMetricsReportList reports;
-        vector<uint8_t> buffer;
-        processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, true, ADB_DUMP,
-                                FAST, &buffer);
-        EXPECT_TRUE(buffer.size() > 0);
-        EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-        backfillDimensionPath(&reports);
-        backfillStringInReport(&reports);
-        backfillStartEndTimestamp(&reports);
-        ASSERT_EQ(1, reports.reports_size());
-        ASSERT_EQ(1, reports.reports(0).metrics_size());
-        StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
-        sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(),
-                                        &gaugeMetrics);
-        ASSERT_EQ(2, gaugeMetrics.data_size());
-
-        auto data = gaugeMetrics.data(0);
-        EXPECT_EQ(util::APP_START_OCCURRED, data.dimensions_in_what().field());
-        ASSERT_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());
-        EXPECT_EQ(appUid1, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-        ASSERT_EQ(3, data.bucket_info_size());
-        if (sampling_type == GaugeMetric::FIRST_N_SAMPLES) {
-            ASSERT_EQ(2, data.bucket_info(0).atom_size());
-            ASSERT_EQ(2, data.bucket_info(0).elapsed_timestamp_nanos_size());
-            ASSERT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
-            EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-            EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-                      data.bucket_info(0).end_bucket_elapsed_nanos());
-            EXPECT_EQ(AppStartOccurred::HOT,
-                      data.bucket_info(0).atom(0).app_start_occurred().type());
-            EXPECT_EQ("activity_name2",
-                      data.bucket_info(0).atom(0).app_start_occurred().activity_name());
-            EXPECT_EQ(102L,
-                      data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
-            EXPECT_EQ(AppStartOccurred::COLD,
-                      data.bucket_info(0).atom(1).app_start_occurred().type());
-            EXPECT_EQ("activity_name3",
-                      data.bucket_info(0).atom(1).app_start_occurred().activity_name());
-            EXPECT_EQ(103L,
-                      data.bucket_info(0).atom(1).app_start_occurred().activity_start_millis());
-
-            ASSERT_EQ(1, data.bucket_info(1).atom_size());
-            ASSERT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
-            EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-                      data.bucket_info(1).start_bucket_elapsed_nanos());
-            EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-                      data.bucket_info(1).end_bucket_elapsed_nanos());
-            EXPECT_EQ(AppStartOccurred::WARM,
-                      data.bucket_info(1).atom(0).app_start_occurred().type());
-            EXPECT_EQ("activity_name4",
-                      data.bucket_info(1).atom(0).app_start_occurred().activity_name());
-            EXPECT_EQ(104L,
-                      data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis());
-
-            ASSERT_EQ(2, data.bucket_info(2).atom_size());
-            ASSERT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
-            EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-                      data.bucket_info(2).start_bucket_elapsed_nanos());
-            EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-                      data.bucket_info(2).end_bucket_elapsed_nanos());
-            EXPECT_EQ(AppStartOccurred::COLD,
-                      data.bucket_info(2).atom(0).app_start_occurred().type());
-            EXPECT_EQ("activity_name5",
-                      data.bucket_info(2).atom(0).app_start_occurred().activity_name());
-            EXPECT_EQ(105L,
-                      data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis());
-            EXPECT_EQ(AppStartOccurred::HOT,
-                      data.bucket_info(2).atom(1).app_start_occurred().type());
-            EXPECT_EQ("activity_name6",
-                      data.bucket_info(2).atom(1).app_start_occurred().activity_name());
-            EXPECT_EQ(106L,
-                      data.bucket_info(2).atom(1).app_start_occurred().activity_start_millis());
-        } else {
-            ASSERT_EQ(1, data.bucket_info(0).atom_size());
-            ASSERT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-            EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-            EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-                      data.bucket_info(0).end_bucket_elapsed_nanos());
-            EXPECT_EQ(AppStartOccurred::HOT,
-                      data.bucket_info(0).atom(0).app_start_occurred().type());
-            EXPECT_EQ("activity_name2",
-                      data.bucket_info(0).atom(0).app_start_occurred().activity_name());
-            EXPECT_EQ(102L,
-                      data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
-
-            ASSERT_EQ(1, data.bucket_info(1).atom_size());
-            ASSERT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
-            EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-                      data.bucket_info(1).start_bucket_elapsed_nanos());
-            EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-                      data.bucket_info(1).end_bucket_elapsed_nanos());
-            EXPECT_EQ(AppStartOccurred::WARM,
-                      data.bucket_info(1).atom(0).app_start_occurred().type());
-            EXPECT_EQ("activity_name4",
-                      data.bucket_info(1).atom(0).app_start_occurred().activity_name());
-            EXPECT_EQ(104L,
-                      data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis());
-
-            ASSERT_EQ(1, data.bucket_info(2).atom_size());
-            ASSERT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
-            EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-                      data.bucket_info(2).start_bucket_elapsed_nanos());
-            EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-                      data.bucket_info(2).end_bucket_elapsed_nanos());
-            EXPECT_EQ(AppStartOccurred::COLD,
-                      data.bucket_info(2).atom(0).app_start_occurred().type());
-            EXPECT_EQ("activity_name5",
-                      data.bucket_info(2).atom(0).app_start_occurred().activity_name());
-            EXPECT_EQ(105L,
-                      data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis());
-        }
-
-        data = gaugeMetrics.data(1);
-
-        EXPECT_EQ(data.dimensions_in_what().field(), util::APP_START_OCCURRED);
-        ASSERT_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());
-        EXPECT_EQ(appUid2, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-        ASSERT_EQ(1, data.bucket_info_size());
-        ASSERT_EQ(1, data.bucket_info(0).atom_size());
-        ASSERT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-        EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-                  data.bucket_info(0).start_bucket_elapsed_nanos());
-        EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-                  data.bucket_info(0).end_bucket_elapsed_nanos());
-        EXPECT_EQ(AppStartOccurred::COLD, data.bucket_info(0).atom(0).app_start_occurred().type());
-        EXPECT_EQ("activity_name7",
-                  data.bucket_info(0).atom(0).app_start_occurred().activity_name());
-        EXPECT_EQ(201L, data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
-    }
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
deleted file mode 100644
index e320419..0000000
--- a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
+++ /dev/null
@@ -1,1833 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <gtest/gtest.h>
-
-#include "src/StatsLogProcessor.h"
-#include "src/stats_log_util.h"
-#include "tests/statsd_test_util.h"
-
-#include <vector>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-#ifdef __ANDROID__
-
-namespace {
-
-StatsdConfig CreateStatsdConfig() {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-    auto saverModeMatcher = CreateBatterySaverModeStartAtomMatcher();
-    auto crashMatcher = CreateProcessCrashAtomMatcher();
-    auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-
-    *config.add_atom_matcher() = saverModeMatcher;
-    *config.add_atom_matcher() = crashMatcher;
-    *config.add_atom_matcher() = screenOnMatcher;
-
-    int64_t metricId = 123456;
-    auto countMetric = config.add_count_metric();
-    countMetric->set_id(metricId);
-    countMetric->set_what(crashMatcher.id());
-    countMetric->set_bucket(FIVE_MINUTES);
-    countMetric->mutable_dimensions_in_what()->set_field(
-        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();
-    metric_activation1->set_metric_id(metricId);
-    auto event_activation1 = metric_activation1->add_event_activation();
-    event_activation1->set_atom_matcher_id(saverModeMatcher.id());
-    event_activation1->set_ttl_seconds(60 * 6);  // 6 minutes
-    auto event_activation2 = metric_activation1->add_event_activation();
-    event_activation2->set_atom_matcher_id(screenOnMatcher.id());
-    event_activation2->set_ttl_seconds(60 * 2);  // 2 minutes
-
-    return config;
-}
-
-StatsdConfig CreateStatsdConfigWithOneDeactivation() {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-    auto saverModeMatcher = CreateBatterySaverModeStartAtomMatcher();
-    auto crashMatcher = CreateProcessCrashAtomMatcher();
-    auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-    auto brightnessChangedMatcher = CreateScreenBrightnessChangedAtomMatcher();
-
-    *config.add_atom_matcher() = saverModeMatcher;
-    *config.add_atom_matcher() = crashMatcher;
-    *config.add_atom_matcher() = screenOnMatcher;
-    *config.add_atom_matcher() = brightnessChangedMatcher;
-
-    int64_t metricId = 123456;
-    auto countMetric = config.add_count_metric();
-    countMetric->set_id(metricId);
-    countMetric->set_what(crashMatcher.id());
-    countMetric->set_bucket(FIVE_MINUTES);
-    countMetric->mutable_dimensions_in_what()->set_field(
-        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();
-    metric_activation1->set_metric_id(metricId);
-    auto event_activation1 = metric_activation1->add_event_activation();
-    event_activation1->set_atom_matcher_id(saverModeMatcher.id());
-    event_activation1->set_ttl_seconds(60 * 6);  // 6 minutes
-    event_activation1->set_deactivation_atom_matcher_id(brightnessChangedMatcher.id());
-    auto event_activation2 = metric_activation1->add_event_activation();
-    event_activation2->set_atom_matcher_id(screenOnMatcher.id());
-    event_activation2->set_ttl_seconds(60 * 2);  // 2 minutes
-
-    return config;
-}
-
-StatsdConfig CreateStatsdConfigWithTwoDeactivations() {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-    auto saverModeMatcher = CreateBatterySaverModeStartAtomMatcher();
-    auto crashMatcher = CreateProcessCrashAtomMatcher();
-    auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-    auto brightnessChangedMatcher = CreateScreenBrightnessChangedAtomMatcher();
-    auto brightnessChangedMatcher2 = CreateScreenBrightnessChangedAtomMatcher();
-    brightnessChangedMatcher2.set_id(StringToId("ScreenBrightnessChanged2"));
-
-    *config.add_atom_matcher() = saverModeMatcher;
-    *config.add_atom_matcher() = crashMatcher;
-    *config.add_atom_matcher() = screenOnMatcher;
-    *config.add_atom_matcher() = brightnessChangedMatcher;
-    *config.add_atom_matcher() = brightnessChangedMatcher2;
-
-    int64_t metricId = 123456;
-    auto countMetric = config.add_count_metric();
-    countMetric->set_id(metricId);
-    countMetric->set_what(crashMatcher.id());
-    countMetric->set_bucket(FIVE_MINUTES);
-    countMetric->mutable_dimensions_in_what()->set_field(
-        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();
-    metric_activation1->set_metric_id(metricId);
-    auto event_activation1 = metric_activation1->add_event_activation();
-    event_activation1->set_atom_matcher_id(saverModeMatcher.id());
-    event_activation1->set_ttl_seconds(60 * 6);  // 6 minutes
-    event_activation1->set_deactivation_atom_matcher_id(brightnessChangedMatcher.id());
-    auto event_activation2 = metric_activation1->add_event_activation();
-    event_activation2->set_atom_matcher_id(screenOnMatcher.id());
-    event_activation2->set_ttl_seconds(60 * 2);  // 2 minutes
-    event_activation2->set_deactivation_atom_matcher_id(brightnessChangedMatcher2.id());
-
-    return config;
-}
-
-StatsdConfig CreateStatsdConfigWithSameDeactivations() {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-    auto saverModeMatcher = CreateBatterySaverModeStartAtomMatcher();
-    auto crashMatcher = CreateProcessCrashAtomMatcher();
-    auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-    auto brightnessChangedMatcher = CreateScreenBrightnessChangedAtomMatcher();
-
-    *config.add_atom_matcher() = saverModeMatcher;
-    *config.add_atom_matcher() = crashMatcher;
-    *config.add_atom_matcher() = screenOnMatcher;
-    *config.add_atom_matcher() = brightnessChangedMatcher;
-
-    int64_t metricId = 123456;
-    auto countMetric = config.add_count_metric();
-    countMetric->set_id(metricId);
-    countMetric->set_what(crashMatcher.id());
-    countMetric->set_bucket(FIVE_MINUTES);
-    countMetric->mutable_dimensions_in_what()->set_field(
-        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();
-    metric_activation1->set_metric_id(metricId);
-    auto event_activation1 = metric_activation1->add_event_activation();
-    event_activation1->set_atom_matcher_id(saverModeMatcher.id());
-    event_activation1->set_ttl_seconds(60 * 6);  // 6 minutes
-    event_activation1->set_deactivation_atom_matcher_id(brightnessChangedMatcher.id());
-    auto event_activation2 = metric_activation1->add_event_activation();
-    event_activation2->set_atom_matcher_id(screenOnMatcher.id());
-    event_activation2->set_ttl_seconds(60 * 2);  // 2 minutes
-    event_activation2->set_deactivation_atom_matcher_id(brightnessChangedMatcher.id());
-
-    return config;
-}
-
-StatsdConfig CreateStatsdConfigWithTwoMetricsTwoDeactivations() {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-    auto saverModeMatcher = CreateBatterySaverModeStartAtomMatcher();
-    auto crashMatcher = CreateProcessCrashAtomMatcher();
-    auto foregroundMatcher = CreateMoveToForegroundAtomMatcher();
-    auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-    auto brightnessChangedMatcher = CreateScreenBrightnessChangedAtomMatcher();
-    auto brightnessChangedMatcher2 = CreateScreenBrightnessChangedAtomMatcher();
-    brightnessChangedMatcher2.set_id(StringToId("ScreenBrightnessChanged2"));
-
-    *config.add_atom_matcher() = saverModeMatcher;
-    *config.add_atom_matcher() = crashMatcher;
-    *config.add_atom_matcher() = screenOnMatcher;
-    *config.add_atom_matcher() = brightnessChangedMatcher;
-    *config.add_atom_matcher() = brightnessChangedMatcher2;
-    *config.add_atom_matcher() = foregroundMatcher;
-
-    int64_t metricId = 123456;
-    auto countMetric = config.add_count_metric();
-    countMetric->set_id(metricId);
-    countMetric->set_what(crashMatcher.id());
-    countMetric->set_bucket(FIVE_MINUTES);
-    countMetric->mutable_dimensions_in_what()->set_field(
-        util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
-    countMetric->mutable_dimensions_in_what()->add_child()->set_field(1);  // uid field
-
-    int64_t metricId2 = 234567;
-    countMetric = config.add_count_metric();
-    countMetric->set_id(metricId2);
-    countMetric->set_what(foregroundMatcher.id());
-    countMetric->set_bucket(FIVE_MINUTES);
-    countMetric->mutable_dimensions_in_what()->set_field(
-        util::ACTIVITY_FOREGROUND_STATE_CHANGED);
-    countMetric->mutable_dimensions_in_what()->add_child()->set_field(1);  // uid field
-
-    auto metric_activation1 = config.add_metric_activation();
-    metric_activation1->set_metric_id(metricId);
-    auto event_activation1 = metric_activation1->add_event_activation();
-    event_activation1->set_atom_matcher_id(saverModeMatcher.id());
-    event_activation1->set_ttl_seconds(60 * 6);  // 6 minutes
-    event_activation1->set_deactivation_atom_matcher_id(brightnessChangedMatcher.id());
-    auto event_activation2 = metric_activation1->add_event_activation();
-    event_activation2->set_atom_matcher_id(screenOnMatcher.id());
-    event_activation2->set_ttl_seconds(60 * 2);  // 2 minutes
-    event_activation2->set_deactivation_atom_matcher_id(brightnessChangedMatcher2.id());
-
-    metric_activation1 = config.add_metric_activation();
-    metric_activation1->set_metric_id(metricId2);
-    event_activation1 = metric_activation1->add_event_activation();
-    event_activation1->set_atom_matcher_id(saverModeMatcher.id());
-    event_activation1->set_ttl_seconds(60 * 6);  // 6 minutes
-    event_activation1->set_deactivation_atom_matcher_id(brightnessChangedMatcher.id());
-    event_activation2 = metric_activation1->add_event_activation();
-    event_activation2->set_atom_matcher_id(screenOnMatcher.id());
-    event_activation2->set_ttl_seconds(60 * 2);  // 2 minutes
-    event_activation2->set_deactivation_atom_matcher_id(brightnessChangedMatcher2.id());
-
-    return config;
-}
-
-}  // namespace
-
-TEST(MetricActivationE2eTest, TestCountMetric) {
-    auto config = CreateStatsdConfig();
-
-    int64_t bucketStartTimeNs = NS_PER_SEC * 10;  // 10 secs
-    int64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-
-    int uid = 12345;
-    int64_t cfgId = 98765;
-    ConfigKey cfgKey(uid, cfgId);
-
-    sp<UidMap> m = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> subscriberAlarmMonitor;
-    vector<int64_t> activeConfigsBroadcast;
-
-    long timeBase1 = 1;
-    int broadcastCount = 0;
-    StatsLogProcessor processor(
-            m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
-            [](const ConfigKey& key) { return true; },
-            [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-                                                             const vector<int64_t>& activeConfigs) {
-                broadcastCount++;
-                EXPECT_EQ(broadcastUid, uid);
-                activeConfigsBroadcast.clear();
-                activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
-                                              activeConfigs.end());
-                return true;
-            });
-
-    processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
-
-    ASSERT_EQ(processor.mMetricsManagers.size(), 1u);
-    sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-    ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-    auto& eventActivationMap = metricProducer->mEventActivationMap;
-
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
-    // triggered by screen on event (tracker index 2).
-    ASSERT_EQ(eventActivationMap.size(), 2u);
-    EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
-    EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-
-    std::unique_ptr<LogEvent> event;
-
-    event = CreateAppCrashEvent(bucketStartTimeNs + 5, 111);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    EXPECT_EQ(broadcastCount, 0);
-
-    // Activated by battery save mode.
-    event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(broadcastCount, 1);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 1);
-    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-
-    // First processed event.
-    event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
-
-    // Activated by screen on event.
-    event = CreateScreenStateChangedEvent(bucketStartTimeNs + 20, android::view::DISPLAY_STATE_ON);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-
-    // 2nd processed event.
-    // The activation by screen_on event expires, but the one by battery save mode is still active.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 333);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    // No new broadcast since the config should still be active.
-    EXPECT_EQ(broadcastCount, 1);
-
-    // 3rd processed event.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 444);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-
-    // All activations expired.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 555);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    // New broadcast since the config is no longer active.
-    EXPECT_EQ(broadcastCount, 2);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 0);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-
-    // Re-activate metric via screen on.
-    event = CreateScreenStateChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10,
-                                          android::view::DISPLAY_STATE_ON);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(broadcastCount, 3);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 1);
-    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-
-    // 4th processed event.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 666);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
-                           ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-
-    StatsLogReport::CountMetricDataWrapper countMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-    ASSERT_EQ(4, countMetrics.data_size());
-
-    auto data = countMetrics.data(0);
-    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    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(1);
-    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    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(2);
-    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    // Partial bucket as metric is deactivated.
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
-              data.bucket_info(0).end_bucket_elapsed_nanos());
-
-    data = countMetrics.data(3);
-    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-              data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-}
-
-TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation) {
-    auto config = CreateStatsdConfigWithOneDeactivation();
-
-    int64_t bucketStartTimeNs = NS_PER_SEC * 10;  // 10 secs
-    int64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-
-    int uid = 12345;
-    int64_t cfgId = 98765;
-    ConfigKey cfgKey(uid, cfgId);
-
-    sp<UidMap> m = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> subscriberAlarmMonitor;
-    vector<int64_t> activeConfigsBroadcast;
-
-    long timeBase1 = 1;
-    int broadcastCount = 0;
-    StatsLogProcessor processor(
-            m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
-            [](const ConfigKey& key) { return true; },
-            [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-                                                             const vector<int64_t>& activeConfigs) {
-                broadcastCount++;
-                EXPECT_EQ(broadcastUid, uid);
-                activeConfigsBroadcast.clear();
-                activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
-                                              activeConfigs.end());
-                return true;
-            });
-
-    processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
-
-    ASSERT_EQ(processor.mMetricsManagers.size(), 1u);
-    sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-    ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-    auto& eventActivationMap = metricProducer->mEventActivationMap;
-    auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
-
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
-    // triggered by screen on event (tracker index 2).
-    ASSERT_EQ(eventActivationMap.size(), 2u);
-    EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
-    EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    ASSERT_EQ(eventDeactivationMap.size(), 1u);
-    EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
-    ASSERT_EQ(eventDeactivationMap[3].size(), 1u);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-
-    std::unique_ptr<LogEvent> event;
-
-    event = CreateAppCrashEvent(bucketStartTimeNs + 5, 111);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    EXPECT_EQ(broadcastCount, 0);
-
-    // Activated by battery save mode.
-    event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(broadcastCount, 1);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 1);
-    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-
-    // First processed event.
-    event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
-
-    // Activated by screen on event.
-    event = CreateScreenStateChangedEvent(bucketStartTimeNs + 20, android::view::DISPLAY_STATE_ON);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-
-    // 2nd processed event.
-    // The activation by screen_on event expires, but the one by battery save mode is still active.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 333);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-    // No new broadcast since the config should still be active.
-    EXPECT_EQ(broadcastCount, 1);
-
-    // 3rd processed event.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 444);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-
-    // All activations expired.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 555);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    // New broadcast since the config is no longer active.
-    EXPECT_EQ(broadcastCount, 2);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 0);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-
-    // Re-activate metric via screen on.
-    event = CreateScreenStateChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10,
-                                          android::view::DISPLAY_STATE_ON);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(broadcastCount, 3);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 1);
-    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-
-    // 4th processed event.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 666);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-
-    // Re-enable battery saver mode activation.
-    event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(broadcastCount, 3);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 1);
-    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-
-    // 5th processed event.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40, 777);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-
-    // Cancel battery saver mode activation.
-    event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60, 64);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(broadcastCount, 3);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 1);
-    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-
-    // Screen-on activation expired.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13, 888);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    // New broadcast since the config is no longer active.
-    EXPECT_EQ(broadcastCount, 4);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 0);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1, 999);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-
-    // Re-enable battery saver mode activation.
-    event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(broadcastCount, 5);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 1);
-    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-
-    // Cancel battery saver mode activation.
-    event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 16, 140);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16);
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    EXPECT_EQ(broadcastCount, 6);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 0);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
-                           ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-
-    StatsLogReport::CountMetricDataWrapper countMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-    ASSERT_EQ(5, countMetrics.data_size());
-
-    auto data = countMetrics.data(0);
-    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    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(1);
-    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    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(2);
-    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    // Partial bucket as metric is deactivated.
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
-              data.bucket_info(0).end_bucket_elapsed_nanos());
-
-    data = countMetrics.data(3);
-    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-              data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 13,
-              data.bucket_info(0).end_bucket_elapsed_nanos());
-
-    data = countMetrics.data(4);
-    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-              data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 13,
-              data.bucket_info(0).end_bucket_elapsed_nanos());
-}
-
-TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations) {
-    auto config = CreateStatsdConfigWithTwoDeactivations();
-
-    int64_t bucketStartTimeNs = NS_PER_SEC * 10;  // 10 secs
-    int64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-
-    int uid = 12345;
-    int64_t cfgId = 98765;
-    ConfigKey cfgKey(uid, cfgId);
-
-    sp<UidMap> m = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> subscriberAlarmMonitor;
-    vector<int64_t> activeConfigsBroadcast;
-
-    long timeBase1 = 1;
-    int broadcastCount = 0;
-    StatsLogProcessor processor(
-            m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
-            [](const ConfigKey& key) { return true; },
-            [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-                                                             const vector<int64_t>& activeConfigs) {
-                broadcastCount++;
-                EXPECT_EQ(broadcastUid, uid);
-                activeConfigsBroadcast.clear();
-                activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
-                                              activeConfigs.end());
-                return true;
-            });
-
-    processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
-
-    ASSERT_EQ(processor.mMetricsManagers.size(), 1u);
-    sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-    ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-    auto& eventActivationMap = metricProducer->mEventActivationMap;
-    auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
-
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
-    // triggered by screen on event (tracker index 2).
-    ASSERT_EQ(eventActivationMap.size(), 2u);
-    EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
-    EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    ASSERT_EQ(eventDeactivationMap.size(), 2u);
-    EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
-    EXPECT_TRUE(eventDeactivationMap.find(4) != eventDeactivationMap.end());
-    ASSERT_EQ(eventDeactivationMap[3].size(), 1u);
-    ASSERT_EQ(eventDeactivationMap[4].size(), 1u);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-
-    std::unique_ptr<LogEvent> event;
-
-    event = CreateAppCrashEvent(bucketStartTimeNs + 5, 111);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    EXPECT_EQ(broadcastCount, 0);
-
-    // Activated by battery save mode.
-    event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(broadcastCount, 1);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 1);
-    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-
-    // First processed event.
-    event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
-
-    // Activated by screen on event.
-    event = CreateScreenStateChangedEvent(bucketStartTimeNs + 20, android::view::DISPLAY_STATE_ON);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-
-    // 2nd processed event.
-    // The activation by screen_on event expires, but the one by battery save mode is still active.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 333);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-    // No new broadcast since the config should still be active.
-    EXPECT_EQ(broadcastCount, 1);
-
-    // 3rd processed event.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 444);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-
-    // All activations expired.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 555);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    // New broadcast since the config is no longer active.
-    EXPECT_EQ(broadcastCount, 2);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 0);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-
-    // Re-activate metric via screen on.
-    event = CreateScreenStateChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10,
-                                          android::view::DISPLAY_STATE_ON);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(broadcastCount, 3);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 1);
-    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-
-    // 4th processed event.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 666);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-
-    // Re-enable battery saver mode activation.
-    event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(broadcastCount, 3);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 1);
-    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-
-    // 5th processed event.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40, 777);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-
-    // Cancel battery saver mode and screen on activation.
-    event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60, 64);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    // New broadcast since the config is no longer active.
-    EXPECT_EQ(broadcastCount, 4);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 0);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-
-    // Screen-on activation expired.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13, 888);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    EXPECT_EQ(broadcastCount, 4);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 0);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1, 999);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-
-    // Re-enable battery saver mode activation.
-    event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(broadcastCount, 5);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 1);
-    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-
-    // Cancel battery saver mode and screen on activation.
-    event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 16, 140);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16);
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    EXPECT_EQ(broadcastCount, 6);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 0);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
-                           ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-
-    StatsLogReport::CountMetricDataWrapper countMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-    ASSERT_EQ(5, countMetrics.data_size());
-
-    auto data = countMetrics.data(0);
-    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    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(1);
-    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    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(2);
-    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    // Partial bucket as metric is deactivated.
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
-              data.bucket_info(0).end_bucket_elapsed_nanos());
-
-    data = countMetrics.data(3);
-    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-              data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
-              data.bucket_info(0).end_bucket_elapsed_nanos());
-
-    data = countMetrics.data(4);
-    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-              data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
-              data.bucket_info(0).end_bucket_elapsed_nanos());
-}
-
-TEST(MetricActivationE2eTest, TestCountMetricWithSameDeactivation) {
-    auto config = CreateStatsdConfigWithSameDeactivations();
-
-    int64_t bucketStartTimeNs = NS_PER_SEC * 10;  // 10 secs
-    int64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-
-    int uid = 12345;
-    int64_t cfgId = 98765;
-    ConfigKey cfgKey(uid, cfgId);
-
-    sp<UidMap> m = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> subscriberAlarmMonitor;
-    vector<int64_t> activeConfigsBroadcast;
-
-    long timeBase1 = 1;
-    int broadcastCount = 0;
-    StatsLogProcessor processor(
-            m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
-            [](const ConfigKey& key) { return true; },
-            [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-                                                             const vector<int64_t>& activeConfigs) {
-                broadcastCount++;
-                EXPECT_EQ(broadcastUid, uid);
-                activeConfigsBroadcast.clear();
-                activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
-                                              activeConfigs.end());
-                return true;
-            });
-
-    processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
-
-    ASSERT_EQ(processor.mMetricsManagers.size(), 1u);
-    sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-    ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-    auto& eventActivationMap = metricProducer->mEventActivationMap;
-    auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
-
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
-    // triggered by screen on event (tracker index 2).
-    ASSERT_EQ(eventActivationMap.size(), 2u);
-    EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
-    EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    ASSERT_EQ(eventDeactivationMap.size(), 1u);
-    EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
-    ASSERT_EQ(eventDeactivationMap[3].size(), 2u);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-    EXPECT_EQ(eventDeactivationMap[3][1], eventActivationMap[2]);
-    EXPECT_EQ(broadcastCount, 0);
-
-    std::unique_ptr<LogEvent> event;
-
-    // Event that should be ignored.
-    event = CreateAppCrashEvent(bucketStartTimeNs + 1, 111);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + 1);
-
-    // Activate metric via screen on for 2 minutes.
-    event = CreateScreenStateChangedEvent(bucketStartTimeNs + 10, android::view::DISPLAY_STATE_ON);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(broadcastCount, 1);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 1);
-    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 10);
-
-    // 1st processed event.
-    event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
-
-    // Enable battery saver mode activation for 5 minutes.
-    event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 + 10);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 + 10);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(broadcastCount, 1);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 + 10);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 10);
-
-    // 2nd processed event.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 + 40, 333);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 + 40);
-
-    // Cancel battery saver mode and screen on activation.
-    int64_t firstDeactivation = bucketStartTimeNs + NS_PER_SEC * 61;
-    event = CreateScreenBrightnessChangedEvent(firstDeactivation, 64);
-    processor.OnLogEvent(event.get(), firstDeactivation);
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    // New broadcast since the config is no longer active.
-    EXPECT_EQ(broadcastCount, 2);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 0);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-
-    // Should be ignored
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 61 + 80, 444);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 61 + 80);
-
-    // Re-enable battery saver mode activation.
-    event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(broadcastCount, 3);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 1);
-    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-
-    // 3rd processed event.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 80, 555);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 80);
-
-    // Cancel battery saver mode activation.
-    int64_t secondDeactivation = bucketStartTimeNs + NS_PER_SEC * 60 * 13;
-    event = CreateScreenBrightnessChangedEvent(secondDeactivation, 140);
-    processor.OnLogEvent(event.get(), secondDeactivation);
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    EXPECT_EQ(broadcastCount, 4);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 0);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-
-    // Should be ignored.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13 + 80, 666);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13 + 80);
-
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
-                           ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-
-    StatsLogReport::CountMetricDataWrapper countMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-    ASSERT_EQ(3, countMetrics.data_size());
-
-    auto data = countMetrics.data(0);
-    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(firstDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
-
-    data = countMetrics.data(1);
-    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(firstDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
-
-    data = countMetrics.data(2);
-    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(555, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    // Partial bucket as metric is deactivated.
-    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-              data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(secondDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
-}
-
-TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations) {
-    auto config = CreateStatsdConfigWithTwoMetricsTwoDeactivations();
-
-    int64_t bucketStartTimeNs = NS_PER_SEC * 10;  // 10 secs
-    int64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-
-    int uid = 12345;
-    int64_t cfgId = 98765;
-    ConfigKey cfgKey(uid, cfgId);
-
-    sp<UidMap> m = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> subscriberAlarmMonitor;
-    vector<int64_t> activeConfigsBroadcast;
-
-    long timeBase1 = 1;
-    int broadcastCount = 0;
-    StatsLogProcessor processor(
-            m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
-            [](const ConfigKey& key) { return true; },
-            [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-                                                             const vector<int64_t>& activeConfigs) {
-                broadcastCount++;
-                EXPECT_EQ(broadcastUid, uid);
-                activeConfigsBroadcast.clear();
-                activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
-                                              activeConfigs.end());
-                return true;
-            });
-
-    processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
-
-    ASSERT_EQ(processor.mMetricsManagers.size(), 1u);
-    sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-    ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 2);
-    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-    auto& eventActivationMap = metricProducer->mEventActivationMap;
-    auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
-    sp<MetricProducer> metricProducer2 = metricsManager->mAllMetricProducers[1];
-    auto& eventActivationMap2 = metricProducer2->mEventActivationMap;
-    auto& eventDeactivationMap2 = metricProducer2->mEventDeactivationMap;
-
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    EXPECT_FALSE(metricProducer2->mIsActive);
-    // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
-    // triggered by screen on event (tracker index 2).
-    ASSERT_EQ(eventActivationMap.size(), 2u);
-    EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
-    EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    ASSERT_EQ(eventDeactivationMap.size(), 2u);
-    EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
-    EXPECT_TRUE(eventDeactivationMap.find(4) != eventDeactivationMap.end());
-    ASSERT_EQ(eventDeactivationMap[3].size(), 1u);
-    ASSERT_EQ(eventDeactivationMap[4].size(), 1u);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-
-    ASSERT_EQ(eventActivationMap2.size(), 2u);
-    EXPECT_TRUE(eventActivationMap2.find(0) != eventActivationMap2.end());
-    EXPECT_TRUE(eventActivationMap2.find(2) != eventActivationMap2.end());
-    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap2[0]->start_ns, 0);
-    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap2[2]->start_ns, 0);
-    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    ASSERT_EQ(eventDeactivationMap2.size(), 2u);
-    EXPECT_TRUE(eventDeactivationMap2.find(3) != eventDeactivationMap2.end());
-    EXPECT_TRUE(eventDeactivationMap2.find(4) != eventDeactivationMap2.end());
-    ASSERT_EQ(eventDeactivationMap[3].size(), 1u);
-    ASSERT_EQ(eventDeactivationMap[4].size(), 1u);
-    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-
-    std::unique_ptr<LogEvent> event;
-
-    event = CreateAppCrashEvent(bucketStartTimeNs + 5, 111);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
-    event = CreateMoveToForegroundEvent(bucketStartTimeNs + 5, 1111);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_FALSE(metricProducer->mIsActive);
-    EXPECT_FALSE(metricProducer2->mIsActive);
-    EXPECT_EQ(broadcastCount, 0);
-
-    // Activated by battery save mode.
-    event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_EQ(broadcastCount, 1);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 1);
-    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-    EXPECT_TRUE(metricProducer2->mIsActive);
-    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap2[2]->start_ns, 0);
-    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-
-    // First processed event.
-    event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
-    event = CreateMoveToForegroundEvent(bucketStartTimeNs + 15, 2222);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
-
-    // Activated by screen on event.
-    event = CreateScreenStateChangedEvent(bucketStartTimeNs + 20, android::view::DISPLAY_STATE_ON);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-    EXPECT_TRUE(metricProducer2->mIsActive);
-    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20);
-    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-
-    // 2nd processed event.
-    // The activation by screen_on event expires, but the one by battery save mode is still active.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 333);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-    event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 3333);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-    EXPECT_TRUE(metricProducer2->mIsActive);
-    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20);
-    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-    // No new broadcast since the config should still be active.
-    EXPECT_EQ(broadcastCount, 1);
-
-    // 3rd processed event.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 444);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-    event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 4444);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-
-    // All activations expired.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 555);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-    event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 5555);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-    EXPECT_FALSE(metricsManager->isActive());
-    // New broadcast since the config is no longer active.
-    EXPECT_EQ(broadcastCount, 2);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 0);
-    EXPECT_FALSE(metricProducer->mIsActive);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-    EXPECT_FALSE(metricProducer2->mIsActive);
-    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20);
-    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-
-    // Re-activate metric via screen on.
-    event = CreateScreenStateChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10,
-                                          android::view::DISPLAY_STATE_ON);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_EQ(broadcastCount, 3);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 1);
-    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-    EXPECT_TRUE(metricProducer2->mIsActive);
-    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
-    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-
-    // 4th processed event.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 666);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-    event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 6666);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-
-    // Re-enable battery saver mode activation.
-    event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_EQ(broadcastCount, 3);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 1);
-    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-    EXPECT_TRUE(metricProducer2->mIsActive);
-    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-
-    // 5th processed event.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40, 777);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-    event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40, 7777);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-
-    // Cancel battery saver mode and screen on activation.
-    event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60, 64);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
-    EXPECT_FALSE(metricsManager->isActive());
-    // New broadcast since the config is no longer active.
-    EXPECT_EQ(broadcastCount, 4);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 0);
-    EXPECT_FALSE(metricProducer->mIsActive);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-    EXPECT_FALSE(metricProducer2->mIsActive);
-    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-
-    // Screen-on activation expired.
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13, 888);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-    event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13, 8888);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_EQ(broadcastCount, 4);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 0);
-    EXPECT_FALSE(metricProducer->mIsActive);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-    EXPECT_FALSE(metricProducer2->mIsActive);
-    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-
-    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1, 999);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-    event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1, 9999);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-
-    // Re-enable battery saver mode activation.
-    event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-    EXPECT_TRUE(metricsManager->isActive());
-    EXPECT_EQ(broadcastCount, 5);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 1);
-    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-    EXPECT_TRUE(metricProducer->mIsActive);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-    EXPECT_TRUE(metricProducer2->mIsActive);
-    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
-    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-
-    // Cancel battery saver mode and screen on activation.
-    event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 16, 140);
-    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16);
-    EXPECT_FALSE(metricsManager->isActive());
-    EXPECT_EQ(broadcastCount, 6);
-    ASSERT_EQ(activeConfigsBroadcast.size(), 0);
-    EXPECT_FALSE(metricProducer->mIsActive);
-    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-    EXPECT_FALSE(metricProducer2->mIsActive);
-    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
-                           ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(2, reports.reports(0).metrics_size());
-
-    StatsLogReport::CountMetricDataWrapper countMetrics;
-
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-    ASSERT_EQ(5, countMetrics.data_size());
-
-    auto data = countMetrics.data(0);
-    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    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(1);
-    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    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(2);
-    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    // Partial bucket as metric is deactivated.
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
-              data.bucket_info(0).end_bucket_elapsed_nanos());
-
-    data = countMetrics.data(3);
-    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-              data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
-              data.bucket_info(0).end_bucket_elapsed_nanos());
-
-    data = countMetrics.data(4);
-    EXPECT_EQ(util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-              data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
-              data.bucket_info(0).end_bucket_elapsed_nanos());
-
-    countMetrics.clear_data();
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(1).count_metrics(), &countMetrics);
-    ASSERT_EQ(5, countMetrics.data_size());
-
-    data = countMetrics.data(0);
-    EXPECT_EQ(util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(2222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    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(1);
-    EXPECT_EQ(util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(3333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    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(2);
-    EXPECT_EQ(util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(4444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    // Partial bucket as metric is deactivated.
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
-              data.bucket_info(0).end_bucket_elapsed_nanos());
-
-    data = countMetrics.data(3);
-    EXPECT_EQ(util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(6666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-              data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
-              data.bucket_info(0).end_bucket_elapsed_nanos());
-
-    data = countMetrics.data(4);
-    EXPECT_EQ(util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_EQ(7777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(1, data.bucket_info(0).count());
-    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-              data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
-              data.bucket_info(0).end_bucket_elapsed_nanos());
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
deleted file mode 100644
index 5e77ee0..0000000
--- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
+++ /dev/null
@@ -1,348 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <gtest/gtest.h>
-
-#include "src/StatsLogProcessor.h"
-#include "src/stats_log_util.h"
-#include "tests/statsd_test_util.h"
-
-#include <vector>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-#ifdef __ANDROID__
-namespace {
-
-StatsdConfig CreateStatsdConfig() {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-
-    *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
-
-    *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
-    *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
-
-    *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
-    *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
-
-    auto appCrashMatcher = CreateProcessCrashAtomMatcher();
-    *config.add_atom_matcher() = appCrashMatcher;
-
-    auto screenIsOffPredicate = CreateScreenIsOffPredicate();
-
-    auto isSyncingPredicate = CreateIsSyncingPredicate();
-    auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
-    *syncDimension = CreateAttributionUidDimensions(
-        util::SYNC_STATE_CHANGED, {Position::FIRST});
-    syncDimension->add_child()->set_field(2 /* name field*/);
-
-    auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
-    *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
-        CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */ });
-
-    *config.add_predicate() = screenIsOffPredicate;
-    *config.add_predicate() = isSyncingPredicate;
-    *config.add_predicate() = isInBackgroundPredicate;
-
-    auto combinationPredicate = config.add_predicate();
-    combinationPredicate->set_id(StringToId("combinationPredicate"));
-    combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
-    addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
-    addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
-    addPredicateToPredicateCombination(isInBackgroundPredicate, combinationPredicate);
-
-    auto countMetric = config.add_count_metric();
-    countMetric->set_id(StringToId("AppCrashes"));
-    countMetric->set_what(appCrashMatcher.id());
-    countMetric->set_condition(combinationPredicate->id());
-    // The metric is dimensioning by uid only.
-    *countMetric->mutable_dimensions_in_what() =
-        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(util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
-    dimensionWhat->add_child()->set_field(1);  // uid field.
-    *links->mutable_fields_in_condition() = CreateAttributionUidDimensions(
-            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(util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
-    dimensionWhat->add_child()->set_field(1);  // uid field.
-    auto dimensionCondition = links->mutable_fields_in_condition();
-    dimensionCondition->set_field(util::ACTIVITY_FOREGROUND_STATE_CHANGED);
-    dimensionCondition->add_child()->set_field(1);  // uid field.
-    return config;
-}
-}  // namespace
-
-// If we want to test multiple dump data, we must do it in separate tests, because in the e2e tests,
-// we should use the real API which will clear the data after dump data is called.
-TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks1) {
-    auto config = CreateStatsdConfig();
-    uint64_t bucketStartTimeNs = 10000000000;
-    uint64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-
-    ConfigKey cfgKey;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-
-    int appUid = 123;
-    auto crashEvent1 = CreateAppCrashEvent(bucketStartTimeNs + 1, appUid);
-    auto crashEvent2 = CreateAppCrashEvent(bucketStartTimeNs + 201, appUid);
-    auto crashEvent3 = CreateAppCrashEvent(bucketStartTimeNs + 2 * bucketSizeNs - 101, appUid);
-
-    auto crashEvent4 = CreateAppCrashEvent(bucketStartTimeNs + 51, appUid);
-    auto crashEvent5 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 299, appUid);
-    auto crashEvent6 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 2001, appUid);
-
-    auto crashEvent7 = CreateAppCrashEvent(bucketStartTimeNs + 16, appUid);
-    auto crashEvent8 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 249, appUid);
-
-    auto crashEvent9 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 351, appUid);
-    auto crashEvent10 = CreateAppCrashEvent(bucketStartTimeNs + 2 * bucketSizeNs - 2, appUid);
-
-    auto screenTurnedOnEvent = CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 2, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-    auto screenTurnedOffEvent = CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 200, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
-    auto screenTurnedOnEvent2 =
-            CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs - 100,
-                                          android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-
-    std::vector<int> attributionUids = {appUid, appUid + 1};
-    std::vector<string> attributionTags = {"App1", "GMSCoreModule1"};
-
-    auto syncOnEvent1 = CreateSyncStartEvent(bucketStartTimeNs + 50, attributionUids,
-                                             attributionTags, "ReadEmail");
-    auto syncOffEvent1 = CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 300, attributionUids,
-                                            attributionTags, "ReadEmail");
-    auto syncOnEvent2 = CreateSyncStartEvent(bucketStartTimeNs + bucketSizeNs + 2000,
-                                             attributionUids, attributionTags, "ReadDoc");
-
-    auto moveToBackgroundEvent1 = CreateMoveToBackgroundEvent(bucketStartTimeNs + 15, appUid);
-    auto moveToForegroundEvent1 =
-            CreateMoveToForegroundEvent(bucketStartTimeNs + bucketSizeNs + 250, appUid);
-
-    auto moveToBackgroundEvent2 =
-            CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 350, appUid);
-    auto moveToForegroundEvent2 =
-            CreateMoveToForegroundEvent(bucketStartTimeNs + 2 * bucketSizeNs - 1, appUid);
-
-    /*
-                    bucket #1                               bucket #2
-
-
-       |      |   |  |                      |   |          |        |   |   |     (crashEvents)
-    |-------------------------------------|-----------------------------------|---------
-
-             |                                           |                        (MoveToBkground)
-
-                                             |                               |    (MoveToForeground)
-
-                |                                                 |                (SyncIsOn)
-                                                  |                                (SyncIsOff)
-          |                                                               |        (ScreenIsOn)
-                   |                                                               (ScreenIsOff)
-    */
-    std::vector<std::unique_ptr<LogEvent>> events;
-    events.push_back(std::move(crashEvent1));
-    events.push_back(std::move(crashEvent2));
-    events.push_back(std::move(crashEvent3));
-    events.push_back(std::move(crashEvent4));
-    events.push_back(std::move(crashEvent5));
-    events.push_back(std::move(crashEvent6));
-    events.push_back(std::move(crashEvent7));
-    events.push_back(std::move(crashEvent8));
-    events.push_back(std::move(crashEvent9));
-    events.push_back(std::move(crashEvent10));
-    events.push_back(std::move(screenTurnedOnEvent));
-    events.push_back(std::move(screenTurnedOffEvent));
-    events.push_back(std::move(screenTurnedOnEvent2));
-    events.push_back(std::move(syncOnEvent1));
-    events.push_back(std::move(syncOffEvent1));
-    events.push_back(std::move(syncOnEvent2));
-    events.push_back(std::move(moveToBackgroundEvent1));
-    events.push_back(std::move(moveToForegroundEvent1));
-    events.push_back(std::move(moveToBackgroundEvent2));
-    events.push_back(std::move(moveToForegroundEvent2));
-
-    sortLogEventsByTimestamp(&events);
-
-    for (const auto& event : events) {
-        processor->OnLogEvent(event.get());
-    }
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true, ADB_DUMP,
-                            FAST, &buffer);
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(reports.reports_size(), 1);
-    ASSERT_EQ(reports.reports(0).metrics_size(), 1);
-    ASSERT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
-    ASSERT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 1);
-    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(), util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
-    ASSERT_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);
-    EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid);
-}
-
-TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks2) {
-    auto config = CreateStatsdConfig();
-    uint64_t bucketStartTimeNs = 10000000000;
-    uint64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-
-    ConfigKey cfgKey;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-
-    int appUid = 123;
-    auto crashEvent1 = CreateAppCrashEvent(bucketStartTimeNs + 1, appUid);
-    auto crashEvent2 = CreateAppCrashEvent(bucketStartTimeNs + 201, appUid);
-    auto crashEvent3 = CreateAppCrashEvent(bucketStartTimeNs + 2 * bucketSizeNs - 101, appUid);
-
-    auto crashEvent4 = CreateAppCrashEvent(bucketStartTimeNs + 51, appUid);
-    auto crashEvent5 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 299, appUid);
-    auto crashEvent6 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 2001, appUid);
-
-    auto crashEvent7 = CreateAppCrashEvent(bucketStartTimeNs + 16, appUid);
-    auto crashEvent8 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 249, appUid);
-
-    auto crashEvent9 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 351, appUid);
-    auto crashEvent10 = CreateAppCrashEvent(bucketStartTimeNs + 2 * bucketSizeNs - 2, appUid);
-
-    auto screenTurnedOnEvent = CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 2, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-    auto screenTurnedOffEvent = CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 200, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
-    auto screenTurnedOnEvent2 =
-            CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs - 100,
-                                          android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-
-    std::vector<int> attributionUids = {appUid, appUid + 1};
-    std::vector<string> attributionTags = {"App1", "GMSCoreModule1"};
-
-    auto syncOnEvent1 = CreateSyncStartEvent(bucketStartTimeNs + 50, attributionUids,
-                                             attributionTags, "ReadEmail");
-    auto syncOffEvent1 = CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 300, attributionUids,
-                                            attributionTags, "ReadEmail");
-    auto syncOnEvent2 = CreateSyncStartEvent(bucketStartTimeNs + bucketSizeNs + 2000,
-                                             attributionUids, attributionTags, "ReadDoc");
-
-    auto moveToBackgroundEvent1 = CreateMoveToBackgroundEvent(bucketStartTimeNs + 15, appUid);
-    auto moveToForegroundEvent1 =
-            CreateMoveToForegroundEvent(bucketStartTimeNs + bucketSizeNs + 250, appUid);
-
-    auto moveToBackgroundEvent2 =
-            CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 350, appUid);
-    auto moveToForegroundEvent2 =
-            CreateMoveToForegroundEvent(bucketStartTimeNs + 2 * bucketSizeNs - 1, appUid);
-
-    /*
-                    bucket #1                               bucket #2
-
-
-       |      |   |  |                      |   |          |        |   |   |     (crashEvents)
-    |-------------------------------------|-----------------------------------|---------
-
-             |                                           |                        (MoveToBkground)
-
-                                             |                               |    (MoveToForeground)
-
-                |                                                 |                (SyncIsOn)
-                                                  |                                (SyncIsOff)
-          |                                                               |        (ScreenIsOn)
-                   |                                                               (ScreenIsOff)
-    */
-    std::vector<std::unique_ptr<LogEvent>> events;
-    events.push_back(std::move(crashEvent1));
-    events.push_back(std::move(crashEvent2));
-    events.push_back(std::move(crashEvent3));
-    events.push_back(std::move(crashEvent4));
-    events.push_back(std::move(crashEvent5));
-    events.push_back(std::move(crashEvent6));
-    events.push_back(std::move(crashEvent7));
-    events.push_back(std::move(crashEvent8));
-    events.push_back(std::move(crashEvent9));
-    events.push_back(std::move(crashEvent10));
-    events.push_back(std::move(screenTurnedOnEvent));
-    events.push_back(std::move(screenTurnedOffEvent));
-    events.push_back(std::move(screenTurnedOnEvent2));
-    events.push_back(std::move(syncOnEvent1));
-    events.push_back(std::move(syncOffEvent1));
-    events.push_back(std::move(syncOnEvent2));
-    events.push_back(std::move(moveToBackgroundEvent1));
-    events.push_back(std::move(moveToForegroundEvent1));
-    events.push_back(std::move(moveToBackgroundEvent2));
-    events.push_back(std::move(moveToForegroundEvent2));
-
-    sortLogEventsByTimestamp(&events);
-
-    for (const auto& event : events) {
-        processor->OnLogEvent(event.get());
-    }
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true, ADB_DUMP,
-                            FAST, &buffer);
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(reports.reports_size(), 1);
-    ASSERT_EQ(reports.reports(0).metrics_size(), 1);
-    ASSERT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
-    ASSERT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 2);
-    EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
-    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(), util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
-    ASSERT_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);
-    EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid);
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
deleted file mode 100644
index c03b925..0000000
--- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
+++ /dev/null
@@ -1,433 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <android/binder_ibinder.h>
-#include <android/binder_interface_utils.h>
-#include <gtest/gtest.h>
-
-#include <vector>
-
-#include "src/StatsLogProcessor.h"
-#include "src/StatsService.h"
-#include "src/stats_log_util.h"
-#include "tests/statsd_test_util.h"
-
-using::ndk::SharedRefBase;
-using std::shared_ptr;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-#ifdef __ANDROID__
-namespace {
-const string kApp1 = "app1.sharing.1";
-const int kConfigKey = 789130123;  // Randomly chosen to avoid collisions with existing configs.
-const int kCallingUid = 0; // Randomly chosen
-
-void SendConfig(shared_ptr<StatsService>& service, const StatsdConfig& config) {
-    string str;
-    config.SerializeToString(&str);
-    std::vector<uint8_t> configAsVec(str.begin(), str.end());
-    service->addConfiguration(kConfigKey, configAsVec, kCallingUid);
-}
-
-ConfigMetricsReport GetReports(sp<StatsLogProcessor> processor, int64_t timestamp,
-                               bool include_current = false) {
-    vector<uint8_t> output;
-    ConfigKey configKey(AIBinder_getCallingUid(), kConfigKey);
-    processor->onDumpReport(configKey, timestamp, include_current /* include_current_bucket*/,
-                            true /* erase_data */, ADB_DUMP, NO_TIME_CONSTRAINTS, &output);
-    ConfigMetricsReportList reports;
-    reports.ParseFromArray(output.data(), output.size());
-    EXPECT_EQ(1, reports.reports_size());
-    return reports.reports(kCallingUid);
-}
-
-StatsdConfig MakeConfig() {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-
-    auto appCrashMatcher = CreateProcessCrashAtomMatcher();
-    *config.add_atom_matcher() = appCrashMatcher;
-    auto countMetric = config.add_count_metric();
-    countMetric->set_id(StringToId("AppCrashes"));
-    countMetric->set_what(appCrashMatcher.id());
-    countMetric->set_bucket(FIVE_MINUTES);
-    return config;
-}
-
-StatsdConfig MakeValueMetricConfig(int64_t minTime) {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-    config.add_default_pull_packages("AID_ROOT");  // Fake puller is registered with root.
-
-    auto pulledAtomMatcher =
-            CreateSimpleAtomMatcher("TestMatcher", util::SUBSYSTEM_SLEEP_STATE);
-    *config.add_atom_matcher() = pulledAtomMatcher;
-    *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
-
-    auto valueMetric = config.add_value_metric();
-    valueMetric->set_id(123456);
-    valueMetric->set_what(pulledAtomMatcher.id());
-    *valueMetric->mutable_value_field() =
-            CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
-    *valueMetric->mutable_dimensions_in_what() =
-            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);
-    valueMetric->set_skip_zero_diff_output(false);
-    return config;
-}
-
-StatsdConfig MakeGaugeMetricConfig(int64_t minTime) {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-    config.add_default_pull_packages("AID_ROOT");  // Fake puller is registered with root.
-
-    auto pulledAtomMatcher =
-                CreateSimpleAtomMatcher("TestMatcher", util::SUBSYSTEM_SLEEP_STATE);
-    *config.add_atom_matcher() = pulledAtomMatcher;
-    *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
-
-    auto gaugeMetric = config.add_gauge_metric();
-    gaugeMetric->set_id(123456);
-    gaugeMetric->set_what(pulledAtomMatcher.id());
-    gaugeMetric->mutable_gauge_fields_filter()->set_include_all(true);
-    *gaugeMetric->mutable_dimensions_in_what() =
-            CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {1 /* subsystem name */});
-    gaugeMetric->set_bucket(FIVE_MINUTES);
-    gaugeMetric->set_min_bucket_size_nanos(minTime);
-    return config;
-}
-}  // anonymous namespace
-
-TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit) {
-    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-    SendConfig(service, MakeConfig());
-    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
-                                             // initialized with.
-
-    service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get());
-    service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 2, 100).get());
-
-    ConfigMetricsReport report = GetReports(service->mProcessor, start + 3);
-    // Expect no metrics since the bucket has not finished yet.
-    ASSERT_EQ(1, report.metrics_size());
-    ASSERT_EQ(0, report.metrics(0).count_metrics().data_size());
-}
-
-TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) {
-    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-    SendConfig(service, MakeConfig());
-    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
-                                             // initialized with.
-
-    // Force the uidmap to update at timestamp 2.
-    service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get());
-    // This is a new installation, so there shouldn't be a split (should be same as the without
-    // split case).
-    service->mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"),
-                                String16(""));
-    // Goes into the second bucket.
-    service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 3, 100).get());
-
-    ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
-    ASSERT_EQ(1, report.metrics_size());
-    ASSERT_EQ(0, report.metrics(0).count_metrics().data_size());
-}
-
-TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) {
-    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-    SendConfig(service, MakeConfig());
-    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
-                                             // initialized with.
-    service->mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())},
-                                {String16("")});
-
-    // Force the uidmap to update at timestamp 2.
-    service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get());
-    service->mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"),
-                                String16(""));
-    // Goes into the second bucket.
-    service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 3, 100).get());
-
-    ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
-    backfillStartEndTimestamp(&report);
-
-    ASSERT_EQ(1, report.metrics_size());
-    ASSERT_EQ(1, report.metrics(0).count_metrics().data_size());
-    ASSERT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info_size());
-    EXPECT_TRUE(report.metrics(0)
-                        .count_metrics()
-                        .data(0)
-                        .bucket_info(0)
-                        .has_start_bucket_elapsed_nanos());
-    EXPECT_TRUE(report.metrics(0)
-                        .count_metrics()
-                        .data(0)
-                        .bucket_info(0)
-                        .has_end_bucket_elapsed_nanos());
-    EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
-}
-
-TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) {
-    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-    SendConfig(service, MakeConfig());
-    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
-                                             // initialized with.
-    service->mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())},
-                                {String16("")});
-
-    // Force the uidmap to update at timestamp 2.
-    service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get());
-    service->mUidMap->removeApp(start + 2, String16(kApp1.c_str()), 1);
-    // Goes into the second bucket.
-    service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 3, 100).get());
-
-    ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
-    backfillStartEndTimestamp(&report);
-
-    ASSERT_EQ(1, report.metrics_size());
-    ASSERT_EQ(1, report.metrics(0).count_metrics().data_size());
-    ASSERT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info_size());
-    EXPECT_TRUE(report.metrics(0)
-                        .count_metrics()
-                        .data(0)
-                        .bucket_info(0)
-                        .has_start_bucket_elapsed_nanos());
-    EXPECT_TRUE(report.metrics(0)
-                        .count_metrics()
-                        .data(0)
-                        .bucket_info(0)
-                        .has_end_bucket_elapsed_nanos());
-    EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
-}
-
-TEST(PartialBucketE2eTest, TestCountMetricSplitOnBoot) {
-    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-    SendConfig(service, MakeConfig());
-    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
-                                             // initialized with.
-
-    // Goes into the first bucket
-    service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + NS_PER_SEC, 100).get());
-    int64_t bootCompleteTimeNs = start + 2 * NS_PER_SEC;
-    service->mProcessor->onStatsdInitCompleted(bootCompleteTimeNs);
-    // Goes into the second bucket.
-    service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 3 * NS_PER_SEC, 100).get());
-
-    ConfigMetricsReport report = GetReports(service->mProcessor, start + 4 * NS_PER_SEC);
-    backfillStartEndTimestamp(&report);
-
-    ASSERT_EQ(1, report.metrics_size());
-    ASSERT_EQ(1, report.metrics(0).count_metrics().data_size());
-    ASSERT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info_size());
-    EXPECT_TRUE(report.metrics(0)
-                        .count_metrics()
-                        .data(0)
-                        .bucket_info(0)
-                        .has_start_bucket_elapsed_nanos());
-    EXPECT_EQ(MillisToNano(NanoToMillis(bootCompleteTimeNs)),
-              report.metrics(0).count_metrics().data(0).bucket_info(0).end_bucket_elapsed_nanos());
-    EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
-}
-
-TEST(PartialBucketE2eTest, TestValueMetricWithoutMinPartialBucket) {
-    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-    service->mPullerManager->RegisterPullAtomCallback(
-            /*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(""));
-    SendConfig(service, MakeValueMetricConfig(0));
-    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
-                                             // initialized with.
-
-    service->mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
-    int64_t appUpgradeTimeNs = 5 * 60 * NS_PER_SEC + start + 2 * NS_PER_SEC;
-    service->mUidMap->updateApp(appUpgradeTimeNs, String16(kApp1.c_str()), 1, 2, String16("v2"),
-                                String16(""));
-
-    ConfigMetricsReport report =
-            GetReports(service->mProcessor, 5 * 60 * NS_PER_SEC + start + 100 * NS_PER_SEC);
-    backfillStartEndTimestamp(&report);
-
-    ASSERT_EQ(1, report.metrics_size());
-    ASSERT_EQ(0, report.metrics(0).value_metrics().skipped_size());
-
-    // The fake subsystem state sleep puller returns two atoms.
-    ASSERT_EQ(2, report.metrics(0).value_metrics().data_size());
-    ASSERT_EQ(2, report.metrics(0).value_metrics().data(0).bucket_info_size());
-    EXPECT_EQ(MillisToNano(NanoToMillis(appUpgradeTimeNs)),
-              report.metrics(0).value_metrics().data(0).bucket_info(1).end_bucket_elapsed_nanos());
-}
-
-TEST(PartialBucketE2eTest, TestValueMetricWithMinPartialBucket) {
-    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-    service->mPullerManager->RegisterPullAtomCallback(
-            /*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(""));
-    SendConfig(service, MakeValueMetricConfig(60 * NS_PER_SEC /* One minute */));
-    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
-                                             // initialized with.
-
-    const int64_t endSkipped = 5 * 60 * NS_PER_SEC + start + 2 * NS_PER_SEC;
-    service->mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
-    service->mUidMap->updateApp(endSkipped, String16(kApp1.c_str()), 1, 2, String16("v2"),
-                               String16(""));
-
-    ConfigMetricsReport report =
-            GetReports(service->mProcessor, 5 * 60 * NS_PER_SEC + start + 100 * NS_PER_SEC);
-    backfillStartEndTimestamp(&report);
-
-    ASSERT_EQ(1, report.metrics_size());
-    ASSERT_EQ(1, report.metrics(0).value_metrics().skipped_size());
-    EXPECT_TRUE(report.metrics(0).value_metrics().skipped(0).has_start_bucket_elapsed_nanos());
-    // Can't test the start time since it will be based on the actual time when the pulling occurs.
-    EXPECT_EQ(MillisToNano(NanoToMillis(endSkipped)),
-              report.metrics(0).value_metrics().skipped(0).end_bucket_elapsed_nanos());
-
-    ASSERT_EQ(2, report.metrics(0).value_metrics().data_size());
-    ASSERT_EQ(1, report.metrics(0).value_metrics().data(0).bucket_info_size());
-}
-
-TEST(PartialBucketE2eTest, TestValueMetricOnBootWithoutMinPartialBucket) {
-    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-    // Initial pull will fail since puller is not registered.
-    SendConfig(service, MakeValueMetricConfig(0));
-    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
-                                             // initialized with.
-
-    service->mPullerManager->RegisterPullAtomCallback(
-            /*uid=*/0, util::SUBSYSTEM_SLEEP_STATE, NS_PER_SEC, NS_PER_SEC * 10, {},
-            SharedRefBase::make<FakeSubsystemSleepCallback>());
-
-    int64_t bootCompleteTimeNs = start + NS_PER_SEC;
-    service->mProcessor->onStatsdInitCompleted(bootCompleteTimeNs);
-
-    service->mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
-
-    ConfigMetricsReport report = GetReports(service->mProcessor, 5 * 60 * NS_PER_SEC + start + 100);
-    backfillStartEndTimestamp(&report);
-
-    // First bucket is dropped due to the initial pull failing
-    ASSERT_EQ(1, report.metrics_size());
-    ASSERT_EQ(1, report.metrics(0).value_metrics().skipped_size());
-    EXPECT_EQ(MillisToNano(NanoToMillis(bootCompleteTimeNs)),
-              report.metrics(0).value_metrics().skipped(0).end_bucket_elapsed_nanos());
-
-    // The fake subsystem state sleep puller returns two atoms.
-    ASSERT_EQ(2, report.metrics(0).value_metrics().data_size());
-    ASSERT_EQ(1, report.metrics(0).value_metrics().data(0).bucket_info_size());
-    EXPECT_EQ(
-            MillisToNano(NanoToMillis(bootCompleteTimeNs)),
-            report.metrics(0).value_metrics().data(0).bucket_info(0).start_bucket_elapsed_nanos());
-}
-
-TEST(PartialBucketE2eTest, TestGaugeMetricWithoutMinPartialBucket) {
-    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-    service->mPullerManager->RegisterPullAtomCallback(
-            /*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(""));
-    SendConfig(service, MakeGaugeMetricConfig(0));
-    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
-                                             // initialized with.
-
-    service->mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
-    service->mUidMap->updateApp(5 * 60 * NS_PER_SEC + start + 2, String16(kApp1.c_str()), 1, 2,
-                               String16("v2"), String16(""));
-
-    ConfigMetricsReport report = GetReports(service->mProcessor, 5 * 60 * NS_PER_SEC + start + 100);
-    backfillStartEndTimestamp(&report);
-    ASSERT_EQ(1, report.metrics_size());
-    ASSERT_EQ(0, report.metrics(0).gauge_metrics().skipped_size());
-    // The fake subsystem state sleep puller returns two atoms.
-    ASSERT_EQ(2, report.metrics(0).gauge_metrics().data_size());
-    ASSERT_EQ(2, report.metrics(0).gauge_metrics().data(0).bucket_info_size());
-}
-
-TEST(PartialBucketE2eTest, TestGaugeMetricWithMinPartialBucket) {
-    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-    // Partial buckets don't occur when app is first installed.
-    service->mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
-    service->mPullerManager->RegisterPullAtomCallback(
-            /*uid=*/0, util::SUBSYSTEM_SLEEP_STATE, NS_PER_SEC, NS_PER_SEC * 10, {},
-            SharedRefBase::make<FakeSubsystemSleepCallback>());
-    SendConfig(service, MakeGaugeMetricConfig(60 * NS_PER_SEC /* One minute */));
-    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
-                                             // initialized with.
-
-    const int64_t endSkipped = 5 * 60 * NS_PER_SEC + start + 2;
-    service->mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
-    service->mUidMap->updateApp(endSkipped, String16(kApp1.c_str()), 1, 2, String16("v2"),
-                                String16(""));
-
-    ConfigMetricsReport report =
-            GetReports(service->mProcessor, 5 * 60 * NS_PER_SEC + start + 100 * NS_PER_SEC);
-    backfillStartEndTimestamp(&report);
-    ASSERT_EQ(1, report.metrics_size());
-    ASSERT_EQ(1, report.metrics(0).gauge_metrics().skipped_size());
-    // Can't test the start time since it will be based on the actual time when the pulling occurs.
-    EXPECT_TRUE(report.metrics(0).gauge_metrics().skipped(0).has_start_bucket_elapsed_nanos());
-    EXPECT_EQ(MillisToNano(NanoToMillis(endSkipped)),
-              report.metrics(0).gauge_metrics().skipped(0).end_bucket_elapsed_nanos());
-    ASSERT_EQ(2, report.metrics(0).gauge_metrics().data_size());
-    ASSERT_EQ(1, report.metrics(0).gauge_metrics().data(0).bucket_info_size());
-}
-
-TEST(PartialBucketE2eTest, TestGaugeMetricOnBootWithoutMinPartialBucket) {
-    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-    // Initial pull will fail since puller hasn't been registered.
-    SendConfig(service, MakeGaugeMetricConfig(0));
-    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
-                                             // initialized with.
-
-    service->mPullerManager->RegisterPullAtomCallback(
-            /*uid=*/0, util::SUBSYSTEM_SLEEP_STATE, NS_PER_SEC, NS_PER_SEC * 10, {},
-            SharedRefBase::make<FakeSubsystemSleepCallback>());
-
-    int64_t bootCompleteTimeNs = start + NS_PER_SEC;
-    service->mProcessor->onStatsdInitCompleted(bootCompleteTimeNs);
-
-    service->mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
-
-    ConfigMetricsReport report = GetReports(service->mProcessor, 5 * 60 * NS_PER_SEC + start + 100);
-    backfillStartEndTimestamp(&report);
-
-    ASSERT_EQ(1, report.metrics_size());
-    ASSERT_EQ(0, report.metrics(0).gauge_metrics().skipped_size());
-    // The fake subsystem state sleep puller returns two atoms.
-    ASSERT_EQ(2, report.metrics(0).gauge_metrics().data_size());
-    // No data in the first bucket, so nothing is reported
-    ASSERT_EQ(1, report.metrics(0).gauge_metrics().data(0).bucket_info_size());
-    EXPECT_EQ(
-            MillisToNano(NanoToMillis(bootCompleteTimeNs)),
-            report.metrics(0).gauge_metrics().data(0).bucket_info(0).start_bucket_elapsed_nanos());
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
deleted file mode 100644
index 4d39282..0000000
--- a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
+++ /dev/null
@@ -1,679 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <android/binder_interface_utils.h>
-#include <gtest/gtest.h>
-
-#include "src/StatsLogProcessor.h"
-#include "src/stats_log_util.h"
-#include "tests/statsd_test_util.h"
-
-#include <vector>
-
-using ::ndk::SharedRefBase;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-#ifdef __ANDROID__
-
-namespace {
-
-const int64_t metricId = 123456;
-
-StatsdConfig CreateStatsdConfig(bool useCondition = true) {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-    config.add_default_pull_packages("AID_ROOT");  // Fake puller is registered with root.
-    auto pulledAtomMatcher =
-            CreateSimpleAtomMatcher("TestMatcher", util::SUBSYSTEM_SLEEP_STATE);
-    *config.add_atom_matcher() = pulledAtomMatcher;
-    *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
-
-    auto screenIsOffPredicate = CreateScreenIsOffPredicate();
-    *config.add_predicate() = screenIsOffPredicate;
-
-    auto valueMetric = config.add_value_metric();
-    valueMetric->set_id(metricId);
-    valueMetric->set_what(pulledAtomMatcher.id());
-    if (useCondition) {
-        valueMetric->set_condition(screenIsOffPredicate.id());
-    }
-    *valueMetric->mutable_value_field() =
-            CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
-    *valueMetric->mutable_dimensions_in_what() =
-            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);
-    valueMetric->set_max_pull_delay_sec(INT_MAX);
-    return config;
-}
-
-StatsdConfig CreateStatsdConfigWithStates() {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");     // LogEvent defaults to UID of root.
-    config.add_default_pull_packages("AID_ROOT");  // Fake puller is registered with root.
-
-    auto pulledAtomMatcher = CreateSimpleAtomMatcher("TestMatcher", util::SUBSYSTEM_SLEEP_STATE);
-    *config.add_atom_matcher() = pulledAtomMatcher;
-    *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = CreateBatteryStateNoneMatcher();
-    *config.add_atom_matcher() = CreateBatteryStateUsbMatcher();
-
-    auto screenOnPredicate = CreateScreenIsOnPredicate();
-    *config.add_predicate() = screenOnPredicate;
-
-    auto screenOffPredicate = CreateScreenIsOffPredicate();
-    *config.add_predicate() = screenOffPredicate;
-
-    auto deviceUnpluggedPredicate = CreateDeviceUnpluggedPredicate();
-    *config.add_predicate() = deviceUnpluggedPredicate;
-
-    auto screenOnOnBatteryPredicate = config.add_predicate();
-    screenOnOnBatteryPredicate->set_id(StringToId("screenOnOnBatteryPredicate"));
-    screenOnOnBatteryPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
-    addPredicateToPredicateCombination(screenOnPredicate, screenOnOnBatteryPredicate);
-    addPredicateToPredicateCombination(deviceUnpluggedPredicate, screenOnOnBatteryPredicate);
-
-    auto screenOffOnBatteryPredicate = config.add_predicate();
-    screenOffOnBatteryPredicate->set_id(StringToId("ScreenOffOnBattery"));
-    screenOffOnBatteryPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
-    addPredicateToPredicateCombination(screenOffPredicate, screenOffOnBatteryPredicate);
-    addPredicateToPredicateCombination(deviceUnpluggedPredicate, screenOffOnBatteryPredicate);
-
-    const State screenState =
-            CreateScreenStateWithSimpleOnOffMap(/*screen on id=*/321, /*screen off id=*/123);
-    *config.add_state() = screenState;
-
-    // ValueMetricSubsystemSleepWhileScreenOnOnBattery
-    auto valueMetric1 = config.add_value_metric();
-    valueMetric1->set_id(metricId);
-    valueMetric1->set_what(pulledAtomMatcher.id());
-    valueMetric1->set_condition(screenOnOnBatteryPredicate->id());
-    *valueMetric1->mutable_value_field() =
-            CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
-    valueMetric1->set_bucket(FIVE_MINUTES);
-    valueMetric1->set_use_absolute_value_on_reset(true);
-    valueMetric1->set_skip_zero_diff_output(false);
-    valueMetric1->set_max_pull_delay_sec(INT_MAX);
-
-    // ValueMetricSubsystemSleepWhileScreenOffOnBattery
-    ValueMetric* valueMetric2 = config.add_value_metric();
-    valueMetric2->set_id(StringToId("ValueMetricSubsystemSleepWhileScreenOffOnBattery"));
-    valueMetric2->set_what(pulledAtomMatcher.id());
-    valueMetric2->set_condition(screenOffOnBatteryPredicate->id());
-    *valueMetric2->mutable_value_field() =
-            CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
-    valueMetric2->set_bucket(FIVE_MINUTES);
-    valueMetric2->set_use_absolute_value_on_reset(true);
-    valueMetric2->set_skip_zero_diff_output(false);
-    valueMetric2->set_max_pull_delay_sec(INT_MAX);
-
-    // ValueMetricSubsystemSleepWhileOnBatterySliceScreen
-    ValueMetric* valueMetric3 = config.add_value_metric();
-    valueMetric3->set_id(StringToId("ValueMetricSubsystemSleepWhileOnBatterySliceScreen"));
-    valueMetric3->set_what(pulledAtomMatcher.id());
-    valueMetric3->set_condition(deviceUnpluggedPredicate.id());
-    *valueMetric3->mutable_value_field() =
-            CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
-    valueMetric3->add_slice_by_state(screenState.id());
-    valueMetric3->set_bucket(FIVE_MINUTES);
-    valueMetric3->set_use_absolute_value_on_reset(true);
-    valueMetric3->set_skip_zero_diff_output(false);
-    valueMetric3->set_max_pull_delay_sec(INT_MAX);
-    return config;
-}
-
-}  // namespace
-
-/**
- * Tests the initial condition and condition after the first log events for
- * value metrics with either a combination condition or simple condition.
- *
- * Metrics should be initialized with condition kUnknown (given that the
- * predicate is using the default InitialValue of UNKNOWN). The condition should
- * be updated to either kFalse or kTrue if a condition event is logged for all
- * children conditions.
- */
-TEST(ValueMetricE2eTest, TestInitialConditionChanges) {
-    StatsdConfig config = CreateStatsdConfigWithStates();
-    int64_t baseTimeNs = getElapsedRealtimeNs();
-    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
-
-    ConfigKey cfgKey;
-    int32_t tagId = util::SUBSYSTEM_SLEEP_STATE;
-    auto processor =
-            CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-                                    SharedRefBase::make<FakeSubsystemSleepCallback>(), tagId);
-
-    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-    EXPECT_EQ(3, metricsManager->mAllMetricProducers.size());
-
-    // Combination condition metric - screen on and device unplugged
-    sp<MetricProducer> metricProducer1 = metricsManager->mAllMetricProducers[0];
-    // Simple condition metric - device unplugged
-    sp<MetricProducer> metricProducer2 = metricsManager->mAllMetricProducers[2];
-
-    EXPECT_EQ(ConditionState::kUnknown, metricProducer1->mCondition);
-    EXPECT_EQ(ConditionState::kUnknown, metricProducer2->mCondition);
-
-    auto screenOnEvent =
-            CreateScreenStateChangedEvent(configAddedTimeNs + 30, android::view::DISPLAY_STATE_ON);
-    processor->OnLogEvent(screenOnEvent.get());
-    EXPECT_EQ(ConditionState::kUnknown, metricProducer1->mCondition);
-    EXPECT_EQ(ConditionState::kUnknown, metricProducer2->mCondition);
-
-    auto screenOffEvent =
-            CreateScreenStateChangedEvent(configAddedTimeNs + 40, android::view::DISPLAY_STATE_OFF);
-    processor->OnLogEvent(screenOffEvent.get());
-    EXPECT_EQ(ConditionState::kUnknown, metricProducer1->mCondition);
-    EXPECT_EQ(ConditionState::kUnknown, metricProducer2->mCondition);
-
-    auto pluggedUsbEvent = CreateBatteryStateChangedEvent(
-            configAddedTimeNs + 50, BatteryPluggedStateEnum::BATTERY_PLUGGED_USB);
-    processor->OnLogEvent(pluggedUsbEvent.get());
-    EXPECT_EQ(ConditionState::kFalse, metricProducer1->mCondition);
-    EXPECT_EQ(ConditionState::kFalse, metricProducer2->mCondition);
-
-    auto pluggedNoneEvent = CreateBatteryStateChangedEvent(
-            configAddedTimeNs + 70, BatteryPluggedStateEnum::BATTERY_PLUGGED_NONE);
-    processor->OnLogEvent(pluggedNoneEvent.get());
-    EXPECT_EQ(ConditionState::kFalse, metricProducer1->mCondition);
-    EXPECT_EQ(ConditionState::kTrue, metricProducer2->mCondition);
-}
-
-TEST(ValueMetricE2eTest, TestPulledEvents) {
-    auto config = CreateStatsdConfig();
-    int64_t baseTimeNs = getElapsedRealtimeNs();
-    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
-
-    ConfigKey cfgKey;
-    auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-                                             SharedRefBase::make<FakeSubsystemSleepCallback>(),
-                                             util::SUBSYSTEM_SLEEP_STATE);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-    processor->mPullerManager->ForceClearPullerCache();
-
-    int startBucketNum = processor->mMetricsManagers.begin()
-                                 ->second->mAllMetricProducers[0]
-                                 ->getCurrentBucketNum();
-    EXPECT_GT(startBucketNum, (int64_t)0);
-
-    // When creating the config, the value metric producer should register the alarm at the
-    // end of the current bucket.
-    ASSERT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-    EXPECT_EQ(bucketSizeNs,
-              processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-    int64_t& expectedPullTimeNs =
-            processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
-
-    auto screenOffEvent =
-            CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF);
-    processor->OnLogEvent(screenOffEvent.get());
-
-    auto screenOnEvent =
-            CreateScreenStateChangedEvent(configAddedTimeNs + 65, android::view::DISPLAY_STATE_ON);
-    processor->OnLogEvent(screenOnEvent.get());
-
-    screenOffEvent =
-            CreateScreenStateChangedEvent(configAddedTimeNs + 75, android::view::DISPLAY_STATE_OFF);
-    processor->OnLogEvent(screenOffEvent.get());
-
-    // Pulling alarm arrives on time and reset the sequential pulling alarm.
-    processor->informPullAlarmFired(expectedPullTimeNs + 1);
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, expectedPullTimeNs);
-
-    processor->informPullAlarmFired(expectedPullTimeNs + 1);
-
-    screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 2 * bucketSizeNs + 15,
-                                                  android::view::DISPLAY_STATE_ON);
-    processor->OnLogEvent(screenOnEvent.get());
-
-    processor->informPullAlarmFired(expectedPullTimeNs + 1);
-
-    processor->informPullAlarmFired(expectedPullTimeNs + 1);
-
-    screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 4 * bucketSizeNs + 11,
-                                                   android::view::DISPLAY_STATE_OFF);
-    processor->OnLogEvent(screenOffEvent.get());
-
-    processor->informPullAlarmFired(expectedPullTimeNs + 1);
-
-    processor->informPullAlarmFired(expectedPullTimeNs + 1);
-
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
-                            ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-    StatsLogReport::ValueMetricDataWrapper valueMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
-    ASSERT_GT((int)valueMetrics.data_size(), 1);
-
-    auto data = valueMetrics.data(0);
-    EXPECT_EQ(util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-    // We have 4 buckets, the first one was incomplete since the condition was unknown.
-    ASSERT_EQ(4, data.bucket_info_size());
-
-    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-    ASSERT_EQ(1, data.bucket_info(0).values_size());
-
-    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
-    ASSERT_EQ(1, data.bucket_info(1).values_size());
-
-    EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
-    ASSERT_EQ(1, data.bucket_info(2).values_size());
-
-    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos());
-    ASSERT_EQ(1, data.bucket_info(3).values_size());
-}
-
-TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm) {
-    auto config = CreateStatsdConfig();
-    int64_t baseTimeNs = getElapsedRealtimeNs();
-    // 10 mins == 2 bucket durations.
-    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
-
-    ConfigKey cfgKey;
-    auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-                                             SharedRefBase::make<FakeSubsystemSleepCallback>(),
-                                             util::SUBSYSTEM_SLEEP_STATE);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-    processor->mPullerManager->ForceClearPullerCache();
-
-    int startBucketNum = processor->mMetricsManagers.begin()
-                                 ->second->mAllMetricProducers[0]
-                                 ->getCurrentBucketNum();
-    EXPECT_GT(startBucketNum, (int64_t)0);
-
-    // When creating the config, the value metric producer should register the alarm at the
-    // end of the current bucket.
-    ASSERT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-    EXPECT_EQ(bucketSizeNs,
-              processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-    int64_t& expectedPullTimeNs =
-            processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
-
-    // Screen off/on/off events.
-    auto screenOffEvent =
-            CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF);
-    processor->OnLogEvent(screenOffEvent.get());
-
-    auto screenOnEvent =
-            CreateScreenStateChangedEvent(configAddedTimeNs + 65, android::view::DISPLAY_STATE_ON);
-    processor->OnLogEvent(screenOnEvent.get());
-
-    screenOffEvent =
-            CreateScreenStateChangedEvent(configAddedTimeNs + 75, android::view::DISPLAY_STATE_OFF);
-    processor->OnLogEvent(screenOffEvent.get());
-
-    // Pulling alarm arrives late by 2 buckets and 1 ns. 2 buckets late is too far away in the
-    // future, data will be skipped.
-    processor->informPullAlarmFired(expectedPullTimeNs + 2 * bucketSizeNs + 1);
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, expectedPullTimeNs);
-
-    // This screen state change will start a new bucket.
-    screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 4 * bucketSizeNs + 65,
-                                                  android::view::DISPLAY_STATE_ON);
-    processor->OnLogEvent(screenOnEvent.get());
-
-    // The alarm is delayed but we already created a bucket thanks to the screen state condition.
-    // This bucket does not have to be skipped since the alarm arrives in time for the next bucket.
-    processor->informPullAlarmFired(expectedPullTimeNs + bucketSizeNs + 21);
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, expectedPullTimeNs);
-
-    screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 6 * bucketSizeNs + 31,
-                                                   android::view::DISPLAY_STATE_OFF);
-    processor->OnLogEvent(screenOffEvent.get());
-
-    processor->informPullAlarmFired(expectedPullTimeNs + bucketSizeNs + 21);
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 8 * bucketSizeNs, expectedPullTimeNs);
-
-    processor->informPullAlarmFired(expectedPullTimeNs + 1);
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 9 * bucketSizeNs, expectedPullTimeNs);
-
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, configAddedTimeNs + 9 * bucketSizeNs + 10, false, true,
-                            ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-    StatsLogReport::ValueMetricDataWrapper valueMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
-    ASSERT_GT((int)valueMetrics.data_size(), 1);
-
-    auto data = valueMetrics.data(0);
-    EXPECT_EQ(util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-    ASSERT_EQ(3, data.bucket_info_size());
-
-    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-    ASSERT_EQ(1, data.bucket_info(0).values_size());
-
-    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
-    ASSERT_EQ(1, data.bucket_info(1).values_size());
-
-    EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 10 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
-    ASSERT_EQ(1, data.bucket_info(2).values_size());
-}
-
-TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation) {
-    auto config = CreateStatsdConfig(false);
-    int64_t baseTimeNs = getElapsedRealtimeNs();
-    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
-
-    auto batterySaverStartMatcher = CreateBatterySaverModeStartAtomMatcher();
-    *config.add_atom_matcher() = batterySaverStartMatcher;
-    const int64_t ttlNs = 2 * bucketSizeNs;  // Two buckets.
-    auto metric_activation = config.add_metric_activation();
-    metric_activation->set_metric_id(metricId);
-    metric_activation->set_activation_type(ACTIVATE_IMMEDIATELY);
-    auto event_activation = metric_activation->add_event_activation();
-    event_activation->set_atom_matcher_id(batterySaverStartMatcher.id());
-    event_activation->set_ttl_seconds(ttlNs / 1000000000);
-
-    ConfigKey cfgKey;
-    auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-                                             SharedRefBase::make<FakeSubsystemSleepCallback>(),
-                                             util::SUBSYSTEM_SLEEP_STATE);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-    processor->mPullerManager->ForceClearPullerCache();
-
-    int startBucketNum = processor->mMetricsManagers.begin()
-                                 ->second->mAllMetricProducers[0]
-                                 ->getCurrentBucketNum();
-    EXPECT_GT(startBucketNum, (int64_t)0);
-    EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-
-    // When creating the config, the value metric producer should register the alarm at the
-    // end of the current bucket.
-    ASSERT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-    EXPECT_EQ(bucketSizeNs,
-              processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-    int64_t& expectedPullTimeNs =
-            processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
-
-    // Pulling alarm arrives on time and reset the sequential pulling alarm.
-    processor->informPullAlarmFired(expectedPullTimeNs + 1);  // 15 mins + 1 ns.
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, expectedPullTimeNs);
-    EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-
-    // Activate the metric. A pull occurs here
-    const int64_t activationNs = configAddedTimeNs + bucketSizeNs + (2 * 1000 * 1000);  // 2 millis.
-    auto batterySaverOnEvent = CreateBatterySaverOnEvent(activationNs);
-    processor->OnLogEvent(batterySaverOnEvent.get());  // 15 mins + 2 ms.
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-
-    processor->informPullAlarmFired(expectedPullTimeNs + 1);  // 20 mins + 1 ns.
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, expectedPullTimeNs);
-
-    processor->informPullAlarmFired(expectedPullTimeNs + 2);  // 25 mins + 2 ns.
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, expectedPullTimeNs);
-
-    // Create random event to deactivate metric.
-    auto deactivationEvent = CreateScreenBrightnessChangedEvent(activationNs + ttlNs + 1, 50);
-    processor->OnLogEvent(deactivationEvent.get());
-    EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-
-    processor->informPullAlarmFired(expectedPullTimeNs + 3);
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, expectedPullTimeNs);
-
-    processor->informPullAlarmFired(expectedPullTimeNs + 4);
-    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, expectedPullTimeNs);
-
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
-                            ADB_DUMP, FAST, &buffer);
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(1, reports.reports_size());
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-    StatsLogReport::ValueMetricDataWrapper valueMetrics;
-    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
-    ASSERT_GT((int)valueMetrics.data_size(), 0);
-
-    auto data = valueMetrics.data(0);
-    EXPECT_EQ(util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
-    ASSERT_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());
-    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-    // We have 2 full buckets, the two surrounding the activation are dropped.
-    ASSERT_EQ(2, data.bucket_info_size());
-
-    auto bucketInfo = data.bucket_info(0);
-    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-    ASSERT_EQ(1, bucketInfo.values_size());
-
-    bucketInfo = data.bucket_info(1);
-    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
-    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-    ASSERT_EQ(1, bucketInfo.values_size());
-}
-
-/**
- * Test initialization of a simple value metric that is sliced by a state.
- *
- * ValueCpuUserTimePerScreenState
- */
-TEST(ValueMetricE2eTest, TestInitWithSlicedState) {
-    // Create config.
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-
-    auto pulledAtomMatcher =
-            CreateSimpleAtomMatcher("TestMatcher", util::SUBSYSTEM_SLEEP_STATE);
-    *config.add_atom_matcher() = pulledAtomMatcher;
-
-    auto screenState = CreateScreenState();
-    *config.add_state() = screenState;
-
-    // Create value metric that slices by screen state without a map.
-    int64_t metricId = 123456;
-    auto valueMetric = config.add_value_metric();
-    valueMetric->set_id(metricId);
-    valueMetric->set_bucket(TimeUnit::FIVE_MINUTES);
-    valueMetric->set_what(pulledAtomMatcher.id());
-    *valueMetric->mutable_value_field() =
-            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);
-
-    // Initialize StatsLogProcessor.
-    const uint64_t bucketStartTimeNs = 10000000000;  // 0:10
-    const uint64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000LL;
-    int uid = 12345;
-    int64_t cfgId = 98765;
-    ConfigKey cfgKey(uid, cfgId);
-
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-
-    // Check that StateTrackers were initialized correctly.
-    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
-
-    // Check that ValueMetricProducer was initialized correctly.
-    ASSERT_EQ(1U, processor->mMetricsManagers.size());
-    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-    ASSERT_EQ(1, metricsManager->mAllMetricProducers.size());
-    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-    ASSERT_EQ(1, metricProducer->mSlicedStateAtoms.size());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, metricProducer->mSlicedStateAtoms.at(0));
-    ASSERT_EQ(0, metricProducer->mStateGroupMap.size());
-}
-
-/**
- * Test initialization of a value metric that is sliced by state and has
- * dimensions_in_what.
- *
- * ValueCpuUserTimePerUidPerUidProcessState
- */
-TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithDimensions) {
-    // Create config.
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-
-    auto cpuTimePerUidMatcher =
-            CreateSimpleAtomMatcher("CpuTimePerUidMatcher", util::CPU_TIME_PER_UID);
-    *config.add_atom_matcher() = cpuTimePerUidMatcher;
-
-    auto uidProcessState = CreateUidProcessState();
-    *config.add_state() = uidProcessState;
-
-    // Create value metric that slices by screen state with a complete map.
-    int64_t metricId = 123456;
-    auto valueMetric = config.add_value_metric();
-    valueMetric->set_id(metricId);
-    valueMetric->set_bucket(TimeUnit::FIVE_MINUTES);
-    valueMetric->set_what(cpuTimePerUidMatcher.id());
-    *valueMetric->mutable_value_field() =
-            CreateDimensions(util::CPU_TIME_PER_UID, {2 /* user_time_micros */});
-    *valueMetric->mutable_dimensions_in_what() =
-            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(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);
-
-    // Initialize StatsLogProcessor.
-    const uint64_t bucketStartTimeNs = 10000000000;  // 0:10
-    int uid = 12345;
-    int64_t cfgId = 98765;
-    ConfigKey cfgKey(uid, cfgId);
-
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-
-    // Check that StateTrackers were initialized correctly.
-    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
-
-    // Check that ValueMetricProducer was initialized correctly.
-    ASSERT_EQ(1U, processor->mMetricsManagers.size());
-    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-    EXPECT_TRUE(metricsManager->isConfigValid());
-    ASSERT_EQ(1, metricsManager->mAllMetricProducers.size());
-    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-    ASSERT_EQ(1, metricProducer->mSlicedStateAtoms.size());
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, metricProducer->mSlicedStateAtoms.at(0));
-    ASSERT_EQ(0, metricProducer->mStateGroupMap.size());
-}
-
-/**
- * Test initialization of a value metric that is sliced by state and has
- * dimensions_in_what.
- *
- * ValueCpuUserTimePerUidPerUidProcessState
- */
-TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithIncorrectDimensions) {
-    // Create config.
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-
-    auto cpuTimePerUidMatcher =
-            CreateSimpleAtomMatcher("CpuTimePerUidMatcher", util::CPU_TIME_PER_UID);
-    *config.add_atom_matcher() = cpuTimePerUidMatcher;
-
-    auto uidProcessState = CreateUidProcessState();
-    *config.add_state() = uidProcessState;
-
-    // Create value metric that slices by screen state with a complete map.
-    int64_t metricId = 123456;
-    auto valueMetric = config.add_value_metric();
-    valueMetric->set_id(metricId);
-    valueMetric->set_bucket(TimeUnit::FIVE_MINUTES);
-    valueMetric->set_what(cpuTimePerUidMatcher.id());
-    *valueMetric->mutable_value_field() =
-            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(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);
-
-    // Initialize StatsLogProcessor.
-    const uint64_t bucketStartTimeNs = 10000000000;  // 0:10
-    int uid = 12345;
-    int64_t cfgId = 98765;
-    ConfigKey cfgKey(uid, cfgId);
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-
-    // No StateTrackers are initialized.
-    EXPECT_EQ(0, StateManager::getInstance().getStateTrackersCount());
-
-    // Config initialization fails.
-    ASSERT_EQ(0, processor->mMetricsManagers.size());
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
deleted file mode 100644
index 52bc222..0000000
--- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
+++ /dev/null
@@ -1,355 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <gtest/gtest.h>
-
-#include "src/StatsLogProcessor.h"
-#include "src/stats_log_util.h"
-#include "tests/statsd_test_util.h"
-
-#include <vector>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-#ifdef __ANDROID__
-
-namespace {
-
-StatsdConfig CreateStatsdConfig(DurationMetric::AggregationType aggregationType) {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-    *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
-    *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
-
-    auto screenIsOffPredicate = CreateScreenIsOffPredicate();
-    *config.add_predicate() = screenIsOffPredicate;
-
-    auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
-    // The predicate is dimensioning by any attribution node and both by uid and tag.
-    FieldMatcher dimensions = CreateAttributionUidAndTagDimensions(
-            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;
-    *config.add_predicate() = holdingWakelockPredicate;
-
-    auto durationMetric = config.add_duration_metric();
-    durationMetric->set_id(StringToId("WakelockDuration"));
-    durationMetric->set_what(holdingWakelockPredicate.id());
-    durationMetric->set_condition(screenIsOffPredicate.id());
-    durationMetric->set_aggregation_type(aggregationType);
-    // The metric is dimensioning by first attribution node and only by uid.
-    *durationMetric->mutable_dimensions_in_what() =
-        CreateAttributionUidDimensions(
-            util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-    durationMetric->set_bucket(FIVE_MINUTES);
-    return config;
-}
-
-std::vector<int> attributionUids1 = {111, 222, 222};
-std::vector<string> attributionTags1 = {"App1", "GMSCoreModule1", "GMSCoreModule2"};
-
-std::vector<int> attributionUids2 = {111, 222, 222};
-std::vector<string> attributionTags2 = {"App2", "GMSCoreModule1", "GMSCoreModule2"};
-
-/*
-Events:
-Screen off is met from (200ns,1 min+500ns].
-Acquire event for wl1 from 2ns to 1min+2ns
-Acquire event for wl2 from 1min-10ns to 2min-15ns
-*/
-void FeedEvents(StatsdConfig config, sp<StatsLogProcessor> processor) {
-    uint64_t bucketStartTimeNs = 10000000000;
-    uint64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-
-    auto screenTurnedOnEvent = CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-    auto screenTurnedOffEvent = CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 200, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
-    auto screenTurnedOnEvent2 =
-            CreateScreenStateChangedEvent(bucketStartTimeNs + bucketSizeNs + 500,
-                                          android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-
-    auto acquireEvent1 = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
-                                                    attributionTags1, "wl1");
-    auto releaseEvent1 = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2,
-                                                    attributionUids1, attributionTags1, "wl1");
-    auto acquireEvent2 = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 10,
-                                                    attributionUids2, attributionTags2, "wl2");
-    auto releaseEvent2 = CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs - 15,
-                                                    attributionUids2, attributionTags2, "wl2");
-
-    std::vector<std::unique_ptr<LogEvent>> events;
-
-    events.push_back(std::move(screenTurnedOnEvent));
-    events.push_back(std::move(screenTurnedOffEvent));
-    events.push_back(std::move(screenTurnedOnEvent2));
-    events.push_back(std::move(acquireEvent1));
-    events.push_back(std::move(acquireEvent2));
-    events.push_back(std::move(releaseEvent1));
-    events.push_back(std::move(releaseEvent2));
-
-    sortLogEventsByTimestamp(&events);
-
-    for (const auto& event : events) {
-        processor->OnLogEvent(event.get());
-    }
-}
-
-}  // namespace
-
-TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration1) {
-    ConfigKey cfgKey;
-    auto config = CreateStatsdConfig(DurationMetric::SUM);
-    uint64_t bucketStartTimeNs = 10000000000;
-    uint64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-    FeedEvents(config, processor);
-    vector<uint8_t> buffer;
-    ConfigMetricsReportList reports;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true, ADB_DUMP,
-                            FAST, &buffer);
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-
-    ASSERT_EQ(reports.reports_size(), 1);
-    ASSERT_EQ(reports.reports(0).metrics_size(), 1);
-    // Only 1 dimension output. The tag dimension in the predicate has been aggregated.
-    ASSERT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
-
-    auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-    // Validate dimension value.
-    ValidateAttributionUidDimension(data.dimensions_in_what(),
-                                    util::WAKELOCK_STATE_CHANGED, 111);
-    // Validate bucket info.
-    ASSERT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1);
-    data = reports.reports(0).metrics(0).duration_metrics().data(0);
-    // The wakelock holding interval starts from the screen off event and to the end of the 1st
-    // bucket.
-    EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), bucketSizeNs - 200);
-}
-
-TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration2) {
-    ConfigKey cfgKey;
-    auto config = CreateStatsdConfig(DurationMetric::SUM);
-    uint64_t bucketStartTimeNs = 10000000000;
-    uint64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-    FeedEvents(config, processor);
-    vector<uint8_t> buffer;
-    ConfigMetricsReportList reports;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true, ADB_DUMP,
-                            FAST, &buffer);
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(reports.reports_size(), 1);
-    ASSERT_EQ(reports.reports(0).metrics_size(), 1);
-    ASSERT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
-    // Dump the report after the end of 2nd bucket.
-    ASSERT_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);
-    // Validate dimension value.
-    ValidateAttributionUidDimension(data.dimensions_in_what(),
-                                    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.
-    EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(),
-              bucketStartTimeNs + bucketSizeNs - (bucketStartTimeNs + 200));
-    // The wakelock holding interval in the 2nd bucket starts at the beginning of the bucket and
-    // ends at the second screen on event.
-    EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 500UL);
-}
-
-TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration3) {
-    ConfigKey cfgKey;
-    auto config = CreateStatsdConfig(DurationMetric::SUM);
-    uint64_t bucketStartTimeNs = 10000000000;
-    uint64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-    FeedEvents(config, processor);
-    vector<uint8_t> buffer;
-    ConfigMetricsReportList reports;
-
-    std::vector<std::unique_ptr<LogEvent>> events;
-    events.push_back(
-            CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 90,
-                                          android::view::DisplayStateEnum::DISPLAY_STATE_OFF));
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100,
-                                                attributionUids1, attributionTags1, "wl3"));
-    events.push_back(CreateReleaseWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs + 100,
-                                                attributionUids1, attributionTags1, "wl3"));
-    sortLogEventsByTimestamp(&events);
-    for (const auto& event : events) {
-        processor->OnLogEvent(event.get());
-    }
-
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true, ADB_DUMP,
-                            FAST, &buffer);
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(reports.reports_size(), 1);
-    ASSERT_EQ(reports.reports(0).metrics_size(), 1);
-    ASSERT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
-    ASSERT_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(),
-                                    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);
-    EXPECT_EQ((unsigned long long)data.bucket_info(4).duration_nanos(), bucketSizeNs);
-    EXPECT_EQ((unsigned long long)data.bucket_info(5).duration_nanos(), 100UL);
-}
-
-TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration1) {
-    ConfigKey cfgKey;
-    auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
-    uint64_t bucketStartTimeNs = 10000000000;
-    uint64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-    FeedEvents(config, processor);
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true, ADB_DUMP,
-                            FAST, &buffer);
-    EXPECT_TRUE(buffer.size() > 0);
-
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-
-    ASSERT_EQ(reports.reports_size(), 1);
-
-    // When using ProtoOutputStream, if nothing written to a sub msg, it won't be treated as
-    // one. It was previsouly 1 because we had a fake onDumpReport which calls add_metric() by
-    // itself.
-    ASSERT_EQ(1, reports.reports(0).metrics_size());
-    ASSERT_EQ(0, reports.reports(0).metrics(0).duration_metrics().data_size());
-}
-
-TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration2) {
-    ConfigKey cfgKey;
-    auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
-    uint64_t bucketStartTimeNs = 10000000000;
-    uint64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-    FeedEvents(config, processor);
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true, ADB_DUMP,
-                            FAST, &buffer);
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(reports.reports_size(), 1);
-    ASSERT_EQ(reports.reports(0).metrics_size(), 1);
-    ASSERT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
-    // Dump the report after the end of 2nd bucket. One dimension with one bucket.
-    ASSERT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1);
-    auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-    // Validate dimension value.
-    ValidateAttributionUidDimension(data.dimensions_in_what(),
-                                    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);
-}
-
-TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration3) {
-    ConfigKey cfgKey;
-    auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
-    uint64_t bucketStartTimeNs = 10000000000;
-    uint64_t bucketSizeNs =
-            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-    ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
-    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-    FeedEvents(config, processor);
-    ConfigMetricsReportList reports;
-    vector<uint8_t> buffer;
-
-    std::vector<std::unique_ptr<LogEvent>> events;
-    events.push_back(
-            CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 90,
-                                          android::view::DisplayStateEnum::DISPLAY_STATE_OFF));
-    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100,
-                                                attributionUids1, attributionTags1, "wl3"));
-    events.push_back(CreateReleaseWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs + 100,
-                                                attributionUids1, attributionTags1, "wl3"));
-    sortLogEventsByTimestamp(&events);
-    for (const auto& event : events) {
-        processor->OnLogEvent(event.get());
-    }
-
-    processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true, ADB_DUMP,
-                            FAST, &buffer);
-    EXPECT_TRUE(buffer.size() > 0);
-    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-    backfillDimensionPath(&reports);
-    backfillStringInReport(&reports);
-    backfillStartEndTimestamp(&reports);
-    ASSERT_EQ(reports.reports_size(), 1);
-    ASSERT_EQ(reports.reports(0).metrics_size(), 1);
-    ASSERT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
-    ASSERT_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(),
-                                    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(),
-              bucketStartTimeNs + 5 * bucketSizeNs);
-    EXPECT_EQ((unsigned long long)data.bucket_info(1).end_bucket_elapsed_nanos(),
-              bucketStartTimeNs + 6 * bucketSizeNs);
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp b/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp
deleted file mode 100644
index 85a6088..0000000
--- a/cmds/statsd/tests/external/StatsCallbackPuller_test.cpp
+++ /dev/null
@@ -1,219 +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.
-
-#include "src/external/StatsCallbackPuller.h"
-
-#include <aidl/android/os/BnPullAtomCallback.h>
-#include <aidl/android/os/IPullAtomResultReceiver.h>
-#include <aidl/android/util/StatsEventParcel.h>
-#include <android/binder_interface_utils.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <stdio.h>
-
-#include <chrono>
-#include <thread>
-#include <vector>
-
-#include "../metrics/metrics_test_helper.h"
-#include "src/stats_log_util.h"
-#include "stats_event.h"
-#include "tests/statsd_test_util.h"
-
-#ifdef __ANDROID__
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using namespace testing;
-using Status = ::ndk::ScopedAStatus;
-using aidl::android::os::BnPullAtomCallback;
-using aidl::android::os::IPullAtomResultReceiver;
-using aidl::android::util::StatsEventParcel;
-using ::ndk::SharedRefBase;
-using std::make_shared;
-using std::shared_ptr;
-using std::vector;
-using std::this_thread::sleep_for;
-using testing::Contains;
-
-namespace {
-int pullTagId = -12;
-bool pullSuccess;
-vector<int64_t> values;
-int64_t pullDelayNs;
-int64_t pullTimeoutNs;
-int64_t pullCoolDownNs;
-std::thread pullThread;
-
-AStatsEvent* createSimpleEvent(int64_t value) {
-    AStatsEvent* event = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(event, pullTagId);
-    AStatsEvent_writeInt64(event, value);
-    AStatsEvent_build(event);
-    return event;
-}
-
-void executePull(const shared_ptr<IPullAtomResultReceiver>& resultReceiver) {
-    // Convert stats_events into StatsEventParcels.
-    vector<StatsEventParcel> parcels;
-    for (int i = 0; i < values.size(); i++) {
-        AStatsEvent* event = createSimpleEvent(values[i]);
-        size_t size;
-        uint8_t* buffer = AStatsEvent_getBuffer(event, &size);
-
-        StatsEventParcel p;
-        // vector.assign() creates a copy, but this is inevitable unless
-        // stats_event.h/c uses a vector as opposed to a buffer.
-        p.buffer.assign(buffer, buffer + size);
-        parcels.push_back(std::move(p));
-        AStatsEvent_release(event);
-    }
-
-    sleep_for(std::chrono::nanoseconds(pullDelayNs));
-    resultReceiver->pullFinished(pullTagId, pullSuccess, parcels);
-}
-
-class FakePullAtomCallback : public BnPullAtomCallback {
-public:
-    Status onPullAtom(int atomTag,
-                      const shared_ptr<IPullAtomResultReceiver>& resultReceiver) override {
-        // Force pull to happen in separate thread to simulate binder.
-        pullThread = std::thread(executePull, resultReceiver);
-        return Status::ok();
-    }
-};
-
-class StatsCallbackPullerTest : public ::testing::Test {
-public:
-    StatsCallbackPullerTest() {
-    }
-
-    void SetUp() override {
-        pullSuccess = false;
-        pullDelayNs = 0;
-        values.clear();
-        pullTimeoutNs = 10000000000LL;  // 10 seconds.
-        pullCoolDownNs = 1000000000;    // 1 second.
-    }
-
-    void TearDown() override {
-        if (pullThread.joinable()) {
-            pullThread.join();
-        }
-        values.clear();
-    }
-};
-}  // Anonymous namespace.
-
-TEST_F(StatsCallbackPullerTest, PullSuccess) {
-    shared_ptr<FakePullAtomCallback> cb = SharedRefBase::make<FakePullAtomCallback>();
-    int64_t value = 43;
-    pullSuccess = true;
-    values.push_back(value);
-
-    StatsCallbackPuller puller(pullTagId, cb, pullCoolDownNs, pullTimeoutNs, {});
-
-    vector<std::shared_ptr<LogEvent>> dataHolder;
-    int64_t startTimeNs = getElapsedRealtimeNs();
-    EXPECT_TRUE(puller.PullInternal(&dataHolder));
-    int64_t endTimeNs = getElapsedRealtimeNs();
-
-    ASSERT_EQ(1, dataHolder.size());
-    EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
-    EXPECT_LT(startTimeNs, dataHolder[0]->GetElapsedTimestampNs());
-    EXPECT_GT(endTimeNs, dataHolder[0]->GetElapsedTimestampNs());
-    ASSERT_EQ(1, dataHolder[0]->size());
-    EXPECT_EQ(value, dataHolder[0]->getValues()[0].mValue.int_value);
-}
-
-TEST_F(StatsCallbackPullerTest, PullFail) {
-    shared_ptr<FakePullAtomCallback> cb = SharedRefBase::make<FakePullAtomCallback>();
-    pullSuccess = false;
-    int64_t value = 1234;
-    values.push_back(value);
-
-    StatsCallbackPuller puller(pullTagId, cb, pullCoolDownNs, pullTimeoutNs, {});
-
-    vector<shared_ptr<LogEvent>> dataHolder;
-    EXPECT_FALSE(puller.PullInternal(&dataHolder));
-    ASSERT_EQ(0, dataHolder.size());
-}
-
-TEST_F(StatsCallbackPullerTest, PullTimeout) {
-    shared_ptr<FakePullAtomCallback> cb = SharedRefBase::make<FakePullAtomCallback>();
-    pullSuccess = true;
-    pullDelayNs = MillisToNano(5);  // 5ms.
-    pullTimeoutNs = 10000;    // 10 microseconds.
-    int64_t value = 4321;
-    values.push_back(value);
-
-    StatsCallbackPuller puller(pullTagId, cb, pullCoolDownNs, pullTimeoutNs, {});
-
-    vector<shared_ptr<LogEvent>> dataHolder;
-    int64_t startTimeNs = getElapsedRealtimeNs();
-    // Returns true to let StatsPuller code evaluate the timeout.
-    EXPECT_TRUE(puller.PullInternal(&dataHolder));
-    int64_t endTimeNs = getElapsedRealtimeNs();
-    int64_t actualPullDurationNs = endTimeNs - startTimeNs;
-
-    // Pull should take at least the timeout amount of time, but should stop early because the delay
-    // is bigger.
-    EXPECT_LT(pullTimeoutNs, actualPullDurationNs);
-    EXPECT_GT(pullDelayNs, actualPullDurationNs);
-    ASSERT_EQ(0, dataHolder.size());
-
-    // Let the pull return and make sure that the dataHolder is not modified.
-    pullThread.join();
-    ASSERT_EQ(0, dataHolder.size());
-}
-
-// Register a puller and ensure that the timeout logic works.
-TEST_F(StatsCallbackPullerTest, RegisterAndTimeout) {
-    shared_ptr<FakePullAtomCallback> cb = SharedRefBase::make<FakePullAtomCallback>();
-    pullSuccess = true;
-    pullDelayNs = MillisToNano(5);  // 5 ms.
-    pullTimeoutNs = 10000;    // 10 microsseconds.
-    int64_t value = 4321;
-    int32_t uid = 123;
-    values.push_back(value);
-
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    pullerManager->RegisterPullAtomCallback(uid, pullTagId, pullCoolDownNs, pullTimeoutNs,
-                                            vector<int32_t>(), cb);
-    vector<shared_ptr<LogEvent>> dataHolder;
-    int64_t startTimeNs = getElapsedRealtimeNs();
-    // Returns false, since StatsPuller code will evaluate the timeout.
-    EXPECT_FALSE(pullerManager->Pull(pullTagId, {uid}, startTimeNs, &dataHolder));
-    int64_t endTimeNs = getElapsedRealtimeNs();
-    int64_t actualPullDurationNs = endTimeNs - startTimeNs;
-
-    // Pull should take at least the timeout amount of time, but should stop early because the delay
-    // is bigger. Make sure that the time is closer to the timeout, than to the intended delay.
-    EXPECT_LT(pullTimeoutNs, actualPullDurationNs);
-    EXPECT_GT(pullDelayNs / 5, actualPullDurationNs);
-    ASSERT_EQ(0, dataHolder.size());
-
-    // Let the pull return and make sure that the dataHolder is not modified.
-    pullThread.join();
-    ASSERT_EQ(0, dataHolder.size());
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/external/StatsPullerManager_test.cpp b/cmds/statsd/tests/external/StatsPullerManager_test.cpp
deleted file mode 100644
index 0d539f4..0000000
--- a/cmds/statsd/tests/external/StatsPullerManager_test.cpp
+++ /dev/null
@@ -1,150 +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.
-
-#include "src/external/StatsPullerManager.h"
-
-#include <aidl/android/os/IPullAtomResultReceiver.h>
-#include <aidl/android/util/StatsEventParcel.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include "stats_event.h"
-#include "tests/statsd_test_util.h"
-
-using aidl::android::util::StatsEventParcel;
-using ::ndk::SharedRefBase;
-using std::make_shared;
-using std::shared_ptr;
-using std::vector;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-namespace {
-
-int pullTagId1 = 10101;
-int pullTagId2 = 10102;
-int uid1 = 9999;
-int uid2 = 8888;
-ConfigKey configKey(50, 12345);
-ConfigKey badConfigKey(60, 54321);
-int unregisteredUid = 98765;
-int64_t coolDownNs = NS_PER_SEC;
-int64_t timeoutNs = NS_PER_SEC / 2;
-
-AStatsEvent* createSimpleEvent(int32_t atomId, int32_t value) {
-    AStatsEvent* event = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(event, atomId);
-    AStatsEvent_writeInt32(event, value);
-    AStatsEvent_build(event);
-    return event;
-}
-
-class FakePullAtomCallback : public BnPullAtomCallback {
-public:
-    FakePullAtomCallback(int32_t uid) : mUid(uid){};
-    Status onPullAtom(int atomTag,
-                      const shared_ptr<IPullAtomResultReceiver>& resultReceiver) override {
-        vector<StatsEventParcel> parcels;
-        AStatsEvent* event = createSimpleEvent(atomTag, mUid);
-        size_t size;
-        uint8_t* buffer = AStatsEvent_getBuffer(event, &size);
-
-        StatsEventParcel p;
-        // vector.assign() creates a copy, but this is inevitable unless
-        // stats_event.h/c uses a vector as opposed to a buffer.
-        p.buffer.assign(buffer, buffer + size);
-        parcels.push_back(std::move(p));
-        AStatsEvent_release(event);
-        resultReceiver->pullFinished(atomTag, /*success*/ true, parcels);
-        return Status::ok();
-    }
-    int32_t mUid;
-};
-
-class FakePullUidProvider : public PullUidProvider {
-public:
-    vector<int32_t> getPullAtomUids(int atomId) override {
-        if (atomId == pullTagId1) {
-            return {uid2, uid1};
-        } else if (atomId == pullTagId2) {
-            return {uid2};
-        }
-        return {};
-    }
-};
-
-sp<StatsPullerManager> createPullerManagerAndRegister() {
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    shared_ptr<FakePullAtomCallback> cb1 = SharedRefBase::make<FakePullAtomCallback>(uid1);
-    pullerManager->RegisterPullAtomCallback(uid1, pullTagId1, coolDownNs, timeoutNs, {}, cb1);
-    shared_ptr<FakePullAtomCallback> cb2 = SharedRefBase::make<FakePullAtomCallback>(uid2);
-    pullerManager->RegisterPullAtomCallback(uid2, pullTagId1, coolDownNs, timeoutNs, {}, cb2);
-    pullerManager->RegisterPullAtomCallback(uid1, pullTagId2, coolDownNs, timeoutNs, {}, cb1);
-    return pullerManager;
-}
-}  // anonymous namespace
-
-TEST(StatsPullerManagerTest, TestPullInvalidUid) {
-    sp<StatsPullerManager> pullerManager = createPullerManagerAndRegister();
-
-    vector<shared_ptr<LogEvent>> data;
-    EXPECT_FALSE(pullerManager->Pull(pullTagId1, {unregisteredUid}, /*timestamp =*/1, &data));
-}
-
-TEST(StatsPullerManagerTest, TestPullChoosesCorrectUid) {
-    sp<StatsPullerManager> pullerManager = createPullerManagerAndRegister();
-
-    vector<shared_ptr<LogEvent>> data;
-    EXPECT_TRUE(pullerManager->Pull(pullTagId1, {uid1}, /*timestamp =*/1, &data));
-    ASSERT_EQ(data.size(), 1);
-    EXPECT_EQ(data[0]->GetTagId(), pullTagId1);
-    ASSERT_EQ(data[0]->getValues().size(), 1);
-    EXPECT_EQ(data[0]->getValues()[0].mValue.int_value, uid1);
-}
-
-TEST(StatsPullerManagerTest, TestPullInvalidConfigKey) {
-    sp<StatsPullerManager> pullerManager = createPullerManagerAndRegister();
-    sp<FakePullUidProvider> uidProvider = new FakePullUidProvider();
-    pullerManager->RegisterPullUidProvider(configKey, uidProvider);
-
-    vector<shared_ptr<LogEvent>> data;
-    EXPECT_FALSE(pullerManager->Pull(pullTagId1, badConfigKey, /*timestamp =*/1, &data));
-}
-
-TEST(StatsPullerManagerTest, TestPullConfigKeyGood) {
-    sp<StatsPullerManager> pullerManager = createPullerManagerAndRegister();
-    sp<FakePullUidProvider> uidProvider = new FakePullUidProvider();
-    pullerManager->RegisterPullUidProvider(configKey, uidProvider);
-
-    vector<shared_ptr<LogEvent>> data;
-    EXPECT_TRUE(pullerManager->Pull(pullTagId1, configKey, /*timestamp =*/1, &data));
-    EXPECT_EQ(data[0]->GetTagId(), pullTagId1);
-    ASSERT_EQ(data[0]->getValues().size(), 1);
-    EXPECT_EQ(data[0]->getValues()[0].mValue.int_value, uid2);
-}
-
-TEST(StatsPullerManagerTest, TestPullConfigKeyNoPullerWithUid) {
-    sp<StatsPullerManager> pullerManager = createPullerManagerAndRegister();
-    sp<FakePullUidProvider> uidProvider = new FakePullUidProvider();
-    pullerManager->RegisterPullUidProvider(configKey, uidProvider);
-
-    vector<shared_ptr<LogEvent>> data;
-    EXPECT_FALSE(pullerManager->Pull(pullTagId2, configKey, /*timestamp =*/1, &data));
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/tests/external/StatsPuller_test.cpp b/cmds/statsd/tests/external/StatsPuller_test.cpp
deleted file mode 100644
index 55a9036..0000000
--- a/cmds/statsd/tests/external/StatsPuller_test.cpp
+++ /dev/null
@@ -1,316 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <stdio.h>
-
-#include <chrono>
-#include <thread>
-#include <vector>
-
-#include "../metrics/metrics_test_helper.h"
-#include "src/stats_log_util.h"
-#include "stats_event.h"
-#include "tests/statsd_test_util.h"
-
-#ifdef __ANDROID__
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using namespace testing;
-using std::make_shared;
-using std::shared_ptr;
-using std::vector;
-using std::this_thread::sleep_for;
-using testing::Contains;
-
-namespace {
-int pullTagId = 10014;
-
-bool pullSuccess;
-vector<std::shared_ptr<LogEvent>> pullData;
-long pullDelayNs;
-
-class FakePuller : public StatsPuller {
-public:
-    FakePuller()
-        : StatsPuller(pullTagId, /*coolDownNs=*/MillisToNano(10), /*timeoutNs=*/MillisToNano(5)){};
-
-private:
-    bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override {
-        (*data) = pullData;
-        sleep_for(std::chrono::nanoseconds(pullDelayNs));
-        return pullSuccess;
-    }
-};
-
-FakePuller puller;
-
-std::unique_ptr<LogEvent> createSimpleEvent(int64_t eventTimeNs, int64_t value) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, pullTagId);
-    AStatsEvent_overwriteTimestamp(statsEvent, eventTimeNs);
-    AStatsEvent_writeInt64(statsEvent, value);
-
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-class StatsPullerTest : public ::testing::Test {
-public:
-    StatsPullerTest() {
-    }
-
-    void SetUp() override {
-        puller.ForceClearCache();
-        pullSuccess = false;
-        pullDelayNs = 0;
-        pullData.clear();
-    }
-};
-
-}  // Anonymous namespace.
-
-TEST_F(StatsPullerTest, PullSuccess) {
-    pullData.push_back(createSimpleEvent(1111L, 33));
-
-    pullSuccess = true;
-
-    vector<std::shared_ptr<LogEvent>> dataHolder;
-    EXPECT_TRUE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
-    ASSERT_EQ(1, dataHolder.size());
-    EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
-    EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
-    ASSERT_EQ(1, dataHolder[0]->size());
-    EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
-
-    sleep_for(std::chrono::milliseconds(11));
-
-    pullData.clear();
-    pullData.push_back(createSimpleEvent(2222L, 44));
-
-    pullSuccess = true;
-
-    EXPECT_TRUE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
-    ASSERT_EQ(1, dataHolder.size());
-    EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
-    EXPECT_EQ(2222L, dataHolder[0]->GetElapsedTimestampNs());
-    ASSERT_EQ(1, dataHolder[0]->size());
-    EXPECT_EQ(44, dataHolder[0]->getValues()[0].mValue.int_value);
-}
-
-TEST_F(StatsPullerTest, PullFailAfterSuccess) {
-    pullData.push_back(createSimpleEvent(1111L, 33));
-
-    pullSuccess = true;
-
-    vector<std::shared_ptr<LogEvent>> dataHolder;
-    EXPECT_TRUE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
-    ASSERT_EQ(1, dataHolder.size());
-    EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
-    EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
-    ASSERT_EQ(1, dataHolder[0]->size());
-    EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
-
-    sleep_for(std::chrono::milliseconds(11));
-
-    pullData.clear();
-    pullData.push_back(createSimpleEvent(2222L, 44));
-
-    pullSuccess = false;
-    dataHolder.clear();
-    EXPECT_FALSE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
-    ASSERT_EQ(0, dataHolder.size());
-
-    // Fails due to hitting the cool down.
-    pullSuccess = true;
-    dataHolder.clear();
-    EXPECT_FALSE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
-    ASSERT_EQ(0, dataHolder.size());
-}
-
-// Test pull takes longer than timeout, 2nd pull happens shorter than cooldown
-TEST_F(StatsPullerTest, PullTakeTooLongAndPullFast) {
-    pullData.push_back(createSimpleEvent(1111L, 33));
-    pullSuccess = true;
-    // timeout is 5ms
-    pullDelayNs = MillisToNano(6);
-
-    vector<std::shared_ptr<LogEvent>> dataHolder;
-    EXPECT_FALSE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
-    ASSERT_EQ(0, dataHolder.size());
-
-    pullData.clear();
-    pullData.push_back(createSimpleEvent(2222L, 44));
-    pullDelayNs = 0;
-
-    pullSuccess = true;
-    dataHolder.clear();
-    EXPECT_FALSE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
-    ASSERT_EQ(0, dataHolder.size());
-}
-
-TEST_F(StatsPullerTest, PullFail) {
-    pullData.push_back(createSimpleEvent(1111L, 33));
-
-    pullSuccess = false;
-
-    vector<std::shared_ptr<LogEvent>> dataHolder;
-    EXPECT_FALSE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
-    ASSERT_EQ(0, dataHolder.size());
-}
-
-TEST_F(StatsPullerTest, PullTakeTooLong) {
-    pullData.push_back(createSimpleEvent(1111L, 33));
-
-    pullSuccess = true;
-    pullDelayNs = MillisToNano(6);
-
-    vector<std::shared_ptr<LogEvent>> dataHolder;
-    EXPECT_FALSE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
-    ASSERT_EQ(0, dataHolder.size());
-}
-
-TEST_F(StatsPullerTest, PullTooFast) {
-    pullData.push_back(createSimpleEvent(1111L, 33));
-
-    pullSuccess = true;
-
-    vector<std::shared_ptr<LogEvent>> dataHolder;
-    EXPECT_TRUE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
-    ASSERT_EQ(1, dataHolder.size());
-    EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
-    EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
-    ASSERT_EQ(1, dataHolder[0]->size());
-    EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
-
-    pullData.clear();
-    pullData.push_back(createSimpleEvent(2222L, 44));
-
-    pullSuccess = true;
-
-    dataHolder.clear();
-    EXPECT_TRUE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
-    ASSERT_EQ(1, dataHolder.size());
-    EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
-    EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
-    ASSERT_EQ(1, dataHolder[0]->size());
-    EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
-}
-
-TEST_F(StatsPullerTest, PullFailsAndTooFast) {
-    pullData.push_back(createSimpleEvent(1111L, 33));
-
-    pullSuccess = false;
-
-    vector<std::shared_ptr<LogEvent>> dataHolder;
-    EXPECT_FALSE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
-    ASSERT_EQ(0, dataHolder.size());
-
-    pullData.clear();
-    pullData.push_back(createSimpleEvent(2222L, 44));
-
-    pullSuccess = true;
-
-    EXPECT_FALSE(puller.Pull(getElapsedRealtimeNs(), &dataHolder));
-    ASSERT_EQ(0, dataHolder.size());
-}
-
-TEST_F(StatsPullerTest, PullSameEventTime) {
-    pullData.push_back(createSimpleEvent(1111L, 33));
-
-    pullSuccess = true;
-    int64_t eventTimeNs = getElapsedRealtimeNs();
-
-    vector<std::shared_ptr<LogEvent>> dataHolder;
-    EXPECT_TRUE(puller.Pull(eventTimeNs, &dataHolder));
-    ASSERT_EQ(1, dataHolder.size());
-    EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
-    EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
-    ASSERT_EQ(1, dataHolder[0]->size());
-    EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
-
-    pullData.clear();
-    pullData.push_back(createSimpleEvent(2222L, 44));
-
-    // Sleep to ensure the cool down expires.
-    sleep_for(std::chrono::milliseconds(11));
-    pullSuccess = true;
-
-    dataHolder.clear();
-    EXPECT_TRUE(puller.Pull(eventTimeNs, &dataHolder));
-    ASSERT_EQ(1, dataHolder.size());
-    EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
-    EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
-    ASSERT_EQ(1, dataHolder[0]->size());
-    EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
-}
-
-// Test pull takes longer than timeout, 2nd pull happens at same event time
-TEST_F(StatsPullerTest, PullTakeTooLongAndPullSameEventTime) {
-    pullData.push_back(createSimpleEvent(1111L, 33));
-    pullSuccess = true;
-    int64_t eventTimeNs = getElapsedRealtimeNs();
-    // timeout is 5ms
-    pullDelayNs = MillisToNano(6);
-
-    vector<std::shared_ptr<LogEvent>> dataHolder;
-    EXPECT_FALSE(puller.Pull(eventTimeNs, &dataHolder));
-    ASSERT_EQ(0, dataHolder.size());
-
-    // Sleep to ensure the cool down expires. 6ms is taken by the delay, so only 5 is needed here.
-    sleep_for(std::chrono::milliseconds(5));
-
-    pullData.clear();
-    pullData.push_back(createSimpleEvent(2222L, 44));
-    pullDelayNs = 0;
-
-    pullSuccess = true;
-    dataHolder.clear();
-    EXPECT_FALSE(puller.Pull(eventTimeNs, &dataHolder));
-    ASSERT_EQ(0, dataHolder.size());
-}
-
-TEST_F(StatsPullerTest, PullFailsAndPullSameEventTime) {
-    pullData.push_back(createSimpleEvent(1111L, 33));
-
-    pullSuccess = false;
-    int64_t eventTimeNs = getElapsedRealtimeNs();
-
-    vector<std::shared_ptr<LogEvent>> dataHolder;
-    EXPECT_FALSE(puller.Pull(eventTimeNs, &dataHolder));
-    ASSERT_EQ(0, dataHolder.size());
-
-    // Sleep to ensure the cool down expires.
-    sleep_for(std::chrono::milliseconds(11));
-
-    pullData.clear();
-    pullData.push_back(createSimpleEvent(2222L, 44));
-
-    pullSuccess = true;
-
-    EXPECT_FALSE(puller.Pull(eventTimeNs, &dataHolder));
-    ASSERT_EQ(0, dataHolder.size());
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/external/puller_util_test.cpp b/cmds/statsd/tests/external/puller_util_test.cpp
deleted file mode 100644
index a21dc87..0000000
--- a/cmds/statsd/tests/external/puller_util_test.cpp
+++ /dev/null
@@ -1,408 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "external/puller_util.h"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <stdio.h>
-
-#include <vector>
-
-#include "../metrics/metrics_test_helper.h"
-#include "FieldValue.h"
-#include "annotations.h"
-#include "stats_event.h"
-#include "tests/statsd_test_util.h"
-
-#ifdef __ANDROID__
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using namespace testing;
-using std::shared_ptr;
-using std::vector;
-/*
- * Test merge isolated and host uid
- */
-namespace {
-const int uidAtomTagId = 100;
-const vector<int> additiveFields = {3};
-const int nonUidAtomTagId = 200;
-const int timestamp = 1234;
-const int isolatedUid1 = 30;
-const int isolatedUid2 = 40;
-const int isolatedNonAdditiveData = 32;
-const int isolatedAdditiveData = 31;
-const int hostUid = 20;
-const int hostNonAdditiveData = 22;
-const int hostAdditiveData = 21;
-const int attributionAtomTagId = 300;
-
-sp<MockUidMap> makeMockUidMap() {
-    return makeMockUidMapForOneHost(hostUid, {isolatedUid1, isolatedUid2});
-}
-
-}  // anonymous namespace
-
-TEST(PullerUtilTest, MergeNoDimension) {
-    vector<shared_ptr<LogEvent>> data = {
-            // 30->22->31
-            makeUidLogEvent(uidAtomTagId, timestamp, isolatedUid1, hostNonAdditiveData,
-                            isolatedAdditiveData),
-
-            // 20->22->21
-            makeUidLogEvent(uidAtomTagId, timestamp, hostUid, hostNonAdditiveData,
-                            hostAdditiveData),
-    };
-
-    sp<MockUidMap> uidMap = makeMockUidMap();
-    mapAndMergeIsolatedUidsToHostUid(data, uidMap, uidAtomTagId, additiveFields);
-
-    ASSERT_EQ(1, (int)data.size());
-    const vector<FieldValue>* actualFieldValues = &data[0]->getValues();
-    ASSERT_EQ(3, actualFieldValues->size());
-    EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
-    EXPECT_EQ(hostNonAdditiveData, actualFieldValues->at(1).mValue.int_value);
-    EXPECT_EQ(isolatedAdditiveData + hostAdditiveData, actualFieldValues->at(2).mValue.int_value);
-}
-
-TEST(PullerUtilTest, MergeWithDimension) {
-    vector<shared_ptr<LogEvent>> data = {
-            // 30->32->31
-            makeUidLogEvent(uidAtomTagId, timestamp, isolatedUid1, isolatedNonAdditiveData,
-                            isolatedAdditiveData),
-
-            // 20->32->21
-            makeUidLogEvent(uidAtomTagId, timestamp, hostUid, isolatedNonAdditiveData,
-                            hostAdditiveData),
-
-            // 20->22->21
-            makeUidLogEvent(uidAtomTagId, timestamp, hostUid, hostNonAdditiveData,
-                            hostAdditiveData),
-    };
-
-    sp<MockUidMap> uidMap = makeMockUidMap();
-    mapAndMergeIsolatedUidsToHostUid(data, uidMap, uidAtomTagId, additiveFields);
-
-    ASSERT_EQ(2, (int)data.size());
-
-    const vector<FieldValue>* actualFieldValues = &data[0]->getValues();
-    ASSERT_EQ(3, actualFieldValues->size());
-    EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
-    EXPECT_EQ(hostNonAdditiveData, actualFieldValues->at(1).mValue.int_value);
-    EXPECT_EQ(hostAdditiveData, actualFieldValues->at(2).mValue.int_value);
-
-    actualFieldValues = &data[1]->getValues();
-    ASSERT_EQ(3, actualFieldValues->size());
-    EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
-    EXPECT_EQ(isolatedNonAdditiveData, actualFieldValues->at(1).mValue.int_value);
-    EXPECT_EQ(hostAdditiveData + isolatedAdditiveData, actualFieldValues->at(2).mValue.int_value);
-}
-
-TEST(PullerUtilTest, NoMergeHostUidOnly) {
-    vector<shared_ptr<LogEvent>> data = {
-            // 20->32->31
-            makeUidLogEvent(uidAtomTagId, timestamp, hostUid, isolatedNonAdditiveData,
-                            isolatedAdditiveData),
-
-            // 20->22->21
-            makeUidLogEvent(uidAtomTagId, timestamp, hostUid, hostNonAdditiveData,
-                            hostAdditiveData),
-    };
-
-    sp<MockUidMap> uidMap = makeMockUidMap();
-    mapAndMergeIsolatedUidsToHostUid(data, uidMap, uidAtomTagId, additiveFields);
-
-    ASSERT_EQ(2, (int)data.size());
-
-    const vector<FieldValue>* actualFieldValues = &data[0]->getValues();
-    ASSERT_EQ(3, actualFieldValues->size());
-    EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
-    EXPECT_EQ(hostNonAdditiveData, actualFieldValues->at(1).mValue.int_value);
-    EXPECT_EQ(hostAdditiveData, actualFieldValues->at(2).mValue.int_value);
-
-    actualFieldValues = &data[1]->getValues();
-    ASSERT_EQ(3, actualFieldValues->size());
-    EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
-    EXPECT_EQ(isolatedNonAdditiveData, actualFieldValues->at(1).mValue.int_value);
-    EXPECT_EQ(isolatedAdditiveData, actualFieldValues->at(2).mValue.int_value);
-}
-
-TEST(PullerUtilTest, IsolatedUidOnly) {
-    vector<shared_ptr<LogEvent>> data = {
-            // 30->32->31
-            makeUidLogEvent(uidAtomTagId, timestamp, isolatedUid1, isolatedNonAdditiveData,
-                            isolatedAdditiveData),
-
-            // 30->22->21
-            makeUidLogEvent(uidAtomTagId, timestamp, isolatedUid1, hostNonAdditiveData,
-                            hostAdditiveData),
-    };
-
-    sp<MockUidMap> uidMap = makeMockUidMap();
-    mapAndMergeIsolatedUidsToHostUid(data, uidMap, uidAtomTagId, additiveFields);
-
-    ASSERT_EQ(2, (int)data.size());
-
-    // 20->32->31
-    const vector<FieldValue>* actualFieldValues = &data[0]->getValues();
-    ASSERT_EQ(3, actualFieldValues->size());
-    EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
-    EXPECT_EQ(hostNonAdditiveData, actualFieldValues->at(1).mValue.int_value);
-    EXPECT_EQ(hostAdditiveData, actualFieldValues->at(2).mValue.int_value);
-
-    // 20->22->21
-    actualFieldValues = &data[1]->getValues();
-    ASSERT_EQ(3, actualFieldValues->size());
-    EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
-    EXPECT_EQ(isolatedNonAdditiveData, actualFieldValues->at(1).mValue.int_value);
-    EXPECT_EQ(isolatedAdditiveData, actualFieldValues->at(2).mValue.int_value);
-}
-
-TEST(PullerUtilTest, MultipleIsolatedUidToOneHostUid) {
-    vector<shared_ptr<LogEvent>> data = {
-            // 30->32->31
-            makeUidLogEvent(uidAtomTagId, timestamp, isolatedUid1, isolatedNonAdditiveData,
-                            isolatedAdditiveData),
-
-            // 31->32->21
-            makeUidLogEvent(uidAtomTagId, timestamp, isolatedUid2, isolatedNonAdditiveData,
-                            hostAdditiveData),
-
-            // 20->32->21
-            makeUidLogEvent(uidAtomTagId, timestamp, hostUid, isolatedNonAdditiveData,
-                            hostAdditiveData),
-    };
-
-    sp<MockUidMap> uidMap = makeMockUidMap();
-    mapAndMergeIsolatedUidsToHostUid(data, uidMap, uidAtomTagId, additiveFields);
-
-    ASSERT_EQ(1, (int)data.size());
-
-    const vector<FieldValue>* actualFieldValues = &data[0]->getValues();
-    ASSERT_EQ(3, actualFieldValues->size());
-    EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
-    EXPECT_EQ(isolatedNonAdditiveData, actualFieldValues->at(1).mValue.int_value);
-    EXPECT_EQ(isolatedAdditiveData + hostAdditiveData + hostAdditiveData,
-              actualFieldValues->at(2).mValue.int_value);
-}
-
-TEST(PullerUtilTest, NoNeedToMerge) {
-    vector<shared_ptr<LogEvent>> data = {
-            // 32->31
-            CreateTwoValueLogEvent(nonUidAtomTagId, timestamp, isolatedNonAdditiveData,
-                                   isolatedAdditiveData),
-
-            // 22->21
-            CreateTwoValueLogEvent(nonUidAtomTagId, timestamp, hostNonAdditiveData,
-                                   hostAdditiveData),
-
-    };
-
-    sp<MockUidMap> uidMap = makeMockUidMap();
-    mapAndMergeIsolatedUidsToHostUid(data, uidMap, nonUidAtomTagId, {} /*no additive fields*/);
-
-    ASSERT_EQ(2, (int)data.size());
-
-    const vector<FieldValue>* actualFieldValues = &data[0]->getValues();
-    ASSERT_EQ(2, actualFieldValues->size());
-    EXPECT_EQ(isolatedNonAdditiveData, actualFieldValues->at(0).mValue.int_value);
-    EXPECT_EQ(isolatedAdditiveData, actualFieldValues->at(1).mValue.int_value);
-
-    actualFieldValues = &data[1]->getValues();
-    ASSERT_EQ(2, actualFieldValues->size());
-    EXPECT_EQ(hostNonAdditiveData, actualFieldValues->at(0).mValue.int_value);
-    EXPECT_EQ(hostAdditiveData, actualFieldValues->at(1).mValue.int_value);
-}
-
-TEST(PullerUtilTest, MergeNoDimensionAttributionChain) {
-    vector<shared_ptr<LogEvent>> data = {
-            // 30->tag1->400->tag2->22->31
-            makeAttributionLogEvent(attributionAtomTagId, timestamp, {isolatedUid1, 400},
-                                    {"tag1", "tag2"}, hostNonAdditiveData, isolatedAdditiveData),
-
-            // 20->tag1->400->tag2->22->21
-            makeAttributionLogEvent(attributionAtomTagId, timestamp, {hostUid, 400},
-                                    {"tag1", "tag2"}, hostNonAdditiveData, hostAdditiveData),
-    };
-
-    sp<MockUidMap> uidMap = makeMockUidMap();
-    mapAndMergeIsolatedUidsToHostUid(data, uidMap, attributionAtomTagId, additiveFields);
-
-    ASSERT_EQ(1, (int)data.size());
-    const vector<FieldValue>* actualFieldValues = &data[0]->getValues();
-    ASSERT_EQ(6, actualFieldValues->size());
-    EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
-    EXPECT_EQ("tag1", actualFieldValues->at(1).mValue.str_value);
-    EXPECT_EQ(400, actualFieldValues->at(2).mValue.int_value);
-    EXPECT_EQ("tag2", actualFieldValues->at(3).mValue.str_value);
-    EXPECT_EQ(hostNonAdditiveData, actualFieldValues->at(4).mValue.int_value);
-    EXPECT_EQ(isolatedAdditiveData + hostAdditiveData, actualFieldValues->at(5).mValue.int_value);
-}
-
-TEST(PullerUtilTest, MergeWithDimensionAttributionChain) {
-    vector<shared_ptr<LogEvent>> data = {
-            // 200->tag1->30->tag2->32->31
-            makeAttributionLogEvent(attributionAtomTagId, timestamp, {200, isolatedUid1},
-                                    {"tag1", "tag2"}, isolatedNonAdditiveData,
-                                    isolatedAdditiveData),
-
-            // 200->tag1->20->tag2->32->21
-            makeAttributionLogEvent(attributionAtomTagId, timestamp, {200, hostUid},
-                                    {"tag1", "tag2"}, isolatedNonAdditiveData, hostAdditiveData),
-
-            // 200->tag1->20->tag2->22->21
-            makeAttributionLogEvent(attributionAtomTagId, timestamp, {200, hostUid},
-                                    {"tag1", "tag2"}, hostNonAdditiveData, hostAdditiveData),
-    };
-
-    sp<MockUidMap> uidMap = makeMockUidMap();
-    mapAndMergeIsolatedUidsToHostUid(data, uidMap, attributionAtomTagId, additiveFields);
-
-    ASSERT_EQ(2, (int)data.size());
-
-    const vector<FieldValue>* actualFieldValues = &data[0]->getValues();
-    ASSERT_EQ(6, actualFieldValues->size());
-    EXPECT_EQ(200, actualFieldValues->at(0).mValue.int_value);
-    EXPECT_EQ("tag1", actualFieldValues->at(1).mValue.str_value);
-    EXPECT_EQ(hostUid, actualFieldValues->at(2).mValue.int_value);
-    EXPECT_EQ("tag2", actualFieldValues->at(3).mValue.str_value);
-    EXPECT_EQ(hostNonAdditiveData, actualFieldValues->at(4).mValue.int_value);
-    EXPECT_EQ(hostAdditiveData, actualFieldValues->at(5).mValue.int_value);
-
-    actualFieldValues = &data[1]->getValues();
-    ASSERT_EQ(6, actualFieldValues->size());
-    EXPECT_EQ(200, actualFieldValues->at(0).mValue.int_value);
-    EXPECT_EQ("tag1", actualFieldValues->at(1).mValue.str_value);
-    EXPECT_EQ(hostUid, actualFieldValues->at(2).mValue.int_value);
-    EXPECT_EQ("tag2", actualFieldValues->at(3).mValue.str_value);
-    EXPECT_EQ(isolatedNonAdditiveData, actualFieldValues->at(4).mValue.int_value);
-    EXPECT_EQ(hostAdditiveData + isolatedAdditiveData, actualFieldValues->at(5).mValue.int_value);
-}
-
-TEST(PullerUtilTest, NoMergeHostUidOnlyAttributionChain) {
-    vector<shared_ptr<LogEvent>> data = {
-            // 20->tag1->400->tag2->32->31
-            makeAttributionLogEvent(attributionAtomTagId, timestamp, {hostUid, 400},
-                                    {"tag1", "tag2"}, isolatedNonAdditiveData,
-                                    isolatedAdditiveData),
-
-            // 20->tag1->400->tag2->22->21
-            makeAttributionLogEvent(attributionAtomTagId, timestamp, {hostUid, 400},
-                                    {"tag1", "tag2"}, hostNonAdditiveData, hostAdditiveData),
-    };
-
-    sp<MockUidMap> uidMap = makeMockUidMap();
-    mapAndMergeIsolatedUidsToHostUid(data, uidMap, attributionAtomTagId, additiveFields);
-
-    ASSERT_EQ(2, (int)data.size());
-
-    const vector<FieldValue>* actualFieldValues = &data[0]->getValues();
-    ASSERT_EQ(6, actualFieldValues->size());
-    EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
-    EXPECT_EQ("tag1", actualFieldValues->at(1).mValue.str_value);
-    EXPECT_EQ(400, actualFieldValues->at(2).mValue.int_value);
-    EXPECT_EQ("tag2", actualFieldValues->at(3).mValue.str_value);
-    EXPECT_EQ(hostNonAdditiveData, actualFieldValues->at(4).mValue.int_value);
-    EXPECT_EQ(hostAdditiveData, actualFieldValues->at(5).mValue.int_value);
-
-    actualFieldValues = &data[1]->getValues();
-    ASSERT_EQ(6, actualFieldValues->size());
-    EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
-    EXPECT_EQ("tag1", actualFieldValues->at(1).mValue.str_value);
-    EXPECT_EQ(400, actualFieldValues->at(2).mValue.int_value);
-    EXPECT_EQ("tag2", actualFieldValues->at(3).mValue.str_value);
-    EXPECT_EQ(isolatedNonAdditiveData, actualFieldValues->at(4).mValue.int_value);
-    EXPECT_EQ(isolatedAdditiveData, actualFieldValues->at(5).mValue.int_value);
-}
-
-TEST(PullerUtilTest, IsolatedUidOnlyAttributionChain) {
-    vector<shared_ptr<LogEvent>> data = {
-            // 30->tag1->400->tag2->32->31
-            makeAttributionLogEvent(attributionAtomTagId, timestamp, {isolatedUid1, 400},
-                                    {"tag1", "tag2"}, isolatedNonAdditiveData,
-                                    isolatedAdditiveData),
-
-            // 30->tag1->400->tag2->22->21
-            makeAttributionLogEvent(attributionAtomTagId, timestamp, {isolatedUid1, 400},
-                                    {"tag1", "tag2"}, hostNonAdditiveData, hostAdditiveData),
-    };
-
-    sp<MockUidMap> uidMap = makeMockUidMap();
-    mapAndMergeIsolatedUidsToHostUid(data, uidMap, attributionAtomTagId, additiveFields);
-
-    ASSERT_EQ(2, (int)data.size());
-
-    // 20->tag1->400->tag2->32->31
-    const vector<FieldValue>* actualFieldValues = &data[0]->getValues();
-    ASSERT_EQ(6, actualFieldValues->size());
-    EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
-    EXPECT_EQ("tag1", actualFieldValues->at(1).mValue.str_value);
-    EXPECT_EQ(400, actualFieldValues->at(2).mValue.int_value);
-    EXPECT_EQ("tag2", actualFieldValues->at(3).mValue.str_value);
-    EXPECT_EQ(hostNonAdditiveData, actualFieldValues->at(4).mValue.int_value);
-    EXPECT_EQ(hostAdditiveData, actualFieldValues->at(5).mValue.int_value);
-
-    // 20->tag1->400->tag2->22->21
-    actualFieldValues = &data[1]->getValues();
-    ASSERT_EQ(6, actualFieldValues->size());
-    EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
-    EXPECT_EQ("tag1", actualFieldValues->at(1).mValue.str_value);
-    EXPECT_EQ(400, actualFieldValues->at(2).mValue.int_value);
-    EXPECT_EQ("tag2", actualFieldValues->at(3).mValue.str_value);
-    EXPECT_EQ(isolatedNonAdditiveData, actualFieldValues->at(4).mValue.int_value);
-    EXPECT_EQ(isolatedAdditiveData, actualFieldValues->at(5).mValue.int_value);
-}
-
-TEST(PullerUtilTest, MultipleIsolatedUidToOneHostUidAttributionChain) {
-    vector<shared_ptr<LogEvent>> data = {
-            // 30->tag1->400->tag2->32->31
-            makeAttributionLogEvent(attributionAtomTagId, timestamp, {isolatedUid1, 400},
-                                    {"tag1", "tag2"}, isolatedNonAdditiveData,
-                                    isolatedAdditiveData),
-
-            // 31->tag1->400->tag2->32->21
-            makeAttributionLogEvent(attributionAtomTagId, timestamp, {isolatedUid2, 400},
-                                    {"tag1", "tag2"}, isolatedNonAdditiveData, hostAdditiveData),
-
-            // 20->tag1->400->tag2->32->21
-            makeAttributionLogEvent(attributionAtomTagId, timestamp, {hostUid, 400},
-                                    {"tag1", "tag2"}, isolatedNonAdditiveData, hostAdditiveData),
-    };
-
-    sp<MockUidMap> uidMap = makeMockUidMap();
-    mapAndMergeIsolatedUidsToHostUid(data, uidMap, attributionAtomTagId, additiveFields);
-
-    ASSERT_EQ(1, (int)data.size());
-
-    const vector<FieldValue>* actualFieldValues = &data[0]->getValues();
-    ASSERT_EQ(6, actualFieldValues->size());
-    EXPECT_EQ(hostUid, actualFieldValues->at(0).mValue.int_value);
-    EXPECT_EQ("tag1", actualFieldValues->at(1).mValue.str_value);
-    EXPECT_EQ(400, actualFieldValues->at(2).mValue.int_value);
-    EXPECT_EQ("tag2", actualFieldValues->at(3).mValue.str_value);
-    EXPECT_EQ(isolatedNonAdditiveData, actualFieldValues->at(4).mValue.int_value);
-    EXPECT_EQ(isolatedAdditiveData + hostAdditiveData + hostAdditiveData,
-              actualFieldValues->at(5).mValue.int_value);
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
deleted file mode 100644
index 428c46f..0000000
--- a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
+++ /dev/null
@@ -1,544 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/guardrail/StatsdStats.h"
-#include "statslog_statsdtest.h"
-#include "tests/statsd_test_util.h"
-
-#include <gtest/gtest.h>
-#include <vector>
-
-#ifdef __ANDROID__
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using std::vector;
-
-TEST(StatsdStatsTest, TestValidConfigAdd) {
-    StatsdStats stats;
-    ConfigKey key(0, 12345);
-    const int metricsCount = 10;
-    const int conditionsCount = 20;
-    const int matchersCount = 30;
-    const int alertsCount = 10;
-    stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, {},
-                             true /*valid config*/);
-    vector<uint8_t> output;
-    stats.dumpStats(&output, false /*reset stats*/);
-
-    StatsdStatsReport report;
-    bool good = report.ParseFromArray(&output[0], output.size());
-    EXPECT_TRUE(good);
-    ASSERT_EQ(1, report.config_stats_size());
-    const auto& configReport = report.config_stats(0);
-    EXPECT_EQ(0, configReport.uid());
-    EXPECT_EQ(12345, configReport.id());
-    EXPECT_EQ(metricsCount, configReport.metric_count());
-    EXPECT_EQ(conditionsCount, configReport.condition_count());
-    EXPECT_EQ(matchersCount, configReport.matcher_count());
-    EXPECT_EQ(alertsCount, configReport.alert_count());
-    EXPECT_EQ(true, configReport.is_valid());
-    EXPECT_FALSE(configReport.has_deletion_time_sec());
-}
-
-TEST(StatsdStatsTest, TestInvalidConfigAdd) {
-    StatsdStats stats;
-    ConfigKey key(0, 12345);
-    const int metricsCount = 10;
-    const int conditionsCount = 20;
-    const int matchersCount = 30;
-    const int alertsCount = 10;
-    stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, {},
-                             false /*bad config*/);
-    vector<uint8_t> output;
-    stats.dumpStats(&output, false);
-
-    StatsdStatsReport report;
-    bool good = report.ParseFromArray(&output[0], output.size());
-    EXPECT_TRUE(good);
-    ASSERT_EQ(1, report.config_stats_size());
-    const auto& configReport = report.config_stats(0);
-    // The invalid config should be put into icebox with a deletion time.
-    EXPECT_TRUE(configReport.has_deletion_time_sec());
-}
-
-TEST(StatsdStatsTest, TestConfigRemove) {
-    StatsdStats stats;
-    ConfigKey key(0, 12345);
-    const int metricsCount = 10;
-    const int conditionsCount = 20;
-    const int matchersCount = 30;
-    const int alertsCount = 10;
-    stats.noteConfigReceived(key, metricsCount, conditionsCount, matchersCount, alertsCount, {},
-                             true);
-    vector<uint8_t> output;
-    stats.dumpStats(&output, false);
-    StatsdStatsReport report;
-    bool good = report.ParseFromArray(&output[0], output.size());
-    EXPECT_TRUE(good);
-    ASSERT_EQ(1, report.config_stats_size());
-    const auto& configReport = report.config_stats(0);
-    EXPECT_FALSE(configReport.has_deletion_time_sec());
-
-    stats.noteConfigRemoved(key);
-    stats.dumpStats(&output, false);
-    good = report.ParseFromArray(&output[0], output.size());
-    EXPECT_TRUE(good);
-    ASSERT_EQ(1, report.config_stats_size());
-    const auto& configReport2 = report.config_stats(0);
-    EXPECT_TRUE(configReport2.has_deletion_time_sec());
-}
-
-TEST(StatsdStatsTest, TestSubStats) {
-    StatsdStats stats;
-    ConfigKey key(0, 12345);
-    stats.noteConfigReceived(key, 2, 3, 4, 5, {std::make_pair(123, 456)}, true);
-
-    stats.noteMatcherMatched(key, StringToId("matcher1"));
-    stats.noteMatcherMatched(key, StringToId("matcher1"));
-    stats.noteMatcherMatched(key, StringToId("matcher2"));
-
-    stats.noteConditionDimensionSize(key, StringToId("condition1"), 250);
-    stats.noteConditionDimensionSize(key, StringToId("condition1"), 240);
-
-    stats.noteMetricDimensionSize(key, StringToId("metric1"), 201);
-    stats.noteMetricDimensionSize(key, StringToId("metric1"), 202);
-
-    stats.noteAnomalyDeclared(key, StringToId("alert1"));
-    stats.noteAnomalyDeclared(key, StringToId("alert1"));
-    stats.noteAnomalyDeclared(key, StringToId("alert2"));
-
-    // broadcast-> 2
-    stats.noteBroadcastSent(key);
-    stats.noteBroadcastSent(key);
-
-    // data drop -> 1
-    stats.noteDataDropped(key, 123);
-
-    // dump report -> 3
-    stats.noteMetricsReportSent(key, 0);
-    stats.noteMetricsReportSent(key, 0);
-    stats.noteMetricsReportSent(key, 0);
-
-    // activation_time_sec -> 2
-    stats.noteActiveStatusChanged(key, true);
-    stats.noteActiveStatusChanged(key, true);
-
-    // deactivation_time_sec -> 1
-    stats.noteActiveStatusChanged(key, false);
-
-    vector<uint8_t> output;
-    stats.dumpStats(&output, true);  // Dump and reset stats
-    StatsdStatsReport report;
-    bool good = report.ParseFromArray(&output[0], output.size());
-    EXPECT_TRUE(good);
-    ASSERT_EQ(1, report.config_stats_size());
-    const auto& configReport = report.config_stats(0);
-    ASSERT_EQ(2, configReport.broadcast_sent_time_sec_size());
-    ASSERT_EQ(1, configReport.data_drop_time_sec_size());
-    ASSERT_EQ(1, configReport.data_drop_bytes_size());
-    EXPECT_EQ(123, configReport.data_drop_bytes(0));
-    ASSERT_EQ(3, configReport.dump_report_time_sec_size());
-    ASSERT_EQ(3, configReport.dump_report_data_size_size());
-    ASSERT_EQ(2, configReport.activation_time_sec_size());
-    ASSERT_EQ(1, configReport.deactivation_time_sec_size());
-    ASSERT_EQ(1, configReport.annotation_size());
-    EXPECT_EQ(123, configReport.annotation(0).field_int64());
-    EXPECT_EQ(456, configReport.annotation(0).field_int32());
-
-    ASSERT_EQ(2, configReport.matcher_stats_size());
-    // matcher1 is the first in the list
-    if (configReport.matcher_stats(0).id() == StringToId("matcher1")) {
-        EXPECT_EQ(2, configReport.matcher_stats(0).matched_times());
-        EXPECT_EQ(1, configReport.matcher_stats(1).matched_times());
-        EXPECT_EQ(StringToId("matcher2"), configReport.matcher_stats(1).id());
-    } else {
-        // matcher1 is the second in the list.
-        EXPECT_EQ(1, configReport.matcher_stats(0).matched_times());
-        EXPECT_EQ(StringToId("matcher2"), configReport.matcher_stats(0).id());
-
-        EXPECT_EQ(2, configReport.matcher_stats(1).matched_times());
-        EXPECT_EQ(StringToId("matcher1"), configReport.matcher_stats(1).id());
-    }
-
-    ASSERT_EQ(2, configReport.alert_stats_size());
-    bool alert1first = configReport.alert_stats(0).id() == StringToId("alert1");
-    EXPECT_EQ(StringToId("alert1"), configReport.alert_stats(alert1first ? 0 : 1).id());
-    EXPECT_EQ(2, configReport.alert_stats(alert1first ? 0 : 1).alerted_times());
-    EXPECT_EQ(StringToId("alert2"), configReport.alert_stats(alert1first ? 1 : 0).id());
-    EXPECT_EQ(1, configReport.alert_stats(alert1first ? 1 : 0).alerted_times());
-
-    ASSERT_EQ(1, configReport.condition_stats_size());
-    EXPECT_EQ(StringToId("condition1"), configReport.condition_stats(0).id());
-    EXPECT_EQ(250, configReport.condition_stats(0).max_tuple_counts());
-
-    ASSERT_EQ(1, configReport.metric_stats_size());
-    EXPECT_EQ(StringToId("metric1"), configReport.metric_stats(0).id());
-    EXPECT_EQ(202, configReport.metric_stats(0).max_tuple_counts());
-
-    // after resetting the stats, some new events come
-    stats.noteMatcherMatched(key, StringToId("matcher99"));
-    stats.noteConditionDimensionSize(key, StringToId("condition99"), 300);
-    stats.noteMetricDimensionSize(key, StringToId("metric99tion99"), 270);
-    stats.noteAnomalyDeclared(key, StringToId("alert99"));
-
-    // now the config stats should only contain the stats about the new event.
-    stats.dumpStats(&output, false);
-    good = report.ParseFromArray(&output[0], output.size());
-    EXPECT_TRUE(good);
-    ASSERT_EQ(1, report.config_stats_size());
-    const auto& configReport2 = report.config_stats(0);
-    ASSERT_EQ(1, configReport2.matcher_stats_size());
-    EXPECT_EQ(StringToId("matcher99"), configReport2.matcher_stats(0).id());
-    EXPECT_EQ(1, configReport2.matcher_stats(0).matched_times());
-
-    ASSERT_EQ(1, configReport2.condition_stats_size());
-    EXPECT_EQ(StringToId("condition99"), configReport2.condition_stats(0).id());
-    EXPECT_EQ(300, configReport2.condition_stats(0).max_tuple_counts());
-
-    ASSERT_EQ(1, configReport2.metric_stats_size());
-    EXPECT_EQ(StringToId("metric99tion99"), configReport2.metric_stats(0).id());
-    EXPECT_EQ(270, configReport2.metric_stats(0).max_tuple_counts());
-
-    ASSERT_EQ(1, configReport2.alert_stats_size());
-    EXPECT_EQ(StringToId("alert99"), configReport2.alert_stats(0).id());
-    EXPECT_EQ(1, configReport2.alert_stats(0).alerted_times());
-}
-
-TEST(StatsdStatsTest, TestAtomLog) {
-    StatsdStats stats;
-    time_t now = time(nullptr);
-    // old event, we get it from the stats buffer. should be ignored.
-    stats.noteAtomLogged(util::SENSOR_STATE_CHANGED, 1000);
-
-    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);
-    StatsdStatsReport report;
-    bool good = report.ParseFromArray(&output[0], output.size());
-    EXPECT_TRUE(good);
-
-    ASSERT_EQ(2, report.atom_stats_size());
-    bool sensorAtomGood = false;
-    bool dropboxAtomGood = false;
-
-    for (const auto& atomStats : report.atom_stats()) {
-        if (atomStats.tag() == util::SENSOR_STATE_CHANGED && atomStats.count() == 3) {
-            sensorAtomGood = true;
-        }
-        if (atomStats.tag() == util::APP_CRASH_OCCURRED && atomStats.count() == 1) {
-            dropboxAtomGood = true;
-        }
-    }
-
-    EXPECT_TRUE(dropboxAtomGood);
-    EXPECT_TRUE(sensorAtomGood);
-}
-
-TEST(StatsdStatsTest, TestNonPlatformAtomLog) {
-    StatsdStats stats;
-    time_t now = time(nullptr);
-    int newAtom1 = StatsdStats::kMaxPushedAtomId + 1;
-    int newAtom2 = StatsdStats::kMaxPushedAtomId + 2;
-
-    stats.noteAtomLogged(newAtom1, now + 1);
-    stats.noteAtomLogged(newAtom1, now + 2);
-    stats.noteAtomLogged(newAtom2, now + 3);
-
-    vector<uint8_t> output;
-    stats.dumpStats(&output, false);
-    StatsdStatsReport report;
-    bool good = report.ParseFromArray(&output[0], output.size());
-    EXPECT_TRUE(good);
-
-    ASSERT_EQ(2, report.atom_stats_size());
-    bool newAtom1Good = false;
-    bool newAtom2Good = false;
-
-    for (const auto& atomStats : report.atom_stats()) {
-        if (atomStats.tag() == newAtom1 && atomStats.count() == 2) {
-            newAtom1Good = true;
-        }
-        if (atomStats.tag() == newAtom2 && atomStats.count() == 1) {
-            newAtom2Good = true;
-        }
-    }
-
-    EXPECT_TRUE(newAtom1Good);
-    EXPECT_TRUE(newAtom2Good);
-}
-
-TEST(StatsdStatsTest, TestPullAtomStats) {
-    StatsdStats stats;
-
-    stats.updateMinPullIntervalSec(util::DISK_SPACE, 3333L);
-    stats.updateMinPullIntervalSec(util::DISK_SPACE, 2222L);
-    stats.updateMinPullIntervalSec(util::DISK_SPACE, 4444L);
-
-    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);
-    stats.notePullBinderCallFailed(util::DISK_SPACE);
-    stats.notePullUidProviderNotFound(util::DISK_SPACE);
-    stats.notePullerNotFound(util::DISK_SPACE);
-    stats.notePullerNotFound(util::DISK_SPACE);
-    stats.notePullTimeout(util::DISK_SPACE, 3000L, 6000L);
-    stats.notePullTimeout(util::DISK_SPACE, 4000L, 7000L);
-
-    vector<uint8_t> output;
-    stats.dumpStats(&output, false);
-    StatsdStatsReport report;
-    bool good = report.ParseFromArray(&output[0], output.size());
-    EXPECT_TRUE(good);
-
-    ASSERT_EQ(1, report.pulled_atom_stats_size());
-
-    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());
-    EXPECT_EQ(2222L, report.pulled_atom_stats(0).average_pull_time_nanos());
-    EXPECT_EQ(3333L, report.pulled_atom_stats(0).max_pull_time_nanos());
-    EXPECT_EQ(2223L, report.pulled_atom_stats(0).average_pull_delay_nanos());
-    EXPECT_EQ(3335L, report.pulled_atom_stats(0).max_pull_delay_nanos());
-    EXPECT_EQ(2L, report.pulled_atom_stats(0).registered_count());
-    EXPECT_EQ(1L, report.pulled_atom_stats(0).unregistered_count());
-    EXPECT_EQ(1L, report.pulled_atom_stats(0).binder_call_failed());
-    EXPECT_EQ(1L, report.pulled_atom_stats(0).failed_uid_provider_not_found());
-    EXPECT_EQ(2L, report.pulled_atom_stats(0).puller_not_found());
-    ASSERT_EQ(2, report.pulled_atom_stats(0).pull_atom_metadata_size());
-    EXPECT_EQ(3000L, report.pulled_atom_stats(0).pull_atom_metadata(0).pull_timeout_uptime_millis());
-    EXPECT_EQ(4000L, report.pulled_atom_stats(0).pull_atom_metadata(1).pull_timeout_uptime_millis());
-    EXPECT_EQ(6000L, report.pulled_atom_stats(0).pull_atom_metadata(0)
-            .pull_timeout_elapsed_millis());
-    EXPECT_EQ(7000L, report.pulled_atom_stats(0).pull_atom_metadata(1)
-            .pull_timeout_elapsed_millis());
-}
-
-TEST(StatsdStatsTest, TestAtomMetricsStats) {
-    StatsdStats stats;
-    time_t now = time(nullptr);
-    // old event, we get it from the stats buffer. should be ignored.
-    stats.noteBucketDropped(1000L);
-
-    stats.noteBucketBoundaryDelayNs(1000L, -1L);
-    stats.noteBucketBoundaryDelayNs(1000L, -10L);
-    stats.noteBucketBoundaryDelayNs(1000L, 2L);
-
-    stats.noteBucketBoundaryDelayNs(1001L, 1L);
-
-    vector<uint8_t> output;
-    stats.dumpStats(&output, false);
-    StatsdStatsReport report;
-    bool good = report.ParseFromArray(&output[0], output.size());
-    EXPECT_TRUE(good);
-
-    ASSERT_EQ(2, report.atom_metric_stats().size());
-
-    auto atomStats = report.atom_metric_stats(0);
-    EXPECT_EQ(1000L, atomStats.metric_id());
-    EXPECT_EQ(1L, atomStats.bucket_dropped());
-    EXPECT_EQ(-10L, atomStats.min_bucket_boundary_delay_ns());
-    EXPECT_EQ(2L, atomStats.max_bucket_boundary_delay_ns());
-
-    auto atomStats2 = report.atom_metric_stats(1);
-    EXPECT_EQ(1001L, atomStats2.metric_id());
-    EXPECT_EQ(0L, atomStats2.bucket_dropped());
-    EXPECT_EQ(0L, atomStats2.min_bucket_boundary_delay_ns());
-    EXPECT_EQ(1L, atomStats2.max_bucket_boundary_delay_ns());
-}
-
-TEST(StatsdStatsTest, TestAnomalyMonitor) {
-    StatsdStats stats;
-    stats.noteRegisteredAnomalyAlarmChanged();
-    stats.noteRegisteredAnomalyAlarmChanged();
-
-    vector<uint8_t> output;
-    stats.dumpStats(&output, false);
-    StatsdStatsReport report;
-    bool good = report.ParseFromArray(&output[0], output.size());
-    EXPECT_TRUE(good);
-
-    EXPECT_EQ(2, report.anomaly_alarm_stats().alarms_registered());
-}
-
-TEST(StatsdStatsTest, TestTimestampThreshold) {
-    StatsdStats stats;
-    vector<int32_t> timestamps;
-    for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) {
-        timestamps.push_back(i);
-    }
-    ConfigKey key(0, 12345);
-    stats.noteConfigReceived(key, 2, 3, 4, 5, {}, true);
-
-    for (int i = 0; i < StatsdStats::kMaxTimestampCount; i++) {
-        stats.noteDataDropped(key, timestamps[i]);
-        stats.noteBroadcastSent(key, timestamps[i]);
-        stats.noteMetricsReportSent(key, 0, timestamps[i]);
-        stats.noteActiveStatusChanged(key, true, timestamps[i]);
-        stats.noteActiveStatusChanged(key, false, timestamps[i]);
-    }
-
-    int32_t newTimestamp = 10000;
-
-    // now it should trigger removing oldest timestamp
-    stats.noteDataDropped(key, 123, 10000);
-    stats.noteBroadcastSent(key, 10000);
-    stats.noteMetricsReportSent(key, 0, 10000);
-    stats.noteActiveStatusChanged(key, true, 10000);
-    stats.noteActiveStatusChanged(key, false, 10000);
-
-    EXPECT_TRUE(stats.mConfigStats.find(key) != stats.mConfigStats.end());
-    const auto& configStats = stats.mConfigStats[key];
-
-    size_t maxCount = StatsdStats::kMaxTimestampCount;
-    ASSERT_EQ(maxCount, configStats->broadcast_sent_time_sec.size());
-    ASSERT_EQ(maxCount, configStats->data_drop_time_sec.size());
-    ASSERT_EQ(maxCount, configStats->dump_report_stats.size());
-    ASSERT_EQ(maxCount, configStats->activation_time_sec.size());
-    ASSERT_EQ(maxCount, configStats->deactivation_time_sec.size());
-
-    // the oldest timestamp is the second timestamp in history
-    EXPECT_EQ(1, configStats->broadcast_sent_time_sec.front());
-    EXPECT_EQ(1, configStats->data_drop_bytes.front());
-    EXPECT_EQ(1, configStats->dump_report_stats.front().first);
-    EXPECT_EQ(1, configStats->activation_time_sec.front());
-    EXPECT_EQ(1, configStats->deactivation_time_sec.front());
-
-    // the last timestamp is the newest timestamp.
-    EXPECT_EQ(newTimestamp, configStats->broadcast_sent_time_sec.back());
-    EXPECT_EQ(newTimestamp, configStats->data_drop_time_sec.back());
-    EXPECT_EQ(123, configStats->data_drop_bytes.back());
-    EXPECT_EQ(newTimestamp, configStats->dump_report_stats.back().first);
-    EXPECT_EQ(newTimestamp, configStats->activation_time_sec.back());
-    EXPECT_EQ(newTimestamp, configStats->deactivation_time_sec.back());
-}
-
-TEST(StatsdStatsTest, TestSystemServerCrash) {
-    StatsdStats stats;
-    vector<int32_t> timestamps;
-    for (int i = 0; i < StatsdStats::kMaxSystemServerRestarts; i++) {
-        timestamps.push_back(i);
-        stats.noteSystemServerRestart(timestamps[i]);
-    }
-    vector<uint8_t> output;
-    stats.dumpStats(&output, false);
-    StatsdStatsReport report;
-    EXPECT_TRUE(report.ParseFromArray(&output[0], output.size()));
-    const int maxCount = StatsdStats::kMaxSystemServerRestarts;
-    ASSERT_EQ(maxCount, (int)report.system_restart_sec_size());
-
-    stats.noteSystemServerRestart(StatsdStats::kMaxSystemServerRestarts + 1);
-    output.clear();
-    stats.dumpStats(&output, false);
-    EXPECT_TRUE(report.ParseFromArray(&output[0], output.size()));
-    ASSERT_EQ(maxCount, (int)report.system_restart_sec_size());
-    EXPECT_EQ(StatsdStats::kMaxSystemServerRestarts + 1, report.system_restart_sec(maxCount - 1));
-}
-
-TEST(StatsdStatsTest, TestActivationBroadcastGuardrailHit) {
-    StatsdStats stats;
-    int uid1 = 1;
-    int uid2 = 2;
-    stats.noteActivationBroadcastGuardrailHit(uid1, 10);
-    stats.noteActivationBroadcastGuardrailHit(uid1, 20);
-
-    // Test that we only keep 20 timestamps.
-    for (int i = 0; i < 100; i++) {
-        stats.noteActivationBroadcastGuardrailHit(uid2, i);
-    }
-
-    vector<uint8_t> output;
-    stats.dumpStats(&output, false);
-    StatsdStatsReport report;
-    EXPECT_TRUE(report.ParseFromArray(&output[0], output.size()));
-
-    ASSERT_EQ(2, report.activation_guardrail_stats_size());
-    bool uid1Good = false;
-    bool uid2Good = false;
-    for (const auto& guardrailTimes : report.activation_guardrail_stats()) {
-        if (uid1 == guardrailTimes.uid()) {
-            uid1Good = true;
-            ASSERT_EQ(2, guardrailTimes.guardrail_met_sec_size());
-            EXPECT_EQ(10, guardrailTimes.guardrail_met_sec(0));
-            EXPECT_EQ(20, guardrailTimes.guardrail_met_sec(1));
-        } else if (uid2 == guardrailTimes.uid()) {
-            int maxCount = StatsdStats::kMaxTimestampCount;
-            uid2Good = true;
-            ASSERT_EQ(maxCount, guardrailTimes.guardrail_met_sec_size());
-            for (int i = 0; i < maxCount; i++) {
-                EXPECT_EQ(100 - maxCount + i, guardrailTimes.guardrail_met_sec(i));
-            }
-        } else {
-            FAIL() << "Unexpected uid.";
-        }
-    }
-    EXPECT_TRUE(uid1Good);
-    EXPECT_TRUE(uid2Good);
-}
-
-TEST(StatsdStatsTest, TestAtomErrorStats) {
-    StatsdStats stats;
-
-    int pushAtomTag = 100;
-    int pullAtomTag = 1000;
-    int numErrors = 10;
-
-    for (int i = 0; i < numErrors; i++) {
-        // We must call noteAtomLogged as well because only those pushed atoms
-        // that have been logged will have stats printed about them in the
-        // proto.
-        stats.noteAtomLogged(pushAtomTag, /*timeSec=*/0);
-        stats.noteAtomError(pushAtomTag, /*pull=*/false);
-
-        stats.noteAtomError(pullAtomTag, /*pull=*/true);
-    }
-
-    vector<uint8_t> output;
-    stats.dumpStats(&output, false);
-    StatsdStatsReport report;
-    EXPECT_TRUE(report.ParseFromArray(&output[0], output.size()));
-
-    // Check error count = numErrors for push atom
-    ASSERT_EQ(1, report.atom_stats_size());
-    const auto& pushedAtomStats = report.atom_stats(0);
-    EXPECT_EQ(pushAtomTag, pushedAtomStats.tag());
-    EXPECT_EQ(numErrors, pushedAtomStats.error_count());
-
-    // Check error count = numErrors for pull atom
-    ASSERT_EQ(1, report.pulled_atom_stats_size());
-    const auto& pulledAtomStats = report.pulled_atom_stats(0);
-    EXPECT_EQ(pullAtomTag, pulledAtomStats.atom_id());
-    EXPECT_EQ(numErrors, pulledAtomStats.atom_error_count());
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/indexed_priority_queue_test.cpp b/cmds/statsd/tests/indexed_priority_queue_test.cpp
deleted file mode 100644
index 3a65456..0000000
--- a/cmds/statsd/tests/indexed_priority_queue_test.cpp
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "src/anomaly/indexed_priority_queue.h"
-
-#include <gtest/gtest.h>
-
-using namespace android::os::statsd;
-
-/** struct for template in indexed_priority_queue */
-struct AATest : public RefBase {
-    AATest(uint32_t val, std::string a, std::string b) : val(val), a(a), b(b) {
-    }
-
-    const int val;
-    const std::string a;
-    const std::string b;
-
-    struct Smaller {
-        bool operator()(const sp<const AATest> a, const sp<const AATest> b) const {
-            return (a->val < b->val);
-        }
-    };
-};
-
-#ifdef __ANDROID__
-TEST(indexed_priority_queue, empty_and_size) {
-    std::string emptyMetricId;
-    std::string emptyDimensionId;
-    indexed_priority_queue<AATest, AATest::Smaller> ipq;
-    sp<const AATest> aa4 = new AATest{4, emptyMetricId, emptyDimensionId};
-    sp<const AATest> aa8 = new AATest{8, emptyMetricId, emptyDimensionId};
-
-    ASSERT_EQ(0u, ipq.size());
-    EXPECT_TRUE(ipq.empty());
-
-    ipq.push(aa4);
-    ASSERT_EQ(1u, ipq.size());
-    EXPECT_FALSE(ipq.empty());
-
-    ipq.push(aa8);
-    ASSERT_EQ(2u, ipq.size());
-    EXPECT_FALSE(ipq.empty());
-
-    ipq.remove(aa4);
-    ASSERT_EQ(1u, ipq.size());
-    EXPECT_FALSE(ipq.empty());
-
-    ipq.remove(aa8);
-    ASSERT_EQ(0u, ipq.size());
-    EXPECT_TRUE(ipq.empty());
-}
-
-TEST(indexed_priority_queue, top) {
-    std::string emptyMetricId;
-    std::string emptyDimensionId;
-    indexed_priority_queue<AATest, AATest::Smaller> ipq;
-    sp<const AATest> aa2 = new AATest{2, emptyMetricId, emptyDimensionId};
-    sp<const AATest> aa4 = new AATest{4, emptyMetricId, emptyDimensionId};
-    sp<const AATest> aa8 = new AATest{8, emptyMetricId, emptyDimensionId};
-    sp<const AATest> aa12 = new AATest{12, emptyMetricId, emptyDimensionId};
-    sp<const AATest> aa16 = new AATest{16, emptyMetricId, emptyDimensionId};
-    sp<const AATest> aa20 = new AATest{20, emptyMetricId, emptyDimensionId};
-
-    EXPECT_EQ(ipq.top(), nullptr);
-
-    // add 8, 4, 12
-    ipq.push(aa8);
-    EXPECT_EQ(ipq.top(), aa8);
-
-    ipq.push(aa12);
-    EXPECT_EQ(ipq.top(), aa8);
-
-    ipq.push(aa4);
-    EXPECT_EQ(ipq.top(), aa4);
-
-    // remove 12, 4
-    ipq.remove(aa12);
-    EXPECT_EQ(ipq.top(), aa4);
-
-    ipq.remove(aa4);
-    EXPECT_EQ(ipq.top(), aa8);
-
-    // add 16, 2, 20
-    ipq.push(aa16);
-    EXPECT_EQ(ipq.top(), aa8);
-
-    ipq.push(aa2);
-    EXPECT_EQ(ipq.top(), aa2);
-
-    ipq.push(aa20);
-    EXPECT_EQ(ipq.top(), aa2);
-
-    // remove 2, 20, 16, 8
-    ipq.remove(aa2);
-    EXPECT_EQ(ipq.top(), aa8);
-
-    ipq.remove(aa20);
-    EXPECT_EQ(ipq.top(), aa8);
-
-    ipq.remove(aa16);
-    EXPECT_EQ(ipq.top(), aa8);
-
-    ipq.remove(aa8);
-    EXPECT_EQ(ipq.top(), nullptr);
-}
-
-TEST(indexed_priority_queue, push_same_aa) {
-    std::string emptyMetricId;
-    std::string emptyDimensionId;
-    indexed_priority_queue<AATest, AATest::Smaller> ipq;
-    sp<const AATest> aa4_a = new AATest{4, emptyMetricId, emptyDimensionId};
-    sp<const AATest> aa4_b = new AATest{4, emptyMetricId, emptyDimensionId};
-
-    ipq.push(aa4_a);
-    ASSERT_EQ(1u, ipq.size());
-    EXPECT_TRUE(ipq.contains(aa4_a));
-    EXPECT_FALSE(ipq.contains(aa4_b));
-
-    ipq.push(aa4_a);
-    ASSERT_EQ(1u, ipq.size());
-    EXPECT_TRUE(ipq.contains(aa4_a));
-    EXPECT_FALSE(ipq.contains(aa4_b));
-
-    ipq.push(aa4_b);
-    ASSERT_EQ(2u, ipq.size());
-    EXPECT_TRUE(ipq.contains(aa4_a));
-    EXPECT_TRUE(ipq.contains(aa4_b));
-}
-
-TEST(indexed_priority_queue, remove_nonexistant) {
-    std::string emptyMetricId;
-    std::string emptyDimensionId;
-    indexed_priority_queue<AATest, AATest::Smaller> ipq;
-    sp<const AATest> aa4 = new AATest{4, emptyMetricId, emptyDimensionId};
-    sp<const AATest> aa5 = new AATest{5, emptyMetricId, emptyDimensionId};
-
-    ipq.push(aa4);
-    ipq.remove(aa5);
-    ASSERT_EQ(1u, ipq.size());
-    EXPECT_TRUE(ipq.contains(aa4));
-    EXPECT_FALSE(ipq.contains(aa5));
-}
-
-TEST(indexed_priority_queue, remove_same_aa) {
-    indexed_priority_queue<AATest, AATest::Smaller> ipq;
-    std::string emptyMetricId;
-    std::string emptyDimensionId;
-    sp<const AATest> aa4_a = new AATest{4, emptyMetricId, emptyDimensionId};
-    sp<const AATest> aa4_b = new AATest{4, emptyMetricId, emptyDimensionId};
-
-    ipq.push(aa4_a);
-    ipq.push(aa4_b);
-    ASSERT_EQ(2u, ipq.size());
-    EXPECT_TRUE(ipq.contains(aa4_a));
-    EXPECT_TRUE(ipq.contains(aa4_b));
-
-    ipq.remove(aa4_b);
-    ASSERT_EQ(1u, ipq.size());
-    EXPECT_TRUE(ipq.contains(aa4_a));
-    EXPECT_FALSE(ipq.contains(aa4_b));
-
-    ipq.remove(aa4_a);
-    ASSERT_EQ(0u, ipq.size());
-    EXPECT_FALSE(ipq.contains(aa4_a));
-    EXPECT_FALSE(ipq.contains(aa4_b));
-}
-
-TEST(indexed_priority_queue, nulls) {
-    indexed_priority_queue<AATest, AATest::Smaller> ipq;
-
-    EXPECT_TRUE(ipq.empty());
-    EXPECT_FALSE(ipq.contains(nullptr));
-
-    ipq.push(nullptr);
-    EXPECT_TRUE(ipq.empty());
-    EXPECT_FALSE(ipq.contains(nullptr));
-
-    ipq.remove(nullptr);
-    EXPECT_TRUE(ipq.empty());
-    EXPECT_FALSE(ipq.contains(nullptr));
-}
-
-TEST(indexed_priority_queue, pop) {
-    indexed_priority_queue<AATest, AATest::Smaller> ipq;
-    std::string emptyMetricId;
-    std::string emptyDimensionId;
-    sp<const AATest> a = new AATest{1, emptyMetricId, emptyDimensionId};
-    sp<const AATest> b = new AATest{2, emptyMetricId, emptyDimensionId};
-    sp<const AATest> c = new AATest{3, emptyMetricId, emptyDimensionId};
-
-    ipq.push(c);
-    ipq.push(b);
-    ipq.push(a);
-    ASSERT_EQ(3u, ipq.size());
-
-    ipq.pop();
-    ASSERT_EQ(2u, ipq.size());
-    EXPECT_FALSE(ipq.contains(a));
-    EXPECT_TRUE(ipq.contains(b));
-    EXPECT_TRUE(ipq.contains(c));
-
-    ipq.pop();
-    ASSERT_EQ(1u, ipq.size());
-    EXPECT_FALSE(ipq.contains(a));
-    EXPECT_FALSE(ipq.contains(b));
-    EXPECT_TRUE(ipq.contains(c));
-
-    ipq.pop();
-    ASSERT_EQ(0u, ipq.size());
-    EXPECT_FALSE(ipq.contains(a));
-    EXPECT_FALSE(ipq.contains(b));
-    EXPECT_FALSE(ipq.contains(c));
-    EXPECT_TRUE(ipq.empty());
-
-    ipq.pop(); // pop an empty queue
-    EXPECT_TRUE(ipq.empty());
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/log_event/LogEventQueue_test.cpp b/cmds/statsd/tests/log_event/LogEventQueue_test.cpp
deleted file mode 100644
index a15f95b..0000000
--- a/cmds/statsd/tests/log_event/LogEventQueue_test.cpp
+++ /dev/null
@@ -1,115 +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.
-
-#include "logd/LogEventQueue.h"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <stdio.h>
-
-#include <thread>
-
-#include "stats_event.h"
-#include "tests/statsd_test_util.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using namespace android;
-using namespace testing;
-
-using std::unique_ptr;
-
-namespace {
-
-std::unique_ptr<LogEvent> makeLogEvent(uint64_t timestampNs) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, 10);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-} // anonymous namespace
-
-#ifdef __ANDROID__
-TEST(LogEventQueue_test, TestGoodConsumer) {
-    LogEventQueue queue(50);
-    int64_t timeBaseNs = 100;
-    std::thread writer([&queue, timeBaseNs] {
-        for (int i = 0; i < 100; i++) {
-            int64_t oldestEventNs;
-            bool success = queue.push(makeLogEvent(timeBaseNs + i * 1000), &oldestEventNs);
-            EXPECT_TRUE(success);
-            std::this_thread::sleep_for(std::chrono::milliseconds(1));
-        }
-    });
-
-    std::thread reader([&queue, timeBaseNs] {
-        for (int i = 0; i < 100; i++) {
-            auto event = queue.waitPop();
-            EXPECT_TRUE(event != nullptr);
-            // All events are in right order.
-            EXPECT_EQ(timeBaseNs + i * 1000, event->GetElapsedTimestampNs());
-        }
-    });
-
-    reader.join();
-    writer.join();
-}
-
-TEST(LogEventQueue_test, TestSlowConsumer) {
-    LogEventQueue queue(50);
-    int64_t timeBaseNs = 100;
-    std::thread writer([&queue, timeBaseNs] {
-        int failure_count = 0;
-        int64_t oldestEventNs;
-        for (int i = 0; i < 100; i++) {
-            bool success = queue.push(makeLogEvent(timeBaseNs + i * 1000), &oldestEventNs);
-            if (!success) failure_count++;
-            std::this_thread::sleep_for(std::chrono::milliseconds(1));
-        }
-
-        // There is some remote chance that reader thread not get chance to run before writer thread
-        // ends. That's why the following comparison is not "==".
-        // There will be at least 45 events lost due to overflow.
-        EXPECT_TRUE(failure_count >= 45);
-        // The oldest event must be at least the 6th event.
-        EXPECT_TRUE(oldestEventNs <= (100 + 5 * 1000));
-    });
-
-    std::thread reader([&queue, timeBaseNs] {
-        // The consumer quickly processed 5 events, then it got stuck (not reading anymore).
-        for (int i = 0; i < 5; i++) {
-            auto event = queue.waitPop();
-            EXPECT_TRUE(event != nullptr);
-            // All events are in right order.
-            EXPECT_EQ(timeBaseNs + i * 1000, event->GetElapsedTimestampNs());
-        }
-    });
-
-    reader.join();
-    writer.join();
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/tests/metadata_util_test.cpp b/cmds/statsd/tests/metadata_util_test.cpp
deleted file mode 100644
index 7707890..0000000
--- a/cmds/statsd/tests/metadata_util_test.cpp
+++ /dev/null
@@ -1,69 +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.
- */
-#include <gtest/gtest.h>
-
-#include "metadata_util.h"
-#include "tests/statsd_test_util.h"
-
-#ifdef __ANDROID__
-
-namespace android {
-namespace os {
-namespace statsd {
-
-TEST(MetadataUtilTest, TestWriteAndReadMetricDimensionKey) {
-    HashableDimensionKey dim;
-    HashableDimensionKey dim2;
-    int pos1[] = {1, 1, 1};
-    int pos2[] = {1, 1, 2};
-    int pos3[] = {1, 1, 3};
-    int pos4[] = {2, 0, 0};
-    Field field1(10, pos1, 2);
-    Field field2(10, pos2, 2);
-    Field field3(10, pos3, 2);
-    Field field4(10, pos4, 0);
-
-    Value value1((int32_t)10025);
-    Value value2("tag");
-    Value value3((int32_t)987654);
-    Value value4((int32_t)99999);
-
-    dim.addValue(FieldValue(field1, value1));
-    dim.addValue(FieldValue(field2, value2));
-    dim.addValue(FieldValue(field3, value3));
-    dim.addValue(FieldValue(field4, value4));
-
-    dim2.addValue(FieldValue(field1, value1));
-    dim2.addValue(FieldValue(field2, value2));
-
-    MetricDimensionKey dimKey(dim, dim2);
-
-    metadata::MetricDimensionKey metadataDimKey;
-    writeMetricDimensionKeyToMetadataDimensionKey(dimKey, &metadataDimKey);
-
-    MetricDimensionKey loadedDimKey = loadMetricDimensionKeyFromProto(metadataDimKey);
-
-    ASSERT_EQ(loadedDimKey, dimKey);
-    ASSERT_EQ(std::hash<MetricDimensionKey>{}(loadedDimKey),
-            std::hash<MetricDimensionKey>{}(dimKey));
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
deleted file mode 100644
index 8e2864c..0000000
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ /dev/null
@@ -1,477 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/metrics/CountMetricProducer.h"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <math.h>
-#include <stdio.h>
-
-#include <vector>
-
-#include "metrics_test_helper.h"
-#include "src/stats_log_util.h"
-#include "stats_event.h"
-#include "tests/statsd_test_util.h"
-
-using namespace testing;
-using android::sp;
-using std::set;
-using std::unordered_map;
-using std::vector;
-
-#ifdef __ANDROID__
-
-namespace android {
-namespace os {
-namespace statsd {
-
-
-namespace {
-const ConfigKey kConfigKey(0, 12345);
-const uint64_t protoHash = 0x1234567890;
-
-void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, atomId);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-
-    parseStatsEventToLogEvent(statsEvent, logEvent);
-}
-
-void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId, string uid) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, atomId);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-    AStatsEvent_writeString(statsEvent, uid.c_str());
-
-    parseStatsEventToLogEvent(statsEvent, logEvent);
-}
-
-}  // namespace
-
-// Setup for parameterized tests.
-class CountMetricProducerTest_PartialBucket : public TestWithParam<BucketSplitEvent> {};
-
-INSTANTIATE_TEST_SUITE_P(CountMetricProducerTest_PartialBucket,
-                         CountMetricProducerTest_PartialBucket,
-                         testing::Values(APP_UPGRADE, BOOT_COMPLETE));
-
-TEST(CountMetricProducerTest, TestFirstBucket) {
-    CountMetric metric;
-    metric.set_id(1);
-    metric.set_bucket(ONE_MINUTE);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
-                                      wizard, protoHash, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2);
-    EXPECT_EQ(600500000000, countProducer.mCurrentBucketStartTimeNs);
-    EXPECT_EQ(10, countProducer.mCurrentBucketNum);
-    EXPECT_EQ(660000000005, countProducer.getCurrentBucketEndTimeNs());
-}
-
-TEST(CountMetricProducerTest, TestNonDimensionalEvents) {
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-    int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
-    int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
-    int tagId = 1;
-
-    CountMetric metric;
-    metric.set_id(1);
-    metric.set_bucket(ONE_MINUTE);
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
-                                      wizard, protoHash, bucketStartTimeNs, bucketStartTimeNs);
-
-    // 2 events in bucket 1.
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event2, bucketStartTimeNs + 2, tagId);
-
-    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-
-    // Flushes at event #2.
-    countProducer.flushIfNeededLocked(bucketStartTimeNs + 2);
-    ASSERT_EQ(0UL, countProducer.mPastBuckets.size());
-
-    // Flushes.
-    countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
-    ASSERT_EQ(1UL, countProducer.mPastBuckets.size());
-    EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-                countProducer.mPastBuckets.end());
-    const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-    ASSERT_EQ(1UL, buckets.size());
-    EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
-    EXPECT_EQ(2LL, buckets[0].mCount);
-
-    // 1 matched event happens in bucket 2.
-    LogEvent event3(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event3, bucketStartTimeNs + bucketSizeNs + 2, tagId);
-
-    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
-
-    countProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
-    ASSERT_EQ(1UL, countProducer.mPastBuckets.size());
-    EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-                countProducer.mPastBuckets.end());
-    ASSERT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    const auto& bucketInfo2 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1];
-    EXPECT_EQ(bucket2StartTimeNs, bucketInfo2.mBucketStartNs);
-    EXPECT_EQ(bucket2StartTimeNs + bucketSizeNs, bucketInfo2.mBucketEndNs);
-    EXPECT_EQ(1LL, bucketInfo2.mCount);
-
-    // nothing happens in bucket 3. we should not record anything for bucket 3.
-    countProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
-    ASSERT_EQ(1UL, countProducer.mPastBuckets.size());
-    EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-                countProducer.mPastBuckets.end());
-    const auto& buckets3 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-    ASSERT_EQ(2UL, buckets3.size());
-}
-
-TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition) {
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-
-    CountMetric metric;
-    metric.set_id(1);
-    metric.set_bucket(ONE_MINUTE);
-    metric.set_condition(StringToId("SCREEN_ON"));
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    CountMetricProducer countProducer(kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard,
-                                      protoHash, bucketStartTimeNs, bucketStartTimeNs);
-
-    countProducer.onConditionChanged(true, bucketStartTimeNs);
-
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event1, bucketStartTimeNs + 1, /*atomId=*/1);
-    countProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
-
-    ASSERT_EQ(0UL, countProducer.mPastBuckets.size());
-
-    countProducer.onConditionChanged(false /*new condition*/, bucketStartTimeNs + 2);
-
-    // Upon this match event, the matched event1 is flushed.
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event2, bucketStartTimeNs + 10, /*atomId=*/1);
-    countProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
-    ASSERT_EQ(0UL, countProducer.mPastBuckets.size());
-
-    countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
-    ASSERT_EQ(1UL, countProducer.mPastBuckets.size());
-    EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-                countProducer.mPastBuckets.end());
-
-    const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-    ASSERT_EQ(1UL, buckets.size());
-    const auto& bucketInfo = buckets[0];
-    EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
-    EXPECT_EQ(1LL, bucketInfo.mCount);
-}
-
-TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-
-    int tagId = 1;
-    int conditionTagId = 2;
-
-    CountMetric metric;
-    metric.set_id(1);
-    metric.set_bucket(ONE_MINUTE);
-    metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON"));
-    MetricConditionLink* link = metric.add_links();
-    link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID"));
-    buildSimpleAtomFieldMatcher(tagId, 1, link->mutable_fields_in_what());
-    buildSimpleAtomFieldMatcher(conditionTagId, 2, link->mutable_fields_in_condition());
-
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event1, bucketStartTimeNs + 1, tagId, /*uid=*/"111");
-
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event2, bucketStartTimeNs + 10, tagId, /*uid=*/"222");
-
-    ConditionKey key1;
-    key1[StringToId("APP_IN_BACKGROUND_PER_UID")] = {
-            getMockedDimensionKey(conditionTagId, 2, "111")};
-
-    ConditionKey key2;
-    key2[StringToId("APP_IN_BACKGROUND_PER_UID")] = {
-            getMockedDimensionKey(conditionTagId, 2, "222")};
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    EXPECT_CALL(*wizard, query(_, key1, _)).WillOnce(Return(ConditionState::kFalse));
-
-    EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue));
-
-    CountMetricProducer countProducer(kConfigKey, metric, 0 /*condition tracker index*/,
-                                      {ConditionState::kUnknown}, wizard, protoHash,
-                                      bucketStartTimeNs, bucketStartTimeNs);
-
-    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-    countProducer.flushIfNeededLocked(bucketStartTimeNs + 1);
-    ASSERT_EQ(0UL, countProducer.mPastBuckets.size());
-
-    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-    countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
-    ASSERT_EQ(1UL, countProducer.mPastBuckets.size());
-    EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-                countProducer.mPastBuckets.end());
-    const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-    ASSERT_EQ(1UL, buckets.size());
-    const auto& bucketInfo = buckets[0];
-    EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
-    EXPECT_EQ(1LL, bucketInfo.mCount);
-}
-
-TEST_P(CountMetricProducerTest_PartialBucket, TestSplitInCurrentBucket) {
-    sp<AlarmMonitor> alarmMonitor;
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-    int64_t eventTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
-
-    int tagId = 1;
-    int conditionTagId = 2;
-
-    CountMetric metric;
-    metric.set_id(1);
-    metric.set_bucket(ONE_MINUTE);
-    Alert alert;
-    alert.set_num_buckets(3);
-    alert.set_trigger_if_sum_gt(2);
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, {}, wizard,
-                                      protoHash, bucketStartTimeNs, bucketStartTimeNs);
-
-    sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
-    EXPECT_TRUE(anomalyTracker != nullptr);
-
-    // Bucket is not flushed yet.
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event1, bucketStartTimeNs + 1, tagId, /*uid=*/"111");
-    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-    ASSERT_EQ(0UL, countProducer.mPastBuckets.size());
-    EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-
-    // App upgrade or boot complete forces bucket flush.
-    // Check that there's a past bucket and the bucket end is not adjusted.
-    switch (GetParam()) {
-        case APP_UPGRADE:
-            countProducer.notifyAppUpgrade(eventTimeNs);
-            break;
-        case BOOT_COMPLETE:
-            countProducer.onStatsdInitCompleted(eventTimeNs);
-            break;
-    }
-    ASSERT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    EXPECT_EQ(bucketStartTimeNs,
-              countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
-    EXPECT_EQ(eventTimeNs,
-              countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
-    EXPECT_EQ(0, countProducer.getCurrentBucketNum());
-    EXPECT_EQ(eventTimeNs, countProducer.mCurrentBucketStartTimeNs);
-    // Anomaly tracker only contains full buckets.
-    EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-
-    int64_t lastEndTimeNs = countProducer.getCurrentBucketEndTimeNs();
-    // Next event occurs in same bucket as partial bucket created.
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event2, bucketStartTimeNs + 59 * NS_PER_SEC + 10, tagId, /*uid=*/"222");
-    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-    ASSERT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    EXPECT_EQ(eventTimeNs, countProducer.mCurrentBucketStartTimeNs);
-    EXPECT_EQ(0, countProducer.getCurrentBucketNum());
-    EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-
-    // Third event in following bucket.
-    LogEvent event3(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event3, bucketStartTimeNs + 62 * NS_PER_SEC + 10, tagId, /*uid=*/"333");
-    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
-    ASSERT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    EXPECT_EQ(lastEndTimeNs, countProducer.mCurrentBucketStartTimeNs);
-    EXPECT_EQ(1, countProducer.getCurrentBucketNum());
-    EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-}
-
-TEST_P(CountMetricProducerTest_PartialBucket, TestSplitInNextBucket) {
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-    int64_t eventTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
-
-    int tagId = 1;
-    int conditionTagId = 2;
-
-    CountMetric metric;
-    metric.set_id(1);
-    metric.set_bucket(ONE_MINUTE);
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, {}, wizard,
-                                      protoHash, bucketStartTimeNs, bucketStartTimeNs);
-
-    // Bucket is flushed yet.
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event1, bucketStartTimeNs + 1, tagId, /*uid=*/"111");
-    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-    ASSERT_EQ(0UL, countProducer.mPastBuckets.size());
-
-    // App upgrade or boot complete forces bucket flush.
-    // Check that there's a past bucket and the bucket end is not adjusted since the upgrade
-    // occurred after the bucket end time.
-    switch (GetParam()) {
-        case APP_UPGRADE:
-            countProducer.notifyAppUpgrade(eventTimeNs);
-            break;
-        case BOOT_COMPLETE:
-            countProducer.onStatsdInitCompleted(eventTimeNs);
-            break;
-    }
-    ASSERT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    EXPECT_EQ(bucketStartTimeNs,
-              countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-              countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
-    EXPECT_EQ(eventTimeNs, countProducer.mCurrentBucketStartTimeNs);
-
-    // Next event occurs in same bucket as partial bucket created.
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event2, bucketStartTimeNs + 70 * NS_PER_SEC + 10, tagId, /*uid=*/"222");
-    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-    ASSERT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-
-    // Third event in following bucket.
-    LogEvent event3(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event3, bucketStartTimeNs + 121 * NS_PER_SEC + 10, tagId, /*uid=*/"333");
-    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
-    ASSERT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    EXPECT_EQ((int64_t)eventTimeNs,
-              countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketStartNs);
-    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-              countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketEndNs);
-}
-
-TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) {
-    sp<AlarmMonitor> alarmMonitor;
-    Alert alert;
-    alert.set_id(11);
-    alert.set_metric_id(1);
-    alert.set_trigger_if_sum_gt(2);
-    alert.set_num_buckets(2);
-    const int32_t refPeriodSec = 1;
-    alert.set_refractory_period_secs(refPeriodSec);
-
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-    int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
-    int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
-
-    CountMetric metric;
-    metric.set_id(1);
-    metric.set_bucket(ONE_MINUTE);
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
-                                      wizard, protoHash, bucketStartTimeNs, bucketStartTimeNs);
-
-    sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
-
-    int tagId = 1;
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event2, bucketStartTimeNs + 2, tagId);
-    LogEvent event3(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event3, bucketStartTimeNs + 2 * bucketSizeNs + 1, tagId);
-    LogEvent event4(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event4, bucketStartTimeNs + 3 * bucketSizeNs + 1, tagId);
-    LogEvent event5(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event5, bucketStartTimeNs + 3 * bucketSizeNs + 2, tagId);
-    LogEvent event6(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event6, bucketStartTimeNs + 3 * bucketSizeNs + 3, tagId);
-    LogEvent event7(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event7, bucketStartTimeNs + 3 * bucketSizeNs + 2 * NS_PER_SEC, tagId);
-
-    // Two events in bucket #0.
-    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-
-    ASSERT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
-    EXPECT_EQ(2L, countProducer.mCurrentSlicedCounter->begin()->second);
-    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
-
-    // One event in bucket #2. No alarm as bucket #0 is trashed out.
-    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
-    ASSERT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
-    EXPECT_EQ(1L, countProducer.mCurrentSlicedCounter->begin()->second);
-    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
-
-    // Two events in bucket #3.
-    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
-    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event5);
-    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event6);
-    ASSERT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
-    EXPECT_EQ(3L, countProducer.mCurrentSlicedCounter->begin()->second);
-    // Anomaly at event 6 is within refractory period. The alarm is at event 5 timestamp not event 6
-    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-              std::ceil(1.0 * event5.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
-
-    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event7);
-    ASSERT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
-    EXPECT_EQ(4L, countProducer.mCurrentSlicedCounter->begin()->second);
-    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-              std::ceil(1.0 * event7.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
-}
-
-TEST(CountMetricProducerTest, TestOneWeekTimeUnit) {
-    CountMetric metric;
-    metric.set_id(1);
-    metric.set_bucket(ONE_WEEK);
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    int64_t oneDayNs = 24 * 60 * 60 * 1e9;
-    int64_t fiveWeeksNs = 5 * 7 * oneDayNs;
-
-    CountMetricProducer countProducer(kConfigKey, metric, -1 /* meaning no condition */, {}, wizard,
-                                      protoHash, oneDayNs, fiveWeeksNs);
-
-    int64_t fiveWeeksOneDayNs = fiveWeeksNs + oneDayNs;
-
-    EXPECT_EQ(fiveWeeksNs, countProducer.mCurrentBucketStartTimeNs);
-    EXPECT_EQ(4, countProducer.mCurrentBucketNum);
-    EXPECT_EQ(fiveWeeksOneDayNs, countProducer.getCurrentBucketEndTimeNs());
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
deleted file mode 100644
index bb2ede4..0000000
--- a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
+++ /dev/null
@@ -1,518 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/metrics/DurationMetricProducer.h"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <stdio.h>
-
-#include <set>
-#include <unordered_map>
-#include <vector>
-
-#include "metrics_test_helper.h"
-#include "src/condition/ConditionWizard.h"
-#include "src/stats_log_util.h"
-#include "stats_event.h"
-#include "tests/statsd_test_util.h"
-
-using namespace android::os::statsd;
-using namespace testing;
-using android::sp;
-using std::set;
-using std::unordered_map;
-using std::vector;
-
-#ifdef __ANDROID__
-
-namespace android {
-namespace os {
-namespace statsd {
-
-
-namespace {
-
-const ConfigKey kConfigKey(0, 12345);
-const uint64_t protoHash = 0x1234567890;
-void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, atomId);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-
-    parseStatsEventToLogEvent(statsEvent, logEvent);
-}
-
-}  // namespace
-
-// Setup for parameterized tests.
-class DurationMetricProducerTest_PartialBucket : public TestWithParam<BucketSplitEvent> {};
-
-INSTANTIATE_TEST_SUITE_P(DurationMetricProducerTest_PartialBucket,
-                         DurationMetricProducerTest_PartialBucket,
-                         testing::Values(APP_UPGRADE, BOOT_COMPLETE));
-
-TEST(DurationMetricTrackerTest, TestFirstBucket) {
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    DurationMetric metric;
-    metric.set_id(1);
-    metric.set_bucket(ONE_MINUTE);
-    metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-
-    FieldMatcher dimensions;
-
-    DurationMetricProducer durationProducer(
-            kConfigKey, metric, -1 /*no condition*/, {}, -1 /*what index not needed*/,
-            1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
-            wizard, protoHash, dimensions, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2);
-
-    EXPECT_EQ(600500000000, durationProducer.mCurrentBucketStartTimeNs);
-    EXPECT_EQ(10, durationProducer.mCurrentBucketNum);
-    EXPECT_EQ(660000000005, durationProducer.getCurrentBucketEndTimeNs());
-}
-
-TEST(DurationMetricTrackerTest, TestNoCondition) {
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-
-    DurationMetric metric;
-    metric.set_id(1);
-    metric.set_bucket(ONE_MINUTE);
-    metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-
-    int tagId = 1;
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event2, bucketStartTimeNs + bucketSizeNs + 2, tagId);
-
-    FieldMatcher dimensions;
-
-    DurationMetricProducer durationProducer(
-            kConfigKey, metric, -1 /*no condition*/, {}, -1 /*what index not needed*/,
-            1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
-            wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-
-    durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
-    durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
-    durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
-    ASSERT_EQ(1UL, durationProducer.mPastBuckets.size());
-    EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-                durationProducer.mPastBuckets.end());
-    const auto& buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-    ASSERT_EQ(2UL, buckets.size());
-    EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
-    EXPECT_EQ(bucketSizeNs - 1LL, buckets[0].mDuration);
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketStartNs);
-    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[1].mBucketEndNs);
-    EXPECT_EQ(2LL, buckets[1].mDuration);
-}
-
-TEST(DurationMetricTrackerTest, TestNonSlicedCondition) {
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-
-    DurationMetric metric;
-    metric.set_id(1);
-    metric.set_bucket(ONE_MINUTE);
-    metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-
-    int tagId = 1;
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event2, bucketStartTimeNs + 2, tagId);
-    LogEvent event3(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event3, bucketStartTimeNs + bucketSizeNs + 1, tagId);
-    LogEvent event4(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event4, bucketStartTimeNs + bucketSizeNs + 3, tagId);
-
-    FieldMatcher dimensions;
-
-    DurationMetricProducer durationProducer(
-            kConfigKey, metric, 0 /* condition index */, {ConditionState::kUnknown},
-            -1 /*what index not needed*/, 1 /* start index */, 2 /* stop index */,
-            3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions,
-            bucketStartTimeNs, bucketStartTimeNs);
-    durationProducer.mCondition = ConditionState::kFalse;
-
-    EXPECT_FALSE(durationProducer.mCondition);
-    EXPECT_FALSE(durationProducer.isConditionSliced());
-
-    durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
-    durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
-    durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
-    ASSERT_EQ(0UL, durationProducer.mPastBuckets.size());
-
-    durationProducer.onMatchedLogEvent(1 /* start index*/, event3);
-    durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2);
-    durationProducer.onMatchedLogEvent(2 /* stop index*/, event4);
-    durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
-    ASSERT_EQ(1UL, durationProducer.mPastBuckets.size());
-    EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-                durationProducer.mPastBuckets.end());
-    const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-    ASSERT_EQ(1UL, buckets2.size());
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs);
-    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs);
-    EXPECT_EQ(1LL, buckets2[0].mDuration);
-}
-
-TEST(DurationMetricTrackerTest, TestNonSlicedConditionUnknownState) {
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-
-    DurationMetric metric;
-    metric.set_id(1);
-    metric.set_bucket(ONE_MINUTE);
-    metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-
-    int tagId = 1;
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event2, bucketStartTimeNs + 2, tagId);
-    LogEvent event3(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event3, bucketStartTimeNs + bucketSizeNs + 1, tagId);
-    LogEvent event4(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event4, bucketStartTimeNs + bucketSizeNs + 3, tagId);
-
-    FieldMatcher dimensions;
-
-    DurationMetricProducer durationProducer(
-            kConfigKey, metric, 0 /* condition index */, {ConditionState::kUnknown},
-            -1 /*what index not needed*/, 1 /* start index */, 2 /* stop index */,
-            3 /* stop_all index */, false /*nesting*/, wizard, protoHash, dimensions,
-            bucketStartTimeNs, bucketStartTimeNs);
-
-    EXPECT_EQ(ConditionState::kUnknown, durationProducer.mCondition);
-    EXPECT_FALSE(durationProducer.isConditionSliced());
-
-    durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
-    durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
-    durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
-    ASSERT_EQ(0UL, durationProducer.mPastBuckets.size());
-
-    durationProducer.onMatchedLogEvent(1 /* start index*/, event3);
-    durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2);
-    durationProducer.onMatchedLogEvent(2 /* stop index*/, event4);
-    durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
-    ASSERT_EQ(1UL, durationProducer.mPastBuckets.size());
-    const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-    ASSERT_EQ(1UL, buckets2.size());
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs);
-    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs);
-    EXPECT_EQ(1LL, buckets2[0].mDuration);
-}
-
-TEST_P(DurationMetricProducerTest_PartialBucket, TestSumDuration) {
-    /**
-     * The duration starts from the first bucket, through the two partial buckets (10-70sec),
-     * another bucket, and ends at the beginning of the next full bucket.
-     * Expected buckets:
-     *  - [10,25]: 14 secs
-     *  - [25,70]: All 45 secs
-     *  - [70,130]: All 60 secs
-     *  - [130, 210]: Only 5 secs (event ended at 135sec)
-     */
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-    int tagId = 1;
-
-    DurationMetric metric;
-    metric.set_id(1);
-    metric.set_bucket(ONE_MINUTE);
-    metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    FieldMatcher dimensions;
-
-    DurationMetricProducer durationProducer(
-            kConfigKey, metric, -1 /* no condition */, {}, -1 /*what index not needed*/,
-            1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
-            wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-
-    int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event1, startTimeNs, tagId);
-    durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
-    ASSERT_EQ(0UL, durationProducer.mPastBuckets.size());
-    EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-
-    int64_t partialBucketSplitTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
-    switch (GetParam()) {
-        case APP_UPGRADE:
-            durationProducer.notifyAppUpgrade(partialBucketSplitTimeNs);
-            break;
-        case BOOT_COMPLETE:
-            durationProducer.onStatsdInitCompleted(partialBucketSplitTimeNs);
-            break;
-    }
-    ASSERT_EQ(1UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    std::vector<DurationBucket> buckets =
-            durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-    EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
-    EXPECT_EQ(partialBucketSplitTimeNs, buckets[0].mBucketEndNs);
-    EXPECT_EQ(partialBucketSplitTimeNs - startTimeNs, buckets[0].mDuration);
-    EXPECT_EQ(partialBucketSplitTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-    EXPECT_EQ(0, durationProducer.getCurrentBucketNum());
-
-    // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
-    int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event2, endTimeNs, tagId);
-    durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
-    buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-    ASSERT_EQ(3UL, buckets.size());
-    EXPECT_EQ(partialBucketSplitTimeNs, buckets[1].mBucketStartNs);
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketEndNs);
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - partialBucketSplitTimeNs, buckets[1].mDuration);
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[2].mBucketStartNs);
-    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs);
-    EXPECT_EQ(bucketSizeNs, buckets[2].mDuration);
-}
-
-TEST_P(DurationMetricProducerTest_PartialBucket, TestSumDurationWithSplitInFollowingBucket) {
-    /**
-     * Expected buckets (start at 11s, upgrade at 75s, end at 135s):
-     *  - [10,70]: 59 secs
-     *  - [70,75]: 5 sec
-     *  - [75,130]: 55 secs
-     */
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-    int tagId = 1;
-
-    DurationMetric metric;
-    metric.set_id(1);
-    metric.set_bucket(ONE_MINUTE);
-    metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    FieldMatcher dimensions;
-
-    DurationMetricProducer durationProducer(
-            kConfigKey, metric, -1 /* no condition */, {}, -1 /*what index not needed*/,
-            1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
-            wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-
-    int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event1, startTimeNs, tagId);
-    durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
-    ASSERT_EQ(0UL, durationProducer.mPastBuckets.size());
-    EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-
-    int64_t partialBucketSplitTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
-    switch (GetParam()) {
-        case APP_UPGRADE:
-            durationProducer.notifyAppUpgrade(partialBucketSplitTimeNs);
-            break;
-        case BOOT_COMPLETE:
-            durationProducer.onStatsdInitCompleted(partialBucketSplitTimeNs);
-            break;
-    }
-    ASSERT_EQ(2UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    std::vector<DurationBucket> buckets =
-            durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-    EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs, buckets[0].mDuration);
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketStartNs);
-    EXPECT_EQ(partialBucketSplitTimeNs, buckets[1].mBucketEndNs);
-    EXPECT_EQ(partialBucketSplitTimeNs - (bucketStartTimeNs + bucketSizeNs), buckets[1].mDuration);
-    EXPECT_EQ(partialBucketSplitTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-    EXPECT_EQ(1, durationProducer.getCurrentBucketNum());
-
-    // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
-    int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event2, endTimeNs, tagId);
-    durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
-    buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-    ASSERT_EQ(3UL, buckets.size());
-    EXPECT_EQ(partialBucketSplitTimeNs, buckets[2].mBucketStartNs);
-    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs);
-    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs - partialBucketSplitTimeNs,
-              buckets[2].mDuration);
-}
-
-TEST_P(DurationMetricProducerTest_PartialBucket, TestSumDurationAnomaly) {
-    sp<AlarmMonitor> alarmMonitor;
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-    int tagId = 1;
-
-    // Setup metric with alert.
-    DurationMetric metric;
-    metric.set_id(1);
-    metric.set_bucket(ONE_MINUTE);
-    metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-    Alert alert;
-    alert.set_num_buckets(3);
-    alert.set_trigger_if_sum_gt(2);
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    FieldMatcher dimensions;
-
-    DurationMetricProducer durationProducer(
-            kConfigKey, metric, -1 /* no condition */, {}, -1 /*what index not needed*/,
-            1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
-            wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-
-    sp<AnomalyTracker> anomalyTracker = durationProducer.addAnomalyTracker(alert, alarmMonitor);
-    EXPECT_TRUE(anomalyTracker != nullptr);
-
-    int64_t startTimeNs = bucketStartTimeNs + 1;
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event1, startTimeNs, tagId);
-    durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
-
-    int64_t partialBucketSplitTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
-    switch (GetParam()) {
-        case APP_UPGRADE:
-            durationProducer.notifyAppUpgrade(partialBucketSplitTimeNs);
-            break;
-        case BOOT_COMPLETE:
-            durationProducer.onStatsdInitCompleted(partialBucketSplitTimeNs);
-            break;
-    }
-
-    // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
-    int64_t endTimeNs = startTimeNs + 65 * NS_PER_SEC;
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event2, endTimeNs, tagId);
-    durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
-
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs,
-              anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-}
-
-TEST_P(DurationMetricProducerTest_PartialBucket, TestMaxDuration) {
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-    int tagId = 1;
-
-    DurationMetric metric;
-    metric.set_id(1);
-    metric.set_bucket(ONE_MINUTE);
-    metric.set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    FieldMatcher dimensions;
-
-    DurationMetricProducer durationProducer(
-            kConfigKey, metric, -1 /* no condition */, {}, -1 /*what index not needed*/,
-            1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
-            wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-
-    int64_t startTimeNs = bucketStartTimeNs + 1;
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event1, startTimeNs, tagId);
-    durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
-    ASSERT_EQ(0UL, durationProducer.mPastBuckets.size());
-    EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-
-    int64_t partialBucketSplitTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
-    switch (GetParam()) {
-        case APP_UPGRADE:
-            durationProducer.notifyAppUpgrade(partialBucketSplitTimeNs);
-            break;
-        case BOOT_COMPLETE:
-            durationProducer.onStatsdInitCompleted(partialBucketSplitTimeNs);
-            break;
-    }
-    ASSERT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    EXPECT_EQ(partialBucketSplitTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-    EXPECT_EQ(0, durationProducer.getCurrentBucketNum());
-
-    // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
-    int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event2, endTimeNs, tagId);
-    durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
-    ASSERT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-
-    durationProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
-    std::vector<DurationBucket> buckets =
-            durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-    ASSERT_EQ(1UL, buckets.size());
-    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketStartNs);
-    EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, buckets[0].mBucketEndNs);
-    EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration);
-}
-
-TEST_P(DurationMetricProducerTest_PartialBucket, TestMaxDurationWithSplitInNextBucket) {
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-    int tagId = 1;
-
-    DurationMetric metric;
-    metric.set_id(1);
-    metric.set_bucket(ONE_MINUTE);
-    metric.set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    FieldMatcher dimensions;
-
-    DurationMetricProducer durationProducer(
-            kConfigKey, metric, -1 /* no condition */, {}, -1 /*what index not needed*/,
-            1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
-            wizard, protoHash, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-
-    int64_t startTimeNs = bucketStartTimeNs + 1;
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event1, startTimeNs, tagId);
-    durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
-    ASSERT_EQ(0UL, durationProducer.mPastBuckets.size());
-    EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-
-    int64_t partialBucketSplitTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
-    switch (GetParam()) {
-        case APP_UPGRADE:
-            durationProducer.notifyAppUpgrade(partialBucketSplitTimeNs);
-            break;
-        case BOOT_COMPLETE:
-            durationProducer.onStatsdInitCompleted(partialBucketSplitTimeNs);
-            break;
-    }
-    ASSERT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    EXPECT_EQ(partialBucketSplitTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-    EXPECT_EQ(1, durationProducer.getCurrentBucketNum());
-
-    // Stop occurs in the same partial bucket as created for the app upgrade.
-    int64_t endTimeNs = startTimeNs + 115 * NS_PER_SEC;
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event2, endTimeNs, tagId);
-    durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
-    ASSERT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    EXPECT_EQ(partialBucketSplitTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-
-    durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
-    std::vector<DurationBucket> buckets =
-            durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-    ASSERT_EQ(1UL, buckets.size());
-    EXPECT_EQ(partialBucketSplitTimeNs, buckets[0].mBucketStartNs);
-    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketEndNs);
-    EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration);
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
deleted file mode 100644
index 4bbbd2c..0000000
--- a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
+++ /dev/null
@@ -1,186 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/metrics/EventMetricProducer.h"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <stdio.h>
-
-#include <vector>
-
-#include "metrics_test_helper.h"
-#include "stats_event.h"
-#include "tests/statsd_test_util.h"
-
-using namespace testing;
-using android::sp;
-using std::set;
-using std::unordered_map;
-using std::vector;
-
-#ifdef __ANDROID__
-
-namespace android {
-namespace os {
-namespace statsd {
-
-
-namespace {
-const ConfigKey kConfigKey(0, 12345);
-const uint64_t protoHash = 0x1234567890;
-
-void makeLogEvent(LogEvent* logEvent, int32_t atomId, int64_t timestampNs, string str) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, atomId);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-    AStatsEvent_writeString(statsEvent, str.c_str());
-
-    parseStatsEventToLogEvent(statsEvent, logEvent);
-}
-}  // anonymous namespace
-
-TEST(EventMetricProducerTest, TestNoCondition) {
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t eventStartTimeNs = bucketStartTimeNs + 1;
-    int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
-
-    EventMetric metric;
-    metric.set_id(1);
-
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    CreateNoValuesLogEvent(&event1, 1 /*tagId*/, bucketStartTimeNs + 1);
-
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    CreateNoValuesLogEvent(&event2, 1 /*tagId*/, bucketStartTimeNs + 2);
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    EventMetricProducer eventProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
-                                      wizard, protoHash, bucketStartTimeNs);
-
-    eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
-    eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
-
-    // Check dump report content.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    eventProducer.onDumpReport(bucketStartTimeNs + 20, true /*include current partial bucket*/,
-                               true /*erase data*/, FAST, &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_event_metrics());
-    ASSERT_EQ(2, report.event_metrics().data_size());
-    EXPECT_EQ(bucketStartTimeNs + 1, report.event_metrics().data(0).elapsed_timestamp_nanos());
-    EXPECT_EQ(bucketStartTimeNs + 2, report.event_metrics().data(1).elapsed_timestamp_nanos());
-}
-
-TEST(EventMetricProducerTest, TestEventsWithNonSlicedCondition) {
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t eventStartTimeNs = bucketStartTimeNs + 1;
-    int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
-
-    EventMetric metric;
-    metric.set_id(1);
-    metric.set_condition(StringToId("SCREEN_ON"));
-
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    CreateNoValuesLogEvent(&event1, 1 /*tagId*/, bucketStartTimeNs + 1);
-
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    CreateNoValuesLogEvent(&event2, 1 /*tagId*/, bucketStartTimeNs + 10);
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    EventMetricProducer eventProducer(kConfigKey, metric, 0 /*condition index*/,
-                                      {ConditionState::kUnknown}, wizard, protoHash,
-                                      bucketStartTimeNs);
-
-    eventProducer.onConditionChanged(true /*condition*/, bucketStartTimeNs);
-    eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
-
-    eventProducer.onConditionChanged(false /*condition*/, bucketStartTimeNs + 2);
-
-    eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
-
-    // Check dump report content.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    eventProducer.onDumpReport(bucketStartTimeNs + 20, true /*include current partial bucket*/,
-                               true /*erase data*/, FAST, &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_event_metrics());
-    ASSERT_EQ(1, report.event_metrics().data_size());
-    EXPECT_EQ(bucketStartTimeNs + 1, report.event_metrics().data(0).elapsed_timestamp_nanos());
-}
-
-TEST(EventMetricProducerTest, TestEventsWithSlicedCondition) {
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
-
-    int tagId = 1;
-    int conditionTagId = 2;
-
-    EventMetric metric;
-    metric.set_id(1);
-    metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON"));
-    MetricConditionLink* link = metric.add_links();
-    link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID"));
-    buildSimpleAtomFieldMatcher(tagId, 1, link->mutable_fields_in_what());
-    buildSimpleAtomFieldMatcher(conditionTagId, 2, link->mutable_fields_in_condition());
-
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event1, 1 /*tagId*/, bucketStartTimeNs + 1, "111");
-    ConditionKey key1;
-    key1[StringToId("APP_IN_BACKGROUND_PER_UID")] = {
-            getMockedDimensionKey(conditionTagId, 2, "111")};
-
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    makeLogEvent(&event2, 1 /*tagId*/, bucketStartTimeNs + 10, "222");
-    ConditionKey key2;
-    key2[StringToId("APP_IN_BACKGROUND_PER_UID")] = {
-            getMockedDimensionKey(conditionTagId, 2, "222")};
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    // Condition is false for first event.
-    EXPECT_CALL(*wizard, query(_, key1, _)).WillOnce(Return(ConditionState::kFalse));
-    // Condition is true for second event.
-    EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue));
-
-    EventMetricProducer eventProducer(kConfigKey, metric, 0 /*condition index*/,
-                                      {ConditionState::kUnknown}, wizard, protoHash,
-                                      bucketStartTimeNs);
-
-    eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
-    eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
-
-    // Check dump report content.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    eventProducer.onDumpReport(bucketStartTimeNs + 20, true /*include current partial bucket*/,
-                               true /*erase data*/, FAST, &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_event_metrics());
-    ASSERT_EQ(1, report.event_metrics().data_size());
-    EXPECT_EQ(bucketStartTimeNs + 10, report.event_metrics().data(0).elapsed_timestamp_nanos());
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
deleted file mode 100644
index 1060681..0000000
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ /dev/null
@@ -1,828 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/metrics/GaugeMetricProducer.h"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <math.h>
-#include <stdio.h>
-
-#include <vector>
-
-#include "logd/LogEvent.h"
-#include "metrics_test_helper.h"
-#include "src/matchers/SimpleAtomMatchingTracker.h"
-#include "src/metrics/MetricProducer.h"
-#include "src/stats_log_util.h"
-#include "stats_event.h"
-#include "tests/statsd_test_util.h"
-
-using namespace testing;
-using android::sp;
-using std::set;
-using std::unordered_map;
-using std::vector;
-using std::make_shared;
-
-#ifdef __ANDROID__
-
-namespace android {
-namespace os {
-namespace statsd {
-
-namespace {
-
-const ConfigKey kConfigKey(0, 12345);
-const int tagId = 1;
-const int64_t metricId = 123;
-const uint64_t protoHash = 0x123456789;
-const int logEventMatcherIndex = 0;
-const int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
-const int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-const int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
-const int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
-const int64_t bucket4StartTimeNs = bucketStartTimeNs + 3 * bucketSizeNs;
-const int64_t partialBucketSplitTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
-
-shared_ptr<LogEvent> makeLogEvent(int32_t atomId, int64_t timestampNs, int32_t value1, string str1,
-                                  int32_t value2) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, atomId);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-
-    AStatsEvent_writeInt32(statsEvent, value1);
-    AStatsEvent_writeString(statsEvent, str1.c_str());
-    AStatsEvent_writeInt32(statsEvent, value2);
-
-    shared_ptr<LogEvent> logEvent = std::make_shared<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-}  // anonymous namespace
-
-// Setup for parameterized tests.
-class GaugeMetricProducerTest_PartialBucket : public TestWithParam<BucketSplitEvent> {};
-
-INSTANTIATE_TEST_SUITE_P(GaugeMetricProducerTest_PartialBucket,
-                         GaugeMetricProducerTest_PartialBucket,
-                         testing::Values(APP_UPGRADE, BOOT_COMPLETE));
-
-/*
- * Tests that the first bucket works correctly
- */
-TEST(GaugeMetricProducerTest, TestFirstBucket) {
-    GaugeMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_gauge_fields_filter()->set_include_all(false);
-    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-    gaugeFieldMatcher->set_field(tagId);
-    gaugeFieldMatcher->add_child()->set_field(1);
-    gaugeFieldMatcher->add_child()->set_field(3);
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-
-    // statsd started long ago.
-    // The metric starts in the middle of the bucket
-    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
-                                      wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
-                                      -1, -1, tagId, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2,
-                                      pullerManager);
-    gaugeProducer.prepareFirstBucket();
-
-    EXPECT_EQ(600500000000, gaugeProducer.mCurrentBucketStartTimeNs);
-    EXPECT_EQ(10, gaugeProducer.mCurrentBucketNum);
-    EXPECT_EQ(660000000005, gaugeProducer.getCurrentBucketEndTimeNs());
-}
-
-TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition) {
-    GaugeMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_gauge_fields_filter()->set_include_all(false);
-    metric.set_max_pull_delay_sec(INT_MAX);
-    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-    gaugeFieldMatcher->set_field(tagId);
-    gaugeFieldMatcher->add_child()->set_field(1);
-    gaugeFieldMatcher->add_child()->set_field(3);
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
-                data->clear();
-                data->push_back(makeLogEvent(tagId, eventTimeNs + 10, 3, "some value", 11));
-                return true;
-            }));
-
-    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
-                                      wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
-                                      tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
-                                      pullerManager);
-    gaugeProducer.prepareFirstBucket();
-
-    vector<shared_ptr<LogEvent>> allData;
-    allData.clear();
-    allData.push_back(makeLogEvent(tagId, bucket2StartTimeNs + 1, 10, "some value", 11));
-
-    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-    ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-    auto it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
-    EXPECT_EQ(INT, it->mValue.getType());
-    EXPECT_EQ(10, it->mValue.int_value);
-    it++;
-    EXPECT_EQ(11, it->mValue.int_value);
-    ASSERT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-    EXPECT_EQ(3, gaugeProducer.mPastBuckets.begin()
-                         ->second.back()
-                         .mGaugeAtoms.front()
-                         .mFields->begin()
-                         ->mValue.int_value);
-
-    allData.clear();
-    allData.push_back(makeLogEvent(tagId, bucket3StartTimeNs + 10, 24, "some value", 25));
-    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
-    ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-    it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
-    EXPECT_EQ(INT, it->mValue.getType());
-    EXPECT_EQ(24, it->mValue.int_value);
-    it++;
-    EXPECT_EQ(INT, it->mValue.getType());
-    EXPECT_EQ(25, it->mValue.int_value);
-    // One dimension.
-    ASSERT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-    ASSERT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
-    it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin();
-    EXPECT_EQ(INT, it->mValue.getType());
-    EXPECT_EQ(10L, it->mValue.int_value);
-    it++;
-    EXPECT_EQ(INT, it->mValue.getType());
-    EXPECT_EQ(11L, it->mValue.int_value);
-
-    gaugeProducer.flushIfNeededLocked(bucket4StartTimeNs);
-    ASSERT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
-    // One dimension.
-    ASSERT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-    ASSERT_EQ(3UL, gaugeProducer.mPastBuckets.begin()->second.size());
-    it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin();
-    EXPECT_EQ(INT, it->mValue.getType());
-    EXPECT_EQ(24L, it->mValue.int_value);
-    it++;
-    EXPECT_EQ(INT, it->mValue.getType());
-    EXPECT_EQ(25L, it->mValue.int_value);
-}
-
-TEST_P(GaugeMetricProducerTest_PartialBucket, TestPushedEvents) {
-    sp<AlarmMonitor> alarmMonitor;
-    GaugeMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_gauge_fields_filter()->set_include_all(true);
-
-    Alert alert;
-    alert.set_id(101);
-    alert.set_metric_id(metricId);
-    alert.set_trigger_if_sum_gt(25);
-    alert.set_num_buckets(100);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-
-    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
-                                      wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
-                                      -1 /* -1 means no pulling */, -1, tagId, bucketStartTimeNs,
-                                      bucketStartTimeNs, pullerManager);
-    gaugeProducer.prepareFirstBucket();
-
-    sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
-    EXPECT_TRUE(anomalyTracker != nullptr);
-
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10);
-    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-    EXPECT_EQ(1UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY));
-
-    switch (GetParam()) {
-        case APP_UPGRADE:
-            gaugeProducer.notifyAppUpgrade(partialBucketSplitTimeNs);
-            break;
-        case BOOT_COMPLETE:
-            gaugeProducer.onStatsdInitCompleted(partialBucketSplitTimeNs);
-            break;
-    }
-    EXPECT_EQ(0UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY));
-    ASSERT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    EXPECT_EQ(bucketStartTimeNs,
-              gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
-    EXPECT_EQ(partialBucketSplitTimeNs,
-              gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
-    EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
-    EXPECT_EQ(partialBucketSplitTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
-    // Partial buckets are not sent to anomaly tracker.
-    EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-
-    // Create an event in the same partial bucket.
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 59 * NS_PER_SEC, 1, 10);
-    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-    EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
-    ASSERT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    EXPECT_EQ(bucketStartTimeNs,
-              gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
-    EXPECT_EQ(partialBucketSplitTimeNs,
-              gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
-    EXPECT_EQ((int64_t)partialBucketSplitTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
-    // Partial buckets are not sent to anomaly tracker.
-    EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-
-    // Next event should trigger creation of new bucket and send previous full bucket to anomaly
-    // tracker.
-    LogEvent event3(/*uid=*/0, /*pid=*/0);
-    CreateTwoValueLogEvent(&event3, tagId, bucketStartTimeNs + 65 * NS_PER_SEC, 1, 10);
-    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
-    EXPECT_EQ(1L, gaugeProducer.mCurrentBucketNum);
-    ASSERT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    EXPECT_EQ((int64_t)bucketStartTimeNs + bucketSizeNs, gaugeProducer.mCurrentBucketStartTimeNs);
-    EXPECT_EQ(1, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-
-    // Next event should trigger creation of new bucket.
-    LogEvent event4(/*uid=*/0, /*pid=*/0);
-    CreateTwoValueLogEvent(&event4, tagId, bucketStartTimeNs + 125 * NS_PER_SEC, 1, 10);
-    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
-    EXPECT_EQ(2L, gaugeProducer.mCurrentBucketNum);
-    ASSERT_EQ(3UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-}
-
-TEST_P(GaugeMetricProducerTest_PartialBucket, TestPulled) {
-    GaugeMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.set_max_pull_delay_sec(INT_MAX);
-    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-    gaugeFieldMatcher->set_field(tagId);
-    gaugeFieldMatcher->add_child()->set_field(2);
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            .WillOnce(Return(false))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, partialBucketSplitTimeNs);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs, 2));
-                return true;
-            }));
-
-    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
-                                      wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
-                                      tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
-                                      pullerManager);
-    gaugeProducer.prepareFirstBucket();
-
-    vector<shared_ptr<LogEvent>> allData;
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 1));
-    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
-    ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-    EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
-                         ->second.front()
-                         .mFields->begin()
-                         ->mValue.int_value);
-
-    switch (GetParam()) {
-        case APP_UPGRADE:
-            gaugeProducer.notifyAppUpgrade(partialBucketSplitTimeNs);
-            break;
-        case BOOT_COMPLETE:
-            gaugeProducer.onStatsdInitCompleted(partialBucketSplitTimeNs);
-            break;
-    }
-    ASSERT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    EXPECT_EQ(bucketStartTimeNs,
-              gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
-    EXPECT_EQ(partialBucketSplitTimeNs,
-              gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
-    EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
-    EXPECT_EQ(partialBucketSplitTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
-    ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-    EXPECT_EQ(2, gaugeProducer.mCurrentSlicedBucket->begin()
-                         ->second.front()
-                         .mFields->begin()
-                         ->mValue.int_value);
-
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + bucketSizeNs + 1, 3));
-    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + bucketSizeNs);
-    ASSERT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-    EXPECT_EQ(3, gaugeProducer.mCurrentSlicedBucket->begin()
-                         ->second.front()
-                         .mFields->begin()
-                         ->mValue.int_value);
-}
-
-TEST(GaugeMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
-    GaugeMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.set_max_pull_delay_sec(INT_MAX);
-    metric.set_split_bucket_for_app_upgrade(false);
-    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-    gaugeFieldMatcher->set_field(tagId);
-    gaugeFieldMatcher->add_child()->set_field(2);
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
-            .WillOnce(Return(false));
-
-    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
-                                      wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
-                                      tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
-                                      pullerManager);
-    gaugeProducer.prepareFirstBucket();
-
-    vector<shared_ptr<LogEvent>> allData;
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 1));
-    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
-    ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-    EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
-                         ->second.front()
-                         .mFields->begin()
-                         ->mValue.int_value);
-
-    gaugeProducer.notifyAppUpgrade(partialBucketSplitTimeNs);
-    ASSERT_EQ(0UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
-    EXPECT_EQ(bucketStartTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
-    ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-    EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
-                         ->second.front()
-                         .mFields->begin()
-                         ->mValue.int_value);
-}
-
-TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition) {
-    GaugeMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.set_max_pull_delay_sec(INT_MAX);
-    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-    gaugeFieldMatcher->set_field(tagId);
-    gaugeFieldMatcher->add_child()->set_field(2);
-    metric.set_condition(StringToId("SCREEN_ON"));
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-
-    int64_t conditionChangeNs = bucketStartTimeNs + 8;
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, conditionChangeNs, _))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs + 10, 100));
-                return true;
-            }));
-
-    GaugeMetricProducer gaugeProducer(kConfigKey, metric, 0 /*condition index*/,
-                                      {ConditionState::kUnknown}, wizard, protoHash,
-                                      logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-    gaugeProducer.prepareFirstBucket();
-
-    gaugeProducer.onConditionChanged(true, conditionChangeNs);
-    ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-    EXPECT_EQ(100, gaugeProducer.mCurrentSlicedBucket->begin()
-                           ->second.front()
-                           .mFields->begin()
-                           ->mValue.int_value);
-    ASSERT_EQ(0UL, gaugeProducer.mPastBuckets.size());
-
-    vector<shared_ptr<LogEvent>> allData;
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 110));
-    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-
-    ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-    EXPECT_EQ(110, gaugeProducer.mCurrentSlicedBucket->begin()
-                           ->second.front()
-                           .mFields->begin()
-                           ->mValue.int_value);
-    ASSERT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-    EXPECT_EQ(100, gaugeProducer.mPastBuckets.begin()
-                           ->second.back()
-                           .mGaugeAtoms.front()
-                           .mFields->begin()
-                           ->mValue.int_value);
-
-    gaugeProducer.onConditionChanged(false, bucket2StartTimeNs + 10);
-    gaugeProducer.flushIfNeededLocked(bucket3StartTimeNs + 10);
-    ASSERT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-    ASSERT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(110L, gaugeProducer.mPastBuckets.begin()
-                            ->second.back()
-                            .mGaugeAtoms.front()
-                            .mFields->begin()
-                            ->mValue.int_value);
-}
-
-TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) {
-    const int conditionTag = 65;
-    GaugeMetric metric;
-    metric.set_id(1111111);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_gauge_fields_filter()->set_include_all(true);
-    metric.set_condition(StringToId("APP_DIED"));
-    metric.set_max_pull_delay_sec(INT_MAX);
-    auto dim = metric.mutable_dimensions_in_what();
-    dim->set_field(tagId);
-    dim->add_child()->set_field(1);
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    EXPECT_CALL(*wizard, query(_, _, _))
-            .WillRepeatedly(
-                    Invoke([](const int conditionIndex, const ConditionKey& conditionParameters,
-                              const bool isPartialLink) {
-                        int pos[] = {1, 0, 0};
-                        Field f(conditionTag, pos, 0);
-                        HashableDimensionKey key;
-                        key.mutableValues()->emplace_back(f, Value((int32_t)1000000));
-
-                        return ConditionState::kTrue;
-                    }));
-
-    int64_t sliceConditionChangeNs = bucketStartTimeNs + 8;
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, sliceConditionChangeNs, _))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                data->push_back(CreateTwoValueLogEvent(tagId, eventTimeNs + 10, 1000, 100));
-                return true;
-            }));
-
-    GaugeMetricProducer gaugeProducer(kConfigKey, metric, 0 /*condition index*/,
-                                      {ConditionState::kUnknown}, wizard, protoHash,
-                                      logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-    gaugeProducer.prepareFirstBucket();
-
-    gaugeProducer.onSlicedConditionMayChange(true, sliceConditionChangeNs);
-
-    ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-    const auto& key = gaugeProducer.mCurrentSlicedBucket->begin()->first;
-    ASSERT_EQ(1UL, key.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1000, key.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-
-    ASSERT_EQ(0UL, gaugeProducer.mPastBuckets.size());
-
-    vector<shared_ptr<LogEvent>> allData;
-    allData.clear();
-    allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1000, 110));
-    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-
-    ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-    ASSERT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-}
-
-TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) {
-    sp<AlarmMonitor> alarmMonitor;
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
-            .WillOnce(Return(false));
-
-    GaugeMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.set_max_pull_delay_sec(INT_MAX);
-    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-    gaugeFieldMatcher->set_field(tagId);
-    gaugeFieldMatcher->add_child()->set_field(2);
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-
-    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
-                                      wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
-                                      tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
-                                      pullerManager);
-    gaugeProducer.prepareFirstBucket();
-
-    Alert alert;
-    alert.set_id(101);
-    alert.set_metric_id(metricId);
-    alert.set_trigger_if_sum_gt(25);
-    alert.set_num_buckets(2);
-    const int32_t refPeriodSec = 60;
-    alert.set_refractory_period_secs(refPeriodSec);
-    sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
-
-    int tagId = 1;
-    vector<shared_ptr<LogEvent>> allData;
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 13));
-    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
-    ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-    EXPECT_EQ(13L, gaugeProducer.mCurrentSlicedBucket->begin()
-                           ->second.front()
-                           .mFields->begin()
-                           ->mValue.int_value);
-    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
-
-    std::shared_ptr<LogEvent> event2 =
-            CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + bucketSizeNs + 20, 15);
-
-    allData.clear();
-    allData.push_back(event2);
-    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + bucketSizeNs);
-    ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-    EXPECT_EQ(15L, gaugeProducer.mCurrentSlicedBucket->begin()
-                           ->second.front()
-                           .mFields->begin()
-                           ->mValue.int_value);
-    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-              std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC) + refPeriodSec);
-
-    allData.clear();
-    allData.push_back(
-            CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 10, 26));
-    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 2 * bucketSizeNs);
-    ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-    EXPECT_EQ(26L, gaugeProducer.mCurrentSlicedBucket->begin()
-                           ->second.front()
-                           .mFields->begin()
-                           ->mValue.int_value);
-    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-              std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
-
-    // This event does not have the gauge field. Thus the current bucket value is 0.
-    allData.clear();
-    allData.push_back(CreateNoValuesLogEvent(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 10));
-    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + 3 * bucketSizeNs);
-    ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-    EXPECT_TRUE(gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->empty());
-}
-
-TEST(GaugeMetricProducerTest, TestPullOnTrigger) {
-    GaugeMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
-    metric.mutable_gauge_fields_filter()->set_include_all(false);
-    metric.set_max_pull_delay_sec(INT_MAX);
-    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-    gaugeFieldMatcher->set_field(tagId);
-    gaugeFieldMatcher->add_child()->set_field(1);
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs, 4));
-                return true;
-            }))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs, 5));
-                return true;
-            }))
-            .WillOnce(Return(true));
-
-    int triggerId = 5;
-    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
-                                      wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
-                                      tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
-                                      pullerManager);
-    gaugeProducer.prepareFirstBucket();
-
-    ASSERT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
-
-    LogEvent triggerEvent(/*uid=*/0, /*pid=*/0);
-    CreateNoValuesLogEvent(&triggerEvent, triggerId, bucketStartTimeNs + 10);
-    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
-    ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
-    triggerEvent.setElapsedTimestampNs(bucketStartTimeNs + 20);
-    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
-    ASSERT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
-    triggerEvent.setElapsedTimestampNs(bucket2StartTimeNs + 1);
-    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
-
-    ASSERT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-    ASSERT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.size());
-    EXPECT_EQ(4, gaugeProducer.mPastBuckets.begin()
-                         ->second.back()
-                         .mGaugeAtoms[0]
-                         .mFields->begin()
-                         ->mValue.int_value);
-    EXPECT_EQ(5, gaugeProducer.mPastBuckets.begin()
-                         ->second.back()
-                         .mGaugeAtoms[1]
-                         .mFields->begin()
-                         ->mValue.int_value);
-}
-
-TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput) {
-    GaugeMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
-    metric.mutable_gauge_fields_filter()->set_include_all(true);
-    metric.set_max_pull_delay_sec(INT_MAX);
-    auto dimensionMatcher = metric.mutable_dimensions_in_what();
-    // use field 1 as dimension.
-    dimensionMatcher->set_field(tagId);
-    dimensionMatcher->add_child()->set_field(1);
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 3);
-                data->clear();
-                data->push_back(CreateTwoValueLogEvent(tagId, eventTimeNs, 3, 4));
-                return true;
-            }))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
-                data->clear();
-                data->push_back(CreateTwoValueLogEvent(tagId, eventTimeNs, 4, 5));
-                return true;
-            }))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20);
-                data->clear();
-                data->push_back(CreateTwoValueLogEvent(tagId, eventTimeNs, 4, 6));
-                return true;
-            }))
-            .WillOnce(Return(true));
-
-    int triggerId = 5;
-    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
-                                      wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
-                                      tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
-                                      pullerManager);
-    gaugeProducer.prepareFirstBucket();
-
-    LogEvent triggerEvent(/*uid=*/0, /*pid=*/0);
-    CreateNoValuesLogEvent(&triggerEvent, triggerId, bucketStartTimeNs + 3);
-    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
-    ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-    triggerEvent.setElapsedTimestampNs(bucketStartTimeNs + 10);
-    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
-    ASSERT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->size());
-    ASSERT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
-    triggerEvent.setElapsedTimestampNs(bucketStartTimeNs + 20);
-    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
-    ASSERT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
-    triggerEvent.setElapsedTimestampNs(bucket2StartTimeNs + 1);
-    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
-
-    ASSERT_EQ(2UL, gaugeProducer.mPastBuckets.size());
-    auto bucketIt = gaugeProducer.mPastBuckets.begin();
-    ASSERT_EQ(1UL, bucketIt->second.back().mGaugeAtoms.size());
-    EXPECT_EQ(3, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value);
-    EXPECT_EQ(4, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value);
-    bucketIt++;
-    ASSERT_EQ(2UL, bucketIt->second.back().mGaugeAtoms.size());
-    EXPECT_EQ(4, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value);
-    EXPECT_EQ(5, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value);
-    EXPECT_EQ(6, bucketIt->second.back().mGaugeAtoms[1].mFields->begin()->mValue.int_value);
-}
-
-/*
- * Test that BUCKET_TOO_SMALL dump reason is logged when a flushed bucket size
- * is smaller than the "min_bucket_size_nanos" specified in the metric config.
- */
-TEST(GaugeMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) {
-    GaugeMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(FIVE_MINUTES);
-    metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
-    metric.set_min_bucket_size_nanos(10000000000);  // 10 seconds
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 3, _))
-            // Bucket start.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, eventTimeNs, 10));
-                return true;
-            }));
-
-    int triggerId = 5;
-    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
-                                      wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
-                                      tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
-                                      pullerManager);
-    gaugeProducer.prepareFirstBucket();
-
-    LogEvent triggerEvent(/*uid=*/0, /*pid=*/0);
-    CreateNoValuesLogEvent(&triggerEvent, triggerId, bucketStartTimeNs + 3);
-    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
-
-    // Check dump report.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    gaugeProducer.onDumpReport(bucketStartTimeNs + 9000000, true /* include recent buckets */, true,
-                               FAST /* dump_latency */, &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_gauge_metrics());
-    ASSERT_EQ(0, report.gauge_metrics().data_size());
-    ASSERT_EQ(1, report.gauge_metrics().skipped_size());
-
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
-              report.gauge_metrics().skipped(0).start_bucket_elapsed_millis());
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000),
-              report.gauge_metrics().skipped(0).end_bucket_elapsed_millis());
-    ASSERT_EQ(1, report.gauge_metrics().skipped(0).drop_event_size());
-
-    auto dropEvent = report.gauge_metrics().skipped(0).drop_event(0);
-    EXPECT_EQ(BucketDropReason::BUCKET_TOO_SMALL, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000), dropEvent.drop_time_millis());
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
deleted file mode 100644
index fda3daa..0000000
--- a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
+++ /dev/null
@@ -1,424 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/metrics/duration_helper/MaxDurationTracker.h"
-#include "src/condition/ConditionWizard.h"
-#include "metrics_test_helper.h"
-#include "tests/statsd_test_util.h"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <stdio.h>
-#include <set>
-#include <unordered_map>
-#include <vector>
-
-using namespace android::os::statsd;
-using namespace testing;
-using android::sp;
-using std::set;
-using std::unordered_map;
-using std::vector;
-
-#ifdef __ANDROID__
-
-namespace android {
-namespace os {
-namespace statsd {
-
-const ConfigKey kConfigKey(0, 12345);
-
-const int TagId = 1;
-
-const HashableDimensionKey eventKey = getMockedDimensionKey(TagId, 0, "1");
-const HashableDimensionKey conditionKey = getMockedDimensionKey(TagId, 4, "1");
-const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
-const HashableDimensionKey key2 = getMockedDimensionKey(TagId, 1, "2");
-const int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
-
-TEST(MaxDurationTrackerTest, TestSimpleMaxDuration) {
-    const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "1");
-    const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
-    const HashableDimensionKey key2 = getMockedDimensionKey(TagId, 1, "2");
-
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
-
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
-    int64_t bucketNum = 0;
-
-    int64_t metricId = 1;
-    MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, false, bucketStartTimeNs,
-                               bucketNum, bucketStartTimeNs, bucketSizeNs, false, false, {});
-
-    tracker.noteStart(key1, true, bucketStartTimeNs, ConditionKey());
-    // Event starts again. This would not change anything as it already starts.
-    tracker.noteStart(key1, true, bucketStartTimeNs + 3, ConditionKey());
-    // Stopped.
-    tracker.noteStop(key1, bucketStartTimeNs + 10, false);
-
-    // Another event starts in this bucket.
-    tracker.noteStart(key2, true, bucketStartTimeNs + 20, ConditionKey());
-    tracker.noteStop(key2, bucketStartTimeNs + 40, false /*stop all*/);
-
-    tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
-    EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
-    ASSERT_EQ(1u, buckets[eventKey].size());
-    EXPECT_EQ(20LL, buckets[eventKey][0].mDuration);
-}
-
-TEST(MaxDurationTrackerTest, TestStopAll) {
-    const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "1");
-    const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
-    const HashableDimensionKey key2 = getMockedDimensionKey(TagId, 1, "2");
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
-
-    int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
-    int64_t bucketNum = 0;
-
-    int64_t metricId = 1;
-    MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, false, bucketStartTimeNs,
-                               bucketNum, bucketStartTimeNs, bucketSizeNs, false, false, {});
-
-    tracker.noteStart(key1, true, bucketStartTimeNs + 1, ConditionKey());
-
-    // Another event starts in this bucket.
-    tracker.noteStart(key2, true, bucketStartTimeNs + 20, ConditionKey());
-    tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 40, &buckets);
-    tracker.noteStopAll(bucketStartTimeNs + bucketSizeNs + 40);
-    EXPECT_TRUE(tracker.mInfos.empty());
-    EXPECT_TRUE(buckets.find(eventKey) == buckets.end());
-
-    tracker.flushIfNeeded(bucketStartTimeNs + 3 * bucketSizeNs + 40, &buckets);
-    EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
-    ASSERT_EQ(1u, buckets[eventKey].size());
-    EXPECT_EQ(bucketSizeNs + 40 - 1, buckets[eventKey][0].mDuration);
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[eventKey][0].mBucketStartNs);
-    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[eventKey][0].mBucketEndNs);
-}
-
-TEST(MaxDurationTrackerTest, TestCrossBucketBoundary) {
-    const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "1");
-    const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
-    const HashableDimensionKey key2 = getMockedDimensionKey(TagId, 1, "2");
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
-
-    int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
-    int64_t bucketNum = 0;
-
-    int64_t metricId = 1;
-    MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, false, bucketStartTimeNs,
-                               bucketNum, bucketStartTimeNs, bucketSizeNs, false, false, {});
-
-    // The event starts.
-    tracker.noteStart(DEFAULT_DIMENSION_KEY, true, bucketStartTimeNs + 1, ConditionKey());
-
-    // Starts again. Does not DEFAULT_DIMENSION_KEY anything.
-    tracker.noteStart(DEFAULT_DIMENSION_KEY, true, bucketStartTimeNs + bucketSizeNs + 1,
-                      ConditionKey());
-
-    // The event stops at early 4th bucket.
-    // Notestop is called from DurationMetricProducer's onMatchedLogEvent, which calls
-    // flushIfneeded.
-    tracker.flushIfNeeded(bucketStartTimeNs + (3 * bucketSizeNs) + 20, &buckets);
-    tracker.noteStop(DEFAULT_DIMENSION_KEY, bucketStartTimeNs + (3 * bucketSizeNs) + 20,
-                     false /*stop all*/);
-    EXPECT_TRUE(buckets.find(eventKey) == buckets.end());
-
-    tracker.flushIfNeeded(bucketStartTimeNs + 4 * bucketSizeNs, &buckets);
-    ASSERT_EQ(1u, buckets[eventKey].size());
-    EXPECT_EQ((3 * bucketSizeNs) + 20 - 1, buckets[eventKey][0].mDuration);
-    EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, buckets[eventKey][0].mBucketStartNs);
-    EXPECT_EQ(bucketStartTimeNs + 4 * bucketSizeNs, buckets[eventKey][0].mBucketEndNs);
-}
-
-TEST(MaxDurationTrackerTest, TestCrossBucketBoundary_nested) {
-    const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "1");
-    const HashableDimensionKey key1 = getMockedDimensionKey(TagId, 1, "1");
-    const HashableDimensionKey key2 = getMockedDimensionKey(TagId, 1, "2");
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
-
-    int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
-    int64_t bucketNum = 0;
-
-    int64_t metricId = 1;
-    MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, -1, true, bucketStartTimeNs,
-                               bucketNum, bucketStartTimeNs, bucketSizeNs, false, false, {});
-
-    // 2 starts
-    tracker.noteStart(DEFAULT_DIMENSION_KEY, true, bucketStartTimeNs + 1, ConditionKey());
-    tracker.noteStart(DEFAULT_DIMENSION_KEY, true, bucketStartTimeNs + 10, ConditionKey());
-    // one stop
-    tracker.noteStop(DEFAULT_DIMENSION_KEY, bucketStartTimeNs + 20, false /*stop all*/);
-
-    tracker.flushIfNeeded(bucketStartTimeNs + (2 * bucketSizeNs) + 1, &buckets);
-    // Because of nesting, still not stopped.
-    EXPECT_TRUE(buckets.find(eventKey) == buckets.end());
-
-    // real stop now.
-    tracker.noteStop(DEFAULT_DIMENSION_KEY,
-                     bucketStartTimeNs + (2 * bucketSizeNs) + 5, false);
-    tracker.flushIfNeeded(bucketStartTimeNs + (3 * bucketSizeNs) + 1, &buckets);
-
-    ASSERT_EQ(1u, buckets[eventKey].size());
-    EXPECT_EQ(2 * bucketSizeNs + 5 - 1, buckets[eventKey][0].mDuration);
-}
-
-TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) {
-    const HashableDimensionKey conditionDimKey = key1;
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    ConditionKey conditionKey1;
-    MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 1, "1");
-    conditionKey1[StringToId("APP_BACKGROUND")] = conditionDimKey;
-
-    /**
-    Start in first bucket, stop in second bucket. Condition turns on and off in the first bucket
-    and again turns on and off in the second bucket.
-    */
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
-    int64_t eventStartTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
-    int64_t conditionStarts1 = bucketStartTimeNs + 11 * NS_PER_SEC;
-    int64_t conditionStops1 = bucketStartTimeNs + 14 * NS_PER_SEC;
-    int64_t conditionStarts2 = bucketStartTimeNs + bucketSizeNs + 5 * NS_PER_SEC;
-    int64_t conditionStops2 = conditionStarts2 + 10 * NS_PER_SEC;
-    int64_t eventStopTimeNs = conditionStops2 + 8 * NS_PER_SEC;
-
-    int64_t metricId = 1;
-    MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, false, bucketStartTimeNs,
-                               0, bucketStartTimeNs, bucketSizeNs, true, false, {});
-    EXPECT_TRUE(tracker.mAnomalyTrackers.empty());
-
-    tracker.noteStart(key1, false, eventStartTimeNs, conditionKey1);
-    tracker.noteConditionChanged(key1, true, conditionStarts1);
-    tracker.noteConditionChanged(key1, false, conditionStops1);
-    unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
-    tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
-    ASSERT_EQ(0U, buckets.size());
-
-    tracker.noteConditionChanged(key1, true, conditionStarts2);
-    tracker.noteConditionChanged(key1, false, conditionStops2);
-    tracker.noteStop(key1, eventStopTimeNs, false);
-    tracker.flushIfNeeded(bucketStartTimeNs + 2 * bucketSizeNs + 1, &buckets);
-    ASSERT_EQ(1U, buckets.size());
-    vector<DurationBucket> item = buckets.begin()->second;
-    ASSERT_EQ(1UL, item.size());
-    EXPECT_EQ((int64_t)(13LL * NS_PER_SEC), item[0].mDuration);
-}
-
-TEST(MaxDurationTrackerTest, TestAnomalyDetection) {
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    ConditionKey conditionKey1;
-    MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 2, "maps");
-    conditionKey1[StringToId("APP_BACKGROUND")] = conditionKey;
-
-    unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
-
-    int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
-    int64_t bucketNum = 0;
-    int64_t eventStartTimeNs = 13000000000;
-    int64_t durationTimeNs = 2 * 1000;
-
-    int64_t metricId = 1;
-    Alert alert;
-    alert.set_id(101);
-    alert.set_metric_id(1);
-    alert.set_trigger_if_sum_gt(40 * NS_PER_SEC);
-    alert.set_num_buckets(2);
-    const int32_t refPeriodSec = 45;
-    alert.set_refractory_period_secs(refPeriodSec);
-    sp<AlarmMonitor> alarmMonitor;
-    sp<DurationAnomalyTracker> anomalyTracker =
-        new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
-    MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, false, bucketStartTimeNs,
-                               bucketNum, bucketStartTimeNs, bucketSizeNs, true, false,
-                               {anomalyTracker});
-
-    tracker.noteStart(key1, true, eventStartTimeNs, conditionKey1);
-    sp<const InternalAlarm> alarm = anomalyTracker->mAlarms.begin()->second;
-    EXPECT_EQ((long long)(53ULL * NS_PER_SEC), (long long)(alarm->timestampSec * NS_PER_SEC));
-
-    // Remove the anomaly alarm when the duration is no longer fully met.
-    tracker.noteConditionChanged(key1, false, eventStartTimeNs + 15 * NS_PER_SEC);
-    ASSERT_EQ(0U, anomalyTracker->mAlarms.size());
-
-    // Since the condition was off for 10 seconds, the anomaly should trigger 10 sec later.
-    tracker.noteConditionChanged(key1, true, eventStartTimeNs + 25 * NS_PER_SEC);
-    ASSERT_EQ(1U, anomalyTracker->mAlarms.size());
-    alarm = anomalyTracker->mAlarms.begin()->second;
-    EXPECT_EQ((long long)(63ULL * NS_PER_SEC), (long long)(alarm->timestampSec * NS_PER_SEC));
-}
-
-// This tests that we correctly compute the predicted time of an anomaly assuming that the current
-// state continues forward as-is.
-TEST(MaxDurationTrackerTest, TestAnomalyPredictedTimestamp) {
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    ConditionKey conditionKey1;
-    MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 2, "maps");
-    conditionKey1[StringToId("APP_BACKGROUND")] = conditionKey;
-    ConditionKey conditionKey2;
-    conditionKey2[StringToId("APP_BACKGROUND")] = getMockedDimensionKey(TagId, 4, "2");
-
-    unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
-
-    /**
-     * Suppose we have two sub-dimensions that we're taking the MAX over. In the first of these
-     * nested dimensions, we enter the pause state after 3 seconds. When we resume, the second
-     * dimension has already been running for 4 seconds. Thus, we have 40-4=36 seconds remaining
-     * before we trigger the anomaly.
-     */
-    int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
-    int64_t bucketNum = 0;
-    int64_t eventStartTimeNs = bucketStartTimeNs + 5 * NS_PER_SEC;  // Condition is off at start.
-    int64_t conditionStarts1 = bucketStartTimeNs + 11 * NS_PER_SEC;
-    int64_t conditionStops1 = bucketStartTimeNs + 14 * NS_PER_SEC;
-    int64_t conditionStarts2 = bucketStartTimeNs + 20 * NS_PER_SEC;
-    int64_t eventStartTimeNs2 = conditionStarts2 - 4 * NS_PER_SEC;
-
-    int64_t metricId = 1;
-    Alert alert;
-    alert.set_id(101);
-    alert.set_metric_id(1);
-    alert.set_trigger_if_sum_gt(40 * NS_PER_SEC);
-    alert.set_num_buckets(2);
-    const int32_t refPeriodSec = 45;
-    alert.set_refractory_period_secs(refPeriodSec);
-    sp<AlarmMonitor> alarmMonitor;
-    sp<DurationAnomalyTracker> anomalyTracker =
-        new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
-    MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, false, bucketStartTimeNs,
-                               bucketNum, bucketStartTimeNs, bucketSizeNs, true, false,
-                               {anomalyTracker});
-
-    tracker.noteStart(key1, false, eventStartTimeNs, conditionKey1);
-    tracker.noteConditionChanged(key1, true, conditionStarts1);
-    tracker.noteConditionChanged(key1, false, conditionStops1);
-    tracker.noteStart(key2, true, eventStartTimeNs2, conditionKey2);  // Condition is on already.
-    tracker.noteConditionChanged(key1, true, conditionStarts2);
-    ASSERT_EQ(1U, anomalyTracker->mAlarms.size());
-    auto alarm = anomalyTracker->mAlarms.begin()->second;
-    int64_t anomalyFireTimeSec = alarm->timestampSec;
-    EXPECT_EQ(conditionStarts2 + 36 * NS_PER_SEC,
-            (long long)anomalyFireTimeSec * NS_PER_SEC);
-
-    // Now we test the calculation now that there's a refractory period.
-    // At the correct time, declare the anomaly. This will set a refractory period. Make sure it
-    // gets correctly taken into account in future predictAnomalyTimestampNs calculations.
-    std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> firedAlarms({alarm});
-    anomalyTracker->informAlarmsFired(anomalyFireTimeSec * NS_PER_SEC, firedAlarms);
-    ASSERT_EQ(0u, anomalyTracker->mAlarms.size());
-    int64_t refractoryPeriodEndsSec = anomalyFireTimeSec + refPeriodSec;
-    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), refractoryPeriodEndsSec);
-
-    // Now stop and start again. Make sure the new predictAnomalyTimestampNs takes into account
-    // the refractory period correctly.
-    int64_t eventStopTimeNs = anomalyFireTimeSec * NS_PER_SEC + 10;
-    tracker.noteStop(key1, eventStopTimeNs, false);
-    tracker.noteStop(key2, eventStopTimeNs, false);
-    tracker.noteStart(key1, true, eventStopTimeNs + 1000000, conditionKey1);
-    // Anomaly is ongoing, but we're still in the refractory period.
-    ASSERT_EQ(1U, anomalyTracker->mAlarms.size());
-    alarm = anomalyTracker->mAlarms.begin()->second;
-    EXPECT_EQ(refractoryPeriodEndsSec, (long long)(alarm->timestampSec));
-
-    // Makes sure it is correct after the refractory period is over.
-    tracker.noteStop(key1, eventStopTimeNs + 2000000, false);
-    int64_t justBeforeRefPeriodNs = (refractoryPeriodEndsSec - 2) * NS_PER_SEC;
-    tracker.noteStart(key1, true, justBeforeRefPeriodNs, conditionKey1);
-    alarm = anomalyTracker->mAlarms.begin()->second;
-    EXPECT_EQ(justBeforeRefPeriodNs + 40 * NS_PER_SEC,
-                (unsigned long long)(alarm->timestampSec * NS_PER_SEC));
-}
-
-// Suppose that within one tracker there are two dimensions A and B.
-// Suppose A starts, then B starts, and then A stops. We still need to set an anomaly based on the
-// elapsed duration of B.
-TEST(MaxDurationTrackerTest, TestAnomalyPredictedTimestamp_UpdatedOnStop) {
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    ConditionKey conditionKey1;
-    MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 2, "maps");
-    conditionKey1[StringToId("APP_BACKGROUND")] = conditionKey;
-    ConditionKey conditionKey2;
-    conditionKey2[StringToId("APP_BACKGROUND")] = getMockedDimensionKey(TagId, 4, "2");
-
-    unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
-
-    /**
-     * Suppose we have two sub-dimensions that we're taking the MAX over. In the first of these
-     * nested dimensions, are started for 8 seconds. When we stop, the other nested dimension has
-     * been started for 5 seconds. So we can only allow 35 more seconds from now.
-     */
-    int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketEndTimeNs = bucketStartTimeNs + bucketSizeNs;
-    int64_t bucketNum = 0;
-    int64_t eventStartTimeNs1 = bucketStartTimeNs + 5 * NS_PER_SEC;  // Condition is off at start.
-    int64_t eventStopTimeNs1 = bucketStartTimeNs + 13 * NS_PER_SEC;
-    int64_t eventStartTimeNs2 = bucketStartTimeNs + 8 * NS_PER_SEC;
-
-    int64_t metricId = 1;
-    Alert alert;
-    alert.set_id(101);
-    alert.set_metric_id(1);
-    alert.set_trigger_if_sum_gt(40 * NS_PER_SEC);
-    alert.set_num_buckets(2);
-    const int32_t refPeriodSec = 45;
-    alert.set_refractory_period_secs(refPeriodSec);
-    sp<AlarmMonitor> alarmMonitor;
-    sp<DurationAnomalyTracker> anomalyTracker =
-        new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
-    MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, false, bucketStartTimeNs,
-                               bucketNum, bucketStartTimeNs, bucketSizeNs, true, false,
-                               {anomalyTracker});
-
-    tracker.noteStart(key1, true, eventStartTimeNs1, conditionKey1);
-    tracker.noteStart(key2, true, eventStartTimeNs2, conditionKey2);
-    tracker.noteStop(key1, eventStopTimeNs1, false);
-    ASSERT_EQ(1U, anomalyTracker->mAlarms.size());
-    auto alarm = anomalyTracker->mAlarms.begin()->second;
-    EXPECT_EQ(eventStopTimeNs1 + 35 * NS_PER_SEC,
-              (unsigned long long)(alarm->timestampSec * NS_PER_SEC));
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
deleted file mode 100644
index 1d6f7de..0000000
--- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
+++ /dev/null
@@ -1,576 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/metrics/duration_helper/OringDurationTracker.h"
-#include "src/condition/ConditionWizard.h"
-#include "metrics_test_helper.h"
-#include "tests/statsd_test_util.h"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <math.h>
-#include <stdio.h>
-#include <set>
-#include <unordered_map>
-#include <vector>
-
-using namespace testing;
-using android::sp;
-using std::set;
-using std::unordered_map;
-using std::vector;
-
-#ifdef __ANDROID__
-namespace android {
-namespace os {
-namespace statsd {
-
-const ConfigKey kConfigKey(0, 12345);
-const int TagId = 1;
-const int64_t metricId = 123;
-const HashableDimensionKey eventKey = getMockedDimensionKey(TagId, 0, "event");
-
-const HashableDimensionKey kConditionKey1 = getMockedDimensionKey(TagId, 1, "maps");
-const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
-const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
-const int64_t bucketSizeNs = 30 * NS_PER_SEC;
-
-TEST(OringDurationTrackerTest, TestDurationOverlap) {
-    const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "event");
-
-    const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
-    const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
-
-    int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketNum = 0;
-    int64_t eventStartTimeNs = bucketStartTimeNs + 1;
-    int64_t durationTimeNs = 2 * 1000;
-
-    OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, false,
-                                 bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
-                                 false, false, {});
-
-    tracker.noteStart(kEventKey1, true, eventStartTimeNs, ConditionKey());
-    EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
-    tracker.noteStart(kEventKey1, true, eventStartTimeNs + 10, ConditionKey());  // overlapping wl
-    EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
-
-    tracker.noteStop(kEventKey1, eventStartTimeNs + durationTimeNs, false);
-    tracker.flushIfNeeded(eventStartTimeNs + bucketSizeNs + 1, &buckets);
-    EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
-
-    ASSERT_EQ(1u, buckets[eventKey].size());
-    EXPECT_EQ(durationTimeNs, buckets[eventKey][0].mDuration);
-}
-
-TEST(OringDurationTrackerTest, TestDurationNested) {
-    const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "event");
-
-    const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
-    const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
-
-    int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketNum = 0;
-    int64_t eventStartTimeNs = bucketStartTimeNs + 1;
-
-    OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true, bucketStartTimeNs,
-                                 bucketNum, bucketStartTimeNs, bucketSizeNs, false, false, {});
-
-    tracker.noteStart(kEventKey1, true, eventStartTimeNs, ConditionKey());
-    tracker.noteStart(kEventKey1, true, eventStartTimeNs + 10, ConditionKey());  // overlapping wl
-
-    tracker.noteStop(kEventKey1, eventStartTimeNs + 2000, false);
-    tracker.noteStop(kEventKey1, eventStartTimeNs + 2003, false);
-
-    tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
-    EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
-    ASSERT_EQ(1u, buckets[eventKey].size());
-    EXPECT_EQ(2003LL, buckets[eventKey][0].mDuration);
-}
-
-TEST(OringDurationTrackerTest, TestStopAll) {
-    const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "event");
-
-    const std::vector<HashableDimensionKey> kConditionKey1 =
-        {getMockedDimensionKey(TagId, 1, "maps")};
-    const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
-    const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
-
-    int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketNum = 0;
-    int64_t eventStartTimeNs = bucketStartTimeNs + 1;
-
-    OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true, bucketStartTimeNs,
-                                 bucketNum, bucketStartTimeNs, bucketSizeNs, false, false, {});
-
-    tracker.noteStart(kEventKey1, true, eventStartTimeNs, ConditionKey());
-    tracker.noteStart(kEventKey2, true, eventStartTimeNs + 10, ConditionKey());  // overlapping wl
-
-    tracker.noteStopAll(eventStartTimeNs + 2003);
-
-    tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
-    EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
-    ASSERT_EQ(1u, buckets[eventKey].size());
-    EXPECT_EQ(2003LL, buckets[eventKey][0].mDuration);
-}
-
-TEST(OringDurationTrackerTest, TestCrossBucketBoundary) {
-    const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "event");
-
-    const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
-    const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
-
-    int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketNum = 0;
-    int64_t eventStartTimeNs = bucketStartTimeNs + 1;
-    int64_t durationTimeNs = 2 * 1000;
-
-    OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true, bucketStartTimeNs,
-                                 bucketNum, bucketStartTimeNs, bucketSizeNs, false, false, {});
-
-    tracker.noteStart(kEventKey1, true, eventStartTimeNs, ConditionKey());
-    EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
-    tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs, &buckets);
-    tracker.noteStart(kEventKey1, true, eventStartTimeNs + 2 * bucketSizeNs, ConditionKey());
-    EXPECT_EQ((long long)(bucketStartTimeNs + 2 * bucketSizeNs), tracker.mLastStartTime);
-
-    ASSERT_EQ(2u, buckets[eventKey].size());
-    EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
-    EXPECT_EQ(bucketSizeNs, buckets[eventKey][1].mDuration);
-
-    tracker.noteStop(kEventKey1, eventStartTimeNs + 2 * bucketSizeNs + 10, false);
-    tracker.noteStop(kEventKey1, eventStartTimeNs + 2 * bucketSizeNs + 12, false);
-    tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 12, &buckets);
-    EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
-    ASSERT_EQ(2u, buckets[eventKey].size());
-    EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
-    EXPECT_EQ(bucketSizeNs, buckets[eventKey][1].mDuration);
-}
-
-TEST(OringDurationTrackerTest, TestDurationConditionChange) {
-    const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "event");
-
-    const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
-    const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    ConditionKey key1;
-    key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
-
-    EXPECT_CALL(*wizard, query(_, key1, _))  // #4
-            .WillOnce(Return(ConditionState::kFalse));
-
-    unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
-
-    int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketNum = 0;
-    int64_t eventStartTimeNs = bucketStartTimeNs + 1;
-    int64_t durationTimeNs = 2 * 1000;
-
-    OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, false,
-                                 bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
-                                 true, false, {});
-
-    tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
-
-    tracker.onSlicedConditionMayChange(true, eventStartTimeNs + 5);
-
-    tracker.noteStop(kEventKey1, eventStartTimeNs + durationTimeNs, false);
-
-    tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
-    EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
-    ASSERT_EQ(1u, buckets[eventKey].size());
-    EXPECT_EQ(5LL, buckets[eventKey][0].mDuration);
-}
-
-TEST(OringDurationTrackerTest, TestDurationConditionChange2) {
-    const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "event");
-
-    const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
-    const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    ConditionKey key1;
-    key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
-
-    EXPECT_CALL(*wizard, query(_, key1, _))
-            .Times(2)
-            .WillOnce(Return(ConditionState::kFalse))
-            .WillOnce(Return(ConditionState::kTrue));
-
-    unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
-
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
-    int64_t bucketNum = 0;
-    int64_t eventStartTimeNs = bucketStartTimeNs + 1;
-    int64_t durationTimeNs = 2 * 1000;
-
-    OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, false,
-                                 bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
-                                 true, false, {});
-
-    tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
-    // condition to false; record duration 5n
-    tracker.onSlicedConditionMayChange(true, eventStartTimeNs + 5);
-    // condition to true.
-    tracker.onSlicedConditionMayChange(true, eventStartTimeNs + 1000);
-    // 2nd duration: 1000ns
-    tracker.noteStop(kEventKey1, eventStartTimeNs + durationTimeNs, false);
-
-    tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
-    EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
-    ASSERT_EQ(1u, buckets[eventKey].size());
-    EXPECT_EQ(1005LL, buckets[eventKey][0].mDuration);
-}
-
-TEST(OringDurationTrackerTest, TestDurationConditionChangeNested) {
-    const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "event");
-
-    const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
-    const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    ConditionKey key1;
-    key1[StringToId("APP_BACKGROUND")] = kConditionKey1;
-
-    EXPECT_CALL(*wizard, query(_, key1, _))  // #4
-            .WillOnce(Return(ConditionState::kFalse));
-
-    unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
-
-    int64_t bucketStartTimeNs = 10000000000;
-    int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
-    int64_t bucketNum = 0;
-    int64_t eventStartTimeNs = bucketStartTimeNs + 1;
-
-    OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true, bucketStartTimeNs,
-                                 bucketNum, bucketStartTimeNs, bucketSizeNs, true, false, {});
-
-    tracker.noteStart(kEventKey1, true, eventStartTimeNs, key1);
-    tracker.noteStart(kEventKey1, true, eventStartTimeNs + 2, key1);
-
-    tracker.noteStop(kEventKey1, eventStartTimeNs + 3, false);
-
-    tracker.onSlicedConditionMayChange(true, eventStartTimeNs + 15);
-
-    tracker.noteStop(kEventKey1, eventStartTimeNs + 2003, false);
-
-    tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
-    EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
-    ASSERT_EQ(1u, buckets[eventKey].size());
-    EXPECT_EQ(15LL, buckets[eventKey][0].mDuration);
-}
-
-TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) {
-    const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "event");
-
-    const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
-    const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
-    Alert alert;
-    alert.set_id(101);
-    alert.set_metric_id(1);
-    alert.set_trigger_if_sum_gt(40 * NS_PER_SEC);
-    alert.set_num_buckets(2);
-    alert.set_refractory_period_secs(1);
-
-    unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
-    int64_t bucketNum = 0;
-    int64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
-
-    sp<AlarmMonitor> alarmMonitor;
-    sp<DurationAnomalyTracker> anomalyTracker =
-        new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
-    OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true, bucketStartTimeNs,
-                                 bucketNum, bucketStartTimeNs, bucketSizeNs, true, false,
-                                 {anomalyTracker});
-
-    // Nothing in the past bucket.
-    tracker.noteStart(DEFAULT_DIMENSION_KEY, true, eventStartTimeNs, ConditionKey());
-    EXPECT_EQ((long long)(alert.trigger_if_sum_gt() + eventStartTimeNs),
-              tracker.predictAnomalyTimestampNs(*anomalyTracker, eventStartTimeNs));
-
-    tracker.noteStop(DEFAULT_DIMENSION_KEY, eventStartTimeNs + 3, false);
-    ASSERT_EQ(0u, buckets[eventKey].size());
-
-    int64_t event1StartTimeNs = eventStartTimeNs + 10;
-    tracker.noteStart(kEventKey1, true, event1StartTimeNs, ConditionKey());
-    // No past buckets. The anomaly will happen in bucket #0.
-    EXPECT_EQ((long long)(event1StartTimeNs + alert.trigger_if_sum_gt() - 3),
-              tracker.predictAnomalyTimestampNs(*anomalyTracker, event1StartTimeNs));
-
-    int64_t event1StopTimeNs = eventStartTimeNs + bucketSizeNs + 10;
-    tracker.flushIfNeeded(event1StopTimeNs, &buckets);
-    tracker.noteStop(kEventKey1, event1StopTimeNs, false);
-
-    EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
-    ASSERT_EQ(1u, buckets[eventKey].size());
-    EXPECT_EQ(3LL + bucketStartTimeNs + bucketSizeNs - eventStartTimeNs - 10,
-              buckets[eventKey][0].mDuration);
-
-    const int64_t bucket0Duration = 3ULL + bucketStartTimeNs + bucketSizeNs - eventStartTimeNs - 10;
-    const int64_t bucket1Duration = eventStartTimeNs + 10 - bucketStartTimeNs;
-
-    // One past buckets. The anomaly will happen in bucket #1.
-    int64_t event2StartTimeNs = eventStartTimeNs + bucketSizeNs + 15;
-    tracker.noteStart(kEventKey1, true, event2StartTimeNs, ConditionKey());
-    EXPECT_EQ((long long)(event2StartTimeNs + alert.trigger_if_sum_gt() - bucket0Duration -
-                          bucket1Duration),
-              tracker.predictAnomalyTimestampNs(*anomalyTracker, event2StartTimeNs));
-    tracker.noteStop(kEventKey1, event2StartTimeNs + 1, false);
-
-    // Only one past buckets is applicable. Bucket +0 should be trashed. The anomaly will happen in
-    // bucket #2.
-    int64_t event3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs - 9 * NS_PER_SEC;
-    tracker.noteStart(kEventKey1, true, event3StartTimeNs, ConditionKey());
-    EXPECT_EQ((long long)(event3StartTimeNs + alert.trigger_if_sum_gt() - bucket1Duration - 1LL),
-              tracker.predictAnomalyTimestampNs(*anomalyTracker, event3StartTimeNs));
-}
-
-TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp2) {
-    Alert alert;
-    alert.set_id(101);
-    alert.set_metric_id(1);
-    alert.set_trigger_if_sum_gt(5 * NS_PER_SEC);
-    alert.set_num_buckets(1);
-    alert.set_refractory_period_secs(20);
-
-    int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
-    int64_t bucketNum = 0;
-
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    sp<AlarmMonitor> alarmMonitor;
-    sp<DurationAnomalyTracker> anomalyTracker =
-        new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
-    OringDurationTracker tracker(kConfigKey, metricId, DEFAULT_METRIC_DIMENSION_KEY, wizard, 1,
-
-                                 true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
-                                 bucketSizeNs, true, false, {anomalyTracker});
-
-    int64_t eventStartTimeNs = bucketStartTimeNs + 9 * NS_PER_SEC;
-    tracker.noteStart(DEFAULT_DIMENSION_KEY, true, eventStartTimeNs, ConditionKey());
-    // Anomaly happens in the bucket #1.
-    EXPECT_EQ((long long)(bucketStartTimeNs + 14 * NS_PER_SEC),
-              tracker.predictAnomalyTimestampNs(*anomalyTracker, eventStartTimeNs));
-
-    tracker.noteStop(DEFAULT_DIMENSION_KEY, bucketStartTimeNs + 14 * NS_PER_SEC, false);
-
-    EXPECT_EQ((long long)(bucketStartTimeNs + 34 * NS_PER_SEC) / NS_PER_SEC,
-              anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY));
-
-    int64_t event2StartTimeNs = bucketStartTimeNs + 22 * NS_PER_SEC;
-    EXPECT_EQ((long long)(bucketStartTimeNs + 34 * NS_PER_SEC) / NS_PER_SEC,
-              anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY));
-    EXPECT_EQ((long long)(bucketStartTimeNs + 35 * NS_PER_SEC),
-              tracker.predictAnomalyTimestampNs(*anomalyTracker, event2StartTimeNs));
-}
-
-TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp3) {
-    // Test the cases where the refractory period is smaller than the bucket size, longer than
-    // the bucket size, and longer than 2x of the anomaly detection window.
-    for (int j = 0; j < 3; j++) {
-        int64_t thresholdNs = j * bucketSizeNs + 5 * NS_PER_SEC;
-        for (int i = 0; i <= 7; ++i) {
-
-            Alert alert;
-            alert.set_id(101);
-            alert.set_metric_id(1);
-            alert.set_trigger_if_sum_gt(thresholdNs);
-            alert.set_num_buckets(3);
-            alert.set_refractory_period_secs(
-                bucketSizeNs / NS_PER_SEC / 2 + i * bucketSizeNs / NS_PER_SEC);
-
-            int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
-            int64_t bucketNum = 101;
-
-            sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-            sp<AlarmMonitor> alarmMonitor;
-            sp<DurationAnomalyTracker> anomalyTracker =
-                new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
-            OringDurationTracker tracker(kConfigKey, metricId, DEFAULT_METRIC_DIMENSION_KEY, wizard,
-                                         1, true, bucketStartTimeNs, bucketNum, bucketStartTimeNs,
-                                         bucketSizeNs, true, false, {anomalyTracker});
-
-            int64_t eventStartTimeNs = bucketStartTimeNs + 9 * NS_PER_SEC;
-            tracker.noteStart(DEFAULT_DIMENSION_KEY, true, eventStartTimeNs, ConditionKey());
-            EXPECT_EQ((long long)(eventStartTimeNs + thresholdNs),
-                      tracker.predictAnomalyTimestampNs(*anomalyTracker, eventStartTimeNs));
-            int64_t eventStopTimeNs = eventStartTimeNs + thresholdNs + NS_PER_SEC;
-            tracker.noteStop(DEFAULT_DIMENSION_KEY, eventStopTimeNs, false);
-
-            int64_t refractoryPeriodEndSec =
-                anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY);
-            EXPECT_EQ(eventStopTimeNs / (int64_t)NS_PER_SEC + alert.refractory_period_secs(),
-                       refractoryPeriodEndSec);
-
-            // Acquire and release a wakelock in the next bucket.
-            int64_t event2StartTimeNs = eventStopTimeNs + bucketSizeNs;
-            tracker.noteStart(DEFAULT_DIMENSION_KEY, true, event2StartTimeNs, ConditionKey());
-            int64_t event2StopTimeNs = event2StartTimeNs + 4 * NS_PER_SEC;
-            tracker.noteStop(DEFAULT_DIMENSION_KEY, event2StopTimeNs, false);
-
-            // Test the alarm prediction works well when seeing another wakelock start event.
-            for (int k = 0; k <= 2; ++k) {
-                int64_t event3StartTimeNs = event2StopTimeNs + NS_PER_SEC + k * bucketSizeNs;
-                int64_t alarmTimestampNs =
-                    tracker.predictAnomalyTimestampNs(*anomalyTracker, event3StartTimeNs);
-                EXPECT_GT(alarmTimestampNs, 0u);
-                EXPECT_GE(alarmTimestampNs, event3StartTimeNs);
-                EXPECT_GE(alarmTimestampNs, refractoryPeriodEndSec *(int64_t) NS_PER_SEC);
-            }
-        }
-    }
-}
-
-TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm) {
-    const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "event");
-
-    const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
-    const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
-    Alert alert;
-    alert.set_id(101);
-    alert.set_metric_id(1);
-    alert.set_trigger_if_sum_gt(40 * NS_PER_SEC);
-    alert.set_num_buckets(2);
-    const int32_t refPeriodSec = 45;
-    alert.set_refractory_period_secs(refPeriodSec);
-
-    unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-
-    int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
-    int64_t bucketNum = 0;
-    int64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
-
-    sp<AlarmMonitor> alarmMonitor;
-    sp<DurationAnomalyTracker> anomalyTracker =
-        new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
-    OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true /*nesting*/,
-                                 bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs,
-                                 false, false, {anomalyTracker});
-
-    tracker.noteStart(kEventKey1, true, eventStartTimeNs, ConditionKey());
-    tracker.noteStop(kEventKey1, eventStartTimeNs + 10, false);
-    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
-    EXPECT_TRUE(tracker.mStarted.empty());
-    EXPECT_EQ(10LL, tracker.mStateKeyDurationMap[DEFAULT_DIMENSION_KEY].mDuration);  // 10ns
-
-    ASSERT_EQ(0u, tracker.mStarted.size());
-
-    tracker.noteStart(kEventKey1, true, eventStartTimeNs + 20, ConditionKey());
-    ASSERT_EQ(1u, anomalyTracker->mAlarms.size());
-    EXPECT_EQ((long long)(52ULL * NS_PER_SEC),  // (10s + 1s + 1ns + 20ns) - 10ns + 40s, rounded up
-              (long long)(anomalyTracker->mAlarms.begin()->second->timestampSec * NS_PER_SEC));
-    // The alarm is set to fire at 52s, and when it does, an anomaly would be declared. However,
-    // because this is a unit test, the alarm won't actually fire at all. Since the alarm fails
-    // to fire in time, the anomaly is instead caught when noteStop is called, at around 71s.
-    tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 25, &buckets);
-    tracker.noteStop(kEventKey1, eventStartTimeNs + 2 * bucketSizeNs + 25, false);
-    EXPECT_EQ(anomalyTracker->getSumOverPastBuckets(eventKey), (long long)(bucketSizeNs));
-    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey),
-              std::ceil((eventStartTimeNs + 2 * bucketSizeNs + 25.0) / NS_PER_SEC + refPeriodSec));
-}
-
-TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm) {
-    const MetricDimensionKey eventKey = getMockedMetricDimensionKey(TagId, 0, "event");
-
-    const HashableDimensionKey kEventKey1 = getMockedDimensionKey(TagId, 2, "maps");
-    const HashableDimensionKey kEventKey2 = getMockedDimensionKey(TagId, 3, "maps");
-    Alert alert;
-    alert.set_id(101);
-    alert.set_metric_id(1);
-    alert.set_trigger_if_sum_gt(40 * NS_PER_SEC);
-    alert.set_num_buckets(2);
-    const int32_t refPeriodSec = 45;
-    alert.set_refractory_period_secs(refPeriodSec);
-
-    unordered_map<MetricDimensionKey, vector<DurationBucket>> buckets;
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    ConditionKey conkey;
-    conkey[StringToId("APP_BACKGROUND")] = kConditionKey1;
-    int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
-    int64_t bucketSizeNs = 30 * NS_PER_SEC;
-
-    sp<AlarmMonitor> alarmMonitor;
-    sp<DurationAnomalyTracker> anomalyTracker =
-        new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor);
-    OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, true /*nesting*/,
-                                 bucketStartTimeNs, 0, bucketStartTimeNs, bucketSizeNs, false,
-                                 false, {anomalyTracker});
-
-    tracker.noteStart(kEventKey1, true, 15 * NS_PER_SEC, conkey);  // start key1
-    ASSERT_EQ(1u, anomalyTracker->mAlarms.size());
-    sp<const InternalAlarm> alarm = anomalyTracker->mAlarms.begin()->second;
-    EXPECT_EQ((long long)(55ULL * NS_PER_SEC), (long long)(alarm->timestampSec * NS_PER_SEC));
-    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
-
-    tracker.noteStop(kEventKey1, 17 * NS_PER_SEC, false); // stop key1 (2 seconds later)
-    ASSERT_EQ(0u, anomalyTracker->mAlarms.size());
-    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
-
-    tracker.noteStart(kEventKey1, true, 22 * NS_PER_SEC, conkey);  // start key1 again
-    ASSERT_EQ(1u, anomalyTracker->mAlarms.size());
-    alarm = anomalyTracker->mAlarms.begin()->second;
-    EXPECT_EQ((long long)(60ULL * NS_PER_SEC), (long long)(alarm->timestampSec * NS_PER_SEC));
-    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
-
-    tracker.noteStart(kEventKey2, true, 32 * NS_PER_SEC, conkey);  // start key2
-    ASSERT_EQ(1u, anomalyTracker->mAlarms.size());
-    alarm = anomalyTracker->mAlarms.begin()->second;
-    EXPECT_EQ((long long)(60ULL * NS_PER_SEC), (long long)(alarm->timestampSec * NS_PER_SEC));
-    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
-
-    tracker.noteStop(kEventKey1, 47 * NS_PER_SEC, false); // stop key1
-    ASSERT_EQ(1u, anomalyTracker->mAlarms.size());
-    alarm = anomalyTracker->mAlarms.begin()->second;
-    EXPECT_EQ((long long)(60ULL * NS_PER_SEC), (long long)(alarm->timestampSec * NS_PER_SEC));
-    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U);
-
-    // Now, at 60s, which is 38s after key1 started again, we have reached 40s of 'on' time.
-    std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> firedAlarms({alarm});
-    anomalyTracker->informAlarmsFired(62 * NS_PER_SEC, firedAlarms);
-    ASSERT_EQ(0u, anomalyTracker->mAlarms.size());
-    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 62U + refPeriodSec);
-
-    tracker.noteStop(kEventKey2, 69 * NS_PER_SEC, false); // stop key2
-    ASSERT_EQ(0u, anomalyTracker->mAlarms.size());
-    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 62U + refPeriodSec);
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
deleted file mode 100644
index 6cf4192..0000000
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ /dev/null
@@ -1,6919 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/metrics/ValueMetricProducer.h"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <math.h>
-#include <stdio.h>
-
-#include <vector>
-
-#include "metrics_test_helper.h"
-#include "src/matchers/SimpleAtomMatchingTracker.h"
-#include "src/metrics/MetricProducer.h"
-#include "src/stats_log_util.h"
-#include "tests/statsd_test_util.h"
-
-using namespace testing;
-using android::sp;
-using std::make_shared;
-using std::set;
-using std::shared_ptr;
-using std::unordered_map;
-using std::vector;
-
-#ifdef __ANDROID__
-
-namespace android {
-namespace os {
-namespace statsd {
-
-namespace {
-
-const ConfigKey kConfigKey(0, 12345);
-const int tagId = 1;
-const int64_t metricId = 123;
-const uint64_t protoHash = 0x1234567890;
-const int logEventMatcherIndex = 0;
-const int64_t bucketStartTimeNs = 10000000000;
-const int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-const int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
-const int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
-const int64_t bucket4StartTimeNs = bucketStartTimeNs + 3 * bucketSizeNs;
-const int64_t bucket5StartTimeNs = bucketStartTimeNs + 4 * bucketSizeNs;
-const int64_t bucket6StartTimeNs = bucketStartTimeNs + 5 * bucketSizeNs;
-double epsilon = 0.001;
-
-static void assertPastBucketValuesSingleKey(
-        const std::unordered_map<MetricDimensionKey, std::vector<PastValueBucket>>& mPastBuckets,
-        const std::initializer_list<int>& expectedValuesList,
-        const std::initializer_list<int64_t>& expectedDurationNsList,
-        const std::initializer_list<int64_t>& expectedStartTimeNsList,
-        const std::initializer_list<int64_t>& expectedEndTimeNsList) {
-    vector<int> expectedValues(expectedValuesList);
-    vector<int64_t> expectedDurationNs(expectedDurationNsList);
-    vector<int64_t> expectedStartTimeNs(expectedStartTimeNsList);
-    vector<int64_t> expectedEndTimeNs(expectedEndTimeNsList);
-
-    ASSERT_EQ(expectedValues.size(), expectedDurationNs.size());
-    ASSERT_EQ(expectedValues.size(), expectedStartTimeNs.size());
-    ASSERT_EQ(expectedValues.size(), expectedEndTimeNs.size());
-
-    if (expectedValues.size() == 0) {
-        ASSERT_EQ(0, mPastBuckets.size());
-        return;
-    }
-
-    ASSERT_EQ(1, mPastBuckets.size());
-    ASSERT_EQ(expectedValues.size(), mPastBuckets.begin()->second.size());
-
-    const vector<PastValueBucket>& buckets = mPastBuckets.begin()->second;
-    for (int i = 0; i < expectedValues.size(); i++) {
-        EXPECT_EQ(expectedValues[i], buckets[i].values[0].long_value)
-                << "Values differ at index " << i;
-        EXPECT_EQ(expectedDurationNs[i], buckets[i].mConditionTrueNs)
-                << "Condition duration value differ at index " << i;
-        EXPECT_EQ(expectedStartTimeNs[i], buckets[i].mBucketStartNs)
-                << "Start time differs at index " << i;
-        EXPECT_EQ(expectedEndTimeNs[i], buckets[i].mBucketEndNs)
-                << "End time differs at index " << i;
-    }
-}
-
-static void assertConditionTimer(const ConditionTimer& conditionTimer, bool condition,
-                                 int64_t timerNs, int64_t lastConditionTrueTimestampNs) {
-    EXPECT_EQ(condition, conditionTimer.mCondition);
-    EXPECT_EQ(timerNs, conditionTimer.mTimerNs);
-    EXPECT_EQ(lastConditionTrueTimestampNs, conditionTimer.mLastConditionChangeTimestampNs);
-}
-
-}  // anonymous namespace
-
-class ValueMetricProducerTestHelper {
-public:
-    static sp<ValueMetricProducer> createValueProducerNoConditions(
-            sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric) {
-        sp<EventMatcherWizard> eventMatcherWizard =
-                createEventMatcherWizard(tagId, logEventMatcherIndex);
-        sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-        EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _))
-                .WillOnce(Return());
-        EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _))
-                .WillRepeatedly(Return());
-
-        sp<ValueMetricProducer> valueProducer =
-                new ValueMetricProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
-                                        wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
-                                        tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-        valueProducer->prepareFirstBucket();
-        return valueProducer;
-    }
-
-    static sp<ValueMetricProducer> createValueProducerWithCondition(
-            sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric,
-            ConditionState conditionAfterFirstBucketPrepared) {
-        sp<EventMatcherWizard> eventMatcherWizard =
-                createEventMatcherWizard(tagId, logEventMatcherIndex);
-        sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-        EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _))
-                .WillOnce(Return());
-        EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _))
-                .WillRepeatedly(Return());
-
-        sp<ValueMetricProducer> valueProducer = new ValueMetricProducer(
-                kConfigKey, metric, 0 /*condition index*/, {ConditionState::kUnknown}, wizard,
-                protoHash, logEventMatcherIndex, eventMatcherWizard, tagId, bucketStartTimeNs,
-                bucketStartTimeNs, pullerManager);
-        valueProducer->prepareFirstBucket();
-        valueProducer->mCondition = conditionAfterFirstBucketPrepared;
-        return valueProducer;
-    }
-
-    static sp<ValueMetricProducer> createValueProducerWithState(
-            sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric,
-            vector<int32_t> slicedStateAtoms,
-            unordered_map<int, unordered_map<int, int64_t>> stateGroupMap) {
-        sp<EventMatcherWizard> eventMatcherWizard =
-                createEventMatcherWizard(tagId, logEventMatcherIndex);
-        sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-        EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _))
-                .WillOnce(Return());
-        EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _))
-                .WillRepeatedly(Return());
-
-        sp<ValueMetricProducer> valueProducer = new ValueMetricProducer(
-                kConfigKey, metric, -1 /* no condition */, {}, wizard, protoHash,
-                logEventMatcherIndex, eventMatcherWizard, tagId, bucketStartTimeNs,
-                bucketStartTimeNs, pullerManager, {}, {}, slicedStateAtoms, stateGroupMap);
-        valueProducer->prepareFirstBucket();
-        return valueProducer;
-    }
-
-    static sp<ValueMetricProducer> createValueProducerWithConditionAndState(
-            sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric,
-            vector<int32_t> slicedStateAtoms,
-            unordered_map<int, unordered_map<int, int64_t>> stateGroupMap,
-            ConditionState conditionAfterFirstBucketPrepared) {
-        sp<EventMatcherWizard> eventMatcherWizard =
-                createEventMatcherWizard(tagId, logEventMatcherIndex);
-        sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-        EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _))
-                .WillOnce(Return());
-        EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _))
-                .WillRepeatedly(Return());
-
-        sp<ValueMetricProducer> valueProducer = new ValueMetricProducer(
-                kConfigKey, metric, 0 /* condition tracker index */, {ConditionState::kUnknown},
-                wizard, protoHash, logEventMatcherIndex, eventMatcherWizard, tagId,
-                bucketStartTimeNs, bucketStartTimeNs, pullerManager, {}, {}, slicedStateAtoms,
-                stateGroupMap);
-        valueProducer->prepareFirstBucket();
-        valueProducer->mCondition = conditionAfterFirstBucketPrepared;
-        return valueProducer;
-    }
-
-    static ValueMetric createMetric() {
-        ValueMetric metric;
-        metric.set_id(metricId);
-        metric.set_bucket(ONE_MINUTE);
-        metric.mutable_value_field()->set_field(tagId);
-        metric.mutable_value_field()->add_child()->set_field(2);
-        metric.set_max_pull_delay_sec(INT_MAX);
-        return metric;
-    }
-
-    static ValueMetric createMetricWithCondition() {
-        ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-        metric.set_condition(StringToId("SCREEN_ON"));
-        return metric;
-    }
-
-    static ValueMetric createMetricWithState(string state) {
-        ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-        metric.add_slice_by_state(StringToId(state));
-        return metric;
-    }
-
-    static ValueMetric createMetricWithConditionAndState(string state) {
-        ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-        metric.set_condition(StringToId("SCREEN_ON"));
-        metric.add_slice_by_state(StringToId(state));
-        return metric;
-    }
-};
-
-// Setup for parameterized tests.
-class ValueMetricProducerTest_PartialBucket : public TestWithParam<BucketSplitEvent> {};
-
-INSTANTIATE_TEST_SUITE_P(ValueMetricProducerTest_PartialBucket,
-                         ValueMetricProducerTest_PartialBucket,
-                         testing::Values(APP_UPGRADE, BOOT_COMPLETE));
-
-/*
- * Tests that the first bucket works correctly
- */
-TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-
-    int64_t startTimeBase = 11;
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-
-    // statsd started long ago.
-    // The metric starts in the middle of the bucket
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
-                                      wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
-                                      -1, startTimeBase, 22, pullerManager);
-    valueProducer.prepareFirstBucket();
-
-    EXPECT_EQ(startTimeBase, valueProducer.calcPreviousBucketEndTime(60 * NS_PER_SEC + 10));
-    EXPECT_EQ(startTimeBase, valueProducer.calcPreviousBucketEndTime(60 * NS_PER_SEC + 10));
-    EXPECT_EQ(60 * NS_PER_SEC + startTimeBase,
-              valueProducer.calcPreviousBucketEndTime(2 * 60 * NS_PER_SEC));
-    EXPECT_EQ(2 * 60 * NS_PER_SEC + startTimeBase,
-              valueProducer.calcPreviousBucketEndTime(3 * 60 * NS_PER_SEC));
-}
-
-/*
- * Tests that the first bucket works correctly
- */
-TEST(ValueMetricProducerTest, TestFirstBucket) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-
-    // statsd started long ago.
-    // The metric starts in the middle of the bucket
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
-                                      wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
-                                      -1, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2, pullerManager);
-    valueProducer.prepareFirstBucket();
-
-    EXPECT_EQ(600500000000, valueProducer.mCurrentBucketStartTimeNs);
-    EXPECT_EQ(10, valueProducer.mCurrentBucketNum);
-    EXPECT_EQ(660000000005, valueProducer.getCurrentBucketEndTimeNs());
-}
-
-/*
- * Tests pulled atoms with no conditions
- */
-TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
-                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
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval =
-            valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    ValueMetricProducer::BaseInfo curBaseInfo =
-            valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(11, curBaseInfo.base.long_value);
-    EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(8, curInterval.value.long_value);
-    ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
-    EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
-    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
-
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 23));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(23, curBaseInfo.base.long_value);
-    EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(12, curInterval.value.long_value);
-    ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
-    ASSERT_EQ(2UL, valueProducer->mPastBuckets.begin()->second.size());
-    EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
-    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
-    EXPECT_EQ(12, 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);
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(36, curBaseInfo.base.long_value);
-    EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(13, curInterval.value.long_value);
-    ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
-    ASSERT_EQ(3UL, valueProducer->mPastBuckets.begin()->second.size());
-    EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
-    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
-    EXPECT_EQ(12, valueProducer->mPastBuckets.begin()->second[1].values[0].long_value);
-    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[1].mConditionTrueNs);
-    EXPECT_EQ(13, valueProducer->mPastBuckets.begin()->second[2].values[0].long_value);
-    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[2].mConditionTrueNs);
-}
-
-TEST_P(ValueMetricProducerTest_PartialBucket, TestPartialBucketCreated) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    int64_t partialBucketSplitTimeNs = bucket2StartTimeNs + 2;
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // Initialize bucket.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 1));
-                return true;
-            }))
-            // Partial bucket.
-            .WillOnce(Invoke([partialBucketSplitTimeNs](int tagId, const ConfigKey&,
-                                                        const int64_t eventTimeNs,
-                                                        vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, partialBucketSplitTimeNs);
-                data->clear();
-                data->push_back(
-                        CreateRepeatedValueLogEvent(tagId, partialBucketSplitTimeNs + 8, 5));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
-
-    // First bucket ends.
-    vector<shared_ptr<LogEvent>> allData;
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 10, 2));
-    valueProducer->onDataPulled(allData, /** success */ true, bucket2StartTimeNs);
-
-    // Partial buckets created in 2nd bucket.
-    switch (GetParam()) {
-        case APP_UPGRADE:
-            valueProducer->notifyAppUpgrade(partialBucketSplitTimeNs);
-            break;
-        case BOOT_COMPLETE:
-            valueProducer->onStatsdInitCompleted(partialBucketSplitTimeNs);
-            break;
-    }
-    EXPECT_EQ(partialBucketSplitTimeNs, valueProducer->mCurrentBucketStartTimeNs);
-    EXPECT_EQ(1, valueProducer->getCurrentBucketNum());
-
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {1, 3},
-                                    {bucketSizeNs, partialBucketSplitTimeNs - bucket2StartTimeNs},
-                                    {bucketStartTimeNs, bucket2StartTimeNs},
-                                    {bucket2StartTimeNs, partialBucketSplitTimeNs});
-}
-
-/*
- * Tests pulled atoms with filtering
- */
-TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-
-    FieldValueMatcher fvm;
-    fvm.set_field(1);
-    fvm.set_eq_int(3);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex, {fvm});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 3, 3));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            new ValueMetricProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, wizard,
-                                    protoHash, logEventMatcherIndex, eventMatcherWizard, tagId,
-                                    bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-    valueProducer->prepareFirstBucket();
-
-    vector<shared_ptr<LogEvent>> allData;
-    allData.clear();
-    allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 3, 11));
-
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval =
-            valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    ValueMetricProducer::BaseInfo curBaseInfo =
-            valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(11, curBaseInfo.base.long_value);
-    EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(8, curInterval.value.long_value);
-    ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
-    EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
-    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
-
-    allData.clear();
-    allData.push_back(CreateTwoValueLogEvent(tagId, bucket3StartTimeNs + 1, 4, 23));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
-    // No new data seen, so data has been cleared.
-    ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
-
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(11, curBaseInfo.base.long_value);
-    EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(8, curInterval.value.long_value);
-    ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
-    EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
-    EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
-
-    allData.clear();
-    allData.push_back(CreateTwoValueLogEvent(tagId, bucket4StartTimeNs + 1, 3, 36));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-
-    // the base was reset
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(36, curBaseInfo.base.long_value);
-    EXPECT_EQ(false, curInterval.hasValue);
-    ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
-    ASSERT_EQ(1UL, valueProducer->mPastBuckets.begin()->second.size());
-    EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
-    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, kConfigKey, bucketStartTimeNs, _))
-            .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
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval =
-            valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    ValueMetricProducer::BaseInfo curBaseInfo =
-            valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(11, curBaseInfo.base.long_value);
-    EXPECT_EQ(false, curInterval.hasValue);
-    ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
-
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 10));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[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);
-    ASSERT_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);
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[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);
-    ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
-    ASSERT_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, kConfigKey, bucketStartTimeNs, _))
-            .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
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval =
-            valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    ValueMetricProducer::BaseInfo curBaseInfo =
-            valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(11, curBaseInfo.base.long_value);
-    EXPECT_EQ(false, curInterval.hasValue);
-    ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
-
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 10));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(10, curBaseInfo.base.long_value);
-    EXPECT_EQ(false, curInterval.hasValue);
-    ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
-
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1, 36));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[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);
-    ASSERT_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, kConfigKey, _, _))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8);  // First condition change.
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
-                return true;
-            }))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 1);  // Second condition change.
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 130));
-                return true;
-            }))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket3StartTimeNs + 1);  // Third condition change.
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 180));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
-
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval =
-            valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    ValueMetricProducer::BaseInfo curBaseInfo =
-            valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-    // startUpdated:false sum:0 start:100
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(100, curBaseInfo.base.long_value);
-    EXPECT_EQ(false, curInterval.hasValue);
-    ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
-
-    vector<shared_ptr<LogEvent>> allData;
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 110));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10}, {bucketSizeNs - 8},
-                                    {bucketStartTimeNs}, {bucket2StartTimeNs});
-
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[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},
-                                    {bucketStartTimeNs}, {bucket2StartTimeNs});
-
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[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},
-                                    {bucketStartTimeNs, bucket2StartTimeNs},
-                                    {bucket2StartTimeNs, bucket3StartTimeNs});
-}
-
-TEST_P(ValueMetricProducerTest_PartialBucket, TestPushedEvents) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
-                                      logEventMatcherIndex, eventMatcherWizard, -1,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-    valueProducer.prepareFirstBucket();
-
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10);
-    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-    ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-
-    int64_t partialBucketSplitTimeNs = bucketStartTimeNs + 150;
-    switch (GetParam()) {
-        case APP_UPGRADE:
-            valueProducer.notifyAppUpgrade(partialBucketSplitTimeNs);
-            break;
-        case BOOT_COMPLETE:
-            valueProducer.onStatsdInitCompleted(partialBucketSplitTimeNs);
-            break;
-    }
-    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {10},
-                                    {partialBucketSplitTimeNs - bucketStartTimeNs},
-                                    {bucketStartTimeNs}, {partialBucketSplitTimeNs});
-    EXPECT_EQ(partialBucketSplitTimeNs, valueProducer.mCurrentBucketStartTimeNs);
-    EXPECT_EQ(0, valueProducer.getCurrentBucketNum());
-
-    // Event arrives after the bucket split.
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 59 * NS_PER_SEC, 20);
-    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-
-    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {10},
-                                    {partialBucketSplitTimeNs - bucketStartTimeNs},
-                                    {bucketStartTimeNs}, {partialBucketSplitTimeNs});
-    EXPECT_EQ(partialBucketSplitTimeNs, valueProducer.mCurrentBucketStartTimeNs);
-    EXPECT_EQ(0, valueProducer.getCurrentBucketNum());
-
-    // Next value should create a new bucket.
-    LogEvent event3(/*uid=*/0, /*pid=*/0);
-    CreateRepeatedValueLogEvent(&event3, tagId, bucket2StartTimeNs + 5 * NS_PER_SEC, 10);
-    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
-    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {10, 20},
-                                    {partialBucketSplitTimeNs - bucketStartTimeNs,
-                                     bucket2StartTimeNs - partialBucketSplitTimeNs},
-                                    {bucketStartTimeNs, partialBucketSplitTimeNs},
-                                    {partialBucketSplitTimeNs, bucket2StartTimeNs});
-    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, valueProducer.mCurrentBucketStartTimeNs);
-    EXPECT_EQ(1, valueProducer.getCurrentBucketNum());
-}
-
-TEST_P(ValueMetricProducerTest_PartialBucket, TestPulledValue) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    int64_t partialBucketSplitTimeNs = bucket2StartTimeNs + 150;
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            .WillOnce(Return(true))
-            .WillOnce(Invoke([partialBucketSplitTimeNs](int tagId, const ConfigKey&,
-                                                        const int64_t eventTimeNs,
-                                                        vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, partialBucketSplitTimeNs);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, partialBucketSplitTimeNs, 120));
-                return true;
-            }));
-
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
-                                      logEventMatcherIndex, eventMatcherWizard, tagId,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-    valueProducer.prepareFirstBucket();
-
-    vector<shared_ptr<LogEvent>> allData;
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 100));
-
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-    ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-
-    switch (GetParam()) {
-        case APP_UPGRADE:
-            valueProducer.notifyAppUpgrade(partialBucketSplitTimeNs);
-            break;
-        case BOOT_COMPLETE:
-            valueProducer.onStatsdInitCompleted(partialBucketSplitTimeNs);
-            break;
-    }
-    EXPECT_EQ(partialBucketSplitTimeNs, valueProducer.mCurrentBucketStartTimeNs);
-    EXPECT_EQ(1, valueProducer.getCurrentBucketNum());
-    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {20}, {150}, {bucket2StartTimeNs},
-                                    {partialBucketSplitTimeNs});
-
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 150));
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
-    EXPECT_EQ(bucket3StartTimeNs, valueProducer.mCurrentBucketStartTimeNs);
-    EXPECT_EQ(2, valueProducer.getCurrentBucketNum());
-    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {20, 30}, {150, bucketSizeNs - 150},
-                                    {bucket2StartTimeNs, partialBucketSplitTimeNs},
-                                    {partialBucketSplitTimeNs, bucket3StartTimeNs});
-}
-
-TEST(ValueMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-    metric.set_split_bucket_for_app_upgrade(false);
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
-            .WillOnce(Return(true));
-
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
-                                      logEventMatcherIndex, eventMatcherWizard, tagId,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-    valueProducer.prepareFirstBucket();
-
-    vector<shared_ptr<LogEvent>> allData;
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 100));
-
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-    ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-
-    valueProducer.notifyAppUpgrade(bucket2StartTimeNs + 150);
-    ASSERT_EQ(0UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    EXPECT_EQ(bucket2StartTimeNs, valueProducer.mCurrentBucketStartTimeNs);
-}
-
-TEST_P(ValueMetricProducerTest_PartialBucket, TestPulledValueWhileConditionFalse) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 1);  // Condition change to true time.
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 100));
-                return true;
-            }))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs,
-                          bucket2StartTimeNs - 100);  // Condition change to false time.
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs - 100, 120));
-                return true;
-            }));
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 1);
-
-    valueProducer->onConditionChanged(false, bucket2StartTimeNs - 100);
-    EXPECT_FALSE(valueProducer->mCondition);
-
-    int64_t partialBucketSplitTimeNs = bucket2StartTimeNs - 50;
-    switch (GetParam()) {
-        case APP_UPGRADE:
-            valueProducer->notifyAppUpgrade(partialBucketSplitTimeNs);
-            break;
-        case BOOT_COMPLETE:
-            valueProducer->onStatsdInitCompleted(partialBucketSplitTimeNs);
-            break;
-    }
-    // Expect one full buckets already done and starting a partial bucket.
-    EXPECT_EQ(partialBucketSplitTimeNs, valueProducer->mCurrentBucketStartTimeNs);
-    EXPECT_EQ(0, valueProducer->getCurrentBucketNum());
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20},
-                                    {(bucket2StartTimeNs - 100) - (bucketStartTimeNs + 1)},
-                                    {bucketStartTimeNs}, {partialBucketSplitTimeNs});
-    EXPECT_FALSE(valueProducer->mCondition);
-}
-
-TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
-                                      logEventMatcherIndex, eventMatcherWizard, -1,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-    valueProducer.prepareFirstBucket();
-
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10);
-
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 20);
-
-    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval =
-            valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
-    ValueMetricProducer::BaseInfo curBaseInfo =
-            valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(10, curInterval.value.long_value);
-    EXPECT_EQ(true, curInterval.hasValue);
-
-    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
-    EXPECT_EQ(30, curInterval.value.long_value);
-
-    valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
-    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {30}, {bucketSizeNs},
-                                    {bucketStartTimeNs}, {bucket2StartTimeNs});
-}
-
-TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-
-    ValueMetricProducer valueProducer(kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard,
-                                      protoHash, logEventMatcherIndex, eventMatcherWizard, -1,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-    valueProducer.prepareFirstBucket();
-    valueProducer.mCondition = ConditionState::kFalse;
-
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10);
-    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-    // has 1 slice
-    ASSERT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
-
-    valueProducer.onConditionChangedLocked(true, bucketStartTimeNs + 15);
-
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 20);
-    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval =
-            valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
-    EXPECT_EQ(20, curInterval.value.long_value);
-
-    LogEvent event3(/*uid=*/0, /*pid=*/0);
-    CreateRepeatedValueLogEvent(&event3, tagId, bucketStartTimeNs + 30, 30);
-    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
-
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
-    EXPECT_EQ(50, curInterval.value.long_value);
-
-    valueProducer.onConditionChangedLocked(false, bucketStartTimeNs + 35);
-
-    LogEvent event4(/*uid=*/0, /*pid=*/0);
-    CreateRepeatedValueLogEvent(&event4, tagId, bucketStartTimeNs + 40, 40);
-    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
-
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
-    EXPECT_EQ(50, curInterval.value.long_value);
-
-    valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
-    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {50}, {20}, {bucketStartTimeNs},
-                                    {bucket2StartTimeNs});
-}
-
-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();
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
-                                      wizard, protoHash, logEventMatcherIndex, eventMatcherWizard,
-                                      -1 /*not pulled*/, bucketStartTimeNs, bucketStartTimeNs,
-                                      pullerManager);
-    valueProducer.prepareFirstBucket();
-
-    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(ValueMetricProducerTest, TestAnomalyDetectionMultipleBucketsSkipped) {
-    sp<AlarmMonitor> alarmMonitor;
-    Alert alert;
-    alert.set_id(101);
-    alert.set_metric_id(metricId);
-    alert.set_trigger_if_sum_gt(100);
-    alert.set_num_buckets(1);
-    const int32_t refPeriodSec = 3;
-    alert.set_refractory_period_secs(refPeriodSec);
-
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 1);  // Condition change to true time.
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 0));
-                return true;
-            }))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs,
-                          bucket3StartTimeNs + 100);  // Condition changed to false time.
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 100, 120));
-                return true;
-            }));
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-    sp<AnomalyTracker> anomalyTracker = valueProducer->addAnomalyTracker(alert, alarmMonitor);
-
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 1);
-
-    // multiple buckets should be skipped here.
-    valueProducer->onConditionChanged(false, bucket3StartTimeNs + 100);
-
-    // No alert is fired when multiple buckets are skipped.
-    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
-}
-
-// 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, kConfigKey, bucketStartTimeNs, _))
-            .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
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval =
-            valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    ValueMetricProducer::BaseInfo curBaseInfo =
-            valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-
-    // startUpdated:true sum:0 start:11
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(11, curBaseInfo.base.long_value);
-    EXPECT_EQ(false, curInterval.hasValue);
-    ASSERT_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
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[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},
-                                    {bucket2StartTimeNs}, {bucket3StartTimeNs});
-
-    // 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);
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[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},
-                                    {bucket2StartTimeNs}, {bucket3StartTimeNs});
-    // The 1st bucket is dropped because of no data
-    // The 3rd bucket is dropped due to multiple buckets being skipped.
-    ASSERT_EQ(2, valueProducer->mSkippedBuckets.size());
-
-    EXPECT_EQ(bucketStartTimeNs, valueProducer->mSkippedBuckets[0].bucketStartTimeNs);
-    EXPECT_EQ(bucket2StartTimeNs, valueProducer->mSkippedBuckets[0].bucketEndTimeNs);
-    ASSERT_EQ(1, valueProducer->mSkippedBuckets[0].dropEvents.size());
-    EXPECT_EQ(NO_DATA, valueProducer->mSkippedBuckets[0].dropEvents[0].reason);
-    EXPECT_EQ(bucket2StartTimeNs, valueProducer->mSkippedBuckets[0].dropEvents[0].dropTimeNs);
-
-    EXPECT_EQ(bucket3StartTimeNs, valueProducer->mSkippedBuckets[1].bucketStartTimeNs);
-    EXPECT_EQ(bucket6StartTimeNs, valueProducer->mSkippedBuckets[1].bucketEndTimeNs);
-    ASSERT_EQ(1, valueProducer->mSkippedBuckets[1].dropEvents.size());
-    EXPECT_EQ(MULTIPLE_BUCKETS_SKIPPED, valueProducer->mSkippedBuckets[1].dropEvents[0].reason);
-    EXPECT_EQ(bucket6StartTimeNs, valueProducer->mSkippedBuckets[1].dropEvents[0].dropTimeNs);
-}
-
-/*
- * 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, kConfigKey, _, _))
-            // condition becomes true
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8);  // First condition change.
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
-                return true;
-            }))
-            // condition becomes false
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 1);  // Second condition change.
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 120));
-                return true;
-            }));
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
-
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval =
-            valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    ValueMetricProducer::BaseInfo curBaseInfo =
-            valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(100, curBaseInfo.base.long_value);
-    EXPECT_EQ(false, curInterval.hasValue);
-    ASSERT_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.intervals[0];
-    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8},
-                                    {bucketStartTimeNs}, {bucket2StartTimeNs});
-    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},
-                                    {bucketStartTimeNs}, {bucket2StartTimeNs});
-    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[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, kConfigKey, _, _))
-            // condition becomes true
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
-                return true;
-            }))
-            // condition becomes false
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 1);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 120));
-                return true;
-            }))
-            // condition becomes true again
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 25);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 25, 130));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
-
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval =
-            valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    ValueMetricProducer::BaseInfo curBaseInfo =
-            valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-    // startUpdated:false sum:0 start:100
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(100, curBaseInfo.base.long_value);
-    EXPECT_EQ(false, curInterval.hasValue);
-    ASSERT_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},
-                                    {bucketStartTimeNs}, {bucket2StartTimeNs});
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[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},
-                                    {bucketStartTimeNs}, {bucket2StartTimeNs});
-    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[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.intervals[0];
-    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[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},
-                                    {bucketStartTimeNs}, {bucket2StartTimeNs});
-
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs, 160));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
-    assertPastBucketValuesSingleKey(
-            valueProducer->mPastBuckets, {20, 30}, {bucketSizeNs - 8, bucketSizeNs - 24},
-            {bucketStartTimeNs, bucket2StartTimeNs}, {bucket2StartTimeNs, bucket3StartTimeNs});
-}
-
-TEST(ValueMetricProducerTest, TestPushedAggregateMin) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-    metric.set_aggregation_type(ValueMetric::MIN);
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
-                                      logEventMatcherIndex, eventMatcherWizard, -1,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-    valueProducer.prepareFirstBucket();
-
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10);
-
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 20);
-
-    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval =
-            valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
-    EXPECT_EQ(10, curInterval.value.long_value);
-    EXPECT_EQ(true, curInterval.hasValue);
-
-    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
-    EXPECT_EQ(10, curInterval.value.long_value);
-
-    valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
-    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {10}, {bucketSizeNs},
-                                    {bucketStartTimeNs}, {bucket2StartTimeNs});
-}
-
-TEST(ValueMetricProducerTest, TestPushedAggregateMax) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-    metric.set_aggregation_type(ValueMetric::MAX);
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
-                                      logEventMatcherIndex, eventMatcherWizard, -1,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-    valueProducer.prepareFirstBucket();
-
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10);
-    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval =
-            valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
-    EXPECT_EQ(10, curInterval.value.long_value);
-    EXPECT_EQ(true, curInterval.hasValue);
-
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 20);
-    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
-    EXPECT_EQ(20, curInterval.value.long_value);
-
-    valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
-    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {20}, {bucketSizeNs},
-                                    {bucketStartTimeNs}, {bucket2StartTimeNs});
-}
-
-TEST(ValueMetricProducerTest, TestPushedAggregateAvg) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-    metric.set_aggregation_type(ValueMetric::AVG);
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
-                                      logEventMatcherIndex, eventMatcherWizard, -1,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-    valueProducer.prepareFirstBucket();
-
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10);
-
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 15);
-    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval;
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[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
-    ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
-    EXPECT_EQ(25, curInterval.value.long_value);
-    EXPECT_EQ(2, curInterval.sampleSize);
-
-    valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
-    ASSERT_EQ(1UL, valueProducer.mPastBuckets.size());
-    ASSERT_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);
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
-                                      logEventMatcherIndex, eventMatcherWizard, -1,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-    valueProducer.prepareFirstBucket();
-
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10);
-
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 20, 15);
-    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval =
-            valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
-    EXPECT_EQ(10, curInterval.value.long_value);
-    EXPECT_EQ(true, curInterval.hasValue);
-
-    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
-    EXPECT_EQ(25, curInterval.value.long_value);
-
-    valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
-    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {25}, {bucketSizeNs},
-                                    {bucketStartTimeNs}, {bucket2StartTimeNs});
-}
-
-TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-    metric.set_aggregation_type(ValueMetric::MIN);
-    metric.set_use_diff(true);
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
-                                      logEventMatcherIndex, eventMatcherWizard, -1,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-    valueProducer.prepareFirstBucket();
-
-    LogEvent event1(/*uid=*/0, /*pid=*/0);
-    CreateRepeatedValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 10);
-    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval =
-            valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
-    ValueMetricProducer::BaseInfo curBaseInfo =
-            valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(10, curBaseInfo.base.long_value);
-    EXPECT_EQ(false, curInterval.hasValue);
-
-    LogEvent event2(/*uid=*/0, /*pid=*/0);
-    CreateRepeatedValueLogEvent(&event2, tagId, bucketStartTimeNs + 15, 15);
-    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
-    EXPECT_EQ(true, curInterval.hasValue);
-    EXPECT_EQ(5, curInterval.value.long_value);
-
-    // no change in data.
-    LogEvent event3(/*uid=*/0, /*pid=*/0);
-    CreateRepeatedValueLogEvent(&event3, tagId, bucket2StartTimeNs + 10, 15);
-    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
-
-    ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
-    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(15, curBaseInfo.base.long_value);
-    EXPECT_EQ(true, curInterval.hasValue);
-    EXPECT_EQ(0, curInterval.value.long_value);
-
-    LogEvent event4(/*uid=*/0, /*pid=*/0);
-    CreateRepeatedValueLogEvent(&event4, tagId, bucket2StartTimeNs + 15, 15);
-    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
-    ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
-    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(15, curBaseInfo.base.long_value);
-    EXPECT_EQ(true, curInterval.hasValue);
-    EXPECT_EQ(0, curInterval.value.long_value);
-
-    valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
-    assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {5}, {bucketSizeNs},
-                                    {bucketStartTimeNs}, {bucket2StartTimeNs});
-}
-
-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);
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
-                                      logEventMatcherIndex, eventMatcherWizard, -1,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-    valueProducer.prepareFirstBucket();
-
-    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
-    ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval =
-            valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
-    ValueMetricProducer::BaseInfo curBaseInfo =
-            valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(10, curBaseInfo.base.long_value);
-    EXPECT_EQ(false, curInterval.hasValue);
-    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[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
-    ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
-    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(true, curInterval.hasValue);
-    EXPECT_EQ(5, curInterval.value.long_value);
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[1];
-    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[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);
-    ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
-    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0];
-
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(15, curBaseInfo.base.long_value);
-    EXPECT_EQ(true, curInterval.hasValue);
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[1];
-    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[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);
-    ASSERT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[0];
-    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(15, curBaseInfo.base.long_value);
-    EXPECT_EQ(true, curInterval.hasValue);
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second.intervals[1];
-    curBaseInfo = valueProducer.mCurrentBaseInfo.begin()->second.baseInfos[1];
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(29, curBaseInfo.base.long_value);
-    EXPECT_EQ(true, curInterval.hasValue);
-
-    valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
-
-    ASSERT_EQ(1UL, valueProducer.mPastBuckets.size());
-    ASSERT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
-    ASSERT_EQ(2UL, valueProducer.mPastBuckets.begin()->second[0].values.size());
-    ASSERT_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.
- */
-TEST(ValueMetricProducerTest, TestUseZeroDefaultBase) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-    metric.mutable_dimensions_in_what()->set_field(tagId);
-    metric.mutable_dimensions_in_what()->add_child()->set_field(1);
-    metric.set_use_zero_default_base(true);
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 1, 3));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
-
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    auto iter = valueProducer->mCurrentSlicedBucket.begin();
-    auto& interval1 = iter->second.intervals[0];
-    auto iterBase = valueProducer->mCurrentBaseInfo.begin();
-    auto& baseInfo1 = iterBase->second.baseInfos[0];
-    EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(true, baseInfo1.hasBase);
-    EXPECT_EQ(3, baseInfo1.base.long_value);
-    EXPECT_EQ(false, interval1.hasValue);
-    EXPECT_EQ(true, valueProducer->mHasGlobalBase);
-    ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
-    vector<shared_ptr<LogEvent>> allData;
-
-    allData.clear();
-    allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 2, 4));
-    allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1, 11));
-
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-    EXPECT_EQ(true, baseInfo1.hasBase);
-    EXPECT_EQ(11, baseInfo1.base.long_value);
-    EXPECT_EQ(false, interval1.hasValue);
-    EXPECT_EQ(8, interval1.value.long_value);
-
-    auto it = valueProducer->mCurrentSlicedBucket.begin();
-    for (; it != valueProducer->mCurrentSlicedBucket.end(); it++) {
-        if (it != iter) {
-            break;
-        }
-    }
-    auto itBase = valueProducer->mCurrentBaseInfo.begin();
-    for (; itBase != valueProducer->mCurrentBaseInfo.end(); it++) {
-        if (itBase != iterBase) {
-            break;
-        }
-    }
-    EXPECT_TRUE(it != iter);
-    EXPECT_TRUE(itBase != iterBase);
-    auto& interval2 = it->second.intervals[0];
-    auto& baseInfo2 = itBase->second.baseInfos[0];
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(true, baseInfo2.hasBase);
-    EXPECT_EQ(4, baseInfo2.base.long_value);
-    EXPECT_EQ(false, interval2.hasValue);
-    EXPECT_EQ(4, interval2.value.long_value);
-
-    ASSERT_EQ(2UL, valueProducer->mPastBuckets.size());
-    auto iterator = valueProducer->mPastBuckets.begin();
-    EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
-    EXPECT_EQ(8, iterator->second[0].values[0].long_value);
-    iterator++;
-    EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
-    EXPECT_EQ(4, iterator->second[0].values[0].long_value);
-}
-
-/*
- * Tests using zero default base with failed pull.
- */
-TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-    metric.mutable_dimensions_in_what()->set_field(tagId);
-    metric.mutable_dimensions_in_what()->add_child()->set_field(1);
-    metric.set_use_zero_default_base(true);
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 1, 3));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
-
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    const auto& it = valueProducer->mCurrentSlicedBucket.begin();
-    ValueMetricProducer::Interval& interval1 = it->second.intervals[0];
-    ValueMetricProducer::BaseInfo& baseInfo1 =
-            valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat())
-                    ->second.baseInfos[0];
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(true, baseInfo1.hasBase);
-    EXPECT_EQ(3, baseInfo1.base.long_value);
-    EXPECT_EQ(false, interval1.hasValue);
-    EXPECT_EQ(true, valueProducer->mHasGlobalBase);
-    ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
-    vector<shared_ptr<LogEvent>> allData;
-
-    allData.clear();
-    allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 2, 4));
-    allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1, 11));
-
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-    EXPECT_EQ(true, baseInfo1.hasBase);
-    EXPECT_EQ(11, baseInfo1.base.long_value);
-    EXPECT_EQ(false, interval1.hasValue);
-    EXPECT_EQ(8, interval1.value.long_value);
-
-    auto it2 = valueProducer->mCurrentSlicedBucket.begin();
-    for (; it2 != valueProducer->mCurrentSlicedBucket.end(); it2++) {
-        if (it2 != it) {
-            break;
-        }
-    }
-    EXPECT_TRUE(it2 != it);
-    ValueMetricProducer::Interval& interval2 = it2->second.intervals[0];
-    ValueMetricProducer::BaseInfo& baseInfo2 =
-            valueProducer->mCurrentBaseInfo.find(it2->first.getDimensionKeyInWhat())
-                    ->second.baseInfos[0];
-    EXPECT_EQ(2, it2->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(true, baseInfo2.hasBase);
-    EXPECT_EQ(4, baseInfo2.base.long_value);
-    EXPECT_EQ(false, interval2.hasValue);
-    EXPECT_EQ(4, interval2.value.long_value);
-    ASSERT_EQ(2UL, valueProducer->mPastBuckets.size());
-
-    // next pull somehow did not happen, skip to end of bucket 3
-    allData.clear();
-    allData.push_back(CreateTwoValueLogEvent(tagId, bucket4StartTimeNs + 1, 2, 5));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
-
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    EXPECT_EQ(true, baseInfo2.hasBase);
-    EXPECT_EQ(5, baseInfo2.base.long_value);
-    EXPECT_EQ(false, interval2.hasValue);
-    EXPECT_EQ(true, valueProducer->mHasGlobalBase);
-    ASSERT_EQ(2UL, valueProducer->mPastBuckets.size());
-
-    allData.clear();
-    allData.push_back(CreateTwoValueLogEvent(tagId, bucket5StartTimeNs + 1, 2, 13));
-    allData.push_back(CreateTwoValueLogEvent(tagId, bucket5StartTimeNs + 1, 1, 5));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs);
-
-    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-    // Get new references now that entries have been deleted from the map
-    const auto& it3 = valueProducer->mCurrentSlicedBucket.begin();
-    const auto& it4 = std::next(valueProducer->mCurrentSlicedBucket.begin());
-    ASSERT_EQ(it3->second.intervals.size(), 1);
-    ASSERT_EQ(it4->second.intervals.size(), 1);
-    ValueMetricProducer::Interval& interval3 = it3->second.intervals[0];
-    ValueMetricProducer::Interval& interval4 = it4->second.intervals[0];
-    ValueMetricProducer::BaseInfo& baseInfo3 =
-            valueProducer->mCurrentBaseInfo.find(it3->first.getDimensionKeyInWhat())
-                    ->second.baseInfos[0];
-    ValueMetricProducer::BaseInfo& baseInfo4 =
-            valueProducer->mCurrentBaseInfo.find(it4->first.getDimensionKeyInWhat())
-                    ->second.baseInfos[0];
-
-    EXPECT_EQ(true, baseInfo3.hasBase);
-    EXPECT_EQ(5, baseInfo3.base.long_value);
-    EXPECT_EQ(false, interval3.hasValue);
-    EXPECT_EQ(5, interval3.value.long_value);
-    EXPECT_EQ(true, valueProducer->mHasGlobalBase);
-
-    EXPECT_EQ(true, baseInfo4.hasBase);
-    EXPECT_EQ(13, baseInfo4.base.long_value);
-    EXPECT_EQ(false, interval4.hasValue);
-    EXPECT_EQ(8, interval4.value.long_value);
-
-    ASSERT_EQ(2UL, valueProducer->mPastBuckets.size());
-}
-
-/*
- * Tests trim unused dimension key if no new data is seen in an entire bucket.
- */
-TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-    metric.mutable_dimensions_in_what()->set_field(tagId);
-    metric.mutable_dimensions_in_what()->add_child()->set_field(1);
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 1, 3));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
-
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    auto iter = valueProducer->mCurrentSlicedBucket.begin();
-    auto& interval1 = iter->second.intervals[0];
-    auto iterBase = valueProducer->mCurrentBaseInfo.begin();
-    auto& baseInfo1 = iterBase->second.baseInfos[0];
-    EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(true, baseInfo1.hasBase);
-    EXPECT_EQ(3, baseInfo1.base.long_value);
-    EXPECT_EQ(false, interval1.hasValue);
-    ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
-
-    vector<shared_ptr<LogEvent>> allData;
-    allData.clear();
-    allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 2, 4));
-    allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1, 11));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-
-    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-    EXPECT_EQ(true, baseInfo1.hasBase);
-    EXPECT_EQ(11, baseInfo1.base.long_value);
-    EXPECT_EQ(false, interval1.hasValue);
-    EXPECT_EQ(8, interval1.value.long_value);
-    EXPECT_FALSE(interval1.seenNewData);
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8}, {bucketSizeNs},
-                                    {bucketStartTimeNs}, {bucket2StartTimeNs});
-
-    auto it = valueProducer->mCurrentSlicedBucket.begin();
-    for (; it != valueProducer->mCurrentSlicedBucket.end(); it++) {
-        if (it != iter) {
-            break;
-        }
-    }
-    auto itBase = valueProducer->mCurrentBaseInfo.begin();
-    for (; itBase != valueProducer->mCurrentBaseInfo.end(); it++) {
-        if (itBase != iterBase) {
-            break;
-        }
-    }
-    EXPECT_TRUE(it != iter);
-    EXPECT_TRUE(itBase != iterBase);
-    auto interval2 = it->second.intervals[0];
-    auto baseInfo2 = itBase->second.baseInfos[0];
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(true, baseInfo2.hasBase);
-    EXPECT_EQ(4, baseInfo2.base.long_value);
-    EXPECT_EQ(false, interval2.hasValue);
-    EXPECT_FALSE(interval2.seenNewData);
-
-    // next pull somehow did not happen, skip to end of bucket 3
-    allData.clear();
-    allData.push_back(CreateTwoValueLogEvent(tagId, bucket4StartTimeNs + 1, 2, 5));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
-    // Only one interval left. One was trimmed.
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    interval2 = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    baseInfo2 = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(true, baseInfo2.hasBase);
-    EXPECT_EQ(5, baseInfo2.base.long_value);
-    EXPECT_EQ(false, interval2.hasValue);
-    EXPECT_FALSE(interval2.seenNewData);
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8}, {bucketSizeNs},
-                                    {bucketStartTimeNs}, {bucket2StartTimeNs});
-
-    allData.clear();
-    allData.push_back(CreateTwoValueLogEvent(tagId, bucket5StartTimeNs + 1, 2, 14));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs);
-
-    interval2 = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    baseInfo2 = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(true, baseInfo2.hasBase);
-    EXPECT_EQ(14, baseInfo2.base.long_value);
-    EXPECT_EQ(false, interval2.hasValue);
-    EXPECT_FALSE(interval2.seenNewData);
-    ASSERT_EQ(2UL, valueProducer->mPastBuckets.size());
-    auto iterator = valueProducer->mPastBuckets.begin();
-    EXPECT_EQ(bucket4StartTimeNs, iterator->second[0].mBucketStartNs);
-    EXPECT_EQ(bucket5StartTimeNs, iterator->second[0].mBucketEndNs);
-    EXPECT_EQ(9, iterator->second[0].values[0].long_value);
-    EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
-    iterator++;
-    EXPECT_EQ(bucketStartTimeNs, iterator->second[0].mBucketStartNs);
-    EXPECT_EQ(bucket2StartTimeNs, iterator->second[0].mBucketEndNs);
-    EXPECT_EQ(8, iterator->second[0].values[0].long_value);
-    EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
-}
-
-TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange_EndOfBucket) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    // Used by onConditionChanged.
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 8, _))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval& curInterval =
-            valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    ValueMetricProducer::BaseInfo& curBaseInfo =
-            valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(100, curBaseInfo.base.long_value);
-    EXPECT_EQ(false, curInterval.hasValue);
-
-    vector<shared_ptr<LogEvent>> allData;
-    valueProducer->onDataPulled(allData, /** succeed */ false, bucket2StartTimeNs);
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    EXPECT_EQ(false, curBaseInfo.hasBase);
-    EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(false, valueProducer->mHasGlobalBase);
-}
-
-TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8);  // Condition change to true.
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
-                return true;
-            }))
-            .WillOnce(Return(false));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
-
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval& curInterval =
-            valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    ValueMetricProducer::BaseInfo& curBaseInfo =
-            valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(100, curBaseInfo.base.long_value);
-    EXPECT_EQ(false, curInterval.hasValue);
-    ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
-
-    valueProducer->onConditionChanged(false, bucketStartTimeNs + 20);
-
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(false, curBaseInfo.hasBase);
-    EXPECT_EQ(false, valueProducer->mHasGlobalBase);
-}
-
-TEST(ValueMetricProducerTest, TestResetBaseOnPullFailBeforeConditionChange) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 50));
-                return false;
-            }))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 1);  // Condition change to false.
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 100));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-
-    // Don't directly set mCondition; the real code never does that. Go through regular code path
-    // to avoid unexpected behaviors.
-    // valueProducer->mCondition = ConditionState::kTrue;
-    valueProducer->onConditionChanged(true, bucketStartTimeNs);
-
-    ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
-
-    valueProducer->onConditionChanged(false, bucketStartTimeNs + 1);
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval& curInterval =
-            valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    ValueMetricProducer::BaseInfo curBaseInfo =
-            valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(false, curBaseInfo.hasBase);
-    EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(false, valueProducer->mHasGlobalBase);
-}
-
-TEST(ValueMetricProducerTest, TestResetBaseOnPullDelayExceeded) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-    metric.set_condition(StringToId("SCREEN_ON"));
-    metric.set_max_pull_delay_sec(0);
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 1, _))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 120));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-
-    // Max delay is set to 0 so pull will exceed max delay.
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 1);
-    ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
-}
-
-TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillRepeatedly(Return());
-
-    ValueMetricProducer valueProducer(kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard,
-                                      protoHash, logEventMatcherIndex, eventMatcherWizard, tagId,
-                                      bucket2StartTimeNs, bucket2StartTimeNs, pullerManager);
-    valueProducer.prepareFirstBucket();
-    valueProducer.mCondition = ConditionState::kFalse;
-
-    // Event should be skipped since it is from previous bucket.
-    // Pull should not be called.
-    valueProducer.onConditionChanged(true, bucketStartTimeNs);
-    ASSERT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
-}
-
-TEST(ValueMetricProducerTest, TestBaseSetOnConditionChange) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 1, _))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 100));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-    valueProducer->mHasGlobalBase = false;
-
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 1);
-    valueProducer->mHasGlobalBase = true;
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval& curInterval =
-            valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    ValueMetricProducer::BaseInfo curBaseInfo =
-            valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(100, curBaseInfo.base.long_value);
-    EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(true, valueProducer->mHasGlobalBase);
-}
-
-/*
- * Tests that a bucket is marked invalid when a condition change pull fails.
- */
-TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenOneConditionFailed) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // First onConditionChanged
-            .WillOnce(Return(false))
-            // Second onConditionChanged
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 3);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 130));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kTrue);
-
-    // Bucket start.
-    vector<shared_ptr<LogEvent>> allData;
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 110));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
-
-    // This will fail and should invalidate the whole bucket since we do not have all the data
-    // needed to compute the metric value when the screen was on.
-    valueProducer->onConditionChanged(false, bucketStartTimeNs + 2);
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 3);
-
-    // Bucket end.
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 140));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-
-    valueProducer->flushIfNeededLocked(bucket2StartTimeNs + 1);
-
-    ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
-    // Contains base from last pull which was successful.
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval& curInterval =
-            valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    ValueMetricProducer::BaseInfo curBaseInfo =
-            valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(140, curBaseInfo.base.long_value);
-    EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(true, valueProducer->mHasGlobalBase);
-
-    // Check dump report.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    valueProducer->onDumpReport(bucket2StartTimeNs + 10, false /* include partial bucket */, true,
-                                FAST /* dumpLatency */, &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(0, report.value_metrics().data_size());
-    ASSERT_EQ(1, report.value_metrics().skipped_size());
-
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
-              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
-    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
-              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
-    ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
-
-    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
-    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 2), dropEvent.drop_time_millis());
-}
-
-/*
- * Tests that a bucket is marked invalid when the guardrail is hit.
- */
-TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenGuardRailHit) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-    metric.mutable_dimensions_in_what()->set_field(tagId);
-    metric.mutable_dimensions_in_what()->add_child()->set_field(1);
-    metric.set_condition(StringToId("SCREEN_ON"));
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 2, _))
-            // First onConditionChanged
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                for (int i = 0; i < 2000; i++) {
-                    data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, i));
-                }
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 2);
-    EXPECT_EQ(true, valueProducer->mCurrentBucketIsSkipped);
-    ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
-    ASSERT_EQ(0UL, valueProducer->mSkippedBuckets.size());
-
-    // Bucket 2 start.
-    vector<shared_ptr<LogEvent>> allData;
-    allData.clear();
-    allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1, 10));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-
-    // First bucket added to mSkippedBuckets after flush.
-    ASSERT_EQ(1UL, valueProducer->mSkippedBuckets.size());
-
-    // Check dump report.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    valueProducer->onDumpReport(bucket2StartTimeNs + 10000, false /* include recent buckets */,
-                                true, FAST /* dumpLatency */, &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(0, report.value_metrics().data_size());
-    ASSERT_EQ(1, report.value_metrics().skipped_size());
-
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
-              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
-    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
-              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
-    ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
-
-    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
-    EXPECT_EQ(BucketDropReason::DIMENSION_GUARDRAIL_REACHED, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 2), dropEvent.drop_time_millis());
-}
-
-/*
- * Tests that a bucket is marked invalid when the bucket's initial pull fails.
- */
-TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenInitialPullFailed) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // First onConditionChanged
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 2);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 120));
-                return true;
-            }))
-            // Second onConditionChanged
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 3);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 130));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kTrue);
-
-    // Bucket start.
-    vector<shared_ptr<LogEvent>> allData;
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 110));
-    valueProducer->onDataPulled(allData, /** succeed */ false, bucketStartTimeNs);
-
-    valueProducer->onConditionChanged(false, bucketStartTimeNs + 2);
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 3);
-
-    // Bucket end.
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 140));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-
-    valueProducer->flushIfNeededLocked(bucket2StartTimeNs + 1);
-
-    ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
-    // Contains base from last pull which was successful.
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval& curInterval =
-            valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    ValueMetricProducer::BaseInfo curBaseInfo =
-            valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(140, curBaseInfo.base.long_value);
-    EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(true, valueProducer->mHasGlobalBase);
-
-    // Check dump report.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    valueProducer->onDumpReport(bucket2StartTimeNs + 10000, false /* include recent buckets */,
-                                true, FAST /* dumpLatency */, &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(0, report.value_metrics().data_size());
-    ASSERT_EQ(1, report.value_metrics().skipped_size());
-
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
-              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
-    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
-              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
-    ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
-
-    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
-    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 2), dropEvent.drop_time_millis());
-}
-
-/*
- * Tests that a bucket is marked invalid when the bucket's final pull fails
- * (i.e. failed pull on bucket boundary).
- */
-TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenLastPullFailed) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // First onConditionChanged
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 2);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 120));
-                return true;
-            }))
-            // Second onConditionChanged
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 3);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 8, 130));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kTrue);
-
-    // Bucket start.
-    vector<shared_ptr<LogEvent>> allData;
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 110));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
-
-    valueProducer->onConditionChanged(false, bucketStartTimeNs + 2);
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 3);
-
-    // Bucket end.
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 140));
-    valueProducer->onDataPulled(allData, /** succeed */ false, bucket2StartTimeNs);
-
-    valueProducer->flushIfNeededLocked(bucket2StartTimeNs + 1);
-
-    ASSERT_EQ(0UL, valueProducer->mPastBuckets.size());
-    // Last pull failed so base has been reset.
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval& curInterval =
-            valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    ValueMetricProducer::BaseInfo curBaseInfo =
-            valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(false, curBaseInfo.hasBase);
-    EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(false, valueProducer->mHasGlobalBase);
-
-    // Check dump report.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    valueProducer->onDumpReport(bucket2StartTimeNs + 10000, false /* include recent buckets */,
-                                true, FAST /* dumpLatency */, &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(0, report.value_metrics().data_size());
-    ASSERT_EQ(1, report.value_metrics().skipped_size());
-
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
-              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
-    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
-              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
-    ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
-
-    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
-    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs), dropEvent.drop_time_millis());
-}
-
-TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onDataPulled) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
-            // Start bucket.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
-
-    // Bucket 2 start.
-    vector<shared_ptr<LogEvent>> allData;
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 110));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
-
-    // Bucket 3 empty.
-    allData.clear();
-    allData.push_back(CreateNoValuesLogEvent(tagId, bucket3StartTimeNs + 1));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
-    // Data has been trimmed.
-    ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
-    ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
-}
-
-TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onConditionChanged) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // First onConditionChanged
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
-                return true;
-            }))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
-                data->clear();
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval& curInterval =
-            valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    ValueMetricProducer::BaseInfo curBaseInfo =
-            valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(true, valueProducer->mHasGlobalBase);
-
-    // Empty pull.
-    valueProducer->onConditionChanged(false, bucketStartTimeNs + 10);
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(false, curBaseInfo.hasBase);
-    EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(false, valueProducer->mHasGlobalBase);
-}
-
-TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onBucketBoundary) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // First onConditionChanged
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
-                return true;
-            }))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 11);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 2));
-                return true;
-            }))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 12);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 5));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
-    valueProducer->onConditionChanged(false, bucketStartTimeNs + 11);
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 12);
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval& curInterval =
-            valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    ValueMetricProducer::BaseInfo curBaseInfo =
-            valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(true, curInterval.hasValue);
-    EXPECT_EQ(true, valueProducer->mHasGlobalBase);
-
-    // End of bucket
-    vector<shared_ptr<LogEvent>> allData;
-    allData.clear();
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-    // Data is empty, base should be reset.
-    EXPECT_EQ(false, curBaseInfo.hasBase);
-    EXPECT_EQ(5, curBaseInfo.base.long_value);
-    EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(true, valueProducer->mHasGlobalBase);
-
-    ASSERT_EQ(1UL, valueProducer->mPastBuckets.size());
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {1}, {bucketSizeNs - 12 + 1},
-                                    {bucketStartTimeNs}, {bucket2StartTimeNs});
-}
-
-TEST(ValueMetricProducerTest, TestPartialResetOnBucketBoundaries) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-    metric.mutable_dimensions_in_what()->set_field(tagId);
-    metric.mutable_dimensions_in_what()->add_child()->set_field(1);
-    metric.set_condition(StringToId("SCREEN_ON"));
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 10, _))
-            // First onConditionChanged
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-
-    // End of bucket
-    vector<shared_ptr<LogEvent>> allData;
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 2));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-
-    // Key 1 should be reset since in not present in the most pull.
-    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-    auto iterator = valueProducer->mCurrentSlicedBucket.begin();
-    auto baseInfoIter = valueProducer->mCurrentBaseInfo.begin();
-    EXPECT_EQ(true, baseInfoIter->second.baseInfos[0].hasBase);
-    EXPECT_EQ(2, baseInfoIter->second.baseInfos[0].base.long_value);
-    EXPECT_EQ(false, iterator->second.intervals[0].hasValue);
-    iterator++;
-    baseInfoIter++;
-    EXPECT_EQ(false, baseInfoIter->second.baseInfos[0].hasBase);
-    EXPECT_EQ(1, baseInfoIter->second.baseInfos[0].base.long_value);
-    EXPECT_EQ(false, iterator->second.intervals[0].hasValue);
-
-    EXPECT_EQ(true, valueProducer->mHasGlobalBase);
-}
-
-TEST_P(ValueMetricProducerTest_PartialBucket, TestFullBucketResetWhenLastBucketInvalid) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    int64_t partialBucketSplitTimeNs = bucketStartTimeNs + bucketSizeNs / 2;
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // Initialization.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
-                return true;
-            }))
-            // notifyAppUpgrade.
-            .WillOnce(Invoke([partialBucketSplitTimeNs](int tagId, const ConfigKey&,
-                                                        const int64_t eventTimeNs,
-                                                        vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, partialBucketSplitTimeNs);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, partialBucketSplitTimeNs, 10));
-                return true;
-            }));
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
-    ASSERT_EQ(0UL, valueProducer->mCurrentFullBucket.size());
-
-    switch (GetParam()) {
-        case APP_UPGRADE:
-            valueProducer->notifyAppUpgrade(partialBucketSplitTimeNs);
-            break;
-        case BOOT_COMPLETE:
-            valueProducer->onStatsdInitCompleted(partialBucketSplitTimeNs);
-            break;
-    }
-    EXPECT_EQ(partialBucketSplitTimeNs, valueProducer->mCurrentBucketStartTimeNs);
-    EXPECT_EQ(0, valueProducer->getCurrentBucketNum());
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {9},
-                                    {partialBucketSplitTimeNs - bucketStartTimeNs},
-                                    {bucketStartTimeNs}, {partialBucketSplitTimeNs});
-    ASSERT_EQ(1UL, valueProducer->mCurrentFullBucket.size());
-
-    vector<shared_ptr<LogEvent>> allData;
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 4));
-    // Pull fails and arrives late.
-    valueProducer->onDataPulled(allData, /** fails */ false, bucket3StartTimeNs + 1);
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {9},
-                                    {partialBucketSplitTimeNs - bucketStartTimeNs},
-                                    {bucketStartTimeNs}, {partialBucketSplitTimeNs});
-    ASSERT_EQ(1, valueProducer->mSkippedBuckets.size());
-    ASSERT_EQ(2, valueProducer->mSkippedBuckets[0].dropEvents.size());
-    EXPECT_EQ(PULL_FAILED, valueProducer->mSkippedBuckets[0].dropEvents[0].reason);
-    EXPECT_EQ(MULTIPLE_BUCKETS_SKIPPED, valueProducer->mSkippedBuckets[0].dropEvents[1].reason);
-    EXPECT_EQ(partialBucketSplitTimeNs, valueProducer->mSkippedBuckets[0].bucketStartTimeNs);
-    EXPECT_EQ(bucket3StartTimeNs, valueProducer->mSkippedBuckets[0].bucketEndTimeNs);
-    ASSERT_EQ(0UL, valueProducer->mCurrentFullBucket.size());
-}
-
-TEST(ValueMetricProducerTest, TestBucketBoundariesOnConditionChange) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // Second onConditionChanged.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 10);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 10, 5));
-                return true;
-            }))
-            // Third onConditionChanged.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket3StartTimeNs + 10);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 10, 7));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(
-                    pullerManager, metric, ConditionState::kUnknown);
-
-    valueProducer->onConditionChanged(false, bucketStartTimeNs);
-    ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
-
-    // End of first bucket
-    vector<shared_ptr<LogEvent>> allData;
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 4));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 1);
-    ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
-
-    valueProducer->onConditionChanged(true, bucket2StartTimeNs + 10);
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    auto curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(true, curBaseInfo.hasBase);
-    EXPECT_EQ(5, curBaseInfo.base.long_value);
-    EXPECT_EQ(false, curInterval.hasValue);
-
-    valueProducer->onConditionChanged(false, bucket3StartTimeNs + 10);
-
-    // Bucket should have been completed.
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {2}, {bucketSizeNs - 10},
-                                    {bucket2StartTimeNs}, {bucket3StartTimeNs});
-}
-
-TEST(ValueMetricProducerTest, TestLateOnDataPulledWithoutDiff) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-    metric.set_use_diff(false);
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
-
-    vector<shared_ptr<LogEvent>> allData;
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30, 10));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + 30);
-
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 20));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-
-    // Bucket should have been completed.
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {30}, {bucketSizeNs},
-                                    {bucketStartTimeNs}, {bucket2StartTimeNs});
-}
-
-TEST(ValueMetricProducerTest, TestLateOnDataPulledWithDiff) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
-            // Initialization.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
-
-    vector<shared_ptr<LogEvent>> allData;
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30, 10));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + 30);
-
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 20));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-
-    // Bucket should have been completed.
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {19}, {bucketSizeNs},
-                                    {bucketStartTimeNs}, {bucket2StartTimeNs});
-}
-
-TEST_P(ValueMetricProducerTest_PartialBucket, TestBucketBoundariesOnPartialBucket) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-
-    int64_t partialBucketSplitTimeNs = bucket2StartTimeNs + 2;
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // Initialization.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
-                return true;
-            }))
-            // notifyAppUpgrade.
-            .WillOnce(Invoke([partialBucketSplitTimeNs](int tagId, const ConfigKey&,
-                                                        const int64_t eventTimeNs,
-                                                        vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, partialBucketSplitTimeNs);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, partialBucketSplitTimeNs, 10));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
-
-    switch (GetParam()) {
-        case APP_UPGRADE:
-            valueProducer->notifyAppUpgrade(partialBucketSplitTimeNs);
-            break;
-        case BOOT_COMPLETE:
-            valueProducer->onStatsdInitCompleted(partialBucketSplitTimeNs);
-            break;
-    }
-
-    // Bucket should have been completed.
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {9}, {bucketSizeNs},
-                                    {bucketStartTimeNs}, {bucket2StartTimeNs});
-}
-
-TEST(ValueMetricProducerTest, TestDataIsNotUpdatedWhenNoConditionChanged) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // First on condition changed.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
-                return true;
-            }))
-            // Second on condition changed.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
-    valueProducer->onConditionChanged(false, bucketStartTimeNs + 10);
-    valueProducer->onConditionChanged(false, bucketStartTimeNs + 12);
-
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    auto curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(true, curInterval.hasValue);
-    EXPECT_EQ(2, curInterval.value.long_value);
-
-    vector<shared_ptr<LogEvent>> allData;
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 10));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 1);
-
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {2}, {2}, {bucketStartTimeNs},
-                                    {bucket2StartTimeNs});
-}
-
-// TODO: b/145705635 fix or delete this test
-TEST(ValueMetricProducerTest, TestBucketInvalidIfGlobalBaseIsNotSet) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // First condition change.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 10);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 1));
-                return true;
-            }))
-            // 2nd condition change.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 8);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 1));
-                return true;
-            }))
-            // 3rd condition change.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 10);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 1));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-    valueProducer->onConditionChanged(true, bucket2StartTimeNs + 10);
-
-    vector<shared_ptr<LogEvent>> allData;
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 3, 10));
-    valueProducer->onDataPulled(allData, /** succeed */ false, bucketStartTimeNs + 3);
-
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 20));
-    valueProducer->onDataPulled(allData, /** succeed */ false, bucket2StartTimeNs);
-
-    valueProducer->onConditionChanged(false, bucket2StartTimeNs + 8);
-    valueProducer->onConditionChanged(true, bucket2StartTimeNs + 10);
-
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs, 30));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-
-    // There was not global base available so all buckets are invalid.
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {}, {}, {}, {});
-}
-
-TEST(ValueMetricProducerTest, TestPullNeededFastDump) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillRepeatedly(Return());
-
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
-            // Initial pull.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs, tagId, 1, 1));
-                return true;
-            }));
-
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
-                                      logEventMatcherIndex, eventMatcherWizard, tagId,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-    valueProducer.prepareFirstBucket();
-
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    valueProducer.onDumpReport(bucketStartTimeNs + 10, true /* include recent buckets */, true,
-                               FAST, &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    // Bucket is invalid since we did not pull when dump report was called.
-    ASSERT_EQ(0, report.value_metrics().data_size());
-}
-
-TEST(ValueMetricProducerTest, TestFastDumpWithoutCurrentBucket) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillRepeatedly(Return());
-
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _))
-            // Initial pull.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs, tagId, 1, 1));
-                return true;
-            }));
-
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
-                                      logEventMatcherIndex, eventMatcherWizard, tagId,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-    valueProducer.prepareFirstBucket();
-
-    vector<shared_ptr<LogEvent>> allData;
-    allData.clear();
-    allData.push_back(CreateThreeValueLogEvent(tagId, bucket2StartTimeNs + 1, tagId, 2, 2));
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    valueProducer.onDumpReport(bucket4StartTimeNs, false /* include recent buckets */, true, FAST,
-                               &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    // Previous bucket is part of the report.
-    ASSERT_EQ(1, report.value_metrics().data_size());
-    EXPECT_EQ(0, report.value_metrics().data(0).bucket_info(0).bucket_num());
-}
-
-TEST(ValueMetricProducerTest, TestPullNeededNoTimeConstraints) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-
-    sp<EventMatcherWizard> eventMatcherWizard =
-            createEventMatcherWizard(tagId, logEventMatcherIndex);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillRepeatedly(Return());
-
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // Initial pull.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
-                data->clear();
-                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs, tagId, 1, 1));
-                return true;
-            }))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
-                data->clear();
-                data->push_back(
-                        CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 10, tagId, 3, 3));
-                return true;
-            }));
-
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, protoHash,
-                                      logEventMatcherIndex, eventMatcherWizard, tagId,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-    valueProducer.prepareFirstBucket();
-
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    valueProducer.onDumpReport(bucketStartTimeNs + 10, true /* include recent buckets */, true,
-                               NO_TIME_CONSTRAINTS, &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    ASSERT_EQ(1, report.value_metrics().data_size());
-    ASSERT_EQ(1, report.value_metrics().data(0).bucket_info_size());
-    EXPECT_EQ(2, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
-}
-
-TEST(ValueMetricProducerTest, TestPulledData_noDiff_withoutCondition) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
-    metric.set_use_diff(false);
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
-
-    vector<shared_ptr<LogEvent>> allData;
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 30, 10));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 30);
-
-    // Bucket should have been completed.
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10}, {bucketSizeNs},
-                                    {bucketStartTimeNs}, {bucket2StartTimeNs});
-}
-
-TEST(ValueMetricProducerTest, TestPulledData_noDiff_withMultipleConditionChanges) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-    metric.set_use_diff(false);
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // condition becomes true
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30, 10));
-                return true;
-            }))
-            // condition becomes false
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 20));
-                return true;
-            }));
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
-    valueProducer->onConditionChanged(false, bucketStartTimeNs + 50);
-    // has one slice
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval =
-            valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    ValueMetricProducer::BaseInfo curBaseInfo =
-            valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(false, curBaseInfo.hasBase);
-    EXPECT_EQ(true, curInterval.hasValue);
-    EXPECT_EQ(20, curInterval.value.long_value);
-
-    // Now the alarm is delivered. Condition is off though.
-    vector<shared_ptr<LogEvent>> allData;
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 30, 110));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {50 - 8},
-                                    {bucketStartTimeNs}, {bucket2StartTimeNs});
-    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    curBaseInfo = valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(false, curBaseInfo.hasBase);
-    EXPECT_EQ(false, curInterval.hasValue);
-}
-
-TEST(ValueMetricProducerTest, TestPulledData_noDiff_bucketBoundaryTrue) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-    metric.set_use_diff(false);
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 8, _))
-            // condition becomes true
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30, 10));
-                return true;
-            }));
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
-
-    // Now the alarm is delivered. Condition is off though.
-    vector<shared_ptr<LogEvent>> allData;
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 30, 30));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {30}, {bucketSizeNs - 8},
-                                    {bucketStartTimeNs}, {bucket2StartTimeNs});
-    ValueMetricProducer::Interval curInterval =
-            valueProducer->mCurrentSlicedBucket.begin()->second.intervals[0];
-    ValueMetricProducer::BaseInfo curBaseInfo =
-            valueProducer->mCurrentBaseInfo.begin()->second.baseInfos[0];
-    EXPECT_EQ(false, curBaseInfo.hasBase);
-    EXPECT_EQ(false, curInterval.hasValue);
-}
-
-TEST(ValueMetricProducerTest, TestPulledData_noDiff_bucketBoundaryFalse) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-    metric.set_use_diff(false);
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-
-    // Now the alarm is delivered. Condition is off though.
-    vector<shared_ptr<LogEvent>> allData;
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 30, 30));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-
-    // Condition was always false.
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {}, {}, {}, {});
-}
-
-TEST(ValueMetricProducerTest, TestPulledData_noDiff_withFailure) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-    metric.set_use_diff(false);
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // condition becomes true
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 8);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30, 10));
-                return true;
-            }))
-            .WillOnce(Return(false));
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
-    valueProducer->onConditionChanged(false, bucketStartTimeNs + 50);
-
-    // Now the alarm is delivered. Condition is off though.
-    vector<shared_ptr<LogEvent>> allData;
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 30, 30));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-
-    // No buckets, we had a failure.
-    assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {}, {}, {}, {});
-}
-
-/*
- * Test that DUMP_REPORT_REQUESTED dump reason is logged.
- *
- * For the bucket to be marked invalid during a dump report requested,
- * three things must be true:
- * - we want to include the current partial bucket
- * - we need a pull (metric is pulled and condition is true)
- * - the dump latency must be FAST
- */
-
-TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenDumpReportRequested) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 20, _))
-            // Condition change to true.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 20, 10));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-
-    // Condition change event.
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 20);
-
-    // Check dump report.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    valueProducer->onDumpReport(bucketStartTimeNs + 40, true /* include recent buckets */, true,
-                                FAST /* dumpLatency */, &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(0, report.value_metrics().data_size());
-    ASSERT_EQ(1, report.value_metrics().skipped_size());
-
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
-              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 40),
-              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
-    ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
-
-    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
-    EXPECT_EQ(BucketDropReason::DUMP_REPORT_REQUESTED, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 40), dropEvent.drop_time_millis());
-}
-
-/*
- * Test that EVENT_IN_WRONG_BUCKET dump reason is logged for a late condition
- * change event (i.e. the condition change occurs in the wrong bucket).
- */
-TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenConditionEventWrongBucket) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 50, _))
-            // Condition change to true.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 10));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-
-    // Condition change event.
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 50);
-
-    // Bucket boundary pull.
-    vector<shared_ptr<LogEvent>> allData;
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 15));
-    valueProducer->onDataPulled(allData, /** succeeds */ true, bucket2StartTimeNs + 1);
-
-    // Late condition change event.
-    valueProducer->onConditionChanged(false, bucket2StartTimeNs - 100);
-
-    // Check dump report.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    valueProducer->onDumpReport(bucket2StartTimeNs + 100, true /* include recent buckets */, true,
-                                NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(1, report.value_metrics().data_size());
-    ASSERT_EQ(1, report.value_metrics().skipped_size());
-
-    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
-              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
-    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs + 100),
-              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
-    ASSERT_EQ(2, report.value_metrics().skipped(0).drop_event_size());
-
-    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
-    EXPECT_EQ(BucketDropReason::EVENT_IN_WRONG_BUCKET, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs - 100), dropEvent.drop_time_millis());
-
-    dropEvent = report.value_metrics().skipped(0).drop_event(1);
-    EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs + 100), dropEvent.drop_time_millis());
-}
-
-/*
- * Test that EVENT_IN_WRONG_BUCKET dump reason is logged for a late accumulate
- * event (i.e. the accumulate events call occurs in the wrong bucket).
- */
-TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenAccumulateEventWrongBucket) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // Condition change to true.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 10));
-                return true;
-            }))
-            // Dump report requested.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 100);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 100, 15));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-
-    // Condition change event.
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 50);
-
-    // Bucket boundary pull.
-    vector<shared_ptr<LogEvent>> allData;
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 15));
-    valueProducer->onDataPulled(allData, /** succeeds */ true, bucket2StartTimeNs + 1);
-
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs - 100, 20));
-
-    // Late accumulateEvents event.
-    valueProducer->accumulateEvents(allData, bucket2StartTimeNs - 100, bucket2StartTimeNs - 100);
-
-    // Check dump report.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    valueProducer->onDumpReport(bucket2StartTimeNs + 100, true /* include recent buckets */, true,
-                                NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(1, report.value_metrics().data_size());
-    ASSERT_EQ(1, report.value_metrics().skipped_size());
-
-    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
-              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
-    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs + 100),
-              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
-    ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
-
-    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
-    EXPECT_EQ(BucketDropReason::EVENT_IN_WRONG_BUCKET, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs - 100), dropEvent.drop_time_millis());
-}
-
-/*
- * Test that CONDITION_UNKNOWN dump reason is logged due to an unknown condition
- * when a metric is initialized.
- */
-TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenConditionUnknown) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // Condition change to true.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 10));
-                return true;
-            }))
-            // Dump report requested.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10000);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 100, 15));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(
-                    pullerManager, metric, ConditionState::kUnknown);
-
-    // Condition change event.
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 50);
-
-    // Check dump report.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    int64_t dumpReportTimeNs = bucketStartTimeNs + 10000;
-    valueProducer->onDumpReport(dumpReportTimeNs, true /* include recent buckets */, true,
-                                NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(0, report.value_metrics().data_size());
-    ASSERT_EQ(1, report.value_metrics().skipped_size());
-
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
-              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
-    EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
-              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
-    ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
-
-    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
-    EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(dumpReportTimeNs), dropEvent.drop_time_millis());
-}
-
-/*
- * Test that PULL_FAILED dump reason is logged due to a pull failure in
- * #pullAndMatchEventsLocked.
- */
-TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenPullFailed) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // Condition change to true.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 10));
-                return true;
-            }))
-            // Dump report requested, pull fails.
-            .WillOnce(Return(false));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-
-    // Condition change event.
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 50);
-
-    // Check dump report.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    int64_t dumpReportTimeNs = bucketStartTimeNs + 10000;
-    valueProducer->onDumpReport(dumpReportTimeNs, true /* include recent buckets */, true,
-                                NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(0, report.value_metrics().data_size());
-    ASSERT_EQ(1, report.value_metrics().skipped_size());
-
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
-              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
-    EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
-              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
-    ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
-
-    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
-    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(dumpReportTimeNs), dropEvent.drop_time_millis());
-}
-
-/*
- * Test that MULTIPLE_BUCKETS_SKIPPED dump reason is logged when a log event
- * skips over more than one bucket.
- */
-TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenMultipleBucketsSkipped) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // Condition change to true.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 10));
-                return true;
-            }))
-            // Dump report requested.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket4StartTimeNs + 10);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucket4StartTimeNs + 1000, 15));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-
-    // Condition change event.
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
-
-    // Condition change event that skips forward by three buckets.
-    valueProducer->onConditionChanged(false, bucket4StartTimeNs + 10);
-
-    int64_t dumpTimeNs = bucket4StartTimeNs + 1000;
-
-    // Check dump report.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    valueProducer->onDumpReport(dumpTimeNs, true /* include current buckets */, true,
-                                NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(0, report.value_metrics().data_size());
-    ASSERT_EQ(2, report.value_metrics().skipped_size());
-
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
-              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
-    EXPECT_EQ(NanoToMillis(bucket4StartTimeNs),
-              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
-    ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
-
-    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
-    EXPECT_EQ(BucketDropReason::MULTIPLE_BUCKETS_SKIPPED, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(bucket4StartTimeNs + 10), dropEvent.drop_time_millis());
-
-    // This bucket is skipped because a dumpReport with include current buckets is called.
-    // This creates a new bucket from bucket4StartTimeNs to dumpTimeNs in which we have no data
-    // since the condition is false for the entire bucket interval.
-    EXPECT_EQ(NanoToMillis(bucket4StartTimeNs),
-              report.value_metrics().skipped(1).start_bucket_elapsed_millis());
-    EXPECT_EQ(NanoToMillis(dumpTimeNs),
-              report.value_metrics().skipped(1).end_bucket_elapsed_millis());
-    ASSERT_EQ(1, report.value_metrics().skipped(1).drop_event_size());
-
-    dropEvent = report.value_metrics().skipped(1).drop_event(0);
-    EXPECT_EQ(BucketDropReason::NO_DATA, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(dumpTimeNs), dropEvent.drop_time_millis());
-}
-
-/*
- * Test that BUCKET_TOO_SMALL dump reason is logged when a flushed bucket size
- * is smaller than the "min_bucket_size_nanos" specified in the metric config.
- */
-TEST(ValueMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-    metric.set_min_bucket_size_nanos(10000000000);  // 10 seconds
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // Condition change to true.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 10));
-                return true;
-            }))
-            // Dump report requested.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 9000000);
-                data->clear();
-                data->push_back(
-                        CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 9000000, 15));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-
-    // Condition change event.
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
-
-    // Check dump report.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    int64_t dumpReportTimeNs = bucketStartTimeNs + 9000000;
-    valueProducer->onDumpReport(dumpReportTimeNs, true /* include recent buckets */, true,
-                                NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(0, report.value_metrics().data_size());
-    ASSERT_EQ(1, report.value_metrics().skipped_size());
-
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
-              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
-    EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
-              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
-    ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
-
-    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
-    EXPECT_EQ(BucketDropReason::BUCKET_TOO_SMALL, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(dumpReportTimeNs), dropEvent.drop_time_millis());
-}
-
-/*
- * Test that NO_DATA dump reason is logged when a flushed bucket contains no data.
- */
-TEST(ValueMetricProducerTest_BucketDrop, TestBucketDropWhenDataUnavailable) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(
-                    pullerManager, metric, ConditionState::kFalse);
-
-    // Check dump report.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    int64_t dumpReportTimeNs = bucketStartTimeNs + 10000000000; // 10 seconds
-    valueProducer->onDumpReport(dumpReportTimeNs, true /* include current bucket */, true,
-                                NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(0, report.value_metrics().data_size());
-    ASSERT_EQ(1, report.value_metrics().skipped_size());
-
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
-              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
-    EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
-              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
-    ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
-
-    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
-    EXPECT_EQ(BucketDropReason::NO_DATA, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(dumpReportTimeNs), dropEvent.drop_time_millis());
-}
-
-/*
- * Test that all buckets are dropped due to condition unknown until the first onConditionChanged.
- */
-TEST(ValueMetricProducerTest_BucketDrop, TestConditionUnknownMultipleBuckets) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // Condition change to true.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 10 * NS_PER_SEC);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(
-                        tagId, bucket2StartTimeNs + 10 * NS_PER_SEC, 10));
-                return true;
-            }))
-            // Dump report requested.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 15 * NS_PER_SEC);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(
-                        tagId, bucket2StartTimeNs + 15 * NS_PER_SEC, 15));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(
-                    pullerManager, metric, ConditionState::kUnknown);
-
-    // Bucket should be dropped because of condition unknown.
-    int64_t appUpgradeTimeNs = bucketStartTimeNs + 5 * NS_PER_SEC;
-    valueProducer->notifyAppUpgrade(appUpgradeTimeNs);
-
-    // Bucket also dropped due to condition unknown
-    vector<shared_ptr<LogEvent>> allData;
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 3));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-
-    // This bucket is also dropped due to condition unknown.
-    int64_t conditionChangeTimeNs = bucket2StartTimeNs + 10 * NS_PER_SEC;
-    valueProducer->onConditionChanged(true, conditionChangeTimeNs);
-
-    // Check dump report.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    int64_t dumpReportTimeNs = bucket2StartTimeNs + 15 * NS_PER_SEC; // 15 seconds
-    valueProducer->onDumpReport(dumpReportTimeNs, true /* include current bucket */, true,
-                                NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(0, report.value_metrics().data_size());
-    ASSERT_EQ(3, report.value_metrics().skipped_size());
-
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
-              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
-    EXPECT_EQ(NanoToMillis(appUpgradeTimeNs),
-              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
-    ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
-
-    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
-    EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(appUpgradeTimeNs), dropEvent.drop_time_millis());
-
-    EXPECT_EQ(NanoToMillis(appUpgradeTimeNs),
-              report.value_metrics().skipped(1).start_bucket_elapsed_millis());
-    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
-              report.value_metrics().skipped(1).end_bucket_elapsed_millis());
-    ASSERT_EQ(1, report.value_metrics().skipped(1).drop_event_size());
-
-    dropEvent = report.value_metrics().skipped(1).drop_event(0);
-    EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs), dropEvent.drop_time_millis());
-
-    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
-              report.value_metrics().skipped(2).start_bucket_elapsed_millis());
-    EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
-              report.value_metrics().skipped(2).end_bucket_elapsed_millis());
-    ASSERT_EQ(1, report.value_metrics().skipped(2).drop_event_size());
-
-    dropEvent = report.value_metrics().skipped(2).drop_event(0);
-    EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(conditionChangeTimeNs), dropEvent.drop_time_millis());
-}
-
-/*
- * Test that a skipped bucket is logged when a forced bucket split occurs when the previous bucket
- * was not flushed in time.
- */
-TEST(ValueMetricProducerTest_BucketDrop, TestBucketDropWhenForceBucketSplitBeforeBucketFlush) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // Condition change to true.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 10));
-                return true;
-            }))
-            // App Update.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 1000);
-                data->clear();
-                data->push_back(
-                        CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1000, 15));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
-                                                                            ConditionState::kFalse);
-
-    // Condition changed event
-    int64_t conditionChangeTimeNs = bucketStartTimeNs + 10;
-    valueProducer->onConditionChanged(true, conditionChangeTimeNs);
-
-    // App update event.
-    int64_t appUpdateTimeNs = bucket2StartTimeNs + 1000;
-    valueProducer->notifyAppUpgrade(appUpdateTimeNs);
-
-    // Check dump report.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    int64_t dumpReportTimeNs = bucket2StartTimeNs + 10000000000; // 10 seconds
-    valueProducer->onDumpReport(dumpReportTimeNs, false /* include current buckets */, true,
-                                NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(1, report.value_metrics().data_size());
-    ASSERT_EQ(1, report.value_metrics().skipped_size());
-
-    ASSERT_EQ(1, report.value_metrics().data(0).bucket_info_size());
-    auto data = report.value_metrics().data(0);
-    ASSERT_EQ(0, data.bucket_info(0).bucket_num());
-    EXPECT_EQ(5, data.bucket_info(0).values(0).value_long());
-
-    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
-              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
-    EXPECT_EQ(NanoToMillis(appUpdateTimeNs),
-              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
-    ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
-
-    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
-    EXPECT_EQ(BucketDropReason::NO_DATA, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(appUpdateTimeNs), dropEvent.drop_time_millis());
-}
-
-/*
- * Test multiple bucket drop events in the same bucket.
- */
-TEST(ValueMetricProducerTest_BucketDrop, TestMultipleBucketDropEvents) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs + 10, _))
-            // Condition change to true.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 10));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(
-                    pullerManager, metric, ConditionState::kUnknown);
-
-    // Condition change event.
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
-
-    // Check dump report.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    int64_t dumpReportTimeNs = bucketStartTimeNs + 1000;
-    valueProducer->onDumpReport(dumpReportTimeNs, true /* include recent buckets */, true,
-                                FAST /* dumpLatency */, &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(0, report.value_metrics().data_size());
-    ASSERT_EQ(1, report.value_metrics().skipped_size());
-
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
-              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
-    EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
-              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
-    ASSERT_EQ(2, report.value_metrics().skipped(0).drop_event_size());
-
-    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
-    EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 10), dropEvent.drop_time_millis());
-
-    dropEvent = report.value_metrics().skipped(0).drop_event(1);
-    EXPECT_EQ(BucketDropReason::DUMP_REPORT_REQUESTED, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(dumpReportTimeNs), dropEvent.drop_time_millis());
-}
-
-/*
- * Test that the number of logged bucket drop events is capped at the maximum.
- * The maximum is currently 10 and is set in MetricProducer::maxDropEventsReached().
- */
-TEST(ValueMetricProducerTest_BucketDrop, TestMaxBucketDropEvents) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // First condition change event.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
-                for (int i = 0; i < 2000; i++) {
-                    data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, i));
-                }
-                return true;
-            }))
-            .WillOnce(Return(false))
-            .WillOnce(Return(false))
-            .WillOnce(Return(false))
-            .WillOnce(Return(false))
-            .WillOnce(Return(false))
-            .WillOnce(Return(false))
-            .WillOnce(Return(false))
-            .WillOnce(Return(false))
-            .WillOnce(Return(false))
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 220);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 220, 10));
-                return true;
-            }));
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(
-                    pullerManager, metric, ConditionState::kUnknown);
-
-    // First condition change event causes guardrail to be reached.
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
-
-    // 2-10 condition change events result in failed pulls.
-    valueProducer->onConditionChanged(false, bucketStartTimeNs + 30);
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 50);
-    valueProducer->onConditionChanged(false, bucketStartTimeNs + 70);
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 90);
-    valueProducer->onConditionChanged(false, bucketStartTimeNs + 100);
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 150);
-    valueProducer->onConditionChanged(false, bucketStartTimeNs + 170);
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 190);
-    valueProducer->onConditionChanged(false, bucketStartTimeNs + 200);
-
-    // Condition change event 11
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 220);
-
-    // Check dump report.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    int64_t dumpReportTimeNs = bucketStartTimeNs + 1000;
-    // Because we already have 10 dump events in the current bucket,
-    // this case should not be added to the list of dump events.
-    valueProducer->onDumpReport(bucketStartTimeNs + 1000, true /* include recent buckets */, true,
-                                FAST /* dumpLatency */, &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(0, report.value_metrics().data_size());
-    ASSERT_EQ(1, report.value_metrics().skipped_size());
-
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
-              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
-    EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
-              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
-    ASSERT_EQ(10, report.value_metrics().skipped(0).drop_event_size());
-
-    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
-    EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 10), dropEvent.drop_time_millis());
-
-    dropEvent = report.value_metrics().skipped(0).drop_event(1);
-    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 30), dropEvent.drop_time_millis());
-
-    dropEvent = report.value_metrics().skipped(0).drop_event(2);
-    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 50), dropEvent.drop_time_millis());
-
-    dropEvent = report.value_metrics().skipped(0).drop_event(3);
-    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 70), dropEvent.drop_time_millis());
-
-    dropEvent = report.value_metrics().skipped(0).drop_event(4);
-    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 90), dropEvent.drop_time_millis());
-
-    dropEvent = report.value_metrics().skipped(0).drop_event(5);
-    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 100), dropEvent.drop_time_millis());
-
-    dropEvent = report.value_metrics().skipped(0).drop_event(6);
-    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 150), dropEvent.drop_time_millis());
-
-    dropEvent = report.value_metrics().skipped(0).drop_event(7);
-    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 170), dropEvent.drop_time_millis());
-
-    dropEvent = report.value_metrics().skipped(0).drop_event(8);
-    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 190), dropEvent.drop_time_millis());
-
-    dropEvent = report.value_metrics().skipped(0).drop_event(9);
-    EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 200), dropEvent.drop_time_millis());
-}
-
-/*
- * Test metric with a simple sliced state
- * - Increasing values
- * - Using diff
- * - Second field is value field
- */
-TEST(ValueMetricProducerTest, TestSlicedState) {
-    // Set up ValueMetricProducer.
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithState("SCREEN_STATE");
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // ValueMetricProducer initialized.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
-                return true;
-            }))
-            // Screen state change to ON.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 5 * NS_PER_SEC);
-                data->clear();
-                data->push_back(
-                        CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 5 * NS_PER_SEC, 5));
-                return true;
-            }))
-            // Screen state change to OFF.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10 * NS_PER_SEC);
-                data->clear();
-                data->push_back(
-                        CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC, 9));
-                return true;
-            }))
-            // Screen state change to ON.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 15 * NS_PER_SEC);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(
-                        tagId, bucketStartTimeNs + 15 * NS_PER_SEC, 21));
-                return true;
-            }))
-            // Dump report requested.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50 * NS_PER_SEC);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(
-                        tagId, bucketStartTimeNs + 50 * NS_PER_SEC, 30));
-                return true;
-            }));
-
-    StateManager::getInstance().clear();
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithState(
-                    pullerManager, metric, {util::SCREEN_STATE_CHANGED}, {});
-    EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
-
-    // Set up StateManager and check that StateTrackers are initialized.
-    StateManager::getInstance().registerListener(SCREEN_STATE_ATOM_ID, valueProducer);
-    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
-
-    // Bucket status after metric initialized.
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    // Base for dimension key {}
-    auto it = valueProducer->mCurrentSlicedBucket.begin();
-    auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(3, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for dimension, state key {{}, kStateUnknown}
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_FALSE(it->second.intervals[0].hasValue);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
-
-    // Bucket status after screen state change kStateUnknown->ON.
-    auto screenEvent = CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 5 * NS_PER_SEC, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-    StateManager::getInstance().onLogEvent(*screenEvent);
-    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-    // Base for dimension key {}
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(5, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for dimension, state key {{}, ON}
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_EQ(0, it->second.intervals.size());
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 5 * NS_PER_SEC);
-    // Value for dimension, state key {{}, kStateUnknown}
-    it++;
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_TRUE(it->second.intervals[0].hasValue);
-    EXPECT_EQ(2, it->second.intervals[0].value.long_value);
-    assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
-                         bucketStartTimeNs + 5 * NS_PER_SEC);
-
-    // Bucket status after screen state change ON->OFF.
-    screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 10 * NS_PER_SEC,
-                                                android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
-    StateManager::getInstance().onLogEvent(*screenEvent);
-    ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
-    // Base for dimension key {}
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(9, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for dimension, state key {{}, OFF}
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_EQ(0, it->second.intervals.size());
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
-    // Value for dimension, state key {{}, ON}
-    it++;
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_TRUE(it->second.intervals[0].hasValue);
-    EXPECT_EQ(4, it->second.intervals[0].value.long_value);
-    assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
-                         bucketStartTimeNs + 10 * NS_PER_SEC);
-    // Value for dimension, state key {{}, kStateUnknown}
-    it++;
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_TRUE(it->second.intervals[0].hasValue);
-    EXPECT_EQ(2, it->second.intervals[0].value.long_value);
-    assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
-                         bucketStartTimeNs + 5 * NS_PER_SEC);
-
-    // Bucket status after screen state change OFF->ON.
-    screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 15 * NS_PER_SEC,
-                                                android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-    StateManager::getInstance().onLogEvent(*screenEvent);
-    ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
-    // Base for dimension key {}
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(21, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for dimension, state key {{}, OFF}
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_TRUE(it->second.intervals[0].hasValue);
-    EXPECT_EQ(12, it->second.intervals[0].value.long_value);
-    assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
-                         bucketStartTimeNs + 15 * NS_PER_SEC);
-    // Value for dimension, state key {{}, ON}
-    it++;
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_TRUE(it->second.intervals[0].hasValue);
-    EXPECT_EQ(4, it->second.intervals[0].value.long_value);
-    assertConditionTimer(it->second.conditionTimer, true, 5 * NS_PER_SEC,
-                         bucketStartTimeNs + 15 * NS_PER_SEC);
-    // Value for dimension, state key {{}, kStateUnknown}
-    it++;
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_TRUE(it->second.intervals[0].hasValue);
-    EXPECT_EQ(2, it->second.intervals[0].value.long_value);
-    assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
-                         bucketStartTimeNs + 5 * NS_PER_SEC);
-
-    // Start dump report and check output.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    valueProducer->onDumpReport(bucketStartTimeNs + 50 * NS_PER_SEC,
-                                true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
-                                &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(3, report.value_metrics().data_size());
-
-    // {{}, kStateUnknown}
-    auto data = report.value_metrics().data(0);
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(2, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
-    EXPECT_EQ(5 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-
-    // {{}, ON}
-    data = report.value_metrics().data(1);
-    ASSERT_EQ(1, report.value_metrics().data(1).bucket_info_size());
-    EXPECT_EQ(13, report.value_metrics().data(1).bucket_info(0).values(0).value_long());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value());
-    EXPECT_EQ(40 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-
-    // {{}, OFF}
-    data = report.value_metrics().data(2);
-    ASSERT_EQ(1, report.value_metrics().data(2).bucket_info_size());
-    EXPECT_EQ(12, report.value_metrics().data(2).bucket_info(0).values(0).value_long());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value());
-    EXPECT_EQ(5 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-}
-
-/*
- * Test metric with sliced state with map
- * - Increasing values
- * - Using diff
- * - Second field is value field
- */
-TEST(ValueMetricProducerTest, TestSlicedStateWithMap) {
-    // Set up ValueMetricProducer.
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithState("SCREEN_STATE_ONOFF");
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // ValueMetricProducer initialized.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
-                return true;
-            }))
-            // Screen state change to ON.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 5 * NS_PER_SEC);
-                data->clear();
-                data->push_back(
-                        CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 5 * NS_PER_SEC, 5));
-                return true;
-            }))
-            // Screen state change to VR has no pull because it is in the same
-            // state group as ON.
-
-            // Screen state change to ON has no pull because it is in the same
-            // state group as VR.
-
-            // Screen state change to OFF.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 15 * NS_PER_SEC);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(
-                        tagId, bucketStartTimeNs + 15 * NS_PER_SEC, 21));
-                return true;
-            }))
-            // Dump report requested.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50 * NS_PER_SEC);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(
-                        tagId, bucketStartTimeNs + 50 * NS_PER_SEC, 30));
-                return true;
-            }));
-
-    const StateMap& stateMap =
-            CreateScreenStateOnOffMap(/*screen on id=*/321, /*screen off id=*/123);
-    const StateMap_StateGroup screenOnGroup = stateMap.group(0);
-    const StateMap_StateGroup screenOffGroup = stateMap.group(1);
-
-    unordered_map<int, unordered_map<int, int64_t>> stateGroupMap;
-    for (auto group : stateMap.group()) {
-        for (auto value : group.value()) {
-            stateGroupMap[SCREEN_STATE_ATOM_ID][value] = group.group_id();
-        }
-    }
-
-    StateManager::getInstance().clear();
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithState(
-                    pullerManager, metric, {util::SCREEN_STATE_CHANGED}, stateGroupMap);
-
-    // Set up StateManager and check that StateTrackers are initialized.
-    StateManager::getInstance().registerListener(SCREEN_STATE_ATOM_ID, valueProducer);
-    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
-
-    // Bucket status after metric initialized.
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    // Base for dimension key {}
-    auto it = valueProducer->mCurrentSlicedBucket.begin();
-    auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(3, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for dimension, state key {{}, {kStateUnknown}}
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_FALSE(it->second.intervals[0].hasValue);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
-
-    // Bucket status after screen state change kStateUnknown->ON.
-    auto screenEvent = CreateScreenStateChangedEvent(
-            bucketStartTimeNs + 5 * NS_PER_SEC, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-    StateManager::getInstance().onLogEvent(*screenEvent);
-    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-    // Base for dimension key {}
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(5, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(screenOnGroup.group_id(),
-              itBase->second.currentState.getValues()[0].mValue.long_value);
-    // Value for dimension, state key {{}, ON GROUP}
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(screenOnGroup.group_id(),
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 5 * NS_PER_SEC);
-    // Value for dimension, state key {{}, kStateUnknown}
-    it++;
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_TRUE(it->second.intervals[0].hasValue);
-    EXPECT_EQ(2, it->second.intervals[0].value.long_value);
-    assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
-                         bucketStartTimeNs + 5 * NS_PER_SEC);
-
-    // Bucket status after screen state change ON->VR.
-    // Both ON and VR are in the same state group, so the base should not change.
-    screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 10 * NS_PER_SEC,
-                                                android::view::DisplayStateEnum::DISPLAY_STATE_VR);
-    StateManager::getInstance().onLogEvent(*screenEvent);
-    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-    // Base for dimension key {}
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(5, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(screenOnGroup.group_id(),
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for dimension, state key {{}, ON GROUP}
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(screenOnGroup.group_id(),
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 5 * NS_PER_SEC);
-    // Value for dimension, state key {{}, kStateUnknown}
-    it++;
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_TRUE(it->second.intervals[0].hasValue);
-    EXPECT_EQ(2, it->second.intervals[0].value.long_value);
-    assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
-                         bucketStartTimeNs + 5 * NS_PER_SEC);
-
-    // Bucket status after screen state change VR->ON.
-    // Both ON and VR are in the same state group, so the base should not change.
-    screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 12 * NS_PER_SEC,
-                                                android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-    StateManager::getInstance().onLogEvent(*screenEvent);
-    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-    // Base for dimension key {}
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(5, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(screenOnGroup.group_id(),
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for dimension, state key {{}, ON GROUP}
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(screenOnGroup.group_id(),
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 5 * NS_PER_SEC);
-    // Value for dimension, state key {{}, kStateUnknown}
-    it++;
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_TRUE(it->second.intervals[0].hasValue);
-    EXPECT_EQ(2, it->second.intervals[0].value.long_value);
-    assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
-                         bucketStartTimeNs + 5 * NS_PER_SEC);
-
-    // Bucket status after screen state change VR->OFF.
-    screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 15 * NS_PER_SEC,
-                                                android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
-    StateManager::getInstance().onLogEvent(*screenEvent);
-    ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
-    // Base for dimension key {}
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(21, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(screenOffGroup.group_id(),
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for dimension, state key {{}, OFF GROUP}
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(screenOffGroup.group_id(),
-              it->first.getStateValuesKey().getValues()[0].mValue.long_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 15 * NS_PER_SEC);
-    // Value for dimension, state key {{}, ON GROUP}
-    it++;
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(screenOnGroup.group_id(),
-              it->first.getStateValuesKey().getValues()[0].mValue.long_value);
-    EXPECT_TRUE(it->second.intervals[0].hasValue);
-    EXPECT_EQ(16, it->second.intervals[0].value.long_value);
-    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
-                         bucketStartTimeNs + 15 * NS_PER_SEC);
-    // Value for dimension, state key {{}, kStateUnknown}
-    it++;
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_TRUE(it->second.intervals[0].hasValue);
-    EXPECT_EQ(2, it->second.intervals[0].value.long_value);
-    assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
-                         bucketStartTimeNs + 5 * NS_PER_SEC);
-
-    // Start dump report and check output.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    valueProducer->onDumpReport(bucketStartTimeNs + 50 * NS_PER_SEC,
-                                true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
-                                &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(3, report.value_metrics().data_size());
-
-    // {{}, kStateUnknown}
-    auto data = report.value_metrics().data(0);
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(2, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(-1 /*StateTracker::kStateUnknown*/, data.slice_by_state(0).value());
-    EXPECT_EQ(5 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-
-    // {{}, ON GROUP}
-    data = report.value_metrics().data(1);
-    ASSERT_EQ(1, report.value_metrics().data(1).bucket_info_size());
-    EXPECT_EQ(16, report.value_metrics().data(1).bucket_info(0).values(0).value_long());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-    EXPECT_EQ(screenOnGroup.group_id(), data.slice_by_state(0).group_id());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-
-    // {{}, OFF GROUP}
-    data = report.value_metrics().data(2);
-    ASSERT_EQ(1, report.value_metrics().data(2).bucket_info_size());
-    EXPECT_EQ(9, report.value_metrics().data(2).bucket_info(0).values(0).value_long());
-    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-    EXPECT_EQ(screenOffGroup.group_id(), data.slice_by_state(0).group_id());
-    EXPECT_EQ(35 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-}
-
-/*
- * Test metric that slices by state with a primary field and has dimensions
- * - Increasing values
- * - Using diff
- * - Second field is value field
- */
-TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
-    // Set up ValueMetricProducer.
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithState("UID_PROCESS_STATE");
-    metric.mutable_dimensions_in_what()->set_field(tagId);
-    metric.mutable_dimensions_in_what()->add_child()->set_field(1);
-
-    MetricStateLink* stateLink = metric.add_state_link();
-    stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
-    auto fieldsInWhat = stateLink->mutable_fields_in_what();
-    *fieldsInWhat = CreateDimensions(tagId, {1 /* uid */});
-    auto fieldsInState = stateLink->mutable_fields_in_state();
-    *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
-
-    /*
-    NOTE: "1" denotes uid 1 and "2" denotes uid 2.
-                    bucket # 1                            bucket # 2
-    10     20     30     40     50     60     70     80     90    100    110    120 (seconds)
-    |------------------------------------------|---------------------------------|--
-
-                                                                                    (kStateUnknown)
-    1
-    |-------------|
-          20
-
-    2
-    |----------------------------|
-                 40
-
-                                                                                    (FOREGROUND)
-                  1                                                       1
-                  |----------------------------|-------------|            |------|
-                               40                     20                     10
-
-
-                                                                                    (BACKGROUND)
-                                                             1
-                                                             |------------|
-                                                                   20
-                                 2
-                                 |-------------|---------------------------------|
-                                       20                      50
-    */
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // ValueMetricProducer initialized.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
-                data->clear();
-                data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 2 /*uid*/, 7));
-                data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs, 1 /*uid*/, 3));
-                return true;
-            }))
-            // Uid 1 process state change from kStateUnknown -> Foreground
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20 * NS_PER_SEC);
-                data->clear();
-                data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC,
-                                                       1 /*uid*/, 6));
-
-                // This event should be skipped.
-                data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC,
-                                                       2 /*uid*/, 8));
-                return true;
-            }))
-            // Uid 2 process state change from kStateUnknown -> Background
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 40 * NS_PER_SEC);
-                data->clear();
-                data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC,
-                                                       2 /*uid*/, 9));
-
-                // This event should be skipped.
-                data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC,
-                                                       1 /*uid*/, 12));
-                return true;
-            }))
-            // Uid 1 process state change from Foreground -> Background
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 20 * NS_PER_SEC);
-                data->clear();
-                data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 20 * NS_PER_SEC,
-                                                       1 /*uid*/, 13));
-
-                // This event should be skipped.
-                data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 20 * NS_PER_SEC,
-                                                       2 /*uid*/, 11));
-                return true;
-            }))
-            // Uid 1 process state change from Background -> Foreground
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 40 * NS_PER_SEC);
-                data->clear();
-                data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 40 * NS_PER_SEC,
-                                                       1 /*uid*/, 17));
-
-                // This event should be skipped.
-                data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 40 * NS_PER_SEC,
-                                                       2 /*uid */, 15));
-                return true;
-            }))
-            // Dump report pull.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 50 * NS_PER_SEC);
-                data->clear();
-                data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 50 * NS_PER_SEC,
-                                                       2 /*uid*/, 20));
-                data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 50 * NS_PER_SEC,
-                                                       1 /*uid*/, 21));
-                return true;
-            }));
-
-    StateManager::getInstance().clear();
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithState(
-                    pullerManager, metric, {UID_PROCESS_STATE_ATOM_ID}, {});
-
-    // Set up StateManager and check that StateTrackers are initialized.
-    StateManager::getInstance().registerListener(UID_PROCESS_STATE_ATOM_ID, valueProducer);
-    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
-
-    // Bucket status after metric initialized.
-    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-    // Base for dimension key {uid 1}.
-    auto it = valueProducer->mCurrentSlicedBucket.begin();
-    auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(3, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for dimension, state key {{uid 1}, kStateUnknown}
-    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_FALSE(it->second.intervals[0].hasValue);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
-    // Base for dimension key {uid 2}
-    it++;
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(7, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for dimension, state key {{uid 2}, kStateUnknown}
-    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_FALSE(it->second.intervals[0].hasValue);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
-
-    // Bucket status after uid 1 process state change kStateUnknown -> Foreground.
-    auto uidProcessEvent =
-            CreateUidProcessStateChangedEvent(bucketStartTimeNs + 20 * NS_PER_SEC, 1 /* uid */,
-                                              android::app::PROCESS_STATE_IMPORTANT_FOREGROUND);
-    StateManager::getInstance().onLogEvent(*uidProcessEvent);
-    ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
-    // Base for dimension key {uid 1}.
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(6, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {uid 1, kStateUnknown}.
-    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_TRUE(it->second.intervals[0].hasValue);
-    EXPECT_EQ(3, it->second.intervals[0].value.long_value);
-    assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
-                         bucketStartTimeNs + 20 * NS_PER_SEC);
-    // Value for key {uid 1, FOREGROUND}.
-    it++;
-    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
-
-    // Base for dimension key {uid 2}.
-    it++;
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(7, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {uid 2, kStateUnknown}.
-    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_FALSE(it->second.intervals[0].hasValue);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
-
-    // Bucket status after uid 2 process state change kStateUnknown -> Background.
-    uidProcessEvent =
-            CreateUidProcessStateChangedEvent(bucketStartTimeNs + 40 * NS_PER_SEC, 2 /* uid */,
-                                              android::app::PROCESS_STATE_IMPORTANT_BACKGROUND);
-    StateManager::getInstance().onLogEvent(*uidProcessEvent);
-    ASSERT_EQ(4UL, valueProducer->mCurrentSlicedBucket.size());
-    // Base for dimension key {uid 2}.
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(9, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {uid 2, BACKGROUND}.
-    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 40 * NS_PER_SEC);
-
-    // Base for dimension key {uid 1}.
-    it++;
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(6, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {uid 1, kStateUnknown}.
-    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_TRUE(it->second.intervals[0].hasValue);
-    EXPECT_EQ(3, it->second.intervals[0].value.long_value);
-    assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
-                         bucketStartTimeNs + 20 * NS_PER_SEC);
-
-    // Value for key {uid 1, FOREGROUND}.
-    it++;
-    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
-
-    // Value for key {uid 2, kStateUnknown}
-    it++;
-    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_TRUE(it->second.intervals[0].hasValue);
-    EXPECT_EQ(2, it->second.intervals[0].value.long_value);
-    assertConditionTimer(it->second.conditionTimer, false, 40 * NS_PER_SEC,
-                         bucketStartTimeNs + 40 * NS_PER_SEC);
-
-    // Pull at end of first bucket.
-    vector<shared_ptr<LogEvent>> allData;
-    allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs, 1 /*uid*/, 10));
-    allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs, 2 /*uid*/, 15));
-    valueProducer->onDataPulled(allData, /** succeeds */ true, bucket2StartTimeNs + 1);
-
-    // Buckets flushed after end of first bucket.
-    // None of the buckets should have a value.
-    ASSERT_EQ(4UL, valueProducer->mCurrentSlicedBucket.size());
-    ASSERT_EQ(4UL, valueProducer->mPastBuckets.size());
-    ASSERT_EQ(2UL, valueProducer->mCurrentBaseInfo.size());
-    // Base for dimension key {uid 2}.
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(15, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {uid 2, BACKGROUND}.
-    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_FALSE(it->second.intervals[0].hasValue);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
-    EXPECT_EQ(20 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
-
-    // Base for dimension key {uid 1}
-    it++;
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(10, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {uid 1, kStateUnknown}
-    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* kStateTracker::kUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_FALSE(it->second.intervals[0].hasValue);
-    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
-    EXPECT_EQ(20 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
-
-    // Value for key {uid 1, FOREGROUND}
-    it++;
-    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_FALSE(it->second.intervals[0].hasValue);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
-    EXPECT_EQ(40 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
-
-    // Value for key {uid 2, kStateUnknown}
-    it++;
-    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* kStateTracker::kUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_FALSE(it->second.intervals[0].hasValue);
-    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 40 * NS_PER_SEC);
-    EXPECT_EQ(40 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
-
-    // Bucket status after uid 1 process state change from Foreground -> Background.
-    uidProcessEvent =
-            CreateUidProcessStateChangedEvent(bucket2StartTimeNs + 20 * NS_PER_SEC, 1 /* uid */,
-                                              android::app::PROCESS_STATE_IMPORTANT_BACKGROUND);
-    StateManager::getInstance().onLogEvent(*uidProcessEvent);
-
-    ASSERT_EQ(5UL, valueProducer->mCurrentSlicedBucket.size());
-    ASSERT_EQ(4UL, valueProducer->mPastBuckets.size());
-    ASSERT_EQ(2UL, valueProducer->mCurrentBaseInfo.size());
-    // Base for dimension key {uid 2}.
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(15, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {uid 2, BACKGROUND}.
-    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_FALSE(it->second.intervals[0].hasValue);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
-
-    // Base for dimension key {uid 1}
-    it++;
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(13, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {uid 1, kStateUnknown}
-    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_FALSE(it->second.intervals[0].hasValue);
-    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
-
-    // Value for key {uid 1, BACKGROUND}
-    it++;
-    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs + 20 * NS_PER_SEC);
-
-    // Value for key {uid 1, FOREGROUND}
-    it++;
-    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_TRUE(it->second.intervals[0].hasValue);
-    EXPECT_EQ(3, it->second.intervals[0].value.long_value);
-    assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
-                         bucket2StartTimeNs + 20 * NS_PER_SEC);
-
-    // Value for key {uid 2, kStateUnknown}
-    it++;
-    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_FALSE(it->second.intervals[0].hasValue);
-    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 40 * NS_PER_SEC);
-
-    // Bucket status after uid 1 process state change Background->Foreground.
-    uidProcessEvent =
-            CreateUidProcessStateChangedEvent(bucket2StartTimeNs + 40 * NS_PER_SEC, 1 /* uid */,
-                                              android::app::PROCESS_STATE_IMPORTANT_FOREGROUND);
-    StateManager::getInstance().onLogEvent(*uidProcessEvent);
-
-    ASSERT_EQ(5UL, valueProducer->mCurrentSlicedBucket.size());
-    ASSERT_EQ(2UL, valueProducer->mCurrentBaseInfo.size());
-    // Base for dimension key {uid 2}
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(15, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {uid 2, BACKGROUND}
-    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_FALSE(it->second.intervals[0].hasValue);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
-
-    // Base for dimension key {uid 1}
-    it++;
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(17, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {uid 1, kStateUnknown}
-    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_FALSE(it->second.intervals[0].hasValue);
-    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
-
-    // Value for key {uid 1, BACKGROUND}
-    it++;
-    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_TRUE(it->second.intervals[0].hasValue);
-    EXPECT_EQ(4, it->second.intervals[0].value.long_value);
-    assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
-                         bucket2StartTimeNs + 40 * NS_PER_SEC);
-
-    // Value for key {uid 1, FOREGROUND}
-    it++;
-    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_TRUE(it->second.intervals[0].hasValue);
-    EXPECT_EQ(3, it->second.intervals[0].value.long_value);
-    assertConditionTimer(it->second.conditionTimer, true, 20 * NS_PER_SEC,
-                         bucket2StartTimeNs + 40 * NS_PER_SEC);
-
-    // Value for key {uid 2, kStateUnknown}
-    it++;
-    ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 40 * NS_PER_SEC);
-
-    // Start dump report and check output.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    valueProducer->onDumpReport(bucket2StartTimeNs + 50 * NS_PER_SEC,
-                                true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
-                                &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(5, report.value_metrics().data_size());
-
-    // {uid 1, BACKGROUND}
-    auto data = report.value_metrics().data(0);
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(4, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              data.slice_by_state(0).value());
-    EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-
-    // {uid 2, kStateUnknown}
-    data = report.value_metrics().data(1);
-    ASSERT_EQ(1, report.value_metrics().data(1).bucket_info_size());
-    EXPECT_EQ(2, report.value_metrics().data(1).bucket_info(0).values(0).value_long());
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(-1 /*StateTracker::kStateUnknown*/, data.slice_by_state(0).value());
-    EXPECT_EQ(40 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-
-    // {uid 1, FOREGROUND}
-    data = report.value_metrics().data(2);
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              data.slice_by_state(0).value());
-    ASSERT_EQ(2, report.value_metrics().data(2).bucket_info_size());
-    EXPECT_EQ(4, report.value_metrics().data(2).bucket_info(0).values(0).value_long());
-    EXPECT_EQ(7, report.value_metrics().data(2).bucket_info(1).values(0).value_long());
-    EXPECT_EQ(40 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-    EXPECT_EQ(30 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
-
-    // {uid 1, kStateUnknown}
-    data = report.value_metrics().data(3);
-    ASSERT_EQ(1, report.value_metrics().data(3).bucket_info_size());
-    EXPECT_EQ(3, report.value_metrics().data(3).bucket_info(0).values(0).value_long());
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(-1 /*StateTracker::kStateUnknown*/, data.slice_by_state(0).value());
-    EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-
-    // {uid 2, BACKGROUND}
-    data = report.value_metrics().data(4);
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              data.slice_by_state(0).value());
-    ASSERT_EQ(2, report.value_metrics().data(4).bucket_info_size());
-    EXPECT_EQ(6, report.value_metrics().data(4).bucket_info(0).values(0).value_long());
-    EXPECT_EQ(5, report.value_metrics().data(4).bucket_info(1).values(0).value_long());
-    EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-    EXPECT_EQ(50 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
-}
-
-/*
- * Test slicing condition_true_nanos by state for metric that slices by state when data is not
- * present in pulled data during a state change.
- */
-TEST(ValueMetricProducerTest, TestSlicedStateWithMissingDataInStateChange) {
-    // Set up ValueMetricProducer.
-    ValueMetric metric =
-            ValueMetricProducerTestHelper::createMetricWithState("BATTERY_SAVER_MODE_STATE");
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    /*
-    NOTE: "-" means that the data was not present in the pulled data.
-
-                             bucket # 1
-    10         20         30         40         50         60   (seconds)
-    |-------------------------------------------------------|--
-    x                                                           (kStateUnknown)
-    |-----------|
-         10
-
-                x                               x               (ON)
-                |---------------------|         |-----------|
-                           20                        10
-
-                                      -                         (OFF)
-    */
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // ValueMetricProducer initialized.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
-                return true;
-            }))
-            // Battery saver mode state changed to ON.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10 * NS_PER_SEC);
-                data->clear();
-                data->push_back(
-                        CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC, 5));
-                return true;
-            }))
-            // Battery saver mode state changed to OFF but data for dimension key {} is not present
-            // in the pulled data.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 30 * NS_PER_SEC);
-                data->clear();
-                return true;
-            }))
-            // Battery saver mode state changed to ON.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 40 * NS_PER_SEC);
-                data->clear();
-                data->push_back(
-                        CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC, 7));
-                return true;
-            }))
-            // Dump report pull.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50 * NS_PER_SEC);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(
-                        tagId, bucketStartTimeNs + 50 * NS_PER_SEC, 15));
-                return true;
-            }));
-
-    StateManager::getInstance().clear();
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithState(
-                    pullerManager, metric, {util::BATTERY_SAVER_MODE_STATE_CHANGED}, {});
-    EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
-
-    // Set up StateManager and check that StateTrackers are initialized.
-    StateManager::getInstance().registerListener(util::BATTERY_SAVER_MODE_STATE_CHANGED,
-                                                 valueProducer);
-    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(
-                         util::BATTERY_SAVER_MODE_STATE_CHANGED));
-
-    // Bucket status after metric initialized.
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    // Base for dimension key {}
-    auto it = valueProducer->mCurrentSlicedBucket.begin();
-    auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for dimension, state key {{}, kStateUnknown}
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
-
-    // Bucket status after battery saver mode ON event.
-    unique_ptr<LogEvent> batterySaverOnEvent =
-            CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 10 * NS_PER_SEC);
-    StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
-
-    // Base for dimension key {}
-
-    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
-    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{}, ON}
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
-
-    // Value for key {{}, -1}
-    it++;
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
-                         bucketStartTimeNs + 10 * NS_PER_SEC);
-
-    // Bucket status after battery saver mode OFF event which is not present
-    // in the pulled data.
-    unique_ptr<LogEvent> batterySaverOffEvent =
-            CreateBatterySaverOffEvent(/*timestamp=*/bucketStartTimeNs + 30 * NS_PER_SEC);
-    StateManager::getInstance().onLogEvent(*batterySaverOffEvent);
-
-    // Base for dimension key {}
-    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
-    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_FALSE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{}, ON}
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
-                         bucketStartTimeNs + 30 * NS_PER_SEC);
-
-    // Value for key {{}, -1}
-    it++;
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
-                         bucketStartTimeNs + 10 * NS_PER_SEC);
-
-    // Bucket status after battery saver mode ON event.
-    batterySaverOnEvent =
-            CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 40 * NS_PER_SEC);
-    StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
-
-    // Base for dimension key {}
-    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
-    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{}, ON}
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 20 * NS_PER_SEC,
-                         bucketStartTimeNs + 40 * NS_PER_SEC);
-
-    // Value for key {{}, -1}
-    it++;
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
-                         bucketStartTimeNs + 10 * NS_PER_SEC);
-
-    // Start dump report and check output.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    valueProducer->onDumpReport(bucketStartTimeNs + 50 * NS_PER_SEC,
-                                true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
-                                &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(2, report.value_metrics().data_size());
-
-    // {{}, kStateUnknown}
-    ValueMetricData data = report.value_metrics().data(0);
-    EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
-    EXPECT_EQ(-1 /*StateTracker::kUnknown*/, data.slice_by_state(0).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-
-    // {{}, ON}
-    data = report.value_metrics().data(1);
-    EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON, data.slice_by_state(0).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(30 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-}
-
-/*
- * Test for metric that slices by state when data is not present in pulled data
- * during an event and then a flush occurs for the current bucket. With the new
- * condition timer behavior, a "new" MetricDimensionKey is inserted into
- * `mCurrentSlicedBucket` before intervals are closed/added to that new
- * MetricDimensionKey.
- */
-TEST(ValueMetricProducerTest, TestSlicedStateWithMissingDataThenFlushBucket) {
-    // Set up ValueMetricProducer.
-    ValueMetric metric =
-            ValueMetricProducerTestHelper::createMetricWithState("BATTERY_SAVER_MODE_STATE");
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    /*
-    NOTE: "-" means that the data was not present in the pulled data.
-
-                             bucket # 1
-    10         20         30         40         50         60   (seconds)
-    |-------------------------------------------------------|--
-    -                                                           (kStateUnknown)
-
-                -                                               (ON)
-    */
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // ValueMetricProducer initialized  but data for dimension key {} is not present
-            // in the pulled data..
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
-                data->clear();
-                return true;
-            }))
-            // Battery saver mode state changed to ON but data for dimension key {} is not present
-            // in the pulled data.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10 * NS_PER_SEC);
-                data->clear();
-                return true;
-            }))
-            // Dump report pull.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50 * NS_PER_SEC);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(
-                        tagId, bucketStartTimeNs + 50 * NS_PER_SEC, 15));
-                return true;
-            }));
-
-    StateManager::getInstance().clear();
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithState(
-                    pullerManager, metric, {util::BATTERY_SAVER_MODE_STATE_CHANGED}, {});
-    EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
-
-    // Set up StateManager and check that StateTrackers are initialized.
-    StateManager::getInstance().registerListener(util::BATTERY_SAVER_MODE_STATE_CHANGED,
-                                                 valueProducer);
-    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(
-                         util::BATTERY_SAVER_MODE_STATE_CHANGED));
-
-    // Bucket status after metric initialized.
-    ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
-    ASSERT_EQ(0UL, valueProducer->mCurrentBaseInfo.size());
-
-    // Bucket status after battery saver mode ON event which is not present
-    // in the pulled data.
-    unique_ptr<LogEvent> batterySaverOnEvent =
-            CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 10 * NS_PER_SEC);
-    StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
-
-    ASSERT_EQ(0UL, valueProducer->mCurrentBaseInfo.size());
-    ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
-
-    // Start dump report and check output.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    valueProducer->onDumpReport(bucketStartTimeNs + 50 * NS_PER_SEC,
-                                true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
-                                &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(0, report.value_metrics().data_size());
-    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
-}
-
-TEST(ValueMetricProducerTest, TestSlicedStateWithNoPullOnBucketBoundary) {
-    // Set up ValueMetricProducer.
-    ValueMetric metric =
-            ValueMetricProducerTestHelper::createMetricWithState("BATTERY_SAVER_MODE_STATE");
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    /*
-                 bucket # 1                         bucket # 2
-    10    20    30    40    50    60    70    80   90   100   110   120  (seconds)
-    |------------------------------------|---------------------------|--
-    x                                                                    (kStateUnknown)
-    |-----|
-      10
-          x                                              x               (ON)
-          |-----|                                        |-----------|
-             10                                               20
-                x                                                        (OFF)
-                |------------------------|
-                          40
-    */
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // ValueMetricProducer initialized.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
-                return true;
-            }))
-            // Battery saver mode state changed to ON.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10 * NS_PER_SEC);
-                data->clear();
-                data->push_back(
-                        CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC, 5));
-                return true;
-            }))
-            // Battery saver mode state changed to OFF.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20 * NS_PER_SEC);
-                data->clear();
-                data->push_back(
-                        CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC, 7));
-                return true;
-            }))
-            // Battery saver mode state changed to ON.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 30 * NS_PER_SEC);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(
-                        tagId, bucket2StartTimeNs + 30 * NS_PER_SEC, 10));
-                return true;
-            }))
-            // Dump report pull.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 50 * NS_PER_SEC);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(
-                        tagId, bucket2StartTimeNs + 50 * NS_PER_SEC, 15));
-                return true;
-            }));
-
-    StateManager::getInstance().clear();
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithState(
-                    pullerManager, metric, {util::BATTERY_SAVER_MODE_STATE_CHANGED}, {});
-    EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
-
-    // Set up StateManager and check that StateTrackers are initialized.
-    StateManager::getInstance().registerListener(util::BATTERY_SAVER_MODE_STATE_CHANGED,
-                                                 valueProducer);
-    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(
-                         util::BATTERY_SAVER_MODE_STATE_CHANGED));
-
-    // Bucket status after metric initialized.
-    ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
-    auto it = valueProducer->mCurrentSlicedBucket.begin();
-    auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for dimension, state key {{}, kStateUnknown}
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
-
-    // Bucket status after battery saver mode ON event.
-    unique_ptr<LogEvent> batterySaverOnEvent =
-            CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 10 * NS_PER_SEC);
-    StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
-
-    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
-    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{}, ON}
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
-
-    // Value for key {{}, -1}
-    it++;
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
-                         bucketStartTimeNs + 10 * NS_PER_SEC);
-
-    // Bucket status after battery saver mode OFF event.
-    unique_ptr<LogEvent> batterySaverOffEvent =
-            CreateBatterySaverOffEvent(/*timestamp=*/bucketStartTimeNs + 20 * NS_PER_SEC);
-    StateManager::getInstance().onLogEvent(*batterySaverOffEvent);
-
-    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
-    ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::OFF,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{}, OFF}
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::OFF,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
-
-    // Value for key {{}, ON}
-    it++;
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
-                         bucketStartTimeNs + 20 * NS_PER_SEC);
-
-    // Value for key {{}, -1}
-    it++;
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
-                         bucketStartTimeNs + 10 * NS_PER_SEC);
-
-    // Bucket status after battery saver mode ON event.
-    batterySaverOnEvent =
-            CreateBatterySaverOnEvent(/*timestamp=*/bucket2StartTimeNs + 30 * NS_PER_SEC);
-    StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
-
-    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
-    ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{}, OFF}
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::OFF,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 30 * NS_PER_SEC,
-                         bucket2StartTimeNs + 30 * NS_PER_SEC);
-
-    // Value for key {{}, ON}
-    it++;
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs + 30 * NS_PER_SEC);
-
-    // Value for key {{}, -1}
-    it++;
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
-
-    // Start dump report and check output.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    valueProducer->onDumpReport(bucket2StartTimeNs + 50 * NS_PER_SEC,
-                                true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
-                                &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(3, report.value_metrics().data_size());
-
-    // {{}, kStateUnknown}
-    ValueMetricData data = report.value_metrics().data(0);
-    EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
-    EXPECT_EQ(-1 /*StateTracker::kUnknown*/, data.slice_by_state(0).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-
-    // {{}, ON}
-    data = report.value_metrics().data(1);
-    EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON, data.slice_by_state(0).value());
-    ASSERT_EQ(2, data.bucket_info_size());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-    EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
-
-    // {{}, OFF}
-    data = report.value_metrics().data(2);
-    EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
-    EXPECT_EQ(BatterySaverModeStateChanged::OFF, data.slice_by_state(0).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(40 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-}
-
-/*
- * Test slicing condition_true_nanos by state for metric that slices by state when data is not
- * present in pulled data during a condition change.
- */
-TEST(ValueMetricProducerTest, TestSlicedStateWithDataMissingInConditionChange) {
-    // Set up ValueMetricProducer.
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithConditionAndState(
-            "BATTERY_SAVER_MODE_STATE");
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    /*
-    NOTE: "-" means that the data was not present in the pulled data.
-
-                             bucket # 1
-    10         20         30         40         50         60   (seconds)
-    |-------------------------------------------------------|--
-
-    T                                 F         T               (Condition)
-               x                                                (ON)
-               |----------------------|         -
-                         20
-    */
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // Battery saver mode state changed to ON.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10 * NS_PER_SEC);
-                data->clear();
-                data->push_back(
-                        CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC, 3));
-                return true;
-            }))
-            // Condition changed to false.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 30 * NS_PER_SEC);
-                data->clear();
-                data->push_back(
-                        CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30 * NS_PER_SEC, 5));
-                return true;
-            }))
-            // Condition changed to true but data for dimension key {} is not present in the
-            // pulled data.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 40 * NS_PER_SEC);
-                data->clear();
-                return true;
-            }))
-            // Dump report pull.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50 * NS_PER_SEC);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(
-                        tagId, bucketStartTimeNs + 50 * NS_PER_SEC, 20));
-                return true;
-            }));
-
-    StateManager::getInstance().clear();
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithConditionAndState(
-                    pullerManager, metric, {util::BATTERY_SAVER_MODE_STATE_CHANGED}, {},
-                    ConditionState::kTrue);
-    EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
-
-    // Set up StateManager and check that StateTrackers are initialized.
-    StateManager::getInstance().registerListener(util::BATTERY_SAVER_MODE_STATE_CHANGED,
-                                                 valueProducer);
-    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(
-                         util::BATTERY_SAVER_MODE_STATE_CHANGED));
-
-    // Bucket status after battery saver mode ON event.
-    unique_ptr<LogEvent> batterySaverOnEvent =
-            CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 10 * NS_PER_SEC);
-    StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
-    // Base for dimension key {}
-    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
-    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-    auto it = valueProducer->mCurrentSlicedBucket.begin();
-    auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{}, ON}
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
-
-    // Value for key {{}, -1}
-    it++;
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Bucket status after condition change to false.
-    valueProducer->onConditionChanged(false, bucketStartTimeNs + 30 * NS_PER_SEC);
-    // Base for dimension key {}
-    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
-    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{}, ON}
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
-                         bucketStartTimeNs + 30 * NS_PER_SEC);
-
-    // Value for key {{}, -1}
-    it++;
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Bucket status after condition change to true.
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 40 * NS_PER_SEC);
-    // Base for dimension key {}
-    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
-    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_FALSE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{}, ON}
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
-                         bucketStartTimeNs + 30 * NS_PER_SEC);
-
-    // Value for key {{}, -1}
-    it++;
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Start dump report and check output.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    valueProducer->onDumpReport(bucketStartTimeNs + 50 * NS_PER_SEC,
-                                true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
-                                &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(1, report.value_metrics().data_size());
-
-    // {{}, ON}
-    ValueMetricData data = report.value_metrics().data(0);
-    EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON, data.slice_by_state(0).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-}
-
-/*
- * Test slicing condition_true_nanos by state for metric that slices by state with a primary field,
- * condition, and has multiple dimensions.
- */
-TEST(ValueMetricProducerTest, TestSlicedStateWithMultipleDimensions) {
-    // Set up ValueMetricProducer.
-    ValueMetric metric =
-            ValueMetricProducerTestHelper::createMetricWithConditionAndState("UID_PROCESS_STATE");
-    metric.mutable_dimensions_in_what()->set_field(tagId);
-    metric.mutable_dimensions_in_what()->add_child()->set_field(1);
-    metric.mutable_dimensions_in_what()->add_child()->set_field(3);
-
-    MetricStateLink* stateLink = metric.add_state_link();
-    stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
-    auto fieldsInWhat = stateLink->mutable_fields_in_what();
-    *fieldsInWhat = CreateDimensions(tagId, {1 /* uid */});
-    auto fieldsInState = stateLink->mutable_fields_in_state();
-    *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
-
-    /*
-                    bucket # 1                            bucket # 2
-    10     20     30     40     50     60     70     80     90    100    110    120 (seconds)
-    |------------------------------------------|---------------------------------|--
-
-    T                           F   T                                               (Condition)
-                                                                                    (FOREGROUND)
-           x                                                                        {1, 14}
-           |------|
-              10
-
-           x                                                                        {1, 16}
-           |------|
-              10
-                                                                   x                {2, 8}
-                                                                   |-------------|
-                                                                         20
-
-                                                                                    (BACKGROUND)
-                  x                                                                 {1, 14}
-                  |-------------|   |----------|---------------------------------|
-                        20              15                     50
-
-                  x                                                                 {1, 16}
-                  |-------------|   |----------|---------------------------------|
-                        20              15                     50
-
-                     x                                                              {2, 8}
-                     |----------|   |----------|-------------------|
-                         15             15              30
-    */
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // Uid 1 process state change from kStateUnknown -> Foreground
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10 * NS_PER_SEC);
-                data->clear();
-                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC,
-                                                         1 /*uid*/, 3, 14 /*tag*/));
-                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC,
-                                                         1 /*uid*/, 3, 16 /*tag*/));
-
-                // This event should be skipped.
-                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC,
-                                                         2 /*uid*/, 5, 8 /*tag*/));
-                return true;
-            }))
-            // Uid 1 process state change from Foreground -> Background
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20 * NS_PER_SEC);
-                data->clear();
-                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC,
-                                                         1 /*uid*/, 5, 14 /*tag*/));
-                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC,
-                                                         1 /*uid*/, 5, 16 /*tag*/));
-
-                // This event should be skipped.
-                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC,
-                                                         2 /*uid*/, 7, 8 /*tag*/));
-
-                return true;
-            }))
-            // Uid 2 process state change from kStateUnknown -> Background
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 25 * NS_PER_SEC);
-                data->clear();
-                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 25 * NS_PER_SEC,
-                                                         2 /*uid*/, 9, 8 /*tag*/));
-
-                // This event should be skipped.
-                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 25 * NS_PER_SEC,
-                                                         1 /*uid*/, 9, 14 /* tag */));
-
-                // This event should be skipped.
-                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 25 * NS_PER_SEC,
-                                                         1 /*uid*/, 9, 16 /* tag */));
-
-                return true;
-            }))
-            // Condition changed to false.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 40 * NS_PER_SEC);
-                data->clear();
-                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC,
-                                                         1 /*uid*/, 11, 14 /* tag */));
-                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC,
-                                                         1 /*uid*/, 11, 16 /* tag */));
-                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC,
-                                                         2 /*uid*/, 11, 8 /*tag*/));
-
-                return true;
-            }))
-            // Condition changed to true.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 45 * NS_PER_SEC);
-                data->clear();
-                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 45 * NS_PER_SEC,
-                                                         1 /*uid*/, 13, 14 /* tag */));
-                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 45 * NS_PER_SEC,
-                                                         1 /*uid*/, 13, 16 /* tag */));
-                data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 45 * NS_PER_SEC,
-                                                         2 /*uid*/, 13, 8 /*tag*/));
-                return true;
-            }))
-            // Uid 2 process state change from Background -> Foreground
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 30 * NS_PER_SEC);
-                data->clear();
-                data->push_back(CreateThreeValueLogEvent(
-                        tagId, bucket2StartTimeNs + 30 * NS_PER_SEC, 2 /*uid*/, 18, 8 /*tag*/));
-
-                // This event should be skipped.
-                data->push_back(CreateThreeValueLogEvent(
-                        tagId, bucket2StartTimeNs + 30 * NS_PER_SEC, 1 /*uid*/, 18, 14 /* tag */));
-                // This event should be skipped.
-                data->push_back(CreateThreeValueLogEvent(
-                        tagId, bucket2StartTimeNs + 30 * NS_PER_SEC, 1 /*uid*/, 18, 16 /* tag */));
-
-                return true;
-            }))
-            // Dump report pull.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 50 * NS_PER_SEC);
-                data->clear();
-                data->push_back(CreateThreeValueLogEvent(
-                        tagId, bucket2StartTimeNs + 50 * NS_PER_SEC, 1 /*uid*/, 21, 14 /* tag */));
-                data->push_back(CreateThreeValueLogEvent(
-                        tagId, bucket2StartTimeNs + 50 * NS_PER_SEC, 1 /*uid*/, 21, 16 /* tag */));
-                data->push_back(CreateThreeValueLogEvent(
-                        tagId, bucket2StartTimeNs + 50 * NS_PER_SEC, 2 /*uid*/, 21, 8 /*tag*/));
-                return true;
-            }));
-
-    StateManager::getInstance().clear();
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithConditionAndState(
-                    pullerManager, metric, {UID_PROCESS_STATE_ATOM_ID}, {}, ConditionState::kTrue);
-    EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
-
-    // Set up StateManager and check that StateTrackers are initialized.
-    StateManager::getInstance().registerListener(UID_PROCESS_STATE_ATOM_ID, valueProducer);
-    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
-
-    // Condition is true.
-    // Bucket status after uid 1 process state change kStateUnknown -> Foreground.
-    auto uidProcessEvent =
-            CreateUidProcessStateChangedEvent(bucketStartTimeNs + 10 * NS_PER_SEC, 1 /* uid */,
-                                              android::app::PROCESS_STATE_IMPORTANT_FOREGROUND);
-    StateManager::getInstance().onLogEvent(*uidProcessEvent);
-    ASSERT_EQ(2UL, valueProducer->mCurrentBaseInfo.size());
-    ASSERT_EQ(4UL, valueProducer->mCurrentSlicedBucket.size());
-    // Base for dimension {uid 1, tag 16}.
-    auto it = valueProducer->mCurrentSlicedBucket.begin();
-    auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{uid 1, uid 16}, FOREGROUND}.
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
-    // Value for key {{uid 1, tag 16}, kStateUnknown}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Base for dimension key {uid 1, tag 14}.
-    it++;
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{uid 1, tag 14}, FOREGROUND}.
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
-    // Value for key {{uid 1, tag 14}, kStateUnknown}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Bucket status after uid 1 process state change Foreground -> Background.
-    uidProcessEvent =
-            CreateUidProcessStateChangedEvent(bucketStartTimeNs + 20 * NS_PER_SEC, 1 /* uid */,
-                                              android::app::PROCESS_STATE_IMPORTANT_BACKGROUND);
-    StateManager::getInstance().onLogEvent(*uidProcessEvent);
-    ASSERT_EQ(2UL, valueProducer->mCurrentBaseInfo.size());
-    ASSERT_EQ(6UL, valueProducer->mCurrentSlicedBucket.size());
-    // Base for dimension {uid 1, tag 16}.
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{uid 1, uid 16}, BACKGROUND}.
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
-
-    // Base for dimension key {uid 1, tag 14}.
-    it++;
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{uid 1, tag 14}, BACKGROUND}.
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
-
-    // Value for key {{uid 1, uid 16}, FOREGROUND}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
-                         bucketStartTimeNs + 20 * NS_PER_SEC);
-
-    // Value for key {{uid 1, tag 16}, kStateUnknown}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Value for key {{uid 1, tag 14}, FOREGROUND}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
-                         bucketStartTimeNs + 20 * NS_PER_SEC);
-
-    // Value for key {{uid 1, tag 14}, kStateUnknown}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Bucket status after uid 2 process state change kStateUnknown -> Background.
-    uidProcessEvent =
-            CreateUidProcessStateChangedEvent(bucketStartTimeNs + 25 * NS_PER_SEC, 2 /* uid */,
-                                              android::app::PROCESS_STATE_IMPORTANT_BACKGROUND);
-    StateManager::getInstance().onLogEvent(*uidProcessEvent);
-    ASSERT_EQ(3UL, valueProducer->mCurrentBaseInfo.size());
-    ASSERT_EQ(8UL, valueProducer->mCurrentSlicedBucket.size());
-    // Base for dimension {uid 2, tag 8}.
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{uid 2, uid 8}, BACKGROUND}.
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 25 * NS_PER_SEC);
-
-    // Value for key {{uid 2, uid 8}, kStateUnknown}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Base for dimension {uid 1, tag 16}.
-    it++;
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{uid 1, uid 16}, BACKGROUND}.
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
-
-    // Base for dimension key {uid 1, tag 14}.
-    it++;
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{uid 1, tag 14}, BACKGROUND}.
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
-
-    // Value for key {{uid 1, uid 16}, FOREGROUND}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
-                         bucketStartTimeNs + 20 * NS_PER_SEC);
-
-    // Value for key {{uid 1, tag 16}, kStateUnknown}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Value for key {{uid 1, tag 14}, FOREGROUND}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
-                         bucketStartTimeNs + 20 * NS_PER_SEC);
-
-    // Value for key {{uid 1, tag 14}, kStateUnknown}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Bucket 1 status after condition change to false.
-    // All condition timers should be turned off.
-    valueProducer->onConditionChanged(false, bucketStartTimeNs + 40 * NS_PER_SEC);
-    ASSERT_EQ(3UL, valueProducer->mCurrentBaseInfo.size());
-    ASSERT_EQ(8UL, valueProducer->mCurrentSlicedBucket.size());
-    // Base for dimension {uid 2, tag 8}.
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{uid 2, uid 8}, BACKGROUND}.
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 15 * NS_PER_SEC,
-                         bucketStartTimeNs + 40 * NS_PER_SEC);
-
-    // Value for key {{uid 2, uid 8}, kStateUnknown}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Base for dimension {uid 1, tag 16}.
-    it++;
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{uid 1, uid 16}, BACKGROUND}.
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
-                         bucketStartTimeNs + 40 * NS_PER_SEC);
-
-    // Base for dimension key {uid 1, tag 14}.
-    it++;
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{uid 1, tag 14}, BACKGROUND}.
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
-                         bucketStartTimeNs + 40 * NS_PER_SEC);
-
-    // Value for key {{uid 1, uid 16}, FOREGROUND}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
-                         bucketStartTimeNs + 20 * NS_PER_SEC);
-
-    // Value for key {{uid 1, tag 16}, kStateUnknown}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Value for key {{uid 1, tag 14}, FOREGROUND}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
-                         bucketStartTimeNs + 20 * NS_PER_SEC);
-
-    // Value for key {{uid 1, tag 14}, kStateUnknown}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Bucket 1 status after condition change to true.
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 45 * NS_PER_SEC);
-    ASSERT_EQ(3UL, valueProducer->mCurrentBaseInfo.size());
-    ASSERT_EQ(8UL, valueProducer->mCurrentSlicedBucket.size());
-    // Base for dimension {uid 2, tag 8}.
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{uid 2, uid 8}, BACKGROUND}.
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 15 * NS_PER_SEC,
-                         bucketStartTimeNs + 45 * NS_PER_SEC);
-
-    // Value for key {{uid 2, uid 8}, kStateUnknown}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Base for dimension {uid 1, tag 16}.
-    it++;
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{uid 1, uid 16}, BACKGROUND}.
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 20 * NS_PER_SEC,
-                         bucketStartTimeNs + 45 * NS_PER_SEC);
-
-    // Base for dimension key {uid 1, tag 14}.
-    it++;
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{uid 1, tag 14}, BACKGROUND}.
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 20 * NS_PER_SEC,
-                         bucketStartTimeNs + 45 * NS_PER_SEC);
-
-    // Value for key {{uid 1, uid 16}, FOREGROUND}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
-                         bucketStartTimeNs + 20 * NS_PER_SEC);
-
-    // Value for key {{uid 1, tag 16}, kStateUnknown}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Value for key {{uid 1, tag 14}, FOREGROUND}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
-                         bucketStartTimeNs + 20 * NS_PER_SEC);
-
-    // Value for key {{uid 1, tag 14}, kStateUnknown}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Pull at end of first bucket.
-    vector<shared_ptr<LogEvent>> allData;
-    allData.push_back(
-            CreateThreeValueLogEvent(tagId, bucket2StartTimeNs, 1 /*uid*/, 13, 14 /* tag */));
-    allData.push_back(
-            CreateThreeValueLogEvent(tagId, bucket2StartTimeNs, 1 /*uid*/, 13, 16 /* tag */));
-    allData.push_back(
-            CreateThreeValueLogEvent(tagId, bucket2StartTimeNs, 2 /*uid*/, 13, 8 /*tag*/));
-    valueProducer->onDataPulled(allData, /** succeeds */ true, bucket2StartTimeNs + 1);
-
-    // Buckets flushed after end of first bucket.
-    // All condition timers' behavior should rollover to bucket 2.
-    ASSERT_EQ(8UL, valueProducer->mCurrentSlicedBucket.size());
-    ASSERT_EQ(5UL, valueProducer->mPastBuckets.size());
-    ASSERT_EQ(3UL, valueProducer->mCurrentBaseInfo.size());
-    // Base for dimension {uid 2, tag 8}.
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{uid 2, uid 8}, BACKGROUND}.
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
-    ASSERT_EQ(1, valueProducer->mPastBuckets[it->first].size());
-    EXPECT_EQ(30 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
-
-    // Value for key {{uid 2, uid 8}, kStateUnknown}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Base for dimension {uid 1, tag 16}.
-    it++;
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{uid 1, uid 16}, BACKGROUND}.
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
-    ASSERT_EQ(1, valueProducer->mPastBuckets[it->first].size());
-    EXPECT_EQ(35 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
-
-    // Base for dimension key {uid 1, tag 14}.
-    it++;
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{uid 1, tag 14}, BACKGROUND}.
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
-    ASSERT_EQ(1, valueProducer->mPastBuckets[it->first].size());
-    EXPECT_EQ(35 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
-
-    // Value for key {{uid 1, uid 16}, FOREGROUND}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
-    ASSERT_EQ(1, valueProducer->mPastBuckets[it->first].size());
-    EXPECT_EQ(10 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
-
-    // Value for key {{uid 1, tag 16}, kStateUnknown}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Value for key {{uid 1, tag 14}, FOREGROUND}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
-    ASSERT_EQ(1, valueProducer->mPastBuckets[it->first].size());
-    EXPECT_EQ(10 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
-
-    // Value for key {{uid 1, tag 14}, kStateUnknown}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Bucket 2 status after uid 2 process state change Background->Foreground.
-    uidProcessEvent =
-            CreateUidProcessStateChangedEvent(bucket2StartTimeNs + 30 * NS_PER_SEC, 2 /* uid */,
-                                              android::app::PROCESS_STATE_IMPORTANT_FOREGROUND);
-    StateManager::getInstance().onLogEvent(*uidProcessEvent);
-
-    ASSERT_EQ(9UL, valueProducer->mCurrentSlicedBucket.size());
-    ASSERT_EQ(3UL, valueProducer->mCurrentBaseInfo.size());
-    // Base for dimension {uid 2, tag 8}.
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{uid 2, uid 8}, FOREGROUND}.
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs + 30 * NS_PER_SEC);
-
-    // Value for key {{uid 2, uid 8}, BACKGROUND}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 30 * NS_PER_SEC,
-                         bucket2StartTimeNs + 30 * NS_PER_SEC);
-
-    // Value for key {{uid 2, uid 8}, kStateUnknown}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Base for dimension {uid 1, tag 16}.
-    it++;
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{uid 1, uid 16}, BACKGROUND}.
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
-
-    // Base for dimension key {uid 1, tag 14}.
-    it++;
-    itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{uid 1, tag 14}, BACKGROUND}.
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
-
-    // Value for key {{uid 1, uid 16}, FOREGROUND}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
-
-    // Value for key {{uid 1, tag 16}, kStateUnknown}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Value for key {{uid 1, tag 14}, FOREGROUND}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
-
-    // Value for key {{uid 1, tag 14}, kStateUnknown}.
-    it++;
-    ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
-    EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-    EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Start dump report and check output.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    valueProducer->onDumpReport(bucket2StartTimeNs + 50 * NS_PER_SEC,
-                                true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
-                                &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(6, report.value_metrics().data_size());
-
-    // {{uid 1, tag 14}, FOREGROUND}.
-    auto data = report.value_metrics().data(0);
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              data.slice_by_state(0).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-
-    // {{uid 1, tag 16}, BACKGROUND}.
-    data = report.value_metrics().data(1);
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              data.slice_by_state(0).value());
-    ASSERT_EQ(2, data.bucket_info_size());
-    EXPECT_EQ(35 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-    EXPECT_EQ(50 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
-
-    // {{uid 1, tag 14}, BACKGROUND}.
-    data = report.value_metrics().data(2);
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              data.slice_by_state(0).value());
-    ASSERT_EQ(2, data.bucket_info_size());
-    EXPECT_EQ(35 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-    EXPECT_EQ(50 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
-
-    // {{uid 1, tag 16}, FOREGROUND}.
-    data = report.value_metrics().data(3);
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              data.slice_by_state(0).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-
-    // {{uid 2, tag 8}, FOREGROUND}.
-    data = report.value_metrics().data(4);
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
-              data.slice_by_state(0).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-
-    // {{uid 2, tag 8}, BACKGROUND}.
-    data = report.value_metrics().data(5);
-    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
-              data.slice_by_state(0).value());
-    ASSERT_EQ(2, data.bucket_info_size());
-    EXPECT_EQ(30 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-    EXPECT_EQ(30 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
-}
-
-TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) {
-    // Set up ValueMetricProducer.
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithConditionAndState(
-            "BATTERY_SAVER_MODE_STATE");
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
-            // Condition changed to true.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20 * NS_PER_SEC);
-                data->clear();
-                data->push_back(
-                        CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC, 3));
-                return true;
-            }))
-            // Battery saver mode state changed to OFF.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 30 * NS_PER_SEC);
-                data->clear();
-                data->push_back(
-                        CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30 * NS_PER_SEC, 5));
-                return true;
-            }))
-            // Condition changed to false.
-            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
-                                vector<std::shared_ptr<LogEvent>>* data) {
-                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 10 * NS_PER_SEC);
-                data->clear();
-                data->push_back(CreateRepeatedValueLogEvent(
-                        tagId, bucket2StartTimeNs + 10 * NS_PER_SEC, 15));
-                return true;
-            }));
-
-    StateManager::getInstance().clear();
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithConditionAndState(
-                    pullerManager, metric, {util::BATTERY_SAVER_MODE_STATE_CHANGED}, {},
-                    ConditionState::kFalse);
-    EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
-
-    // Set up StateManager and check that StateTrackers are initialized.
-    StateManager::getInstance().registerListener(util::BATTERY_SAVER_MODE_STATE_CHANGED,
-                                                 valueProducer);
-    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(
-                         util::BATTERY_SAVER_MODE_STATE_CHANGED));
-
-    // Bucket status after battery saver mode ON event.
-    // Condition is false so we do nothing.
-    unique_ptr<LogEvent> batterySaverOnEvent =
-            CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 10 * NS_PER_SEC);
-    StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
-    EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
-    EXPECT_EQ(0UL, valueProducer->mCurrentBaseInfo.size());
-
-    // Bucket status after condition change to true.
-    valueProducer->onConditionChanged(true, bucketStartTimeNs + 20 * NS_PER_SEC);
-    // Base for dimension key {}
-    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
-    std::unordered_map<HashableDimensionKey, ValueMetricProducer::DimensionsInWhatInfo>::iterator
-            itBase = valueProducer->mCurrentBaseInfo.find(DEFAULT_DIMENSION_KEY);
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(3, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{}, ON}
-    ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-    std::unordered_map<MetricDimensionKey, ValueMetricProducer::CurrentValueBucket>::iterator it =
-            valueProducer->mCurrentSlicedBucket.begin();
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
-    // Value for key {{}, -1}
-    it++;
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_FALSE(it->second.intervals[0].hasValue);
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Bucket status after battery saver mode OFF event.
-    unique_ptr<LogEvent> batterySaverOffEvent =
-            CreateBatterySaverOffEvent(/*timestamp=*/bucketStartTimeNs + 30 * NS_PER_SEC);
-    StateManager::getInstance().onLogEvent(*batterySaverOffEvent);
-    // Base for dimension key {}
-    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
-    itBase = valueProducer->mCurrentBaseInfo.find(DEFAULT_DIMENSION_KEY);
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(5, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::OFF,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{}, OFF}
-    ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::OFF,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 30 * NS_PER_SEC);
-    // Value for key {{}, ON}
-    it++;
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_TRUE(it->second.intervals[0].hasValue);
-    EXPECT_EQ(2, it->second.intervals[0].value.long_value);
-    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
-                         bucketStartTimeNs + 30 * NS_PER_SEC);
-    // Value for key {{}, -1}
-    it++;
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Pull at end of first bucket.
-    vector<shared_ptr<LogEvent>> allData;
-    allData.clear();
-    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 11));
-    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-
-    EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
-    EXPECT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
-    // Base for dimension key {}
-    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
-    itBase = valueProducer->mCurrentBaseInfo.find(DEFAULT_DIMENSION_KEY);
-    EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_EQ(11, itBase->second.baseInfos[0].base.long_value);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::OFF,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{}, OFF}
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
-    // Value for key {{}, ON}
-    it++;
-    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 30 * NS_PER_SEC);
-    // Value for key {{}, -1}
-    it++;
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Bucket 2 status after condition change to false.
-    valueProducer->onConditionChanged(false, bucket2StartTimeNs + 10 * NS_PER_SEC);
-    // Base for dimension key {}
-    ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
-    itBase = valueProducer->mCurrentBaseInfo.find(DEFAULT_DIMENSION_KEY);
-    EXPECT_FALSE(itBase->second.baseInfos[0].hasBase);
-    EXPECT_TRUE(itBase->second.hasCurrentState);
-    ASSERT_EQ(1, itBase->second.currentState.getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::OFF,
-              itBase->second.currentState.getValues()[0].mValue.int_value);
-    // Value for key {{}, OFF}
-    ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::OFF,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_TRUE(it->second.intervals[0].hasValue);
-    EXPECT_EQ(4, it->second.intervals[0].value.long_value);
-    assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
-                         bucket2StartTimeNs + 10 * NS_PER_SEC);
-    // Value for key {{}, ON}
-    it++;
-    EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
-    ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON,
-              it->first.getStateValuesKey().getValues()[0].mValue.int_value);
-    EXPECT_FALSE(it->second.intervals[0].hasValue);
-    assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 30 * NS_PER_SEC);
-    // Value for key {{}, -1}
-    it++;
-    assertConditionTimer(it->second.conditionTimer, false, 0, 0);
-
-    // Start dump report and check output.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    valueProducer->onDumpReport(bucket2StartTimeNs + 50 * NS_PER_SEC,
-                                true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
-                                &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(2, report.value_metrics().data_size());
-
-    ValueMetricData data = report.value_metrics().data(0);
-    EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(BatterySaverModeStateChanged::ON, data.slice_by_state(0).value());
-    ASSERT_EQ(1, data.bucket_info_size());
-    EXPECT_EQ(2, data.bucket_info(0).values(0).value_long());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-
-    data = report.value_metrics().data(1);
-    EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
-    EXPECT_TRUE(data.slice_by_state(0).has_value());
-    EXPECT_EQ(BatterySaverModeStateChanged::OFF, data.slice_by_state(0).value());
-    ASSERT_EQ(2, data.bucket_info_size());
-    EXPECT_EQ(6, data.bucket_info(0).values(0).value_long());
-    EXPECT_EQ(4, data.bucket_info(1).values(0).value_long());
-    EXPECT_EQ(30 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
-    EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
-}
-
-/*
- * Test bucket splits when condition is unknown.
- */
-TEST(ValueMetricProducerTest, TestForcedBucketSplitWhenConditionUnknownSkipsBucket) {
-    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-
-    sp<ValueMetricProducer> valueProducer =
-            ValueMetricProducerTestHelper::createValueProducerWithCondition(
-                    pullerManager, metric,
-                    ConditionState::kUnknown);
-
-    // App update event.
-    int64_t appUpdateTimeNs = bucketStartTimeNs + 1000;
-    valueProducer->notifyAppUpgrade(appUpdateTimeNs);
-
-    // Check dump report.
-    ProtoOutputStream output;
-    std::set<string> strSet;
-    int64_t dumpReportTimeNs = bucketStartTimeNs + 10000000000; // 10 seconds
-    valueProducer->onDumpReport(dumpReportTimeNs, false /* include current buckets */, true,
-                                NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
-
-    StatsLogReport report = outputStreamToProto(&output);
-    EXPECT_TRUE(report.has_value_metrics());
-    ASSERT_EQ(0, report.value_metrics().data_size());
-    ASSERT_EQ(1, report.value_metrics().skipped_size());
-
-    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
-              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
-    EXPECT_EQ(NanoToMillis(appUpdateTimeNs),
-              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
-    ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
-
-    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
-    EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
-    EXPECT_EQ(NanoToMillis(appUpdateTimeNs), dropEvent.drop_time_millis());
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.cpp b/cmds/statsd/tests/metrics/metrics_test_helper.cpp
deleted file mode 100644
index 108df04b..0000000
--- a/cmds/statsd/tests/metrics/metrics_test_helper.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "metrics_test_helper.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-HashableDimensionKey getMockedDimensionKey(int tagId, int key, string value) {
-    HashableDimensionKey dimension;
-    int pos[] = {key, 0, 0};
-    dimension.addValue(FieldValue(Field(tagId, pos, 0), Value(value)));
-
-    return dimension;
-}
-
-HashableDimensionKey getMockedDimensionKeyLongValue(int tagId, int key, int64_t value) {
-    HashableDimensionKey dimension;
-    int pos[] = {key, 0, 0};
-    dimension.addValue(FieldValue(Field(tagId, pos, 0), Value(value)));
-
-    return dimension;
-}
-
-MetricDimensionKey getMockedMetricDimensionKey(int tagId, int key, string value) {
-    return MetricDimensionKey(getMockedDimensionKey(tagId, key, value), DEFAULT_DIMENSION_KEY);
-}
-
-MetricDimensionKey getMockedStateDimensionKey(int tagId, int key, int64_t value) {
-    return MetricDimensionKey(DEFAULT_DIMENSION_KEY,
-                              getMockedDimensionKeyLongValue(tagId, key, value));
-}
-
-void buildSimpleAtomFieldMatcher(const int tagId, FieldMatcher* matcher) {
-    matcher->set_field(tagId);
-}
-
-void buildSimpleAtomFieldMatcher(const int tagId, const int fieldNum, FieldMatcher* matcher) {
-    matcher->set_field(tagId);
-    matcher->add_child()->set_field(fieldNum);
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.h b/cmds/statsd/tests/metrics/metrics_test_helper.h
deleted file mode 100644
index 39232c1..0000000
--- a/cmds/statsd/tests/metrics/metrics_test_helper.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-#pragma once
-
-#include "src/condition/ConditionWizard.h"
-#include "src/external/StatsPullerManager.h"
-#include "src/packages/UidMap.h"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-class MockConditionWizard : public ConditionWizard {
-public:
-    MOCK_METHOD3(query,
-                 ConditionState(const int conditionIndex, const ConditionKey& conditionParameters,
-                                const bool isPartialLink));
-};
-
-class MockStatsPullerManager : public StatsPullerManager {
-public:
-    MOCK_METHOD5(RegisterReceiver,
-                 void(int tagId, const ConfigKey& key, wp<PullDataReceiver> receiver,
-                      int64_t nextPulltimeNs, int64_t intervalNs));
-    MOCK_METHOD3(UnRegisterReceiver,
-                 void(int tagId, const ConfigKey& key, wp<PullDataReceiver> receiver));
-    MOCK_METHOD4(Pull, bool(const int pullCode, const ConfigKey& key, const int64_t eventTimeNs,
-                            vector<std::shared_ptr<LogEvent>>* data));
-    MOCK_METHOD4(Pull, bool(const int pullCode, const vector<int32_t>& uids,
-                            const int64_t eventTimeNs, vector<std::shared_ptr<LogEvent>>* data));
-    MOCK_METHOD2(RegisterPullUidProvider,
-                 void(const ConfigKey& configKey, wp<PullUidProvider> provider));
-    MOCK_METHOD2(UnregisterPullUidProvider,
-                 void(const ConfigKey& configKey, wp<PullUidProvider> provider));
-};
-
-HashableDimensionKey getMockedDimensionKey(int tagId, int key, std::string value);
-MetricDimensionKey getMockedMetricDimensionKey(int tagId, int key, std::string value);
-
-HashableDimensionKey getMockedDimensionKeyLongValue(int tagId, int key, int64_t value);
-MetricDimensionKey getMockedStateDimensionKey(int tagId, int key, int64_t value);
-
-// Utils to build FieldMatcher proto for simple one-depth atoms.
-void buildSimpleAtomFieldMatcher(const int tagId, const int atomFieldNum, FieldMatcher* matcher);
-void buildSimpleAtomFieldMatcher(const int tagId, FieldMatcher* matcher);
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
deleted file mode 100644
index d78c14c..0000000
--- a/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
+++ /dev/null
@@ -1,3632 +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.
-
-#include "src/metrics/parsing_utils/config_update_utils.h"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <private/android_filesystem_config.h>
-#include <stdio.h>
-
-#include <set>
-#include <unordered_map>
-#include <vector>
-
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "src/condition/CombinationConditionTracker.h"
-#include "src/condition/SimpleConditionTracker.h"
-#include "src/matchers/CombinationAtomMatchingTracker.h"
-#include "src/metrics/DurationMetricProducer.h"
-#include "src/metrics/GaugeMetricProducer.h"
-#include "src/metrics/ValueMetricProducer.h"
-#include "src/metrics/parsing_utils/metrics_manager_util.h"
-#include "tests/statsd_test_util.h"
-
-using namespace testing;
-using android::sp;
-using android::os::statsd::Predicate;
-using std::map;
-using std::nullopt;
-using std::optional;
-using std::set;
-using std::unordered_map;
-using std::vector;
-
-#ifdef __ANDROID__
-
-namespace android {
-namespace os {
-namespace statsd {
-
-namespace {
-
-ConfigKey key(123, 456);
-const int64_t timeBaseNs = 1000 * NS_PER_SEC;
-
-sp<UidMap> uidMap = new UidMap();
-sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-sp<AlarmMonitor> anomalyAlarmMonitor;
-sp<AlarmMonitor> periodicAlarmMonitor = new AlarmMonitor(
-        /*minDiffToUpdateRegisteredAlarmTimeSec=*/0,
-        [](const shared_ptr<IStatsCompanionService>&, int64_t) {},
-        [](const shared_ptr<IStatsCompanionService>&) {});
-set<int> allTagIds;
-vector<sp<AtomMatchingTracker>> oldAtomMatchingTrackers;
-unordered_map<int64_t, int> oldAtomMatchingTrackerMap;
-vector<sp<ConditionTracker>> oldConditionTrackers;
-unordered_map<int64_t, int> oldConditionTrackerMap;
-vector<sp<MetricProducer>> oldMetricProducers;
-unordered_map<int64_t, int> oldMetricProducerMap;
-std::vector<sp<AnomalyTracker>> oldAnomalyTrackers;
-unordered_map<int64_t, int> oldAlertTrackerMap;
-std::vector<sp<AlarmTracker>> oldAlarmTrackers;
-unordered_map<int, std::vector<int>> tmpConditionToMetricMap;
-unordered_map<int, std::vector<int>> tmpTrackerToMetricMap;
-unordered_map<int, std::vector<int>> tmpTrackerToConditionMap;
-unordered_map<int, std::vector<int>> tmpActivationAtomTrackerToMetricMap;
-unordered_map<int, std::vector<int>> tmpDeactivationAtomTrackerToMetricMap;
-vector<int> metricsWithActivation;
-map<int64_t, uint64_t> oldStateHashes;
-std::set<int64_t> noReportMetricIds;
-
-class ConfigUpdateTest : public ::testing::Test {
-public:
-    ConfigUpdateTest() {
-    }
-
-    void SetUp() override {
-        allTagIds.clear();
-        oldAtomMatchingTrackers.clear();
-        oldAtomMatchingTrackerMap.clear();
-        oldConditionTrackers.clear();
-        oldConditionTrackerMap.clear();
-        oldMetricProducers.clear();
-        oldMetricProducerMap.clear();
-        oldAnomalyTrackers.clear();
-        oldAlarmTrackers.clear();
-        tmpConditionToMetricMap.clear();
-        tmpTrackerToMetricMap.clear();
-        tmpTrackerToConditionMap.clear();
-        tmpActivationAtomTrackerToMetricMap.clear();
-        tmpDeactivationAtomTrackerToMetricMap.clear();
-        oldAlertTrackerMap.clear();
-        metricsWithActivation.clear();
-        oldStateHashes.clear();
-        noReportMetricIds.clear();
-        StateManager::getInstance().clear();
-    }
-};
-
-bool initConfig(const StatsdConfig& config) {
-    return initStatsdConfig(
-            key, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
-            timeBaseNs, timeBaseNs, allTagIds, oldAtomMatchingTrackers, oldAtomMatchingTrackerMap,
-            oldConditionTrackers, oldConditionTrackerMap, oldMetricProducers, oldMetricProducerMap,
-            oldAnomalyTrackers, oldAlarmTrackers, tmpConditionToMetricMap, tmpTrackerToMetricMap,
-            tmpTrackerToConditionMap, tmpActivationAtomTrackerToMetricMap,
-            tmpDeactivationAtomTrackerToMetricMap, oldAlertTrackerMap, metricsWithActivation,
-            oldStateHashes, noReportMetricIds);
-}
-
-EventMetric createEventMetric(string name, int64_t what, optional<int64_t> condition) {
-    EventMetric metric;
-    metric.set_id(StringToId(name));
-    metric.set_what(what);
-    if (condition) {
-        metric.set_condition(condition.value());
-    }
-    return metric;
-}
-
-CountMetric createCountMetric(string name, int64_t what, optional<int64_t> condition,
-                              vector<int64_t> states) {
-    CountMetric metric;
-    metric.set_id(StringToId(name));
-    metric.set_what(what);
-    metric.set_bucket(TEN_MINUTES);
-    if (condition) {
-        metric.set_condition(condition.value());
-    }
-    for (const int64_t state : states) {
-        metric.add_slice_by_state(state);
-    }
-    return metric;
-}
-
-GaugeMetric createGaugeMetric(string name, int64_t what, GaugeMetric::SamplingType samplingType,
-                              optional<int64_t> condition, optional<int64_t> triggerEvent) {
-    GaugeMetric metric;
-    metric.set_id(StringToId(name));
-    metric.set_what(what);
-    metric.set_bucket(TEN_MINUTES);
-    metric.set_sampling_type(samplingType);
-    if (condition) {
-        metric.set_condition(condition.value());
-    }
-    if (triggerEvent) {
-        metric.set_trigger_event(triggerEvent.value());
-    }
-    metric.mutable_gauge_fields_filter()->set_include_all(true);
-    return metric;
-}
-
-DurationMetric createDurationMetric(string name, int64_t what, optional<int64_t> condition,
-                                    vector<int64_t> states) {
-    DurationMetric metric;
-    metric.set_id(StringToId(name));
-    metric.set_what(what);
-    metric.set_bucket(TEN_MINUTES);
-    if (condition) {
-        metric.set_condition(condition.value());
-    }
-    for (const int64_t state : states) {
-        metric.add_slice_by_state(state);
-    }
-    return metric;
-}
-
-ValueMetric createValueMetric(string name, const AtomMatcher& what, optional<int64_t> condition,
-                              vector<int64_t> states) {
-    ValueMetric metric;
-    metric.set_id(StringToId(name));
-    metric.set_what(what.id());
-    metric.set_bucket(TEN_MINUTES);
-    metric.mutable_value_field()->set_field(what.simple_atom_matcher().atom_id());
-    metric.mutable_value_field()->add_child()->set_field(2);
-    if (condition) {
-        metric.set_condition(condition.value());
-    }
-    for (const int64_t state : states) {
-        metric.add_slice_by_state(state);
-    }
-    return metric;
-}
-
-Alert createAlert(string name, int64_t metricId, int buckets, int64_t triggerSum) {
-    Alert alert;
-    alert.set_id(StringToId(name));
-    alert.set_metric_id(metricId);
-    alert.set_num_buckets(buckets);
-    alert.set_trigger_if_sum_gt(triggerSum);
-    return alert;
-}
-
-Subscription createSubscription(string name, Subscription_RuleType type, int64_t ruleId) {
-    Subscription subscription;
-    subscription.set_id(StringToId(name));
-    subscription.set_rule_type(type);
-    subscription.set_rule_id(ruleId);
-    subscription.mutable_broadcast_subscriber_details();
-    return subscription;
-}
-
-Alarm createAlarm(string name, int64_t offsetMillis, int64_t periodMillis) {
-    Alarm alarm;
-    alarm.set_id(StringToId(name));
-    alarm.set_offset_millis(offsetMillis);
-    alarm.set_period_millis(periodMillis);
-    return alarm;
-}
-}  // anonymous namespace
-
-TEST_F(ConfigUpdateTest, TestSimpleMatcherPreserve) {
-    StatsdConfig config;
-    AtomMatcher matcher = CreateSimpleAtomMatcher("TEST", /*atom=*/10);
-    int64_t matcherId = matcher.id();
-    *config.add_atom_matcher() = matcher;
-
-    // Create an initial config.
-    EXPECT_TRUE(initConfig(config));
-
-    vector<UpdateStatus> matchersToUpdate(1, UPDATE_UNKNOWN);
-    vector<bool> cycleTracker(1, false);
-    unordered_map<int64_t, int> newAtomMatchingTrackerMap;
-    newAtomMatchingTrackerMap[matcherId] = 0;
-    EXPECT_TRUE(determineMatcherUpdateStatus(config, 0, oldAtomMatchingTrackerMap,
-                                             oldAtomMatchingTrackers, newAtomMatchingTrackerMap,
-                                             matchersToUpdate, cycleTracker));
-    EXPECT_EQ(matchersToUpdate[0], UPDATE_PRESERVE);
-}
-
-TEST_F(ConfigUpdateTest, TestSimpleMatcherReplace) {
-    StatsdConfig config;
-    AtomMatcher matcher = CreateSimpleAtomMatcher("TEST", /*atom=*/10);
-    *config.add_atom_matcher() = matcher;
-
-    EXPECT_TRUE(initConfig(config));
-
-    StatsdConfig newConfig;
-    // Same id, different atom, so should be replaced.
-    AtomMatcher newMatcher = CreateSimpleAtomMatcher("TEST", /*atom=*/11);
-    int64_t matcherId = newMatcher.id();
-    EXPECT_EQ(matcherId, matcher.id());
-    *newConfig.add_atom_matcher() = newMatcher;
-
-    vector<UpdateStatus> matchersToUpdate(1, UPDATE_UNKNOWN);
-    vector<bool> cycleTracker(1, false);
-    unordered_map<int64_t, int> newAtomMatchingTrackerMap;
-    newAtomMatchingTrackerMap[matcherId] = 0;
-    EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 0, oldAtomMatchingTrackerMap,
-                                             oldAtomMatchingTrackers, newAtomMatchingTrackerMap,
-                                             matchersToUpdate, cycleTracker));
-    EXPECT_EQ(matchersToUpdate[0], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestSimpleMatcherNew) {
-    StatsdConfig config;
-    AtomMatcher matcher = CreateSimpleAtomMatcher("TEST", /*atom=*/10);
-    *config.add_atom_matcher() = matcher;
-
-    EXPECT_TRUE(initConfig(config));
-
-    StatsdConfig newConfig;
-    // Different id, so should be a new matcher.
-    AtomMatcher newMatcher = CreateSimpleAtomMatcher("DIFFERENT_NAME", /*atom=*/10);
-    int64_t matcherId = newMatcher.id();
-    EXPECT_NE(matcherId, matcher.id());
-    *newConfig.add_atom_matcher() = newMatcher;
-
-    vector<UpdateStatus> matchersToUpdate(1, UPDATE_UNKNOWN);
-    vector<bool> cycleTracker(1, false);
-    unordered_map<int64_t, int> newAtomMatchingTrackerMap;
-    newAtomMatchingTrackerMap[matcherId] = 0;
-    EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 0, oldAtomMatchingTrackerMap,
-                                             oldAtomMatchingTrackers, newAtomMatchingTrackerMap,
-                                             matchersToUpdate, cycleTracker));
-    EXPECT_EQ(matchersToUpdate[0], UPDATE_NEW);
-}
-
-TEST_F(ConfigUpdateTest, TestCombinationMatcherPreserve) {
-    StatsdConfig config;
-    AtomMatcher matcher1 = CreateSimpleAtomMatcher("TEST1", /*atom=*/10);
-    int64_t matcher1Id = matcher1.id();
-    *config.add_atom_matcher() = matcher1;
-
-    AtomMatcher matcher2 = CreateSimpleAtomMatcher("TEST2", /*atom=*/11);
-    *config.add_atom_matcher() = matcher2;
-    int64_t matcher2Id = matcher2.id();
-
-    AtomMatcher matcher3;
-    matcher3.set_id(StringToId("TEST3"));
-    AtomMatcher_Combination* combination = matcher3.mutable_combination();
-    combination->set_operation(LogicalOperation::OR);
-    combination->add_matcher(matcher1Id);
-    combination->add_matcher(matcher2Id);
-    int64_t matcher3Id = matcher3.id();
-    *config.add_atom_matcher() = matcher3;
-
-    EXPECT_TRUE(initConfig(config));
-
-    StatsdConfig newConfig;
-    unordered_map<int64_t, int> newAtomMatchingTrackerMap;
-    // Same matchers, different order, all should be preserved.
-    *newConfig.add_atom_matcher() = matcher2;
-    newAtomMatchingTrackerMap[matcher2Id] = 0;
-    *newConfig.add_atom_matcher() = matcher3;
-    newAtomMatchingTrackerMap[matcher3Id] = 1;
-    *newConfig.add_atom_matcher() = matcher1;
-    newAtomMatchingTrackerMap[matcher1Id] = 2;
-
-    vector<UpdateStatus> matchersToUpdate(3, UPDATE_UNKNOWN);
-    vector<bool> cycleTracker(3, false);
-    // Only update the combination. It should recurse the two child matchers and preserve all 3.
-    EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 1, oldAtomMatchingTrackerMap,
-                                             oldAtomMatchingTrackers, newAtomMatchingTrackerMap,
-                                             matchersToUpdate, cycleTracker));
-    EXPECT_EQ(matchersToUpdate[0], UPDATE_PRESERVE);
-    EXPECT_EQ(matchersToUpdate[1], UPDATE_PRESERVE);
-    EXPECT_EQ(matchersToUpdate[2], UPDATE_PRESERVE);
-}
-
-TEST_F(ConfigUpdateTest, TestCombinationMatcherReplace) {
-    StatsdConfig config;
-    AtomMatcher matcher1 = CreateSimpleAtomMatcher("TEST1", /*atom=*/10);
-    int64_t matcher1Id = matcher1.id();
-    *config.add_atom_matcher() = matcher1;
-
-    AtomMatcher matcher2 = CreateSimpleAtomMatcher("TEST2", /*atom=*/11);
-    *config.add_atom_matcher() = matcher2;
-    int64_t matcher2Id = matcher2.id();
-
-    AtomMatcher matcher3;
-    matcher3.set_id(StringToId("TEST3"));
-    AtomMatcher_Combination* combination = matcher3.mutable_combination();
-    combination->set_operation(LogicalOperation::OR);
-    combination->add_matcher(matcher1Id);
-    combination->add_matcher(matcher2Id);
-    int64_t matcher3Id = matcher3.id();
-    *config.add_atom_matcher() = matcher3;
-
-    EXPECT_TRUE(initConfig(config));
-
-    // Change the logical operation of the combination matcher, causing a replacement.
-    matcher3.mutable_combination()->set_operation(LogicalOperation::AND);
-
-    StatsdConfig newConfig;
-    unordered_map<int64_t, int> newAtomMatchingTrackerMap;
-    *newConfig.add_atom_matcher() = matcher2;
-    newAtomMatchingTrackerMap[matcher2Id] = 0;
-    *newConfig.add_atom_matcher() = matcher3;
-    newAtomMatchingTrackerMap[matcher3Id] = 1;
-    *newConfig.add_atom_matcher() = matcher1;
-    newAtomMatchingTrackerMap[matcher1Id] = 2;
-
-    vector<UpdateStatus> matchersToUpdate(3, UPDATE_UNKNOWN);
-    vector<bool> cycleTracker(3, false);
-    // Only update the combination. The simple matchers should not be evaluated.
-    EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 1, oldAtomMatchingTrackerMap,
-                                             oldAtomMatchingTrackers, newAtomMatchingTrackerMap,
-                                             matchersToUpdate, cycleTracker));
-    EXPECT_EQ(matchersToUpdate[0], UPDATE_UNKNOWN);
-    EXPECT_EQ(matchersToUpdate[1], UPDATE_REPLACE);
-    EXPECT_EQ(matchersToUpdate[2], UPDATE_UNKNOWN);
-}
-
-TEST_F(ConfigUpdateTest, TestCombinationMatcherDepsChange) {
-    StatsdConfig config;
-    AtomMatcher matcher1 = CreateSimpleAtomMatcher("TEST1", /*atom=*/10);
-    int64_t matcher1Id = matcher1.id();
-    *config.add_atom_matcher() = matcher1;
-
-    AtomMatcher matcher2 = CreateSimpleAtomMatcher("TEST2", /*atom=*/11);
-    *config.add_atom_matcher() = matcher2;
-    int64_t matcher2Id = matcher2.id();
-
-    AtomMatcher matcher3;
-    matcher3.set_id(StringToId("TEST3"));
-    AtomMatcher_Combination* combination = matcher3.mutable_combination();
-    combination->set_operation(LogicalOperation::OR);
-    combination->add_matcher(matcher1Id);
-    combination->add_matcher(matcher2Id);
-    int64_t matcher3Id = matcher3.id();
-    *config.add_atom_matcher() = matcher3;
-
-    EXPECT_TRUE(initConfig(config));
-
-    // Change a dependency of matcher 3.
-    matcher2.mutable_simple_atom_matcher()->set_atom_id(12);
-
-    StatsdConfig newConfig;
-    unordered_map<int64_t, int> newAtomMatchingTrackerMap;
-    *newConfig.add_atom_matcher() = matcher2;
-    newAtomMatchingTrackerMap[matcher2Id] = 0;
-    *newConfig.add_atom_matcher() = matcher3;
-    newAtomMatchingTrackerMap[matcher3Id] = 1;
-    *newConfig.add_atom_matcher() = matcher1;
-    newAtomMatchingTrackerMap[matcher1Id] = 2;
-
-    vector<UpdateStatus> matchersToUpdate(3, UPDATE_UNKNOWN);
-    vector<bool> cycleTracker(3, false);
-    // Only update the combination.
-    EXPECT_TRUE(determineMatcherUpdateStatus(newConfig, 1, oldAtomMatchingTrackerMap,
-                                             oldAtomMatchingTrackers, newAtomMatchingTrackerMap,
-                                             matchersToUpdate, cycleTracker));
-    // Matcher 2 and matcher3 must be reevaluated. Matcher 1 might, but does not need to be.
-    EXPECT_EQ(matchersToUpdate[0], UPDATE_REPLACE);
-    EXPECT_EQ(matchersToUpdate[1], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestUpdateMatchers) {
-    StatsdConfig config;
-    // Will be preserved.
-    AtomMatcher simple1 = CreateSimpleAtomMatcher("SIMPLE1", /*atom=*/10);
-    int64_t simple1Id = simple1.id();
-    *config.add_atom_matcher() = simple1;
-
-    // Will be replaced.
-    AtomMatcher simple2 = CreateSimpleAtomMatcher("SIMPLE2", /*atom=*/11);
-    *config.add_atom_matcher() = simple2;
-    int64_t simple2Id = simple2.id();
-
-    // Will be removed.
-    AtomMatcher simple3 = CreateSimpleAtomMatcher("SIMPLE3", /*atom=*/12);
-    *config.add_atom_matcher() = simple3;
-    int64_t simple3Id = simple3.id();
-
-    // Will be preserved.
-    AtomMatcher combination1;
-    combination1.set_id(StringToId("combination1"));
-    AtomMatcher_Combination* combination = combination1.mutable_combination();
-    combination->set_operation(LogicalOperation::NOT);
-    combination->add_matcher(simple1Id);
-    int64_t combination1Id = combination1.id();
-    *config.add_atom_matcher() = combination1;
-
-    // Will be replaced since it depends on simple2.
-    AtomMatcher combination2;
-    combination2.set_id(StringToId("combination2"));
-    combination = combination2.mutable_combination();
-    combination->set_operation(LogicalOperation::AND);
-    combination->add_matcher(simple1Id);
-    combination->add_matcher(simple2Id);
-    int64_t combination2Id = combination2.id();
-    *config.add_atom_matcher() = combination2;
-
-    EXPECT_TRUE(initConfig(config));
-
-    // Change simple2, causing simple2 and combination2 to be replaced.
-    simple2.mutable_simple_atom_matcher()->set_atom_id(111);
-
-    // 2 new matchers: simple4 and combination3:
-    AtomMatcher simple4 = CreateSimpleAtomMatcher("SIMPLE4", /*atom=*/13);
-    int64_t simple4Id = simple4.id();
-
-    AtomMatcher combination3;
-    combination3.set_id(StringToId("combination3"));
-    combination = combination3.mutable_combination();
-    combination->set_operation(LogicalOperation::AND);
-    combination->add_matcher(simple4Id);
-    combination->add_matcher(simple2Id);
-    int64_t combination3Id = combination3.id();
-
-    StatsdConfig newConfig;
-    *newConfig.add_atom_matcher() = combination3;
-    *newConfig.add_atom_matcher() = simple2;
-    *newConfig.add_atom_matcher() = combination2;
-    *newConfig.add_atom_matcher() = simple1;
-    *newConfig.add_atom_matcher() = simple4;
-    *newConfig.add_atom_matcher() = combination1;
-
-    set<int> newTagIds;
-    unordered_map<int64_t, int> newAtomMatchingTrackerMap;
-    vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers;
-    set<int64_t> replacedMatchers;
-    EXPECT_TRUE(updateAtomMatchingTrackers(
-            newConfig, uidMap, oldAtomMatchingTrackerMap, oldAtomMatchingTrackers, newTagIds,
-            newAtomMatchingTrackerMap, newAtomMatchingTrackers, replacedMatchers));
-
-    ASSERT_EQ(newTagIds.size(), 3);
-    EXPECT_EQ(newTagIds.count(10), 1);
-    EXPECT_EQ(newTagIds.count(111), 1);
-    EXPECT_EQ(newTagIds.count(13), 1);
-
-    ASSERT_EQ(newAtomMatchingTrackerMap.size(), 6);
-    EXPECT_EQ(newAtomMatchingTrackerMap.at(combination3Id), 0);
-    EXPECT_EQ(newAtomMatchingTrackerMap.at(simple2Id), 1);
-    EXPECT_EQ(newAtomMatchingTrackerMap.at(combination2Id), 2);
-    EXPECT_EQ(newAtomMatchingTrackerMap.at(simple1Id), 3);
-    EXPECT_EQ(newAtomMatchingTrackerMap.at(simple4Id), 4);
-    EXPECT_EQ(newAtomMatchingTrackerMap.at(combination1Id), 5);
-
-    ASSERT_EQ(newAtomMatchingTrackers.size(), 6);
-    // Make sure all atom matchers are initialized:
-    for (const sp<AtomMatchingTracker>& tracker : newAtomMatchingTrackers) {
-        EXPECT_TRUE(tracker->mInitialized);
-    }
-    // Make sure preserved atom matchers are the same.
-    EXPECT_EQ(oldAtomMatchingTrackers[oldAtomMatchingTrackerMap.at(simple1Id)],
-              newAtomMatchingTrackers[newAtomMatchingTrackerMap.at(simple1Id)]);
-    EXPECT_EQ(oldAtomMatchingTrackers[oldAtomMatchingTrackerMap.at(combination1Id)],
-              newAtomMatchingTrackers[newAtomMatchingTrackerMap.at(combination1Id)]);
-    // Make sure replaced matchers are different.
-    EXPECT_NE(oldAtomMatchingTrackers[oldAtomMatchingTrackerMap.at(simple2Id)],
-              newAtomMatchingTrackers[newAtomMatchingTrackerMap.at(simple2Id)]);
-    EXPECT_NE(oldAtomMatchingTrackers[oldAtomMatchingTrackerMap.at(combination2Id)],
-              newAtomMatchingTrackers[newAtomMatchingTrackerMap.at(combination2Id)]);
-
-    // Validation, make sure the matchers have the proper ids/indices. Could do more checks here.
-    EXPECT_EQ(newAtomMatchingTrackers[0]->getId(), combination3Id);
-    EXPECT_EQ(newAtomMatchingTrackers[0]->mIndex, 0);
-    EXPECT_EQ(newAtomMatchingTrackers[1]->getId(), simple2Id);
-    EXPECT_EQ(newAtomMatchingTrackers[1]->mIndex, 1);
-    EXPECT_EQ(newAtomMatchingTrackers[2]->getId(), combination2Id);
-    EXPECT_EQ(newAtomMatchingTrackers[2]->mIndex, 2);
-    EXPECT_EQ(newAtomMatchingTrackers[3]->getId(), simple1Id);
-    EXPECT_EQ(newAtomMatchingTrackers[3]->mIndex, 3);
-    EXPECT_EQ(newAtomMatchingTrackers[4]->getId(), simple4Id);
-    EXPECT_EQ(newAtomMatchingTrackers[4]->mIndex, 4);
-    EXPECT_EQ(newAtomMatchingTrackers[5]->getId(), combination1Id);
-    EXPECT_EQ(newAtomMatchingTrackers[5]->mIndex, 5);
-
-    // Verify child indices of Combination Matchers are correct.
-    CombinationAtomMatchingTracker* combinationTracker1 =
-            static_cast<CombinationAtomMatchingTracker*>(newAtomMatchingTrackers[5].get());
-    vector<int>* childMatchers = &combinationTracker1->mChildren;
-    EXPECT_EQ(childMatchers->size(), 1);
-    EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 3), childMatchers->end());
-
-    CombinationAtomMatchingTracker* combinationTracker2 =
-            static_cast<CombinationAtomMatchingTracker*>(newAtomMatchingTrackers[2].get());
-    childMatchers = &combinationTracker2->mChildren;
-    EXPECT_EQ(childMatchers->size(), 2);
-    EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 1), childMatchers->end());
-    EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 3), childMatchers->end());
-
-    CombinationAtomMatchingTracker* combinationTracker3 =
-            static_cast<CombinationAtomMatchingTracker*>(newAtomMatchingTrackers[0].get());
-    childMatchers = &combinationTracker3->mChildren;
-    EXPECT_EQ(childMatchers->size(), 2);
-    EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 1), childMatchers->end());
-    EXPECT_NE(std::find(childMatchers->begin(), childMatchers->end(), 4), childMatchers->end());
-
-    // Expect replacedMatchers to have simple2 and combination2
-    ASSERT_EQ(replacedMatchers.size(), 2);
-    EXPECT_NE(replacedMatchers.find(simple2Id), replacedMatchers.end());
-    EXPECT_NE(replacedMatchers.find(combination2Id), replacedMatchers.end());
-}
-
-TEST_F(ConfigUpdateTest, TestSimpleConditionPreserve) {
-    StatsdConfig config;
-    AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = startMatcher;
-    AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = stopMatcher;
-
-    Predicate predicate = CreateScreenIsOnPredicate();
-    *config.add_predicate() = predicate;
-
-    // Create an initial config.
-    EXPECT_TRUE(initConfig(config));
-
-    set<int64_t> replacedMatchers;
-    vector<UpdateStatus> conditionsToUpdate(1, UPDATE_UNKNOWN);
-    vector<bool> cycleTracker(1, false);
-    unordered_map<int64_t, int> newConditionTrackerMap;
-    newConditionTrackerMap[predicate.id()] = 0;
-    EXPECT_TRUE(determineConditionUpdateStatus(config, 0, oldConditionTrackerMap,
-                                               oldConditionTrackers, newConditionTrackerMap,
-                                               replacedMatchers, conditionsToUpdate, cycleTracker));
-    EXPECT_EQ(conditionsToUpdate[0], UPDATE_PRESERVE);
-}
-
-TEST_F(ConfigUpdateTest, TestSimpleConditionReplace) {
-    StatsdConfig config;
-    AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = startMatcher;
-    AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = stopMatcher;
-
-    Predicate predicate = CreateScreenIsOnPredicate();
-    *config.add_predicate() = predicate;
-
-    EXPECT_TRUE(initConfig(config));
-
-    // Modify the predicate.
-    config.mutable_predicate(0)->mutable_simple_predicate()->set_count_nesting(true);
-
-    set<int64_t> replacedMatchers;
-    vector<UpdateStatus> conditionsToUpdate(1, UPDATE_UNKNOWN);
-    vector<bool> cycleTracker(1, false);
-    unordered_map<int64_t, int> newConditionTrackerMap;
-    newConditionTrackerMap[predicate.id()] = 0;
-    EXPECT_TRUE(determineConditionUpdateStatus(config, 0, oldConditionTrackerMap,
-                                               oldConditionTrackers, newConditionTrackerMap,
-                                               replacedMatchers, conditionsToUpdate, cycleTracker));
-    EXPECT_EQ(conditionsToUpdate[0], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestSimpleConditionDepsChange) {
-    StatsdConfig config;
-    AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
-    int64_t startMatcherId = startMatcher.id();
-    *config.add_atom_matcher() = startMatcher;
-    AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = stopMatcher;
-
-    Predicate predicate = CreateScreenIsOnPredicate();
-    *config.add_predicate() = predicate;
-
-    EXPECT_TRUE(initConfig(config));
-
-    // Start matcher was replaced.
-    set<int64_t> replacedMatchers;
-    replacedMatchers.insert(startMatcherId);
-
-    vector<UpdateStatus> conditionsToUpdate(1, UPDATE_UNKNOWN);
-    vector<bool> cycleTracker(1, false);
-    unordered_map<int64_t, int> newConditionTrackerMap;
-    newConditionTrackerMap[predicate.id()] = 0;
-    EXPECT_TRUE(determineConditionUpdateStatus(config, 0, oldConditionTrackerMap,
-                                               oldConditionTrackers, newConditionTrackerMap,
-                                               replacedMatchers, conditionsToUpdate, cycleTracker));
-    EXPECT_EQ(conditionsToUpdate[0], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestCombinationConditionPreserve) {
-    StatsdConfig config;
-    AtomMatcher screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = screenOnMatcher;
-    AtomMatcher screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = screenOffMatcher;
-
-    Predicate simple1 = CreateScreenIsOnPredicate();
-    *config.add_predicate() = simple1;
-    Predicate simple2 = CreateScreenIsOffPredicate();
-    *config.add_predicate() = simple2;
-
-    Predicate combination1;
-    combination1.set_id(StringToId("COMBINATION1"));
-    Predicate_Combination* combinationInternal = combination1.mutable_combination();
-    combinationInternal->set_operation(LogicalOperation::NAND);
-    combinationInternal->add_predicate(simple1.id());
-    combinationInternal->add_predicate(simple2.id());
-    *config.add_predicate() = combination1;
-
-    EXPECT_TRUE(initConfig(config));
-
-    // Same predicates, different order
-    StatsdConfig newConfig;
-    unordered_map<int64_t, int> newConditionTrackerMap;
-    *newConfig.add_predicate() = combination1;
-    newConditionTrackerMap[combination1.id()] = 0;
-    *newConfig.add_predicate() = simple2;
-    newConditionTrackerMap[simple2.id()] = 1;
-    *newConfig.add_predicate() = simple1;
-    newConditionTrackerMap[simple1.id()] = 2;
-
-    set<int64_t> replacedMatchers;
-    vector<UpdateStatus> conditionsToUpdate(3, UPDATE_UNKNOWN);
-    vector<bool> cycleTracker(3, false);
-    // Only update the combination. It should recurse the two child predicates and preserve all 3.
-    EXPECT_TRUE(determineConditionUpdateStatus(newConfig, 0, oldConditionTrackerMap,
-                                               oldConditionTrackers, newConditionTrackerMap,
-                                               replacedMatchers, conditionsToUpdate, cycleTracker));
-    EXPECT_EQ(conditionsToUpdate[0], UPDATE_PRESERVE);
-    EXPECT_EQ(conditionsToUpdate[1], UPDATE_PRESERVE);
-    EXPECT_EQ(conditionsToUpdate[2], UPDATE_PRESERVE);
-}
-
-TEST_F(ConfigUpdateTest, TestCombinationConditionReplace) {
-    StatsdConfig config;
-    AtomMatcher screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = screenOnMatcher;
-    AtomMatcher screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = screenOffMatcher;
-
-    Predicate simple1 = CreateScreenIsOnPredicate();
-    *config.add_predicate() = simple1;
-    Predicate simple2 = CreateScreenIsOffPredicate();
-    *config.add_predicate() = simple2;
-
-    Predicate combination1;
-    combination1.set_id(StringToId("COMBINATION1"));
-    Predicate_Combination* combinationInternal = combination1.mutable_combination();
-    combinationInternal->set_operation(LogicalOperation::NAND);
-    combinationInternal->add_predicate(simple1.id());
-    combinationInternal->add_predicate(simple2.id());
-    *config.add_predicate() = combination1;
-
-    EXPECT_TRUE(initConfig(config));
-
-    // Changing the logical operation changes the predicate definition, so it should be replaced.
-    combination1.mutable_combination()->set_operation(LogicalOperation::OR);
-
-    StatsdConfig newConfig;
-    unordered_map<int64_t, int> newConditionTrackerMap;
-    *newConfig.add_predicate() = combination1;
-    newConditionTrackerMap[combination1.id()] = 0;
-    *newConfig.add_predicate() = simple2;
-    newConditionTrackerMap[simple2.id()] = 1;
-    *newConfig.add_predicate() = simple1;
-    newConditionTrackerMap[simple1.id()] = 2;
-
-    set<int64_t> replacedMatchers;
-    vector<UpdateStatus> conditionsToUpdate(3, UPDATE_UNKNOWN);
-    vector<bool> cycleTracker(3, false);
-    // Only update the combination. The simple conditions should not be evaluated.
-    EXPECT_TRUE(determineConditionUpdateStatus(newConfig, 0, oldConditionTrackerMap,
-                                               oldConditionTrackers, newConditionTrackerMap,
-                                               replacedMatchers, conditionsToUpdate, cycleTracker));
-    EXPECT_EQ(conditionsToUpdate[0], UPDATE_REPLACE);
-    EXPECT_EQ(conditionsToUpdate[1], UPDATE_UNKNOWN);
-    EXPECT_EQ(conditionsToUpdate[2], UPDATE_UNKNOWN);
-}
-
-TEST_F(ConfigUpdateTest, TestCombinationConditionDepsChange) {
-    StatsdConfig config;
-    AtomMatcher screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = screenOnMatcher;
-    AtomMatcher screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = screenOffMatcher;
-
-    Predicate simple1 = CreateScreenIsOnPredicate();
-    *config.add_predicate() = simple1;
-    Predicate simple2 = CreateScreenIsOffPredicate();
-    *config.add_predicate() = simple2;
-
-    Predicate combination1;
-    combination1.set_id(StringToId("COMBINATION1"));
-    Predicate_Combination* combinationInternal = combination1.mutable_combination();
-    combinationInternal->set_operation(LogicalOperation::NAND);
-    combinationInternal->add_predicate(simple1.id());
-    combinationInternal->add_predicate(simple2.id());
-    *config.add_predicate() = combination1;
-
-    EXPECT_TRUE(initConfig(config));
-
-    simple2.mutable_simple_predicate()->set_count_nesting(false);
-
-    StatsdConfig newConfig;
-    unordered_map<int64_t, int> newConditionTrackerMap;
-    *newConfig.add_predicate() = combination1;
-    newConditionTrackerMap[combination1.id()] = 0;
-    *newConfig.add_predicate() = simple2;
-    newConditionTrackerMap[simple2.id()] = 1;
-    *newConfig.add_predicate() = simple1;
-    newConditionTrackerMap[simple1.id()] = 2;
-
-    set<int64_t> replacedMatchers;
-    vector<UpdateStatus> conditionsToUpdate(3, UPDATE_UNKNOWN);
-    vector<bool> cycleTracker(3, false);
-    // Only update the combination. Simple2 and combination1 must be evaluated.
-    EXPECT_TRUE(determineConditionUpdateStatus(newConfig, 0, oldConditionTrackerMap,
-                                               oldConditionTrackers, newConditionTrackerMap,
-                                               replacedMatchers, conditionsToUpdate, cycleTracker));
-    EXPECT_EQ(conditionsToUpdate[0], UPDATE_REPLACE);
-    EXPECT_EQ(conditionsToUpdate[1], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestUpdateConditions) {
-    StatsdConfig config;
-    // Add atom matchers. These are mostly needed for initStatsdConfig
-    AtomMatcher matcher1 = CreateScreenTurnedOnAtomMatcher();
-    int64_t matcher1Id = matcher1.id();
-    *config.add_atom_matcher() = matcher1;
-
-    AtomMatcher matcher2 = CreateScreenTurnedOffAtomMatcher();
-    int64_t matcher2Id = matcher2.id();
-    *config.add_atom_matcher() = matcher2;
-
-    AtomMatcher matcher3 = CreateStartScheduledJobAtomMatcher();
-    int64_t matcher3Id = matcher3.id();
-    *config.add_atom_matcher() = matcher3;
-
-    AtomMatcher matcher4 = CreateFinishScheduledJobAtomMatcher();
-    int64_t matcher4Id = matcher4.id();
-    *config.add_atom_matcher() = matcher4;
-
-    AtomMatcher matcher5 = CreateBatterySaverModeStartAtomMatcher();
-    int64_t matcher5Id = matcher5.id();
-    *config.add_atom_matcher() = matcher5;
-
-    AtomMatcher matcher6 = CreateBatterySaverModeStopAtomMatcher();
-    int64_t matcher6Id = matcher6.id();
-    *config.add_atom_matcher() = matcher6;
-
-    // Add the predicates.
-    // Will be preserved.
-    Predicate simple1 = CreateScreenIsOnPredicate();
-    int64_t simple1Id = simple1.id();
-    *config.add_predicate() = simple1;
-
-    // Will be preserved.
-    Predicate simple2 = CreateScheduledJobPredicate();
-    int64_t simple2Id = simple2.id();
-    *config.add_predicate() = simple2;
-
-    // Will be replaced.
-    Predicate simple3 = CreateBatterySaverModePredicate();
-    int64_t simple3Id = simple3.id();
-    *config.add_predicate() = simple3;
-
-    // Will be preserved
-    Predicate combination1;
-    combination1.set_id(StringToId("COMBINATION1"));
-    combination1.mutable_combination()->set_operation(LogicalOperation::AND);
-    combination1.mutable_combination()->add_predicate(simple1Id);
-    combination1.mutable_combination()->add_predicate(simple2Id);
-    int64_t combination1Id = combination1.id();
-    *config.add_predicate() = combination1;
-
-    // Will be replaced since simple3 will be replaced.
-    Predicate combination2;
-    combination2.set_id(StringToId("COMBINATION2"));
-    combination2.mutable_combination()->set_operation(LogicalOperation::OR);
-    combination2.mutable_combination()->add_predicate(simple1Id);
-    combination2.mutable_combination()->add_predicate(simple3Id);
-    int64_t combination2Id = combination2.id();
-    *config.add_predicate() = combination2;
-
-    // Will be removed.
-    Predicate combination3;
-    combination3.set_id(StringToId("COMBINATION3"));
-    combination3.mutable_combination()->set_operation(LogicalOperation::NOT);
-    combination3.mutable_combination()->add_predicate(simple2Id);
-    int64_t combination3Id = combination3.id();
-    *config.add_predicate() = combination3;
-
-    EXPECT_TRUE(initConfig(config));
-
-    // Mark marcher 5 as replaced. Causes simple3, and therefore combination2 to be replaced.
-    set<int64_t> replacedMatchers;
-    replacedMatchers.insert(matcher6Id);
-
-    // Change the condition of simple1 to false.
-    ASSERT_EQ(oldConditionTrackers[0]->getConditionId(), simple1Id);
-    LogEvent event(/*uid=*/0, /*pid=*/0);  // Empty event is fine since there are no dimensions.
-    // Mark the stop matcher as matched, condition should be false.
-    vector<MatchingState> eventMatcherValues(6, MatchingState::kNotMatched);
-    eventMatcherValues[1] = MatchingState::kMatched;
-    vector<ConditionState> tmpConditionCache(6, ConditionState::kNotEvaluated);
-    vector<bool> conditionChangeCache(6, false);
-    oldConditionTrackers[0]->evaluateCondition(event, eventMatcherValues, oldConditionTrackers,
-                                               tmpConditionCache, conditionChangeCache);
-    EXPECT_EQ(tmpConditionCache[0], ConditionState::kFalse);
-    EXPECT_EQ(conditionChangeCache[0], true);
-
-    // New combination predicate. Should have an initial condition of true since it is NOT(simple1).
-    Predicate combination4;
-    combination4.set_id(StringToId("COMBINATION4"));
-    combination4.mutable_combination()->set_operation(LogicalOperation::NOT);
-    combination4.mutable_combination()->add_predicate(simple1Id);
-    int64_t combination4Id = combination4.id();
-    *config.add_predicate() = combination4;
-
-    // Map the matchers in reverse order to force the indices to change.
-    std::unordered_map<int64_t, int> newAtomMatchingTrackerMap;
-    const int matcher6Index = 0;
-    newAtomMatchingTrackerMap[matcher6Id] = 0;
-    const int matcher5Index = 1;
-    newAtomMatchingTrackerMap[matcher5Id] = 1;
-    const int matcher4Index = 2;
-    newAtomMatchingTrackerMap[matcher4Id] = 2;
-    const int matcher3Index = 3;
-    newAtomMatchingTrackerMap[matcher3Id] = 3;
-    const int matcher2Index = 4;
-    newAtomMatchingTrackerMap[matcher2Id] = 4;
-    const int matcher1Index = 5;
-    newAtomMatchingTrackerMap[matcher1Id] = 5;
-
-    StatsdConfig newConfig;
-    *newConfig.add_predicate() = simple3;
-    const int simple3Index = 0;
-    *newConfig.add_predicate() = combination2;
-    const int combination2Index = 1;
-    *newConfig.add_predicate() = combination4;
-    const int combination4Index = 2;
-    *newConfig.add_predicate() = simple2;
-    const int simple2Index = 3;
-    *newConfig.add_predicate() = combination1;
-    const int combination1Index = 4;
-    *newConfig.add_predicate() = simple1;
-    const int simple1Index = 5;
-
-    unordered_map<int64_t, int> newConditionTrackerMap;
-    vector<sp<ConditionTracker>> newConditionTrackers;
-    unordered_map<int, vector<int>> trackerToConditionMap;
-    std::vector<ConditionState> conditionCache;
-    std::set<int64_t> replacedConditions;
-    EXPECT_TRUE(updateConditions(key, newConfig, newAtomMatchingTrackerMap, replacedMatchers,
-                                 oldConditionTrackerMap, oldConditionTrackers,
-                                 newConditionTrackerMap, newConditionTrackers,
-                                 trackerToConditionMap, conditionCache, replacedConditions));
-
-    unordered_map<int64_t, int> expectedConditionTrackerMap = {
-            {simple1Id, simple1Index},           {simple2Id, simple2Index},
-            {simple3Id, simple3Index},           {combination1Id, combination1Index},
-            {combination2Id, combination2Index}, {combination4Id, combination4Index},
-    };
-    EXPECT_THAT(newConditionTrackerMap, ContainerEq(expectedConditionTrackerMap));
-
-    ASSERT_EQ(newConditionTrackers.size(), 6);
-    // Make sure all conditions are initialized:
-    for (const sp<ConditionTracker>& tracker : newConditionTrackers) {
-        EXPECT_TRUE(tracker->mInitialized);
-    }
-
-    // Make sure preserved conditions are the same.
-    EXPECT_EQ(oldConditionTrackers[oldConditionTrackerMap.at(simple1Id)],
-              newConditionTrackers[newConditionTrackerMap.at(simple1Id)]);
-    EXPECT_EQ(oldConditionTrackers[oldConditionTrackerMap.at(simple2Id)],
-              newConditionTrackers[newConditionTrackerMap.at(simple2Id)]);
-    EXPECT_EQ(oldConditionTrackers[oldConditionTrackerMap.at(combination1Id)],
-              newConditionTrackers[newConditionTrackerMap.at(combination1Id)]);
-
-    // Make sure replaced conditions are different and included in replacedConditions.
-    EXPECT_NE(oldConditionTrackers[oldConditionTrackerMap.at(simple3Id)],
-              newConditionTrackers[newConditionTrackerMap.at(simple3Id)]);
-    EXPECT_NE(oldConditionTrackers[oldConditionTrackerMap.at(combination2Id)],
-              newConditionTrackers[newConditionTrackerMap.at(combination2Id)]);
-    EXPECT_THAT(replacedConditions, ContainerEq(set({simple3Id, combination2Id})));
-
-    // Verify the trackerToConditionMap
-    ASSERT_EQ(trackerToConditionMap.size(), 6);
-    const vector<int>& matcher1Conditions = trackerToConditionMap[matcher1Index];
-    EXPECT_THAT(matcher1Conditions, UnorderedElementsAre(simple1Index, combination1Index,
-                                                         combination2Index, combination4Index));
-    const vector<int>& matcher2Conditions = trackerToConditionMap[matcher2Index];
-    EXPECT_THAT(matcher2Conditions, UnorderedElementsAre(simple1Index, combination1Index,
-                                                         combination2Index, combination4Index));
-    const vector<int>& matcher3Conditions = trackerToConditionMap[matcher3Index];
-    EXPECT_THAT(matcher3Conditions, UnorderedElementsAre(simple2Index, combination1Index));
-    const vector<int>& matcher4Conditions = trackerToConditionMap[matcher4Index];
-    EXPECT_THAT(matcher4Conditions, UnorderedElementsAre(simple2Index, combination1Index));
-    const vector<int>& matcher5Conditions = trackerToConditionMap[matcher5Index];
-    EXPECT_THAT(matcher5Conditions, UnorderedElementsAre(simple3Index, combination2Index));
-    const vector<int>& matcher6Conditions = trackerToConditionMap[matcher6Index];
-    EXPECT_THAT(matcher6Conditions, UnorderedElementsAre(simple3Index, combination2Index));
-
-    // Verify the conditionCache. Specifically, simple1 is false and combination4 is true.
-    ASSERT_EQ(conditionCache.size(), 6);
-    EXPECT_EQ(conditionCache[simple1Index], ConditionState::kFalse);
-    EXPECT_EQ(conditionCache[simple2Index], ConditionState::kUnknown);
-    EXPECT_EQ(conditionCache[simple3Index], ConditionState::kUnknown);
-    EXPECT_EQ(conditionCache[combination1Index], ConditionState::kUnknown);
-    EXPECT_EQ(conditionCache[combination2Index], ConditionState::kUnknown);
-    EXPECT_EQ(conditionCache[combination4Index], ConditionState::kTrue);
-
-    // Verify tracker indices/ids are correct.
-    EXPECT_EQ(newConditionTrackers[simple1Index]->getConditionId(), simple1Id);
-    EXPECT_EQ(newConditionTrackers[simple1Index]->mIndex, simple1Index);
-    EXPECT_TRUE(newConditionTrackers[simple1Index]->IsSimpleCondition());
-    EXPECT_EQ(newConditionTrackers[simple2Index]->getConditionId(), simple2Id);
-    EXPECT_EQ(newConditionTrackers[simple2Index]->mIndex, simple2Index);
-    EXPECT_TRUE(newConditionTrackers[simple2Index]->IsSimpleCondition());
-    EXPECT_EQ(newConditionTrackers[simple3Index]->getConditionId(), simple3Id);
-    EXPECT_EQ(newConditionTrackers[simple3Index]->mIndex, simple3Index);
-    EXPECT_TRUE(newConditionTrackers[simple3Index]->IsSimpleCondition());
-    EXPECT_EQ(newConditionTrackers[combination1Index]->getConditionId(), combination1Id);
-    EXPECT_EQ(newConditionTrackers[combination1Index]->mIndex, combination1Index);
-    EXPECT_FALSE(newConditionTrackers[combination1Index]->IsSimpleCondition());
-    EXPECT_EQ(newConditionTrackers[combination2Index]->getConditionId(), combination2Id);
-    EXPECT_EQ(newConditionTrackers[combination2Index]->mIndex, combination2Index);
-    EXPECT_FALSE(newConditionTrackers[combination2Index]->IsSimpleCondition());
-    EXPECT_EQ(newConditionTrackers[combination4Index]->getConditionId(), combination4Id);
-    EXPECT_EQ(newConditionTrackers[combination4Index]->mIndex, combination4Index);
-    EXPECT_FALSE(newConditionTrackers[combination4Index]->IsSimpleCondition());
-
-    // Verify preserved trackers have indices updated.
-    SimpleConditionTracker* simpleTracker1 =
-            static_cast<SimpleConditionTracker*>(newConditionTrackers[simple1Index].get());
-    EXPECT_EQ(simpleTracker1->mStartLogMatcherIndex, matcher1Index);
-    EXPECT_EQ(simpleTracker1->mStopLogMatcherIndex, matcher2Index);
-    EXPECT_EQ(simpleTracker1->mStopAllLogMatcherIndex, -1);
-
-    SimpleConditionTracker* simpleTracker2 =
-            static_cast<SimpleConditionTracker*>(newConditionTrackers[simple2Index].get());
-    EXPECT_EQ(simpleTracker2->mStartLogMatcherIndex, matcher3Index);
-    EXPECT_EQ(simpleTracker2->mStopLogMatcherIndex, matcher4Index);
-    EXPECT_EQ(simpleTracker2->mStopAllLogMatcherIndex, -1);
-
-    CombinationConditionTracker* combinationTracker1 = static_cast<CombinationConditionTracker*>(
-            newConditionTrackers[combination1Index].get());
-    EXPECT_THAT(combinationTracker1->mChildren, UnorderedElementsAre(simple1Index, simple2Index));
-    EXPECT_THAT(combinationTracker1->mUnSlicedChildren,
-                UnorderedElementsAre(simple1Index, simple2Index));
-    EXPECT_THAT(combinationTracker1->mSlicedChildren, IsEmpty());
-}
-
-TEST_F(ConfigUpdateTest, TestUpdateStates) {
-    StatsdConfig config;
-    // Add states.
-    // Will be replaced because we add a state map.
-    State state1 = CreateScreenState();
-    int64_t state1Id = state1.id();
-    *config.add_state() = state1;
-
-    // Will be preserved.
-    State state2 = CreateUidProcessState();
-    int64_t state2Id = state2.id();
-    *config.add_state() = state2;
-
-    // Will be replaced since the atom changes from overlay to screen.
-    State state3 = CreateOverlayState();
-    int64_t state3Id = state3.id();
-    *config.add_state() = state3;
-
-    EXPECT_TRUE(initConfig(config));
-
-    // Change definitions of state1 and state3.
-    int64_t screenOnId = 0x4321, screenOffId = 0x1234;
-    *state1.mutable_map() = CreateScreenStateSimpleOnOffMap(screenOnId, screenOffId);
-    state3.set_atom_id(util::SCREEN_STATE_CHANGED);
-
-    StatsdConfig newConfig;
-    *newConfig.add_state() = state3;
-    *newConfig.add_state() = state1;
-    *newConfig.add_state() = state2;
-
-    unordered_map<int64_t, int> stateAtomIdMap;
-    unordered_map<int64_t, unordered_map<int, int64_t>> allStateGroupMaps;
-    map<int64_t, uint64_t> newStateProtoHashes;
-    set<int64_t> replacedStates;
-    EXPECT_TRUE(updateStates(newConfig, oldStateHashes, stateAtomIdMap, allStateGroupMaps,
-                             newStateProtoHashes, replacedStates));
-    EXPECT_THAT(replacedStates, ContainerEq(set({state1Id, state3Id})));
-
-    unordered_map<int64_t, int> expectedStateAtomIdMap = {
-            {state1Id, util::SCREEN_STATE_CHANGED},
-            {state2Id, util::UID_PROCESS_STATE_CHANGED},
-            {state3Id, util::SCREEN_STATE_CHANGED}};
-    EXPECT_THAT(stateAtomIdMap, ContainerEq(expectedStateAtomIdMap));
-
-    unordered_map<int64_t, unordered_map<int, int64_t>> expectedStateGroupMaps = {
-            {state1Id,
-             {{android::view::DisplayStateEnum::DISPLAY_STATE_OFF, screenOffId},
-              {android::view::DisplayStateEnum::DISPLAY_STATE_ON, screenOnId}}}};
-    EXPECT_THAT(allStateGroupMaps, ContainerEq(expectedStateGroupMaps));
-}
-
-TEST_F(ConfigUpdateTest, TestEventMetricPreserve) {
-    StatsdConfig config;
-    AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = startMatcher;
-    AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = stopMatcher;
-    AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
-    *config.add_atom_matcher() = whatMatcher;
-
-    Predicate predicate = CreateScreenIsOnPredicate();
-    *config.add_predicate() = predicate;
-
-    EventMetric* metric = config.add_event_metric();
-    metric->set_id(12345);
-    metric->set_what(whatMatcher.id());
-    metric->set_condition(predicate.id());
-
-    // Create an initial config.
-    EXPECT_TRUE(initConfig(config));
-
-    unordered_map<int64_t, int> metricToActivationMap;
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
-                                                 metricToActivationMap,
-                                                 /*replacedMatchers*/ {}, /*replacedConditions=*/{},
-                                                 /*replacedStates=*/{}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_PRESERVE);
-}
-
-TEST_F(ConfigUpdateTest, TestEventMetricActivationAdded) {
-    StatsdConfig config;
-    AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = startMatcher;
-    AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = stopMatcher;
-    AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
-    *config.add_atom_matcher() = whatMatcher;
-
-    Predicate predicate = CreateScreenIsOnPredicate();
-    *config.add_predicate() = predicate;
-
-    EventMetric* metric = config.add_event_metric();
-    metric->set_id(12345);
-    metric->set_what(whatMatcher.id());
-    metric->set_condition(predicate.id());
-
-    // Create an initial config.
-    EXPECT_TRUE(initConfig(config));
-
-    // Add a metric activation, which should change the proto, causing replacement.
-    MetricActivation* activation = config.add_metric_activation();
-    activation->set_metric_id(12345);
-    EventActivation* eventActivation = activation->add_event_activation();
-    eventActivation->set_atom_matcher_id(startMatcher.id());
-    eventActivation->set_ttl_seconds(5);
-
-    unordered_map<int64_t, int> metricToActivationMap = {{12345, 0}};
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
-                                                 metricToActivationMap,
-                                                 /*replacedMatchers*/ {}, /*replacedConditions=*/{},
-                                                 /*replacedStates=*/{}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestEventMetricWhatChanged) {
-    StatsdConfig config;
-    AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = startMatcher;
-    AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = stopMatcher;
-    AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
-    *config.add_atom_matcher() = whatMatcher;
-
-    Predicate predicate = CreateScreenIsOnPredicate();
-    *config.add_predicate() = predicate;
-
-    EventMetric* metric = config.add_event_metric();
-    metric->set_id(12345);
-    metric->set_what(whatMatcher.id());
-    metric->set_condition(predicate.id());
-
-    // Create an initial config.
-    EXPECT_TRUE(initConfig(config));
-
-    unordered_map<int64_t, int> metricToActivationMap;
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(
-            config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
-            /*replacedMatchers*/ {whatMatcher.id()}, /*replacedConditions=*/{},
-            /*replacedStates=*/{}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestEventMetricConditionChanged) {
-    StatsdConfig config;
-    AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = startMatcher;
-    AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = stopMatcher;
-    AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
-    *config.add_atom_matcher() = whatMatcher;
-
-    Predicate predicate = CreateScreenIsOnPredicate();
-    *config.add_predicate() = predicate;
-
-    EventMetric* metric = config.add_event_metric();
-    metric->set_id(12345);
-    metric->set_what(whatMatcher.id());
-    metric->set_condition(predicate.id());
-
-    // Create an initial config.
-    EXPECT_TRUE(initConfig(config));
-
-    unordered_map<int64_t, int> metricToActivationMap;
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(
-            config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
-            /*replacedMatchers*/ {}, /*replacedConditions=*/{predicate.id()},
-            /*replacedStates=*/{}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestMetricConditionLinkDepsChanged) {
-    StatsdConfig config;
-    AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = startMatcher;
-    AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = stopMatcher;
-    AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
-    *config.add_atom_matcher() = whatMatcher;
-
-    Predicate predicate = CreateScreenIsOnPredicate();
-    *config.add_predicate() = predicate;
-
-    Predicate linkPredicate = CreateScreenIsOffPredicate();
-    *config.add_predicate() = linkPredicate;
-
-    EventMetric* metric = config.add_event_metric();
-    metric->set_id(12345);
-    metric->set_what(whatMatcher.id());
-    metric->set_condition(predicate.id());
-    // Doesn't make sense as a real metric definition, but suffices as a separate predicate
-    // From the one in the condition.
-    MetricConditionLink* link = metric->add_links();
-    link->set_condition(linkPredicate.id());
-
-    // Create an initial config.
-    EXPECT_TRUE(initConfig(config));
-
-    unordered_map<int64_t, int> metricToActivationMap;
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(
-            config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
-            /*replacedMatchers*/ {}, /*replacedConditions=*/{linkPredicate.id()},
-            /*replacedStates=*/{}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestEventMetricActivationDepsChange) {
-    StatsdConfig config;
-    AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = startMatcher;
-    AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = stopMatcher;
-    AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
-    *config.add_atom_matcher() = whatMatcher;
-
-    Predicate predicate = CreateScreenIsOnPredicate();
-    *config.add_predicate() = predicate;
-
-    EventMetric* metric = config.add_event_metric();
-    metric->set_id(12345);
-    metric->set_what(whatMatcher.id());
-    metric->set_condition(predicate.id());
-
-    MetricActivation* activation = config.add_metric_activation();
-    activation->set_metric_id(12345);
-    EventActivation* eventActivation = activation->add_event_activation();
-    eventActivation->set_atom_matcher_id(startMatcher.id());
-    eventActivation->set_ttl_seconds(5);
-
-    // Create an initial config.
-    EXPECT_TRUE(initConfig(config));
-
-    unordered_map<int64_t, int> metricToActivationMap = {{12345, 0}};
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(
-            config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
-            /*replacedMatchers*/ {startMatcher.id()}, /*replacedConditions=*/{},
-            /*replacedStates=*/{}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestCountMetricPreserve) {
-    StatsdConfig config;
-    AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = startMatcher;
-    AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = stopMatcher;
-    AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
-    *config.add_atom_matcher() = whatMatcher;
-
-    Predicate predicate = CreateScreenIsOnPredicate();
-    *config.add_predicate() = predicate;
-    State sliceState = CreateScreenState();
-    *config.add_state() = sliceState;
-
-    CountMetric* metric = config.add_count_metric();
-    metric->set_id(12345);
-    metric->set_what(whatMatcher.id());
-    metric->set_condition(predicate.id());
-    metric->add_slice_by_state(sliceState.id());
-    metric->set_bucket(ONE_HOUR);
-
-    // Create an initial config.
-    EXPECT_TRUE(initConfig(config));
-
-    unordered_map<int64_t, int> metricToActivationMap;
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
-                                                 metricToActivationMap,
-                                                 /*replacedMatchers*/ {}, /*replacedConditions=*/{},
-                                                 /*replacedStates=*/{}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_PRESERVE);
-}
-
-TEST_F(ConfigUpdateTest, TestCountMetricDefinitionChange) {
-    StatsdConfig config;
-    AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = startMatcher;
-    AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = stopMatcher;
-    AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
-    *config.add_atom_matcher() = whatMatcher;
-
-    Predicate predicate = CreateScreenIsOnPredicate();
-    *config.add_predicate() = predicate;
-
-    CountMetric* metric = config.add_count_metric();
-    metric->set_id(12345);
-    metric->set_what(whatMatcher.id());
-    metric->set_condition(predicate.id());
-    metric->set_bucket(ONE_HOUR);
-
-    // Create an initial config.
-    EXPECT_TRUE(initConfig(config));
-
-    // Change bucket size, which should change the proto, causing replacement.
-    metric->set_bucket(TEN_MINUTES);
-
-    unordered_map<int64_t, int> metricToActivationMap;
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
-                                                 metricToActivationMap,
-                                                 /*replacedMatchers*/ {}, /*replacedConditions=*/{},
-                                                 /*replacedStates=*/{}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestCountMetricWhatChanged) {
-    StatsdConfig config;
-    AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = startMatcher;
-    AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = stopMatcher;
-    AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
-    *config.add_atom_matcher() = whatMatcher;
-
-    Predicate predicate = CreateScreenIsOnPredicate();
-    *config.add_predicate() = predicate;
-
-    CountMetric* metric = config.add_count_metric();
-    metric->set_id(12345);
-    metric->set_what(whatMatcher.id());
-    metric->set_condition(predicate.id());
-    metric->set_bucket(ONE_HOUR);
-
-    // Create an initial config.
-    EXPECT_TRUE(initConfig(config));
-
-    unordered_map<int64_t, int> metricToActivationMap;
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(
-            config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
-            /*replacedMatchers*/ {whatMatcher.id()}, /*replacedConditions=*/{},
-            /*replacedStates=*/{}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestCountMetricConditionChanged) {
-    StatsdConfig config;
-    AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = startMatcher;
-    AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = stopMatcher;
-    AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
-    *config.add_atom_matcher() = whatMatcher;
-
-    Predicate predicate = CreateScreenIsOnPredicate();
-    *config.add_predicate() = predicate;
-
-    CountMetric* metric = config.add_count_metric();
-    metric->set_id(12345);
-    metric->set_what(whatMatcher.id());
-    metric->set_condition(predicate.id());
-    metric->set_bucket(ONE_HOUR);
-
-    // Create an initial config.
-    EXPECT_TRUE(initConfig(config));
-
-    unordered_map<int64_t, int> metricToActivationMap;
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(
-            config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
-            /*replacedMatchers*/ {}, /*replacedConditions=*/{predicate.id()},
-            /*replacedStates=*/{}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestCountMetricStateChanged) {
-    StatsdConfig config;
-    AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = startMatcher;
-    AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = stopMatcher;
-    AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
-    *config.add_atom_matcher() = whatMatcher;
-
-    State sliceState = CreateScreenState();
-    *config.add_state() = sliceState;
-
-    CountMetric* metric = config.add_count_metric();
-    metric->set_id(12345);
-    metric->set_what(whatMatcher.id());
-    metric->add_slice_by_state(sliceState.id());
-    metric->set_bucket(ONE_HOUR);
-
-    // Create an initial config.
-    EXPECT_TRUE(initConfig(config));
-
-    unordered_map<int64_t, int> metricToActivationMap;
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(
-            config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
-            /*replacedMatchers*/ {}, /*replacedConditions=*/{},
-            /*replacedStates=*/{sliceState.id()}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestGaugeMetricPreserve) {
-    StatsdConfig config;
-    AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = startMatcher;
-    AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = stopMatcher;
-    AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
-    *config.add_atom_matcher() = whatMatcher;
-
-    Predicate predicate = CreateScreenIsOnPredicate();
-    *config.add_predicate() = predicate;
-
-    *config.add_gauge_metric() = createGaugeMetric(
-            "GAUGE1", whatMatcher.id(), GaugeMetric::RANDOM_ONE_SAMPLE, predicate.id(), nullopt);
-
-    EXPECT_TRUE(initConfig(config));
-
-    unordered_map<int64_t, int> metricToActivationMap;
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
-                                                 metricToActivationMap,
-                                                 /*replacedMatchers*/ {}, /*replacedConditions=*/{},
-                                                 /*replacedStates=*/{}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_PRESERVE);
-}
-
-TEST_F(ConfigUpdateTest, TestGaugeMetricDefinitionChange) {
-    StatsdConfig config;
-    AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
-    *config.add_atom_matcher() = whatMatcher;
-
-    *config.add_gauge_metric() = createGaugeMetric(
-            "GAUGE1", whatMatcher.id(), GaugeMetric::RANDOM_ONE_SAMPLE, nullopt, nullopt);
-
-    EXPECT_TRUE(initConfig(config));
-
-    // Change split bucket on app upgrade, which should change the proto, causing replacement.
-    config.mutable_gauge_metric(0)->set_split_bucket_for_app_upgrade(false);
-
-    unordered_map<int64_t, int> metricToActivationMap;
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
-                                                 metricToActivationMap,
-                                                 /*replacedMatchers*/ {}, /*replacedConditions=*/{},
-                                                 /*replacedStates=*/{}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestGaugeMetricWhatChanged) {
-    StatsdConfig config;
-    AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
-    *config.add_atom_matcher() = whatMatcher;
-
-    *config.add_gauge_metric() = createGaugeMetric(
-            "GAUGE1", whatMatcher.id(), GaugeMetric::RANDOM_ONE_SAMPLE, nullopt, nullopt);
-
-    EXPECT_TRUE(initConfig(config));
-
-    unordered_map<int64_t, int> metricToActivationMap;
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(
-            config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
-            /*replacedMatchers*/ {whatMatcher.id()}, /*replacedConditions=*/{},
-            /*replacedStates=*/{}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestGaugeMetricConditionChanged) {
-    StatsdConfig config;
-    AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = startMatcher;
-    AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = stopMatcher;
-    AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
-    *config.add_atom_matcher() = whatMatcher;
-
-    Predicate predicate = CreateScreenIsOnPredicate();
-    *config.add_predicate() = predicate;
-
-    *config.add_gauge_metric() = createGaugeMetric(
-            "GAUGE1", whatMatcher.id(), GaugeMetric::RANDOM_ONE_SAMPLE, predicate.id(), nullopt);
-
-    EXPECT_TRUE(initConfig(config));
-
-    unordered_map<int64_t, int> metricToActivationMap;
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(
-            config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
-            /*replacedMatchers*/ {}, /*replacedConditions=*/{predicate.id()},
-            /*replacedStates=*/{}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestGaugeMetricTriggerEventChanged) {
-    StatsdConfig config;
-    AtomMatcher triggerEvent = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = triggerEvent;
-    AtomMatcher whatMatcher = CreateTemperatureAtomMatcher();
-    *config.add_atom_matcher() = whatMatcher;
-
-    *config.add_gauge_metric() = createGaugeMetric(
-            "GAUGE1", whatMatcher.id(), GaugeMetric::FIRST_N_SAMPLES, nullopt, triggerEvent.id());
-
-    EXPECT_TRUE(initConfig(config));
-
-    unordered_map<int64_t, int> metricToActivationMap;
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(
-            config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
-            /*replacedMatchers*/ {triggerEvent.id()}, /*replacedConditions=*/{},
-            /*replacedStates=*/{}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestDurationMetricPreserve) {
-    StatsdConfig config;
-    AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = startMatcher;
-    AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = stopMatcher;
-
-    Predicate what = CreateScreenIsOnPredicate();
-    *config.add_predicate() = what;
-    Predicate condition = CreateScreenIsOffPredicate();
-    *config.add_predicate() = condition;
-
-    State sliceState = CreateScreenState();
-    *config.add_state() = sliceState;
-
-    *config.add_duration_metric() =
-            createDurationMetric("DURATION1", what.id(), condition.id(), {sliceState.id()});
-    EXPECT_TRUE(initConfig(config));
-
-    unordered_map<int64_t, int> metricToActivationMap;
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
-                                                 metricToActivationMap,
-                                                 /*replacedMatchers*/ {}, /*replacedConditions=*/{},
-                                                 /*replacedStates=*/{}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_PRESERVE);
-}
-
-TEST_F(ConfigUpdateTest, TestDurationMetricDefinitionChange) {
-    StatsdConfig config;
-    AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = startMatcher;
-    AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = stopMatcher;
-
-    Predicate what = CreateScreenIsOnPredicate();
-    *config.add_predicate() = what;
-
-    *config.add_duration_metric() = createDurationMetric("DURATION1", what.id(), nullopt, {});
-    EXPECT_TRUE(initConfig(config));
-
-    config.mutable_duration_metric(0)->set_aggregation_type(DurationMetric::MAX_SPARSE);
-
-    unordered_map<int64_t, int> metricToActivationMap;
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
-                                                 metricToActivationMap, /*replacedMatchers*/ {},
-                                                 /*replacedConditions=*/{}, /*replacedStates=*/{},
-                                                 metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestDurationMetricWhatChanged) {
-    StatsdConfig config;
-    AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = startMatcher;
-    AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = stopMatcher;
-
-    Predicate what = CreateScreenIsOnPredicate();
-    *config.add_predicate() = what;
-
-    *config.add_duration_metric() = createDurationMetric("DURATION1", what.id(), nullopt, {});
-    EXPECT_TRUE(initConfig(config));
-
-    unordered_map<int64_t, int> metricToActivationMap;
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(
-            config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
-            /*replacedMatchers*/ {}, /*replacedConditions=*/{what.id()},
-            /*replacedStates=*/{}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestDurationMetricConditionChanged) {
-    StatsdConfig config;
-    AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = startMatcher;
-    AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = stopMatcher;
-
-    Predicate what = CreateScreenIsOnPredicate();
-    *config.add_predicate() = what;
-    Predicate condition = CreateScreenIsOffPredicate();
-    *config.add_predicate() = condition;
-
-    *config.add_duration_metric() = createDurationMetric("DURATION", what.id(), condition.id(), {});
-    EXPECT_TRUE(initConfig(config));
-
-    unordered_map<int64_t, int> metricToActivationMap;
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(
-            config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
-            /*replacedMatchers*/ {}, /*replacedConditions=*/{condition.id()},
-            /*replacedStates=*/{}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestDurationMetricStateChange) {
-    StatsdConfig config;
-    AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = startMatcher;
-    AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = stopMatcher;
-
-    Predicate what = CreateScreenIsOnPredicate();
-    *config.add_predicate() = what;
-
-    State sliceState = CreateScreenState();
-    *config.add_state() = sliceState;
-
-    *config.add_duration_metric() =
-            createDurationMetric("DURATION1", what.id(), nullopt, {sliceState.id()});
-    EXPECT_TRUE(initConfig(config));
-
-    unordered_map<int64_t, int> metricToActivationMap;
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(
-            config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
-            /*replacedMatchers*/ {}, /*replacedConditions=*/{},
-            /*replacedStates=*/{sliceState.id()}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestValueMetricPreserve) {
-    StatsdConfig config;
-    AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = startMatcher;
-    AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = stopMatcher;
-    AtomMatcher whatMatcher = CreateTemperatureAtomMatcher();
-    *config.add_atom_matcher() = whatMatcher;
-
-    Predicate predicate = CreateScreenIsOnPredicate();
-    *config.add_predicate() = predicate;
-    State sliceState = CreateScreenState();
-    *config.add_state() = sliceState;
-
-    *config.add_value_metric() =
-            createValueMetric("VALUE1", whatMatcher, predicate.id(), {sliceState.id()});
-    EXPECT_TRUE(initConfig(config));
-
-    unordered_map<int64_t, int> metricToActivationMap;
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
-                                                 metricToActivationMap,
-                                                 /*replacedMatchers*/ {}, /*replacedConditions=*/{},
-                                                 /*replacedStates=*/{}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_PRESERVE);
-}
-
-TEST_F(ConfigUpdateTest, TestValueMetricDefinitionChange) {
-    StatsdConfig config;
-    AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
-    *config.add_atom_matcher() = whatMatcher;
-
-    *config.add_value_metric() = createValueMetric("VALUE1", whatMatcher, nullopt, {});
-    EXPECT_TRUE(initConfig(config));
-
-    // Change skip zero diff output, which should change the proto, causing replacement.
-    config.mutable_value_metric(0)->set_skip_zero_diff_output(true);
-
-    unordered_map<int64_t, int> metricToActivationMap;
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
-                                                 metricToActivationMap,
-                                                 /*replacedMatchers*/ {}, /*replacedConditions=*/{},
-                                                 /*replacedStates=*/{}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestValueMetricWhatChanged) {
-    StatsdConfig config;
-    AtomMatcher whatMatcher = CreateTemperatureAtomMatcher();
-    *config.add_atom_matcher() = whatMatcher;
-
-    *config.add_value_metric() = createValueMetric("VALUE1", whatMatcher, nullopt, {});
-    EXPECT_TRUE(initConfig(config));
-
-    unordered_map<int64_t, int> metricToActivationMap;
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(
-            config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
-            /*replacedMatchers*/ {whatMatcher.id()}, /*replacedConditions=*/{},
-            /*replacedStates=*/{}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestValueMetricConditionChanged) {
-    StatsdConfig config;
-    AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = startMatcher;
-    AtomMatcher stopMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = stopMatcher;
-    AtomMatcher whatMatcher = CreateTemperatureAtomMatcher();
-    *config.add_atom_matcher() = whatMatcher;
-
-    Predicate predicate = CreateScreenIsOnPredicate();
-    *config.add_predicate() = predicate;
-
-    *config.add_value_metric() = createValueMetric("VALUE1", whatMatcher, predicate.id(), {});
-    EXPECT_TRUE(initConfig(config));
-
-    unordered_map<int64_t, int> metricToActivationMap;
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(
-            config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
-            /*replacedMatchers*/ {}, /*replacedConditions=*/{predicate.id()},
-            /*replacedStates=*/{}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestValueMetricStateChanged) {
-    StatsdConfig config;
-    AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
-    *config.add_atom_matcher() = whatMatcher;
-
-    State sliceState = CreateScreenState();
-    *config.add_state() = sliceState;
-
-    *config.add_value_metric() =
-            createValueMetric("VALUE1", whatMatcher, nullopt, {sliceState.id()});
-    EXPECT_TRUE(initConfig(config));
-
-    unordered_map<int64_t, int> metricToActivationMap;
-    vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
-    EXPECT_TRUE(determineAllMetricUpdateStatuses(
-            config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
-            /*replacedMatchers*/ {}, /*replacedConditions=*/{},
-            /*replacedStates=*/{sliceState.id()}, metricsToUpdate));
-    EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestUpdateEventMetrics) {
-    StatsdConfig config;
-
-    // Add atom matchers/predicates. These are mostly needed for initStatsdConfig
-    AtomMatcher matcher1 = CreateScreenTurnedOnAtomMatcher();
-    int64_t matcher1Id = matcher1.id();
-    *config.add_atom_matcher() = matcher1;
-
-    AtomMatcher matcher2 = CreateScreenTurnedOffAtomMatcher();
-    int64_t matcher2Id = matcher2.id();
-    *config.add_atom_matcher() = matcher2;
-
-    AtomMatcher matcher3 = CreateStartScheduledJobAtomMatcher();
-    int64_t matcher3Id = matcher3.id();
-    *config.add_atom_matcher() = matcher3;
-
-    AtomMatcher matcher4 = CreateFinishScheduledJobAtomMatcher();
-    int64_t matcher4Id = matcher4.id();
-    *config.add_atom_matcher() = matcher4;
-
-    AtomMatcher matcher5 = CreateBatterySaverModeStartAtomMatcher();
-    int64_t matcher5Id = matcher5.id();
-    *config.add_atom_matcher() = matcher5;
-
-    Predicate predicate1 = CreateScreenIsOnPredicate();
-    int64_t predicate1Id = predicate1.id();
-    *config.add_predicate() = predicate1;
-
-    Predicate predicate2 = CreateScheduledJobPredicate();
-    int64_t predicate2Id = predicate2.id();
-    *config.add_predicate() = predicate2;
-
-    // Add a few event metrics.
-    // Will be preserved.
-    EventMetric event1 = createEventMetric("EVENT1", matcher1Id, predicate2Id);
-    int64_t event1Id = event1.id();
-    *config.add_event_metric() = event1;
-
-    // Will be replaced.
-    EventMetric event2 = createEventMetric("EVENT2", matcher2Id, nullopt);
-    int64_t event2Id = event2.id();
-    *config.add_event_metric() = event2;
-
-    // Will be replaced.
-    EventMetric event3 = createEventMetric("EVENT3", matcher3Id, nullopt);
-    int64_t event3Id = event3.id();
-    *config.add_event_metric() = event3;
-
-    MetricActivation event3Activation;
-    event3Activation.set_metric_id(event3Id);
-    EventActivation* eventActivation = event3Activation.add_event_activation();
-    eventActivation->set_atom_matcher_id(matcher5Id);
-    eventActivation->set_ttl_seconds(5);
-    *config.add_metric_activation() = event3Activation;
-
-    // Will be replaced.
-    EventMetric event4 = createEventMetric("EVENT4", matcher4Id, predicate1Id);
-    int64_t event4Id = event4.id();
-    *config.add_event_metric() = event4;
-
-    // Will be deleted.
-    EventMetric event5 = createEventMetric("EVENT5", matcher5Id, nullopt);
-    int64_t event5Id = event5.id();
-    *config.add_event_metric() = event5;
-
-    EXPECT_TRUE(initConfig(config));
-
-    // Used later to ensure the condition wizard is replaced. Get it before doing the update.
-    sp<ConditionWizard> oldConditionWizard = oldMetricProducers[0]->mWizard;
-    EXPECT_EQ(oldConditionWizard->getStrongCount(), oldMetricProducers.size() + 1);
-
-    // Add a condition to event2, causing it to be replaced.
-    event2.set_condition(predicate1Id);
-
-    // Mark matcher 5 as replaced. Causes event3 to be replaced.
-    set<int64_t> replacedMatchers;
-    replacedMatchers.insert(matcher5Id);
-
-    // Mark predicate 1 as replaced. Causes event4 to be replaced.
-    set<int64_t> replacedConditions;
-    replacedConditions.insert(predicate1Id);
-
-    // Fake that predicate 2 is true.
-    ASSERT_EQ(oldMetricProducers[0]->getMetricId(), event1Id);
-    oldMetricProducers[0]->onConditionChanged(true, /*timestamp=*/0);
-    EXPECT_EQ(oldMetricProducers[0]->mCondition, ConditionState::kTrue);
-
-    // New event metric. Should have an initial condition of true since it depends on predicate2.
-    EventMetric event6 = createEventMetric("EVENT6", matcher3Id, predicate2Id);
-    int64_t event6Id = event6.id();
-    MetricActivation event6Activation;
-    event6Activation.set_metric_id(event6Id);
-    eventActivation = event6Activation.add_event_activation();
-    eventActivation->set_atom_matcher_id(matcher5Id);
-    eventActivation->set_ttl_seconds(20);
-
-    // Map the matchers and predicates in reverse order to force the indices to change.
-    std::unordered_map<int64_t, int> newAtomMatchingTrackerMap;
-    const int matcher5Index = 0;
-    newAtomMatchingTrackerMap[matcher5Id] = 0;
-    const int matcher4Index = 1;
-    newAtomMatchingTrackerMap[matcher4Id] = 1;
-    const int matcher3Index = 2;
-    newAtomMatchingTrackerMap[matcher3Id] = 2;
-    const int matcher2Index = 3;
-    newAtomMatchingTrackerMap[matcher2Id] = 3;
-    const int matcher1Index = 4;
-    newAtomMatchingTrackerMap[matcher1Id] = 4;
-    // Use the existing matchers. A bit hacky, but saves code and we don't rely on them.
-    vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers(5);
-    std::reverse_copy(oldAtomMatchingTrackers.begin(), oldAtomMatchingTrackers.end(),
-                      newAtomMatchingTrackers.begin());
-
-    std::unordered_map<int64_t, int> newConditionTrackerMap;
-    const int predicate2Index = 0;
-    newConditionTrackerMap[predicate2Id] = 0;
-    const int predicate1Index = 1;
-    newConditionTrackerMap[predicate1Id] = 1;
-    // Use the existing conditionTrackers. A bit hacky, but saves code and we don't rely on them.
-    vector<sp<ConditionTracker>> newConditionTrackers(2);
-    std::reverse_copy(oldConditionTrackers.begin(), oldConditionTrackers.end(),
-                      newConditionTrackers.begin());
-    // Fake that predicate2 is true.
-    vector<ConditionState> conditionCache = {ConditionState::kTrue, ConditionState::kUnknown};
-
-    StatsdConfig newConfig;
-    *newConfig.add_event_metric() = event6;
-    const int event6Index = 0;
-    *newConfig.add_event_metric() = event3;
-    const int event3Index = 1;
-    *newConfig.add_event_metric() = event1;
-    const int event1Index = 2;
-    *newConfig.add_event_metric() = event4;
-    const int event4Index = 3;
-    *newConfig.add_event_metric() = event2;
-    const int event2Index = 4;
-    *newConfig.add_metric_activation() = event3Activation;
-    *newConfig.add_metric_activation() = event6Activation;
-
-    // Output data structures to validate.
-    unordered_map<int64_t, int> newMetricProducerMap;
-    vector<sp<MetricProducer>> newMetricProducers;
-    unordered_map<int, vector<int>> conditionToMetricMap;
-    unordered_map<int, vector<int>> trackerToMetricMap;
-    set<int64_t> noReportMetricIds;
-    unordered_map<int, vector<int>> activationAtomTrackerToMetricMap;
-    unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
-    vector<int> metricsWithActivation;
-    set<int64_t> replacedMetrics;
-    EXPECT_TRUE(updateMetrics(
-            key, newConfig, /*timeBaseNs=*/123, /*currentTimeNs=*/12345, new StatsPullerManager(),
-            oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, replacedMatchers,
-            newAtomMatchingTrackers, newConditionTrackerMap, replacedConditions,
-            newConditionTrackers, conditionCache, /*stateAtomIdMap=*/{}, /*allStateGroupMaps=*/{},
-            /*replacedStates=*/{}, oldMetricProducerMap, oldMetricProducers, newMetricProducerMap,
-            newMetricProducers, conditionToMetricMap, trackerToMetricMap, noReportMetricIds,
-            activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
-            metricsWithActivation, replacedMetrics));
-
-    unordered_map<int64_t, int> expectedMetricProducerMap = {
-            {event1Id, event1Index}, {event2Id, event2Index}, {event3Id, event3Index},
-            {event4Id, event4Index}, {event6Id, event6Index},
-    };
-    EXPECT_THAT(newMetricProducerMap, ContainerEq(expectedMetricProducerMap));
-    EXPECT_EQ(replacedMetrics, set<int64_t>({event2Id, event3Id, event4Id}));
-
-    // Make sure preserved metrics are the same.
-    ASSERT_EQ(newMetricProducers.size(), 5);
-    EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(event1Id)],
-              newMetricProducers[newMetricProducerMap.at(event1Id)]);
-
-    // Make sure replaced metrics are different.
-    EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(event2Id)],
-              newMetricProducers[newMetricProducerMap.at(event2Id)]);
-    EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(event3Id)],
-              newMetricProducers[newMetricProducerMap.at(event3Id)]);
-    EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(event4Id)],
-              newMetricProducers[newMetricProducerMap.at(event4Id)]);
-
-    // Verify the conditionToMetricMap.
-    ASSERT_EQ(conditionToMetricMap.size(), 2);
-    const vector<int>& condition1Metrics = conditionToMetricMap[predicate1Index];
-    EXPECT_THAT(condition1Metrics, UnorderedElementsAre(event2Index, event4Index));
-    const vector<int>& condition2Metrics = conditionToMetricMap[predicate2Index];
-    EXPECT_THAT(condition2Metrics, UnorderedElementsAre(event1Index, event6Index));
-
-    // Verify the trackerToMetricMap.
-    ASSERT_EQ(trackerToMetricMap.size(), 4);
-    const vector<int>& matcher1Metrics = trackerToMetricMap[matcher1Index];
-    EXPECT_THAT(matcher1Metrics, UnorderedElementsAre(event1Index));
-    const vector<int>& matcher2Metrics = trackerToMetricMap[matcher2Index];
-    EXPECT_THAT(matcher2Metrics, UnorderedElementsAre(event2Index));
-    const vector<int>& matcher3Metrics = trackerToMetricMap[matcher3Index];
-    EXPECT_THAT(matcher3Metrics, UnorderedElementsAre(event3Index, event6Index));
-    const vector<int>& matcher4Metrics = trackerToMetricMap[matcher4Index];
-    EXPECT_THAT(matcher4Metrics, UnorderedElementsAre(event4Index));
-
-    // Verify event activation/deactivation maps.
-    ASSERT_EQ(activationAtomTrackerToMetricMap.size(), 1);
-    EXPECT_THAT(activationAtomTrackerToMetricMap[matcher5Index],
-                UnorderedElementsAre(event3Index, event6Index));
-    ASSERT_EQ(deactivationAtomTrackerToMetricMap.size(), 0);
-    ASSERT_EQ(metricsWithActivation.size(), 2);
-    EXPECT_THAT(metricsWithActivation, UnorderedElementsAre(event3Index, event6Index));
-
-    // Verify tracker indices/ids/conditions are correct.
-    EXPECT_EQ(newMetricProducers[event1Index]->getMetricId(), event1Id);
-    EXPECT_EQ(newMetricProducers[event1Index]->mConditionTrackerIndex, predicate2Index);
-    EXPECT_EQ(newMetricProducers[event1Index]->mCondition, ConditionState::kTrue);
-    EXPECT_EQ(newMetricProducers[event2Index]->getMetricId(), event2Id);
-    EXPECT_EQ(newMetricProducers[event2Index]->mConditionTrackerIndex, predicate1Index);
-    EXPECT_EQ(newMetricProducers[event2Index]->mCondition, ConditionState::kUnknown);
-    EXPECT_EQ(newMetricProducers[event3Index]->getMetricId(), event3Id);
-    EXPECT_EQ(newMetricProducers[event3Index]->mConditionTrackerIndex, -1);
-    EXPECT_EQ(newMetricProducers[event3Index]->mCondition, ConditionState::kTrue);
-    EXPECT_EQ(newMetricProducers[event4Index]->getMetricId(), event4Id);
-    EXPECT_EQ(newMetricProducers[event4Index]->mConditionTrackerIndex, predicate1Index);
-    EXPECT_EQ(newMetricProducers[event4Index]->mCondition, ConditionState::kUnknown);
-    EXPECT_EQ(newMetricProducers[event6Index]->getMetricId(), event6Id);
-    EXPECT_EQ(newMetricProducers[event6Index]->mConditionTrackerIndex, predicate2Index);
-    EXPECT_EQ(newMetricProducers[event6Index]->mCondition, ConditionState::kTrue);
-
-    sp<ConditionWizard> newConditionWizard = newMetricProducers[0]->mWizard;
-    EXPECT_NE(newConditionWizard, oldConditionWizard);
-    EXPECT_EQ(newConditionWizard->getStrongCount(), newMetricProducers.size() + 1);
-    oldMetricProducers.clear();
-    // Only reference to the old wizard should be the one in the test.
-    EXPECT_EQ(oldConditionWizard->getStrongCount(), 1);
-}
-
-TEST_F(ConfigUpdateTest, TestUpdateCountMetrics) {
-    StatsdConfig config;
-
-    // Add atom matchers/predicates/states. These are mostly needed for initStatsdConfig.
-    AtomMatcher matcher1 = CreateScreenTurnedOnAtomMatcher();
-    int64_t matcher1Id = matcher1.id();
-    *config.add_atom_matcher() = matcher1;
-
-    AtomMatcher matcher2 = CreateScreenTurnedOffAtomMatcher();
-    int64_t matcher2Id = matcher2.id();
-    *config.add_atom_matcher() = matcher2;
-
-    AtomMatcher matcher3 = CreateStartScheduledJobAtomMatcher();
-    int64_t matcher3Id = matcher3.id();
-    *config.add_atom_matcher() = matcher3;
-
-    AtomMatcher matcher4 = CreateFinishScheduledJobAtomMatcher();
-    int64_t matcher4Id = matcher4.id();
-    *config.add_atom_matcher() = matcher4;
-
-    AtomMatcher matcher5 = CreateBatterySaverModeStartAtomMatcher();
-    int64_t matcher5Id = matcher5.id();
-    *config.add_atom_matcher() = matcher5;
-
-    Predicate predicate1 = CreateScreenIsOnPredicate();
-    int64_t predicate1Id = predicate1.id();
-    *config.add_predicate() = predicate1;
-
-    State state1 = CreateScreenStateWithOnOffMap(0x123, 0x321);
-    int64_t state1Id = state1.id();
-    *config.add_state() = state1;
-
-    State state2 = CreateScreenState();
-    int64_t state2Id = state2.id();
-    *config.add_state() = state2;
-
-    // Add a few count metrics.
-    // Will be preserved.
-    CountMetric count1 = createCountMetric("COUNT1", matcher1Id, predicate1Id, {state1Id});
-    int64_t count1Id = count1.id();
-    *config.add_count_metric() = count1;
-
-    // Will be replaced.
-    CountMetric count2 = createCountMetric("COUNT2", matcher2Id, nullopt, {});
-    int64_t count2Id = count2.id();
-    *config.add_count_metric() = count2;
-
-    // Will be replaced.
-    CountMetric count3 = createCountMetric("COUNT3", matcher3Id, nullopt, {});
-    int64_t count3Id = count3.id();
-    *config.add_count_metric() = count3;
-
-    // Will be replaced.
-    CountMetric count4 = createCountMetric("COUNT4", matcher4Id, nullopt, {state2Id});
-    int64_t count4Id = count4.id();
-    *config.add_count_metric() = count4;
-
-    // Will be deleted.
-    CountMetric count5 = createCountMetric("COUNT5", matcher5Id, nullopt, {});
-    int64_t count5Id = count5.id();
-    *config.add_count_metric() = count5;
-
-    EXPECT_TRUE(initConfig(config));
-
-    // Change bucket size of count2, causing it to be replaced.
-    count2.set_bucket(ONE_HOUR);
-
-    // Mark matcher 3 as replaced. Causes count3 to be replaced.
-    set<int64_t> replacedMatchers;
-    replacedMatchers.insert(matcher3Id);
-
-    // Mark state 2 as replaced and change the state to be about a different atom.
-    // Causes count4 to be replaced.
-    set<int64_t> replacedStates;
-    replacedStates.insert(state2Id);
-    state2.set_atom_id(util::BATTERY_SAVER_MODE_STATE_CHANGED);
-
-    // Fake that predicate 1 is true for count metric 1.
-    ASSERT_EQ(oldMetricProducers[0]->getMetricId(), count1Id);
-    oldMetricProducers[0]->onConditionChanged(true, /*timestamp=*/0);
-    EXPECT_EQ(oldMetricProducers[0]->mCondition, ConditionState::kTrue);
-
-    EXPECT_EQ(StateManager::getInstance().getStateTrackersCount(), 1);
-    // Tell the StateManager that the screen is on.
-    unique_ptr<LogEvent> event =
-            CreateScreenStateChangedEvent(0, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-    StateManager::getInstance().onLogEvent(*event);
-
-    // New count metric. Should have an initial condition of true since it depends on predicate1.
-    CountMetric count6 = createCountMetric("EVENT6", matcher2Id, predicate1Id, {state1Id});
-    int64_t count6Id = count6.id();
-
-    // Map the matchers and predicates in reverse order to force the indices to change.
-    std::unordered_map<int64_t, int> newAtomMatchingTrackerMap;
-    const int matcher5Index = 0;
-    newAtomMatchingTrackerMap[matcher5Id] = 0;
-    const int matcher4Index = 1;
-    newAtomMatchingTrackerMap[matcher4Id] = 1;
-    const int matcher3Index = 2;
-    newAtomMatchingTrackerMap[matcher3Id] = 2;
-    const int matcher2Index = 3;
-    newAtomMatchingTrackerMap[matcher2Id] = 3;
-    const int matcher1Index = 4;
-    newAtomMatchingTrackerMap[matcher1Id] = 4;
-    // Use the existing matchers. A bit hacky, but saves code and we don't rely on them.
-    vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers(5);
-    std::reverse_copy(oldAtomMatchingTrackers.begin(), oldAtomMatchingTrackers.end(),
-                      newAtomMatchingTrackers.begin());
-
-    std::unordered_map<int64_t, int> newConditionTrackerMap;
-    const int predicate1Index = 0;
-    newConditionTrackerMap[predicate1Id] = 0;
-    // Use the existing conditionTrackers. A bit hacky, but saves code and we don't rely on them.
-    vector<sp<ConditionTracker>> newConditionTrackers(1);
-    std::reverse_copy(oldConditionTrackers.begin(), oldConditionTrackers.end(),
-                      newConditionTrackers.begin());
-    // Fake that predicate1 is true for all new metrics.
-    vector<ConditionState> conditionCache = {ConditionState::kTrue};
-
-    StatsdConfig newConfig;
-    *newConfig.add_count_metric() = count6;
-    const int count6Index = 0;
-    *newConfig.add_count_metric() = count3;
-    const int count3Index = 1;
-    *newConfig.add_count_metric() = count1;
-    const int count1Index = 2;
-    *newConfig.add_count_metric() = count4;
-    const int count4Index = 3;
-    *newConfig.add_count_metric() = count2;
-    const int count2Index = 4;
-
-    *newConfig.add_state() = state1;
-    *newConfig.add_state() = state2;
-
-    unordered_map<int64_t, int> stateAtomIdMap;
-    unordered_map<int64_t, unordered_map<int, int64_t>> allStateGroupMaps;
-    map<int64_t, uint64_t> stateProtoHashes;
-    EXPECT_TRUE(initStates(newConfig, stateAtomIdMap, allStateGroupMaps, stateProtoHashes));
-    EXPECT_EQ(stateAtomIdMap[state2Id], util::BATTERY_SAVER_MODE_STATE_CHANGED);
-
-    // Output data structures to validate.
-    unordered_map<int64_t, int> newMetricProducerMap;
-    vector<sp<MetricProducer>> newMetricProducers;
-    unordered_map<int, vector<int>> conditionToMetricMap;
-    unordered_map<int, vector<int>> trackerToMetricMap;
-    set<int64_t> noReportMetricIds;
-    unordered_map<int, vector<int>> activationAtomTrackerToMetricMap;
-    unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
-    vector<int> metricsWithActivation;
-    set<int64_t> replacedMetrics;
-    EXPECT_TRUE(updateMetrics(
-            key, newConfig, /*timeBaseNs=*/123, /*currentTimeNs=*/12345, new StatsPullerManager(),
-            oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, replacedMatchers,
-            newAtomMatchingTrackers, newConditionTrackerMap, /*replacedConditions=*/{},
-            newConditionTrackers, conditionCache, stateAtomIdMap, allStateGroupMaps, replacedStates,
-            oldMetricProducerMap, oldMetricProducers, newMetricProducerMap, newMetricProducers,
-            conditionToMetricMap, trackerToMetricMap, noReportMetricIds,
-            activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
-            metricsWithActivation, replacedMetrics));
-
-    unordered_map<int64_t, int> expectedMetricProducerMap = {
-            {count1Id, count1Index}, {count2Id, count2Index}, {count3Id, count3Index},
-            {count4Id, count4Index}, {count6Id, count6Index},
-    };
-    EXPECT_THAT(newMetricProducerMap, ContainerEq(expectedMetricProducerMap));
-    EXPECT_EQ(replacedMetrics, set<int64_t>({count2Id, count3Id, count4Id}));
-
-    // Make sure preserved metrics are the same.
-    ASSERT_EQ(newMetricProducers.size(), 5);
-    EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(count1Id)],
-              newMetricProducers[newMetricProducerMap.at(count1Id)]);
-
-    // Make sure replaced metrics are different.
-    EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(count2Id)],
-              newMetricProducers[newMetricProducerMap.at(count2Id)]);
-    EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(count3Id)],
-              newMetricProducers[newMetricProducerMap.at(count3Id)]);
-    EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(count4Id)],
-              newMetricProducers[newMetricProducerMap.at(count4Id)]);
-
-    // Verify the conditionToMetricMap.
-    ASSERT_EQ(conditionToMetricMap.size(), 1);
-    const vector<int>& condition1Metrics = conditionToMetricMap[predicate1Index];
-    EXPECT_THAT(condition1Metrics, UnorderedElementsAre(count1Index, count6Index));
-
-    // Verify the trackerToMetricMap.
-    ASSERT_EQ(trackerToMetricMap.size(), 4);
-    const vector<int>& matcher1Metrics = trackerToMetricMap[matcher1Index];
-    EXPECT_THAT(matcher1Metrics, UnorderedElementsAre(count1Index));
-    const vector<int>& matcher2Metrics = trackerToMetricMap[matcher2Index];
-    EXPECT_THAT(matcher2Metrics, UnorderedElementsAre(count2Index, count6Index));
-    const vector<int>& matcher3Metrics = trackerToMetricMap[matcher3Index];
-    EXPECT_THAT(matcher3Metrics, UnorderedElementsAre(count3Index));
-    const vector<int>& matcher4Metrics = trackerToMetricMap[matcher4Index];
-    EXPECT_THAT(matcher4Metrics, UnorderedElementsAre(count4Index));
-
-    // Verify event activation/deactivation maps.
-    ASSERT_EQ(activationAtomTrackerToMetricMap.size(), 0);
-    ASSERT_EQ(deactivationAtomTrackerToMetricMap.size(), 0);
-    ASSERT_EQ(metricsWithActivation.size(), 0);
-
-    // Verify tracker indices/ids/conditions/states are correct.
-    EXPECT_EQ(newMetricProducers[count1Index]->getMetricId(), count1Id);
-    EXPECT_EQ(newMetricProducers[count1Index]->mConditionTrackerIndex, predicate1Index);
-    EXPECT_EQ(newMetricProducers[count1Index]->mCondition, ConditionState::kTrue);
-    EXPECT_THAT(newMetricProducers[count1Index]->getSlicedStateAtoms(),
-                UnorderedElementsAre(util::SCREEN_STATE_CHANGED));
-    EXPECT_EQ(newMetricProducers[count2Index]->getMetricId(), count2Id);
-    EXPECT_EQ(newMetricProducers[count2Index]->mConditionTrackerIndex, -1);
-    EXPECT_EQ(newMetricProducers[count2Index]->mCondition, ConditionState::kTrue);
-    EXPECT_TRUE(newMetricProducers[count2Index]->getSlicedStateAtoms().empty());
-    EXPECT_EQ(newMetricProducers[count3Index]->getMetricId(), count3Id);
-    EXPECT_EQ(newMetricProducers[count3Index]->mConditionTrackerIndex, -1);
-    EXPECT_EQ(newMetricProducers[count3Index]->mCondition, ConditionState::kTrue);
-    EXPECT_TRUE(newMetricProducers[count3Index]->getSlicedStateAtoms().empty());
-    EXPECT_EQ(newMetricProducers[count4Index]->getMetricId(), count4Id);
-    EXPECT_EQ(newMetricProducers[count4Index]->mConditionTrackerIndex, -1);
-    EXPECT_EQ(newMetricProducers[count4Index]->mCondition, ConditionState::kTrue);
-    EXPECT_THAT(newMetricProducers[count4Index]->getSlicedStateAtoms(),
-                UnorderedElementsAre(util::BATTERY_SAVER_MODE_STATE_CHANGED));
-    EXPECT_EQ(newMetricProducers[count6Index]->getMetricId(), count6Id);
-    EXPECT_EQ(newMetricProducers[count6Index]->mConditionTrackerIndex, predicate1Index);
-    EXPECT_EQ(newMetricProducers[count6Index]->mCondition, ConditionState::kTrue);
-    EXPECT_THAT(newMetricProducers[count6Index]->getSlicedStateAtoms(),
-                UnorderedElementsAre(util::SCREEN_STATE_CHANGED));
-
-    oldMetricProducers.clear();
-    // Ensure that the screen state StateTracker did not get deleted and replaced.
-    EXPECT_EQ(StateManager::getInstance().getStateTrackersCount(), 2);
-    FieldValue screenState;
-    StateManager::getInstance().getStateValue(util::SCREEN_STATE_CHANGED, DEFAULT_DIMENSION_KEY,
-                                              &screenState);
-    EXPECT_EQ(screenState.mValue.int_value, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-}
-
-TEST_F(ConfigUpdateTest, TestUpdateGaugeMetrics) {
-    StatsdConfig config;
-
-    // Add atom matchers/predicates/states. These are mostly needed for initStatsdConfig.
-    AtomMatcher matcher1 = CreateScreenTurnedOnAtomMatcher();
-    int64_t matcher1Id = matcher1.id();
-    *config.add_atom_matcher() = matcher1;
-
-    AtomMatcher matcher2 = CreateScreenTurnedOffAtomMatcher();
-    int64_t matcher2Id = matcher2.id();
-    *config.add_atom_matcher() = matcher2;
-
-    AtomMatcher matcher3 = CreateStartScheduledJobAtomMatcher();
-    int64_t matcher3Id = matcher3.id();
-    *config.add_atom_matcher() = matcher3;
-
-    AtomMatcher matcher4 = CreateTemperatureAtomMatcher();
-    int64_t matcher4Id = matcher4.id();
-    *config.add_atom_matcher() = matcher4;
-
-    AtomMatcher matcher5 = CreateSimpleAtomMatcher("SubsystemSleep", util::SUBSYSTEM_SLEEP_STATE);
-    int64_t matcher5Id = matcher5.id();
-    *config.add_atom_matcher() = matcher5;
-
-    Predicate predicate1 = CreateScreenIsOnPredicate();
-    int64_t predicate1Id = predicate1.id();
-    *config.add_predicate() = predicate1;
-
-    // Add a few gauge metrics.
-    // Will be preserved.
-    GaugeMetric gauge1 = createGaugeMetric("GAUGE1", matcher4Id, GaugeMetric::FIRST_N_SAMPLES,
-                                           predicate1Id, matcher1Id);
-    int64_t gauge1Id = gauge1.id();
-    *config.add_gauge_metric() = gauge1;
-
-    // Will be replaced.
-    GaugeMetric gauge2 =
-            createGaugeMetric("GAUGE2", matcher1Id, GaugeMetric::FIRST_N_SAMPLES, nullopt, nullopt);
-    int64_t gauge2Id = gauge2.id();
-    *config.add_gauge_metric() = gauge2;
-
-    // Will be replaced.
-    GaugeMetric gauge3 = createGaugeMetric("GAUGE3", matcher5Id, GaugeMetric::FIRST_N_SAMPLES,
-                                           nullopt, matcher3Id);
-    int64_t gauge3Id = gauge3.id();
-    *config.add_gauge_metric() = gauge3;
-
-    // Will be replaced.
-    GaugeMetric gauge4 = createGaugeMetric("GAUGE4", matcher3Id, GaugeMetric::RANDOM_ONE_SAMPLE,
-                                           predicate1Id, nullopt);
-    int64_t gauge4Id = gauge4.id();
-    *config.add_gauge_metric() = gauge4;
-
-    // Will be deleted.
-    GaugeMetric gauge5 =
-            createGaugeMetric("GAUGE5", matcher2Id, GaugeMetric::RANDOM_ONE_SAMPLE, nullopt, {});
-    int64_t gauge5Id = gauge5.id();
-    *config.add_gauge_metric() = gauge5;
-
-    EXPECT_TRUE(initConfig(config));
-
-    // Used later to ensure the condition wizard is replaced. Get it before doing the update.
-    sp<EventMatcherWizard> oldMatcherWizard =
-            static_cast<GaugeMetricProducer*>(oldMetricProducers[0].get())->mEventMatcherWizard;
-    EXPECT_EQ(oldMatcherWizard->getStrongCount(), 6);
-
-    // Change gauge2, causing it to be replaced.
-    gauge2.set_max_num_gauge_atoms_per_bucket(50);
-
-    // Mark matcher 3 as replaced. Causes gauge3 and gauge4 to be replaced.
-    set<int64_t> replacedMatchers = {matcher3Id};
-
-    // New gauge metric.
-    GaugeMetric gauge6 = createGaugeMetric("GAUGE6", matcher5Id, GaugeMetric::FIRST_N_SAMPLES,
-                                           predicate1Id, matcher3Id);
-    int64_t gauge6Id = gauge6.id();
-
-    // Map the matchers and predicates in reverse order to force the indices to change.
-    std::unordered_map<int64_t, int> newAtomMatchingTrackerMap;
-    const int matcher5Index = 0;
-    newAtomMatchingTrackerMap[matcher5Id] = 0;
-    const int matcher4Index = 1;
-    newAtomMatchingTrackerMap[matcher4Id] = 1;
-    const int matcher3Index = 2;
-    newAtomMatchingTrackerMap[matcher3Id] = 2;
-    const int matcher2Index = 3;
-    newAtomMatchingTrackerMap[matcher2Id] = 3;
-    const int matcher1Index = 4;
-    newAtomMatchingTrackerMap[matcher1Id] = 4;
-    // Use the existing matchers. A bit hacky, but saves code and we don't rely on them.
-    vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers(5);
-    std::reverse_copy(oldAtomMatchingTrackers.begin(), oldAtomMatchingTrackers.end(),
-                      newAtomMatchingTrackers.begin());
-
-    std::unordered_map<int64_t, int> newConditionTrackerMap;
-    const int predicate1Index = 0;
-    newConditionTrackerMap[predicate1Id] = 0;
-    // Use the existing conditionTrackers. A bit hacky, but saves code and we don't rely on them.
-    vector<sp<ConditionTracker>> newConditionTrackers(1);
-    std::reverse_copy(oldConditionTrackers.begin(), oldConditionTrackers.end(),
-                      newConditionTrackers.begin());
-    // Say that predicate1 is unknown since the initial condition never changed.
-    vector<ConditionState> conditionCache = {ConditionState::kUnknown};
-
-    StatsdConfig newConfig;
-    *newConfig.add_gauge_metric() = gauge6;
-    const int gauge6Index = 0;
-    *newConfig.add_gauge_metric() = gauge3;
-    const int gauge3Index = 1;
-    *newConfig.add_gauge_metric() = gauge1;
-    const int gauge1Index = 2;
-    *newConfig.add_gauge_metric() = gauge4;
-    const int gauge4Index = 3;
-    *newConfig.add_gauge_metric() = gauge2;
-    const int gauge2Index = 4;
-
-    // Output data structures to validate.
-    unordered_map<int64_t, int> newMetricProducerMap;
-    vector<sp<MetricProducer>> newMetricProducers;
-    unordered_map<int, vector<int>> conditionToMetricMap;
-    unordered_map<int, vector<int>> trackerToMetricMap;
-    set<int64_t> noReportMetricIds;
-    unordered_map<int, vector<int>> activationAtomTrackerToMetricMap;
-    unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
-    vector<int> metricsWithActivation;
-    set<int64_t> replacedMetrics;
-    EXPECT_TRUE(updateMetrics(
-            key, newConfig, /*timeBaseNs=*/123, /*currentTimeNs=*/12345, new StatsPullerManager(),
-            oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, replacedMatchers,
-            newAtomMatchingTrackers, newConditionTrackerMap, /*replacedConditions=*/{},
-            newConditionTrackers, conditionCache, /*stateAtomIdMap=*/{}, /*allStateGroupMaps=*/{},
-            /*replacedStates=*/{}, oldMetricProducerMap, oldMetricProducers, newMetricProducerMap,
-            newMetricProducers, conditionToMetricMap, trackerToMetricMap, noReportMetricIds,
-            activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
-            metricsWithActivation, replacedMetrics));
-
-    unordered_map<int64_t, int> expectedMetricProducerMap = {
-            {gauge1Id, gauge1Index}, {gauge2Id, gauge2Index}, {gauge3Id, gauge3Index},
-            {gauge4Id, gauge4Index}, {gauge6Id, gauge6Index},
-    };
-    EXPECT_THAT(newMetricProducerMap, ContainerEq(expectedMetricProducerMap));
-    EXPECT_EQ(replacedMetrics, set<int64_t>({gauge2Id, gauge3Id, gauge4Id}));
-
-    // Make sure preserved metrics are the same.
-    ASSERT_EQ(newMetricProducers.size(), 5);
-    EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(gauge1Id)],
-              newMetricProducers[newMetricProducerMap.at(gauge1Id)]);
-
-    // Make sure replaced metrics are different.
-    EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(gauge2Id)],
-              newMetricProducers[newMetricProducerMap.at(gauge2Id)]);
-    EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(gauge3Id)],
-              newMetricProducers[newMetricProducerMap.at(gauge3Id)]);
-    EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(gauge4Id)],
-              newMetricProducers[newMetricProducerMap.at(gauge4Id)]);
-
-    // Verify the conditionToMetricMap.
-    ASSERT_EQ(conditionToMetricMap.size(), 1);
-    const vector<int>& condition1Metrics = conditionToMetricMap[predicate1Index];
-    EXPECT_THAT(condition1Metrics, UnorderedElementsAre(gauge1Index, gauge4Index, gauge6Index));
-
-    // Verify the trackerToMetricMap.
-    ASSERT_EQ(trackerToMetricMap.size(), 4);
-    const vector<int>& matcher1Metrics = trackerToMetricMap[matcher1Index];
-    EXPECT_THAT(matcher1Metrics, UnorderedElementsAre(gauge1Index, gauge2Index));
-    const vector<int>& matcher3Metrics = trackerToMetricMap[matcher3Index];
-    EXPECT_THAT(matcher3Metrics, UnorderedElementsAre(gauge3Index, gauge4Index, gauge6Index));
-    const vector<int>& matcher4Metrics = trackerToMetricMap[matcher4Index];
-    EXPECT_THAT(matcher4Metrics, UnorderedElementsAre(gauge1Index));
-    const vector<int>& matcher5Metrics = trackerToMetricMap[matcher5Index];
-    EXPECT_THAT(matcher5Metrics, UnorderedElementsAre(gauge3Index, gauge6Index));
-
-    // Verify event activation/deactivation maps.
-    ASSERT_EQ(activationAtomTrackerToMetricMap.size(), 0);
-    ASSERT_EQ(deactivationAtomTrackerToMetricMap.size(), 0);
-    ASSERT_EQ(metricsWithActivation.size(), 0);
-
-    // Verify tracker indices/ids/conditions/states are correct.
-    GaugeMetricProducer* gaugeProducer1 =
-            static_cast<GaugeMetricProducer*>(newMetricProducers[gauge1Index].get());
-    EXPECT_EQ(gaugeProducer1->getMetricId(), gauge1Id);
-    EXPECT_EQ(gaugeProducer1->mConditionTrackerIndex, predicate1Index);
-    EXPECT_EQ(gaugeProducer1->mCondition, ConditionState::kUnknown);
-    EXPECT_EQ(gaugeProducer1->mWhatMatcherIndex, matcher4Index);
-    GaugeMetricProducer* gaugeProducer2 =
-            static_cast<GaugeMetricProducer*>(newMetricProducers[gauge2Index].get());
-    EXPECT_EQ(gaugeProducer2->getMetricId(), gauge2Id);
-    EXPECT_EQ(gaugeProducer2->mConditionTrackerIndex, -1);
-    EXPECT_EQ(gaugeProducer2->mCondition, ConditionState::kTrue);
-    EXPECT_EQ(gaugeProducer2->mWhatMatcherIndex, matcher1Index);
-    GaugeMetricProducer* gaugeProducer3 =
-            static_cast<GaugeMetricProducer*>(newMetricProducers[gauge3Index].get());
-    EXPECT_EQ(gaugeProducer3->getMetricId(), gauge3Id);
-    EXPECT_EQ(gaugeProducer3->mConditionTrackerIndex, -1);
-    EXPECT_EQ(gaugeProducer3->mCondition, ConditionState::kTrue);
-    EXPECT_EQ(gaugeProducer3->mWhatMatcherIndex, matcher5Index);
-    GaugeMetricProducer* gaugeProducer4 =
-            static_cast<GaugeMetricProducer*>(newMetricProducers[gauge4Index].get());
-    EXPECT_EQ(gaugeProducer4->getMetricId(), gauge4Id);
-    EXPECT_EQ(gaugeProducer4->mConditionTrackerIndex, predicate1Index);
-    EXPECT_EQ(gaugeProducer4->mCondition, ConditionState::kUnknown);
-    EXPECT_EQ(gaugeProducer4->mWhatMatcherIndex, matcher3Index);
-    GaugeMetricProducer* gaugeProducer6 =
-            static_cast<GaugeMetricProducer*>(newMetricProducers[gauge6Index].get());
-    EXPECT_EQ(gaugeProducer6->getMetricId(), gauge6Id);
-    EXPECT_EQ(gaugeProducer6->mConditionTrackerIndex, predicate1Index);
-    EXPECT_EQ(gaugeProducer6->mCondition, ConditionState::kUnknown);
-    EXPECT_EQ(gaugeProducer6->mWhatMatcherIndex, matcher5Index);
-
-    sp<EventMatcherWizard> newMatcherWizard = gaugeProducer1->mEventMatcherWizard;
-    EXPECT_NE(newMatcherWizard, oldMatcherWizard);
-    EXPECT_EQ(newMatcherWizard->getStrongCount(), 6);
-    oldMetricProducers.clear();
-    // Only reference to the old wizard should be the one in the test.
-    EXPECT_EQ(oldMatcherWizard->getStrongCount(), 1);
-}
-
-TEST_F(ConfigUpdateTest, TestUpdateDurationMetrics) {
-    StatsdConfig config;
-    // Add atom matchers/predicates/states. These are mostly needed for initStatsdConfig.
-    AtomMatcher matcher1 = CreateScreenTurnedOnAtomMatcher();
-    int64_t matcher1Id = matcher1.id();
-    *config.add_atom_matcher() = matcher1;
-
-    AtomMatcher matcher2 = CreateScreenTurnedOffAtomMatcher();
-    int64_t matcher2Id = matcher2.id();
-    *config.add_atom_matcher() = matcher2;
-
-    AtomMatcher matcher3 = CreateAcquireWakelockAtomMatcher();
-    int64_t matcher3Id = matcher3.id();
-    *config.add_atom_matcher() = matcher3;
-
-    AtomMatcher matcher4 = CreateReleaseWakelockAtomMatcher();
-    int64_t matcher4Id = matcher4.id();
-    *config.add_atom_matcher() = matcher4;
-
-    AtomMatcher matcher5 = CreateMoveToForegroundAtomMatcher();
-    int64_t matcher5Id = matcher5.id();
-    *config.add_atom_matcher() = matcher5;
-
-    AtomMatcher matcher6 = CreateMoveToBackgroundAtomMatcher();
-    int64_t matcher6Id = matcher6.id();
-    *config.add_atom_matcher() = matcher6;
-
-    AtomMatcher matcher7 = CreateBatteryStateNoneMatcher();
-    int64_t matcher7Id = matcher7.id();
-    *config.add_atom_matcher() = matcher7;
-
-    AtomMatcher matcher8 = CreateBatteryStateUsbMatcher();
-    int64_t matcher8Id = matcher8.id();
-    *config.add_atom_matcher() = matcher8;
-
-    Predicate predicate1 = CreateScreenIsOnPredicate();
-    int64_t predicate1Id = predicate1.id();
-    *config.add_predicate() = predicate1;
-
-    Predicate predicate2 = CreateScreenIsOffPredicate();
-    int64_t predicate2Id = predicate2.id();
-    *config.add_predicate() = predicate2;
-
-    Predicate predicate3 = CreateDeviceUnpluggedPredicate();
-    int64_t predicate3Id = predicate3.id();
-    *config.add_predicate() = predicate3;
-
-    Predicate predicate4 = CreateIsInBackgroundPredicate();
-    *predicate4.mutable_simple_predicate()->mutable_dimensions() =
-            CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1});
-    int64_t predicate4Id = predicate4.id();
-    *config.add_predicate() = predicate4;
-
-    Predicate predicate5 = CreateHoldingWakelockPredicate();
-    *predicate5.mutable_simple_predicate()->mutable_dimensions() =
-            CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-    predicate5.mutable_simple_predicate()->set_stop_all(matcher7Id);
-    int64_t predicate5Id = predicate5.id();
-    *config.add_predicate() = predicate5;
-
-    State state1 = CreateScreenStateWithOnOffMap(0x123, 0x321);
-    int64_t state1Id = state1.id();
-    *config.add_state() = state1;
-
-    State state2 = CreateScreenState();
-    int64_t state2Id = state2.id();
-    *config.add_state() = state2;
-
-    // Add a few duration metrics.
-    // Will be preserved.
-    DurationMetric duration1 =
-            createDurationMetric("DURATION1", predicate5Id, predicate4Id, {state2Id});
-    *duration1.mutable_dimensions_in_what() =
-            CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-    MetricConditionLink* link = duration1.add_links();
-    link->set_condition(predicate4Id);
-    *link->mutable_fields_in_what() =
-            CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-    *link->mutable_fields_in_condition() =
-            CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1} /*uid field*/);
-    int64_t duration1Id = duration1.id();
-    *config.add_duration_metric() = duration1;
-
-    // Will be replaced.
-    DurationMetric duration2 = createDurationMetric("DURATION2", predicate1Id, nullopt, {});
-    int64_t duration2Id = duration2.id();
-    *config.add_duration_metric() = duration2;
-
-    // Will be replaced.
-    DurationMetric duration3 = createDurationMetric("DURATION3", predicate3Id, nullopt, {state1Id});
-    int64_t duration3Id = duration3.id();
-    *config.add_duration_metric() = duration3;
-
-    // Will be replaced.
-    DurationMetric duration4 = createDurationMetric("DURATION4", predicate3Id, predicate2Id, {});
-    int64_t duration4Id = duration4.id();
-    *config.add_duration_metric() = duration4;
-
-    // Will be deleted.
-    DurationMetric duration5 = createDurationMetric("DURATION5", predicate2Id, nullopt, {});
-    int64_t duration5Id = duration5.id();
-    *config.add_duration_metric() = duration5;
-
-    EXPECT_TRUE(initConfig(config));
-
-    // Make some sliced conditions true.
-    int uid1 = 10;
-    int uid2 = 11;
-    vector<MatchingState> matchingStates(8, MatchingState::kNotMatched);
-    matchingStates[2] = kMatched;
-    vector<ConditionState> conditionCache(5, ConditionState::kNotEvaluated);
-    vector<bool> changedCache(5, false);
-    unique_ptr<LogEvent> event = CreateAcquireWakelockEvent(timeBaseNs + 3, {uid1}, {"tag"}, "wl1");
-    oldConditionTrackers[4]->evaluateCondition(*event.get(), matchingStates, oldConditionTrackers,
-                                               conditionCache, changedCache);
-    EXPECT_TRUE(oldConditionTrackers[4]->isSliced());
-    EXPECT_TRUE(changedCache[4]);
-    EXPECT_EQ(conditionCache[4], ConditionState::kTrue);
-    oldMetricProducers[0]->onMatchedLogEvent(2, *event.get());
-
-    fill(conditionCache.begin(), conditionCache.end(), ConditionState::kNotEvaluated);
-    fill(changedCache.begin(), changedCache.end(), false);
-    event = CreateAcquireWakelockEvent(timeBaseNs + 3, {uid2}, {"tag"}, "wl2");
-    oldConditionTrackers[4]->evaluateCondition(*event.get(), matchingStates, oldConditionTrackers,
-                                               conditionCache, changedCache);
-    EXPECT_TRUE(changedCache[4]);
-    EXPECT_EQ(conditionCache[4], ConditionState::kTrue);
-    oldMetricProducers[0]->onMatchedLogEvent(2, *event.get());
-
-    // Used later to ensure the condition wizard is replaced. Get it before doing the update.
-    // The duration trackers have a pointer to the wizard, and 2 trackers were created above.
-    sp<ConditionWizard> oldConditionWizard = oldMetricProducers[0]->mWizard;
-    EXPECT_EQ(oldConditionWizard->getStrongCount(), 8);
-
-    // Replace predicate1, predicate3, and state1. Causes duration2/3/4 to be replaced.
-    set<int64_t> replacedConditions({predicate1Id, predicate2Id});
-    set<int64_t> replacedStates({state1Id});
-
-    // New duration metric.
-    DurationMetric duration6 = createDurationMetric("DURATION6", predicate4Id, predicate5Id, {});
-    *duration6.mutable_dimensions_in_what() =
-            CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1} /*uid field*/);
-    link = duration6.add_links();
-    link->set_condition(predicate5Id);
-    *link->mutable_fields_in_what() =
-            CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1} /*uid field*/);
-    *link->mutable_fields_in_condition() =
-            CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-    int64_t duration6Id = duration6.id();
-
-    // Map the matchers and predicates in reverse order to force the indices to change.
-    const int matcher8Index = 0, matcher7Index = 1, matcher6Index = 2, matcher5Index = 3,
-              matcher4Index = 4, matcher3Index = 5, matcher2Index = 6, matcher1Index = 7;
-    std::unordered_map<int64_t, int> newAtomMatchingTrackerMap({{matcher8Id, matcher8Index},
-                                                                {matcher7Id, matcher7Index},
-                                                                {matcher6Id, matcher6Index},
-                                                                {matcher5Id, matcher5Index},
-                                                                {matcher4Id, matcher4Index},
-                                                                {matcher3Id, matcher3Index},
-                                                                {matcher2Id, matcher2Index},
-                                                                {matcher1Id, matcher1Index}});
-    // Use the existing matchers. A bit hacky, but saves code and we don't rely on them.
-    vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers(8);
-    reverse_copy(oldAtomMatchingTrackers.begin(), oldAtomMatchingTrackers.end(),
-                 newAtomMatchingTrackers.begin());
-
-    const int predicate5Index = 0, predicate4Index = 1, predicate3Index = 2, predicate2Index = 3,
-              predicate1Index = 4;
-    std::unordered_map<int64_t, int> newConditionTrackerMap({
-            {predicate5Id, predicate5Index},
-            {predicate4Id, predicate4Index},
-            {predicate3Id, predicate3Index},
-            {predicate2Id, predicate2Index},
-            {predicate1Id, predicate1Index},
-    });
-    // Use the existing conditionTrackers and reinitialize them to get the initial condition cache.
-    vector<sp<ConditionTracker>> newConditionTrackers(5);
-    reverse_copy(oldConditionTrackers.begin(), oldConditionTrackers.end(),
-                 newConditionTrackers.begin());
-    vector<Predicate> conditionProtos(5);
-    reverse_copy(config.predicate().begin(), config.predicate().end(), conditionProtos.begin());
-    for (int i = 0; i < newConditionTrackers.size(); i++) {
-        EXPECT_TRUE(newConditionTrackers[i]->onConfigUpdated(
-                conditionProtos, i, newConditionTrackers, newAtomMatchingTrackerMap,
-                newConditionTrackerMap));
-    }
-    vector<bool> cycleTracker(5, false);
-    fill(conditionCache.begin(), conditionCache.end(), ConditionState::kNotEvaluated);
-    for (int i = 0; i < newConditionTrackers.size(); i++) {
-        EXPECT_TRUE(newConditionTrackers[i]->init(conditionProtos, newConditionTrackers,
-                                                  newConditionTrackerMap, cycleTracker,
-                                                  conditionCache));
-    }
-    // Predicate5 should be true since 2 uids have wakelocks
-    EXPECT_EQ(conditionCache, vector({kTrue, kUnknown, kUnknown, kUnknown, kUnknown}));
-
-    StatsdConfig newConfig;
-    *newConfig.add_duration_metric() = duration6;
-    const int duration6Index = 0;
-    *newConfig.add_duration_metric() = duration3;
-    const int duration3Index = 1;
-    *newConfig.add_duration_metric() = duration1;
-    const int duration1Index = 2;
-    *newConfig.add_duration_metric() = duration4;
-    const int duration4Index = 3;
-    *newConfig.add_duration_metric() = duration2;
-    const int duration2Index = 4;
-
-    for (const Predicate& predicate : conditionProtos) {
-        *newConfig.add_predicate() = predicate;
-    }
-    *newConfig.add_state() = state1;
-    *newConfig.add_state() = state2;
-    unordered_map<int64_t, int> stateAtomIdMap;
-    unordered_map<int64_t, unordered_map<int, int64_t>> allStateGroupMaps;
-    map<int64_t, uint64_t> stateProtoHashes;
-    EXPECT_TRUE(initStates(newConfig, stateAtomIdMap, allStateGroupMaps, stateProtoHashes));
-
-    // Output data structures to validate.
-    unordered_map<int64_t, int> newMetricProducerMap;
-    vector<sp<MetricProducer>> newMetricProducers;
-    unordered_map<int, vector<int>> conditionToMetricMap;
-    unordered_map<int, vector<int>> trackerToMetricMap;
-    set<int64_t> noReportMetricIds;
-    unordered_map<int, vector<int>> activationAtomTrackerToMetricMap;
-    unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
-    vector<int> metricsWithActivation;
-    set<int64_t> replacedMetrics;
-    EXPECT_TRUE(updateMetrics(
-            key, newConfig, /*timeBaseNs=*/123, /*currentTimeNs=*/12345, new StatsPullerManager(),
-            oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, /*replacedMatchers=*/{},
-            newAtomMatchingTrackers, newConditionTrackerMap, replacedConditions,
-            newConditionTrackers, conditionCache, stateAtomIdMap, allStateGroupMaps, replacedStates,
-            oldMetricProducerMap, oldMetricProducers, newMetricProducerMap, newMetricProducers,
-            conditionToMetricMap, trackerToMetricMap, noReportMetricIds,
-            activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
-            metricsWithActivation, replacedMetrics));
-
-    unordered_map<int64_t, int> expectedMetricProducerMap = {
-            {duration1Id, duration1Index}, {duration2Id, duration2Index},
-            {duration3Id, duration3Index}, {duration4Id, duration4Index},
-            {duration6Id, duration6Index},
-    };
-    EXPECT_THAT(newMetricProducerMap, ContainerEq(expectedMetricProducerMap));
-    EXPECT_EQ(replacedMetrics, set<int64_t>({duration2Id, duration3Id, duration4Id}));
-    // Make sure preserved metrics are the same.
-    ASSERT_EQ(newMetricProducers.size(), 5);
-    EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(duration1Id)],
-              newMetricProducers[newMetricProducerMap.at(duration1Id)]);
-
-    // Make sure replaced metrics are different.
-    EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(duration2Id)],
-              newMetricProducers[newMetricProducerMap.at(duration2Id)]);
-    EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(duration3Id)],
-              newMetricProducers[newMetricProducerMap.at(duration3Id)]);
-    EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(duration4Id)],
-              newMetricProducers[newMetricProducerMap.at(duration4Id)]);
-
-    // Verify the conditionToMetricMap. Note that the "what" is not in this map.
-    ASSERT_EQ(conditionToMetricMap.size(), 3);
-    const vector<int>& condition2Metrics = conditionToMetricMap[predicate2Index];
-    EXPECT_THAT(condition2Metrics, UnorderedElementsAre(duration4Index));
-    const vector<int>& condition4Metrics = conditionToMetricMap[predicate4Index];
-    EXPECT_THAT(condition4Metrics, UnorderedElementsAre(duration1Index));
-    const vector<int>& condition5Metrics = conditionToMetricMap[predicate5Index];
-    EXPECT_THAT(condition5Metrics, UnorderedElementsAre(duration6Index));
-
-    // Verify the trackerToMetricMap. The start/stop/stopall indices from the "what" should be here.
-    ASSERT_EQ(trackerToMetricMap.size(), 8);
-    const vector<int>& matcher1Metrics = trackerToMetricMap[matcher1Index];
-    EXPECT_THAT(matcher1Metrics, UnorderedElementsAre(duration2Index));
-    const vector<int>& matcher2Metrics = trackerToMetricMap[matcher2Index];
-    EXPECT_THAT(matcher2Metrics, UnorderedElementsAre(duration2Index));
-    const vector<int>& matcher3Metrics = trackerToMetricMap[matcher3Index];
-    EXPECT_THAT(matcher3Metrics, UnorderedElementsAre(duration1Index));
-    const vector<int>& matcher4Metrics = trackerToMetricMap[matcher4Index];
-    EXPECT_THAT(matcher4Metrics, UnorderedElementsAre(duration1Index));
-    const vector<int>& matcher5Metrics = trackerToMetricMap[matcher5Index];
-    EXPECT_THAT(matcher5Metrics, UnorderedElementsAre(duration6Index));
-    const vector<int>& matcher6Metrics = trackerToMetricMap[matcher6Index];
-    EXPECT_THAT(matcher6Metrics, UnorderedElementsAre(duration6Index));
-    const vector<int>& matcher7Metrics = trackerToMetricMap[matcher7Index];
-    EXPECT_THAT(matcher7Metrics,
-                UnorderedElementsAre(duration1Index, duration3Index, duration4Index));
-    const vector<int>& matcher8Metrics = trackerToMetricMap[matcher8Index];
-    EXPECT_THAT(matcher8Metrics, UnorderedElementsAre(duration3Index, duration4Index));
-
-    // Verify event activation/deactivation maps.
-    ASSERT_EQ(activationAtomTrackerToMetricMap.size(), 0);
-    ASSERT_EQ(deactivationAtomTrackerToMetricMap.size(), 0);
-    ASSERT_EQ(metricsWithActivation.size(), 0);
-
-    // Verify tracker indices/ids/conditions are correct.
-    DurationMetricProducer* durationProducer1 =
-            static_cast<DurationMetricProducer*>(newMetricProducers[duration1Index].get());
-    EXPECT_EQ(durationProducer1->getMetricId(), duration1Id);
-    EXPECT_EQ(durationProducer1->mConditionTrackerIndex, predicate4Index);
-    EXPECT_EQ(durationProducer1->mCondition, ConditionState::kUnknown);
-    EXPECT_EQ(durationProducer1->mStartIndex, matcher3Index);
-    EXPECT_EQ(durationProducer1->mStopIndex, matcher4Index);
-    EXPECT_EQ(durationProducer1->mStopAllIndex, matcher7Index);
-    EXPECT_EQ(durationProducer1->mCurrentSlicedDurationTrackerMap.size(), 2);
-    for (const auto& durationTrackerIt : durationProducer1->mCurrentSlicedDurationTrackerMap) {
-        EXPECT_EQ(durationTrackerIt.second->mConditionTrackerIndex, predicate4Index);
-    }
-    DurationMetricProducer* durationProducer2 =
-            static_cast<DurationMetricProducer*>(newMetricProducers[duration2Index].get());
-    EXPECT_EQ(durationProducer2->getMetricId(), duration2Id);
-    EXPECT_EQ(durationProducer2->mConditionTrackerIndex, -1);
-    EXPECT_EQ(durationProducer2->mCondition, ConditionState::kTrue);
-    EXPECT_EQ(durationProducer2->mStartIndex, matcher1Index);
-    EXPECT_EQ(durationProducer2->mStopIndex, matcher2Index);
-    EXPECT_EQ(durationProducer2->mStopAllIndex, -1);
-    DurationMetricProducer* durationProducer3 =
-            static_cast<DurationMetricProducer*>(newMetricProducers[duration3Index].get());
-    EXPECT_EQ(durationProducer3->getMetricId(), duration3Id);
-    EXPECT_EQ(durationProducer3->mConditionTrackerIndex, -1);
-    EXPECT_EQ(durationProducer3->mCondition, ConditionState::kTrue);
-    EXPECT_EQ(durationProducer3->mStartIndex, matcher7Index);
-    EXPECT_EQ(durationProducer3->mStopIndex, matcher8Index);
-    EXPECT_EQ(durationProducer3->mStopAllIndex, -1);
-    DurationMetricProducer* durationProducer4 =
-            static_cast<DurationMetricProducer*>(newMetricProducers[duration4Index].get());
-    EXPECT_EQ(durationProducer4->getMetricId(), duration4Id);
-    EXPECT_EQ(durationProducer4->mConditionTrackerIndex, predicate2Index);
-    EXPECT_EQ(durationProducer4->mCondition, ConditionState::kUnknown);
-    EXPECT_EQ(durationProducer4->mStartIndex, matcher7Index);
-    EXPECT_EQ(durationProducer4->mStopIndex, matcher8Index);
-    EXPECT_EQ(durationProducer4->mStopAllIndex, -1);
-    DurationMetricProducer* durationProducer6 =
-            static_cast<DurationMetricProducer*>(newMetricProducers[duration6Index].get());
-    EXPECT_EQ(durationProducer6->getMetricId(), duration6Id);
-    EXPECT_EQ(durationProducer6->mConditionTrackerIndex, predicate5Index);
-    // TODO(b/167491517): should this be unknown since the condition is sliced?
-    EXPECT_EQ(durationProducer6->mCondition, ConditionState::kTrue);
-    EXPECT_EQ(durationProducer6->mStartIndex, matcher6Index);
-    EXPECT_EQ(durationProducer6->mStopIndex, matcher5Index);
-    EXPECT_EQ(durationProducer6->mStopAllIndex, -1);
-
-    sp<ConditionWizard> newConditionWizard = newMetricProducers[0]->mWizard;
-    EXPECT_NE(newConditionWizard, oldConditionWizard);
-    EXPECT_EQ(newConditionWizard->getStrongCount(), 8);
-    oldMetricProducers.clear();
-    // Only reference to the old wizard should be the one in the test.
-    EXPECT_EQ(oldConditionWizard->getStrongCount(), 1);
-}
-
-TEST_F(ConfigUpdateTest, TestUpdateValueMetrics) {
-    StatsdConfig config;
-
-    // Add atom matchers/predicates/states. These are mostly needed for initStatsdConfig.
-    AtomMatcher matcher1 = CreateScreenTurnedOnAtomMatcher();
-    int64_t matcher1Id = matcher1.id();
-    *config.add_atom_matcher() = matcher1;
-
-    AtomMatcher matcher2 = CreateScreenTurnedOffAtomMatcher();
-    int64_t matcher2Id = matcher2.id();
-    *config.add_atom_matcher() = matcher2;
-
-    AtomMatcher matcher3 = CreateStartScheduledJobAtomMatcher();
-    int64_t matcher3Id = matcher3.id();
-    *config.add_atom_matcher() = matcher3;
-
-    AtomMatcher matcher4 = CreateTemperatureAtomMatcher();
-    int64_t matcher4Id = matcher4.id();
-    *config.add_atom_matcher() = matcher4;
-
-    AtomMatcher matcher5 = CreateSimpleAtomMatcher("SubsystemSleep", util::SUBSYSTEM_SLEEP_STATE);
-    int64_t matcher5Id = matcher5.id();
-    *config.add_atom_matcher() = matcher5;
-
-    Predicate predicate1 = CreateScreenIsOnPredicate();
-    int64_t predicate1Id = predicate1.id();
-    *config.add_predicate() = predicate1;
-
-    Predicate predicate2 = CreateScreenIsOffPredicate();
-    int64_t predicate2Id = predicate2.id();
-    *config.add_predicate() = predicate2;
-
-    State state1 = CreateScreenStateWithOnOffMap(0x123, 0x321);
-    int64_t state1Id = state1.id();
-    *config.add_state() = state1;
-
-    State state2 = CreateScreenState();
-    int64_t state2Id = state2.id();
-    *config.add_state() = state2;
-
-    // Add a few value metrics.
-    // Note that these will not work as "real" metrics since the value field is always 2.
-    // Will be preserved.
-    ValueMetric value1 = createValueMetric("VALUE1", matcher4, predicate1Id, {state1Id});
-    int64_t value1Id = value1.id();
-    *config.add_value_metric() = value1;
-
-    // Will be replaced - definition change.
-    ValueMetric value2 = createValueMetric("VALUE2", matcher1, nullopt, {});
-    int64_t value2Id = value2.id();
-    *config.add_value_metric() = value2;
-
-    // Will be replaced - condition change.
-    ValueMetric value3 = createValueMetric("VALUE3", matcher5, predicate2Id, {});
-    int64_t value3Id = value3.id();
-    *config.add_value_metric() = value3;
-
-    // Will be replaced - state change.
-    ValueMetric value4 = createValueMetric("VALUE4", matcher3, nullopt, {state2Id});
-    int64_t value4Id = value4.id();
-    *config.add_value_metric() = value4;
-
-    // Will be deleted.
-    ValueMetric value5 = createValueMetric("VALUE5", matcher2, nullopt, {});
-    int64_t value5Id = value5.id();
-    *config.add_value_metric() = value5;
-
-    EXPECT_TRUE(initConfig(config));
-
-    // Used later to ensure the condition wizard is replaced. Get it before doing the update.
-    sp<EventMatcherWizard> oldMatcherWizard =
-            static_cast<ValueMetricProducer*>(oldMetricProducers[0].get())->mEventMatcherWizard;
-    EXPECT_EQ(oldMatcherWizard->getStrongCount(), 6);
-
-    // Change value2, causing it to be replaced.
-    value2.set_aggregation_type(ValueMetric::AVG);
-
-    // Mark predicate 2 as replaced. Causes value3 to be replaced.
-    set<int64_t> replacedConditions = {predicate2Id};
-
-    // Mark state 2 as replaced. Causes value4 to be replaced.
-    set<int64_t> replacedStates = {state2Id};
-
-    // New value metric.
-    ValueMetric value6 = createValueMetric("VALUE6", matcher5, predicate1Id, {state1Id});
-    int64_t value6Id = value6.id();
-
-    // Map the matchers and predicates in reverse order to force the indices to change.
-    std::unordered_map<int64_t, int> newAtomMatchingTrackerMap;
-    const int matcher5Index = 0;
-    newAtomMatchingTrackerMap[matcher5Id] = 0;
-    const int matcher4Index = 1;
-    newAtomMatchingTrackerMap[matcher4Id] = 1;
-    const int matcher3Index = 2;
-    newAtomMatchingTrackerMap[matcher3Id] = 2;
-    const int matcher2Index = 3;
-    newAtomMatchingTrackerMap[matcher2Id] = 3;
-    const int matcher1Index = 4;
-    newAtomMatchingTrackerMap[matcher1Id] = 4;
-    // Use the existing matchers. A bit hacky, but saves code and we don't rely on them.
-    vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers(5);
-    std::reverse_copy(oldAtomMatchingTrackers.begin(), oldAtomMatchingTrackers.end(),
-                      newAtomMatchingTrackers.begin());
-
-    std::unordered_map<int64_t, int> newConditionTrackerMap;
-    const int predicate2Index = 0;
-    newConditionTrackerMap[predicate2Id] = 0;
-    const int predicate1Index = 1;
-    newConditionTrackerMap[predicate1Id] = 1;
-    // Use the existing conditionTrackers. A bit hacky, but saves code and we don't rely on them.
-    vector<sp<ConditionTracker>> newConditionTrackers(2);
-    std::reverse_copy(oldConditionTrackers.begin(), oldConditionTrackers.end(),
-                      newConditionTrackers.begin());
-    // Say that predicate1 & predicate2 is unknown since the initial condition never changed.
-    vector<ConditionState> conditionCache = {ConditionState::kUnknown, ConditionState::kUnknown};
-
-    StatsdConfig newConfig;
-    *newConfig.add_value_metric() = value6;
-    const int value6Index = 0;
-    *newConfig.add_value_metric() = value3;
-    const int value3Index = 1;
-    *newConfig.add_value_metric() = value1;
-    const int value1Index = 2;
-    *newConfig.add_value_metric() = value4;
-    const int value4Index = 3;
-    *newConfig.add_value_metric() = value2;
-    const int value2Index = 4;
-
-    *newConfig.add_state() = state1;
-    *newConfig.add_state() = state2;
-
-    unordered_map<int64_t, int> stateAtomIdMap;
-    unordered_map<int64_t, unordered_map<int, int64_t>> allStateGroupMaps;
-    map<int64_t, uint64_t> stateProtoHashes;
-    EXPECT_TRUE(initStates(newConfig, stateAtomIdMap, allStateGroupMaps, stateProtoHashes));
-
-    // Output data structures to validate.
-    unordered_map<int64_t, int> newMetricProducerMap;
-    vector<sp<MetricProducer>> newMetricProducers;
-    unordered_map<int, vector<int>> conditionToMetricMap;
-    unordered_map<int, vector<int>> trackerToMetricMap;
-    set<int64_t> noReportMetricIds;
-    unordered_map<int, vector<int>> activationAtomTrackerToMetricMap;
-    unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
-    vector<int> metricsWithActivation;
-    set<int64_t> replacedMetrics;
-    EXPECT_TRUE(updateMetrics(
-            key, newConfig, /*timeBaseNs=*/123, /*currentTimeNs=*/12345, new StatsPullerManager(),
-            oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, /*replacedMatchers=*/{},
-            newAtomMatchingTrackers, newConditionTrackerMap, replacedConditions,
-            newConditionTrackers, conditionCache, stateAtomIdMap, allStateGroupMaps, replacedStates,
-            oldMetricProducerMap, oldMetricProducers, newMetricProducerMap, newMetricProducers,
-            conditionToMetricMap, trackerToMetricMap, noReportMetricIds,
-            activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
-            metricsWithActivation, replacedMetrics));
-
-    unordered_map<int64_t, int> expectedMetricProducerMap = {
-            {value1Id, value1Index}, {value2Id, value2Index}, {value3Id, value3Index},
-            {value4Id, value4Index}, {value6Id, value6Index},
-    };
-    EXPECT_THAT(newMetricProducerMap, ContainerEq(expectedMetricProducerMap));
-    EXPECT_EQ(replacedMetrics, set<int64_t>({value2Id, value3Id, value4Id}));
-
-    // Make sure preserved metrics are the same.
-    ASSERT_EQ(newMetricProducers.size(), 5);
-    EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(value1Id)],
-              newMetricProducers[newMetricProducerMap.at(value1Id)]);
-
-    // Make sure replaced metrics are different.
-    EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(value2Id)],
-              newMetricProducers[newMetricProducerMap.at(value2Id)]);
-    EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(value3Id)],
-              newMetricProducers[newMetricProducerMap.at(value3Id)]);
-    EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(value4Id)],
-              newMetricProducers[newMetricProducerMap.at(value4Id)]);
-
-    // Verify the conditionToMetricMap.
-    ASSERT_EQ(conditionToMetricMap.size(), 2);
-    const vector<int>& condition1Metrics = conditionToMetricMap[predicate1Index];
-    EXPECT_THAT(condition1Metrics, UnorderedElementsAre(value1Index, value6Index));
-    const vector<int>& condition2Metrics = conditionToMetricMap[predicate2Index];
-    EXPECT_THAT(condition2Metrics, UnorderedElementsAre(value3Index));
-
-    // Verify the trackerToMetricMap.
-    ASSERT_EQ(trackerToMetricMap.size(), 4);
-    const vector<int>& matcher1Metrics = trackerToMetricMap[matcher1Index];
-    EXPECT_THAT(matcher1Metrics, UnorderedElementsAre(value2Index));
-    const vector<int>& matcher3Metrics = trackerToMetricMap[matcher3Index];
-    EXPECT_THAT(matcher3Metrics, UnorderedElementsAre(value4Index));
-    const vector<int>& matcher4Metrics = trackerToMetricMap[matcher4Index];
-    EXPECT_THAT(matcher4Metrics, UnorderedElementsAre(value1Index));
-    const vector<int>& matcher5Metrics = trackerToMetricMap[matcher5Index];
-    EXPECT_THAT(matcher5Metrics, UnorderedElementsAre(value3Index, value6Index));
-
-    // Verify event activation/deactivation maps.
-    ASSERT_EQ(activationAtomTrackerToMetricMap.size(), 0);
-    ASSERT_EQ(deactivationAtomTrackerToMetricMap.size(), 0);
-    ASSERT_EQ(metricsWithActivation.size(), 0);
-
-    // Verify tracker indices/ids/conditions/states are correct.
-    ValueMetricProducer* valueProducer1 =
-            static_cast<ValueMetricProducer*>(newMetricProducers[value1Index].get());
-    EXPECT_EQ(valueProducer1->getMetricId(), value1Id);
-    EXPECT_EQ(valueProducer1->mConditionTrackerIndex, predicate1Index);
-    EXPECT_EQ(valueProducer1->mCondition, ConditionState::kUnknown);
-    EXPECT_EQ(valueProducer1->mWhatMatcherIndex, matcher4Index);
-    ValueMetricProducer* valueProducer2 =
-            static_cast<ValueMetricProducer*>(newMetricProducers[value2Index].get());
-    EXPECT_EQ(valueProducer2->getMetricId(), value2Id);
-    EXPECT_EQ(valueProducer2->mConditionTrackerIndex, -1);
-    EXPECT_EQ(valueProducer2->mCondition, ConditionState::kTrue);
-    EXPECT_EQ(valueProducer2->mWhatMatcherIndex, matcher1Index);
-    ValueMetricProducer* valueProducer3 =
-            static_cast<ValueMetricProducer*>(newMetricProducers[value3Index].get());
-    EXPECT_EQ(valueProducer3->getMetricId(), value3Id);
-    EXPECT_EQ(valueProducer3->mConditionTrackerIndex, predicate2Index);
-    EXPECT_EQ(valueProducer3->mCondition, ConditionState::kUnknown);
-    EXPECT_EQ(valueProducer3->mWhatMatcherIndex, matcher5Index);
-    ValueMetricProducer* valueProducer4 =
-            static_cast<ValueMetricProducer*>(newMetricProducers[value4Index].get());
-    EXPECT_EQ(valueProducer4->getMetricId(), value4Id);
-    EXPECT_EQ(valueProducer4->mConditionTrackerIndex, -1);
-    EXPECT_EQ(valueProducer4->mCondition, ConditionState::kTrue);
-    EXPECT_EQ(valueProducer4->mWhatMatcherIndex, matcher3Index);
-    ValueMetricProducer* valueProducer6 =
-            static_cast<ValueMetricProducer*>(newMetricProducers[value6Index].get());
-    EXPECT_EQ(valueProducer6->getMetricId(), value6Id);
-    EXPECT_EQ(valueProducer6->mConditionTrackerIndex, predicate1Index);
-    EXPECT_EQ(valueProducer6->mCondition, ConditionState::kUnknown);
-    EXPECT_EQ(valueProducer6->mWhatMatcherIndex, matcher5Index);
-
-    sp<EventMatcherWizard> newMatcherWizard = valueProducer1->mEventMatcherWizard;
-    EXPECT_NE(newMatcherWizard, oldMatcherWizard);
-    EXPECT_EQ(newMatcherWizard->getStrongCount(), 6);
-    oldMetricProducers.clear();
-    // Only reference to the old wizard should be the one in the test.
-    EXPECT_EQ(oldMatcherWizard->getStrongCount(), 1);
-}
-
-TEST_F(ConfigUpdateTest, TestUpdateMetricActivations) {
-    StatsdConfig config;
-    // Add atom matchers
-    AtomMatcher matcher1 = CreateScreenTurnedOnAtomMatcher();
-    int64_t matcher1Id = matcher1.id();
-    *config.add_atom_matcher() = matcher1;
-
-    AtomMatcher matcher2 = CreateScreenTurnedOffAtomMatcher();
-    int64_t matcher2Id = matcher2.id();
-    *config.add_atom_matcher() = matcher2;
-
-    AtomMatcher matcher3 = CreateStartScheduledJobAtomMatcher();
-    int64_t matcher3Id = matcher3.id();
-    *config.add_atom_matcher() = matcher3;
-
-    AtomMatcher matcher4 = CreateFinishScheduledJobAtomMatcher();
-    int64_t matcher4Id = matcher4.id();
-    *config.add_atom_matcher() = matcher4;
-
-    // Add an event metric with multiple activations.
-    EventMetric event1 = createEventMetric("EVENT1", matcher1Id, nullopt);
-    int64_t event1Id = event1.id();
-    *config.add_event_metric() = event1;
-
-    int64_t matcher2TtlSec = 2, matcher3TtlSec = 3, matcher4TtlSec = 4;
-    MetricActivation metricActivation;
-    metricActivation.set_metric_id(event1Id);
-    EventActivation* activation = metricActivation.add_event_activation();
-    activation->set_atom_matcher_id(matcher2Id);
-    activation->set_ttl_seconds(matcher2TtlSec);
-    activation->set_activation_type(ACTIVATE_IMMEDIATELY);
-    activation->set_deactivation_atom_matcher_id(matcher1Id);
-    activation = metricActivation.add_event_activation();
-    activation->set_atom_matcher_id(matcher3Id);
-    activation->set_ttl_seconds(matcher3TtlSec);
-    activation->set_activation_type(ACTIVATE_ON_BOOT);
-    activation->set_deactivation_atom_matcher_id(matcher1Id);
-    activation = metricActivation.add_event_activation();
-    activation->set_atom_matcher_id(matcher4Id);
-    activation->set_ttl_seconds(matcher4TtlSec);
-    activation->set_activation_type(ACTIVATE_IMMEDIATELY);
-    activation->set_deactivation_atom_matcher_id(matcher2Id);
-    *config.add_metric_activation() = metricActivation;
-
-    EXPECT_TRUE(initConfig(config));
-
-    // Activate some of the event activations.
-    ASSERT_EQ(oldMetricProducers[0]->getMetricId(), event1Id);
-    int64_t matcher2StartNs = 12345;
-    oldMetricProducers[0]->activate(oldAtomMatchingTrackerMap[matcher2Id], matcher2StartNs);
-    int64_t matcher3StartNs = 23456;
-    oldMetricProducers[0]->activate(oldAtomMatchingTrackerMap[matcher3Id], matcher3StartNs);
-    EXPECT_TRUE(oldMetricProducers[0]->isActive());
-
-    // Map the matchers and predicates in reverse order to force the indices to change.
-    std::unordered_map<int64_t, int> newAtomMatchingTrackerMap;
-    const int matcher4Index = 0;
-    newAtomMatchingTrackerMap[matcher4Id] = 0;
-    const int matcher3Index = 1;
-    newAtomMatchingTrackerMap[matcher3Id] = 1;
-    const int matcher2Index = 2;
-    newAtomMatchingTrackerMap[matcher2Id] = 2;
-    const int matcher1Index = 3;
-    newAtomMatchingTrackerMap[matcher1Id] = 3;
-    // Use the existing matchers. A bit hacky, but saves code and we don't rely on them.
-    vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers(4);
-    std::reverse_copy(oldAtomMatchingTrackers.begin(), oldAtomMatchingTrackers.end(),
-                      newAtomMatchingTrackers.begin());
-    set<int64_t> replacedMatchers;
-
-    unordered_map<int64_t, int> newConditionTrackerMap;
-    vector<sp<ConditionTracker>> newConditionTrackers;
-    set<int64_t> replacedConditions;
-    vector<ConditionState> conditionCache;
-    unordered_map<int64_t, int> newMetricProducerMap;
-    vector<sp<MetricProducer>> newMetricProducers;
-    unordered_map<int, vector<int>> conditionToMetricMap;
-    unordered_map<int, vector<int>> trackerToMetricMap;
-    set<int64_t> noReportMetricIds;
-    unordered_map<int, vector<int>> activationAtomTrackerToMetricMap;
-    unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
-    vector<int> metricsWithActivation;
-    set<int64_t> replacedMetrics;
-    EXPECT_TRUE(updateMetrics(
-            key, config, /*timeBaseNs=*/123, /*currentTimeNs=*/12345, new StatsPullerManager(),
-            oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, replacedMatchers,
-            newAtomMatchingTrackers, newConditionTrackerMap, replacedConditions,
-            newConditionTrackers, conditionCache, /*stateAtomIdMap=*/{}, /*allStateGroupMaps=*/{},
-            /*replacedStates=*/{}, oldMetricProducerMap, oldMetricProducers, newMetricProducerMap,
-            newMetricProducers, conditionToMetricMap, trackerToMetricMap, noReportMetricIds,
-            activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
-            metricsWithActivation, replacedMetrics));
-
-    // Verify event activation/deactivation maps.
-    ASSERT_EQ(activationAtomTrackerToMetricMap.size(), 3);
-    EXPECT_THAT(activationAtomTrackerToMetricMap[matcher2Index], UnorderedElementsAre(0));
-    EXPECT_THAT(activationAtomTrackerToMetricMap[matcher3Index], UnorderedElementsAre(0));
-    EXPECT_THAT(activationAtomTrackerToMetricMap[matcher4Index], UnorderedElementsAre(0));
-    ASSERT_EQ(deactivationAtomTrackerToMetricMap.size(), 2);
-    EXPECT_THAT(deactivationAtomTrackerToMetricMap[matcher1Index], UnorderedElementsAre(0, 0));
-    EXPECT_THAT(deactivationAtomTrackerToMetricMap[matcher2Index], UnorderedElementsAre(0));
-    ASSERT_EQ(metricsWithActivation.size(), 1);
-    EXPECT_THAT(metricsWithActivation, UnorderedElementsAre(0));
-
-    // Verify mEventActivation and mEventDeactivation map of the producer.
-    sp<MetricProducer> producer = newMetricProducers[0];
-    EXPECT_TRUE(producer->isActive());
-    ASSERT_EQ(producer->mEventActivationMap.size(), 3);
-    shared_ptr<Activation> matcher2Activation = producer->mEventActivationMap[matcher2Index];
-    EXPECT_EQ(matcher2Activation->ttl_ns, matcher2TtlSec * NS_PER_SEC);
-    EXPECT_EQ(matcher2Activation->activationType, ACTIVATE_IMMEDIATELY);
-    EXPECT_EQ(matcher2Activation->state, kActive);
-    EXPECT_EQ(matcher2Activation->start_ns, matcher2StartNs);
-    shared_ptr<Activation> matcher3Activation = producer->mEventActivationMap[matcher3Index];
-    EXPECT_EQ(matcher3Activation->ttl_ns, matcher3TtlSec * NS_PER_SEC);
-    EXPECT_EQ(matcher3Activation->activationType, ACTIVATE_ON_BOOT);
-    EXPECT_EQ(matcher3Activation->state, kActiveOnBoot);
-    shared_ptr<Activation> matcher4Activation = producer->mEventActivationMap[matcher4Index];
-    EXPECT_EQ(matcher4Activation->ttl_ns, matcher4TtlSec * NS_PER_SEC);
-    EXPECT_EQ(matcher4Activation->activationType, ACTIVATE_IMMEDIATELY);
-    EXPECT_EQ(matcher4Activation->state, kNotActive);
-
-    ASSERT_EQ(producer->mEventDeactivationMap.size(), 2);
-    EXPECT_THAT(producer->mEventDeactivationMap[matcher1Index],
-                UnorderedElementsAre(matcher2Activation, matcher3Activation));
-    EXPECT_THAT(producer->mEventDeactivationMap[matcher2Index],
-                UnorderedElementsAre(matcher4Activation));
-}
-
-TEST_F(ConfigUpdateTest, TestUpdateMetricsMultipleTypes) {
-    StatsdConfig config;
-    // Add atom matchers/predicates/states. These are mostly needed for initStatsdConfig
-    AtomMatcher matcher1 = CreateScreenTurnedOnAtomMatcher();
-    int64_t matcher1Id = matcher1.id();
-    *config.add_atom_matcher() = matcher1;
-
-    AtomMatcher matcher2 = CreateScreenTurnedOffAtomMatcher();
-    int64_t matcher2Id = matcher2.id();
-    *config.add_atom_matcher() = matcher2;
-
-    AtomMatcher matcher3 = CreateTemperatureAtomMatcher();
-    int64_t matcher3Id = matcher3.id();
-    *config.add_atom_matcher() = matcher3;
-
-    Predicate predicate1 = CreateScreenIsOnPredicate();
-    int64_t predicate1Id = predicate1.id();
-    *config.add_predicate() = predicate1;
-
-    // Add a few count metrics.
-    // Will be preserved.
-    CountMetric countMetric = createCountMetric("COUNT1", matcher1Id, predicate1Id, {});
-    int64_t countMetricId = countMetric.id();
-    *config.add_count_metric() = countMetric;
-
-    // Will be replaced since matcher2 is replaced.
-    EventMetric eventMetric = createEventMetric("EVENT1", matcher2Id, nullopt);
-    int64_t eventMetricId = eventMetric.id();
-    *config.add_event_metric() = eventMetric;
-
-    // Will be replaced because the definition changes - a predicate is added.
-    GaugeMetric gaugeMetric = createGaugeMetric("GAUGE1", matcher3Id,
-                                                GaugeMetric::RANDOM_ONE_SAMPLE, nullopt, nullopt);
-    int64_t gaugeMetricId = gaugeMetric.id();
-    *config.add_gauge_metric() = gaugeMetric;
-
-    // Preserved.
-    ValueMetric valueMetric = createValueMetric("VALUE1", matcher3, predicate1Id, {});
-    int64_t valueMetricId = valueMetric.id();
-    *config.add_value_metric() = valueMetric;
-
-    // Preserved.
-    DurationMetric durationMetric = createDurationMetric("DURATION1", predicate1Id, nullopt, {});
-    int64_t durationMetricId = durationMetric.id();
-    *config.add_duration_metric() = durationMetric;
-
-    EXPECT_TRUE(initConfig(config));
-
-    // Used later to ensure the condition wizard is replaced. Get it before doing the update.
-    sp<ConditionWizard> oldConditionWizard = oldMetricProducers[0]->mWizard;
-    EXPECT_EQ(oldConditionWizard->getStrongCount(), 6);
-
-    // Mark matcher 2 as replaced. Causes eventMetric to be replaced.
-    set<int64_t> replacedMatchers;
-    replacedMatchers.insert(matcher2Id);
-
-    // Add predicate1 as a predicate on gaugeMetric, causing it to be replaced.
-    gaugeMetric.set_condition(predicate1Id);
-
-    // Map the matchers and predicates in reverse order to force the indices to change.
-    std::unordered_map<int64_t, int> newAtomMatchingTrackerMap;
-    const int matcher3Index = 0;
-    newAtomMatchingTrackerMap[matcher3Id] = 0;
-    const int matcher2Index = 1;
-    newAtomMatchingTrackerMap[matcher2Id] = 1;
-    const int matcher1Index = 2;
-    newAtomMatchingTrackerMap[matcher1Id] = 2;
-    // Use the existing matchers. A bit hacky, but saves code and we don't rely on them.
-    vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers(3);
-    std::reverse_copy(oldAtomMatchingTrackers.begin(), oldAtomMatchingTrackers.end(),
-                      newAtomMatchingTrackers.begin());
-
-    std::unordered_map<int64_t, int> newConditionTrackerMap;
-    const int predicate1Index = 0;
-    newConditionTrackerMap[predicate1Id] = 0;
-    // Use the existing conditionTrackers. A bit hacky, but saves code and we don't rely on them.
-    vector<sp<ConditionTracker>> newConditionTrackers(1);
-    std::reverse_copy(oldConditionTrackers.begin(), oldConditionTrackers.end(),
-                      newConditionTrackers.begin());
-    vector<ConditionState> conditionCache = {ConditionState::kUnknown};
-
-    // The order matters. we parse in the order of: count, duration, event, value, gauge.
-    StatsdConfig newConfig;
-    *newConfig.add_count_metric() = countMetric;
-    const int countMetricIndex = 0;
-    *newConfig.add_duration_metric() = durationMetric;
-    const int durationMetricIndex = 1;
-    *newConfig.add_event_metric() = eventMetric;
-    const int eventMetricIndex = 2;
-    *newConfig.add_value_metric() = valueMetric;
-    const int valueMetricIndex = 3;
-    *newConfig.add_gauge_metric() = gaugeMetric;
-    const int gaugeMetricIndex = 4;
-
-    // Add the predicate since duration metric needs it.
-    *newConfig.add_predicate() = predicate1;
-
-    // Output data structures to validate.
-    unordered_map<int64_t, int> newMetricProducerMap;
-    vector<sp<MetricProducer>> newMetricProducers;
-    unordered_map<int, vector<int>> conditionToMetricMap;
-    unordered_map<int, vector<int>> trackerToMetricMap;
-    set<int64_t> noReportMetricIds;
-    unordered_map<int, vector<int>> activationAtomTrackerToMetricMap;
-    unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
-    vector<int> metricsWithActivation;
-    set<int64_t> replacedMetrics;
-    EXPECT_TRUE(updateMetrics(
-            key, newConfig, /*timeBaseNs=*/123, /*currentTimeNs=*/12345, new StatsPullerManager(),
-            oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, replacedMatchers,
-            newAtomMatchingTrackers, newConditionTrackerMap, /*replacedConditions=*/{},
-            newConditionTrackers, conditionCache, /*stateAtomIdMap*/ {}, /*allStateGroupMaps=*/{},
-            /*replacedStates=*/{}, oldMetricProducerMap, oldMetricProducers, newMetricProducerMap,
-            newMetricProducers, conditionToMetricMap, trackerToMetricMap, noReportMetricIds,
-            activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
-            metricsWithActivation, replacedMetrics));
-
-    unordered_map<int64_t, int> expectedMetricProducerMap = {
-            {countMetricId, countMetricIndex}, {durationMetricId, durationMetricIndex},
-            {eventMetricId, eventMetricIndex}, {valueMetricId, valueMetricIndex},
-            {gaugeMetricId, gaugeMetricIndex},
-    };
-    EXPECT_THAT(newMetricProducerMap, ContainerEq(expectedMetricProducerMap));
-
-    EXPECT_EQ(replacedMetrics, set<int64_t>({eventMetricId, gaugeMetricId}));
-
-    // Make sure preserved metrics are the same.
-    ASSERT_EQ(newMetricProducers.size(), 5);
-    EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(countMetricId)],
-              newMetricProducers[newMetricProducerMap.at(countMetricId)]);
-    EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(durationMetricId)],
-              newMetricProducers[newMetricProducerMap.at(durationMetricId)]);
-    EXPECT_EQ(oldMetricProducers[oldMetricProducerMap.at(valueMetricId)],
-              newMetricProducers[newMetricProducerMap.at(valueMetricId)]);
-
-    // Make sure replaced metrics are different.
-    EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(eventMetricId)],
-              newMetricProducers[newMetricProducerMap.at(eventMetricId)]);
-    EXPECT_NE(oldMetricProducers[oldMetricProducerMap.at(gaugeMetricId)],
-              newMetricProducers[newMetricProducerMap.at(gaugeMetricId)]);
-
-    // Verify the conditionToMetricMap.
-    ASSERT_EQ(conditionToMetricMap.size(), 1);
-    const vector<int>& condition1Metrics = conditionToMetricMap[predicate1Index];
-    EXPECT_THAT(condition1Metrics,
-                UnorderedElementsAre(countMetricIndex, gaugeMetricIndex, valueMetricIndex));
-
-    // Verify the trackerToMetricMap.
-    ASSERT_EQ(trackerToMetricMap.size(), 3);
-    const vector<int>& matcher1Metrics = trackerToMetricMap[matcher1Index];
-    EXPECT_THAT(matcher1Metrics, UnorderedElementsAre(countMetricIndex, durationMetricIndex));
-    const vector<int>& matcher2Metrics = trackerToMetricMap[matcher2Index];
-    EXPECT_THAT(matcher2Metrics, UnorderedElementsAre(eventMetricIndex, durationMetricIndex));
-    const vector<int>& matcher3Metrics = trackerToMetricMap[matcher3Index];
-    EXPECT_THAT(matcher3Metrics, UnorderedElementsAre(gaugeMetricIndex, valueMetricIndex));
-
-    // Verify event activation/deactivation maps.
-    ASSERT_EQ(activationAtomTrackerToMetricMap.size(), 0);
-    ASSERT_EQ(deactivationAtomTrackerToMetricMap.size(), 0);
-    ASSERT_EQ(metricsWithActivation.size(), 0);
-
-    // Verify tracker indices/ids/conditions are correct.
-    EXPECT_EQ(newMetricProducers[countMetricIndex]->getMetricId(), countMetricId);
-    EXPECT_EQ(newMetricProducers[countMetricIndex]->mConditionTrackerIndex, predicate1Index);
-    EXPECT_EQ(newMetricProducers[countMetricIndex]->mCondition, ConditionState::kUnknown);
-    EXPECT_EQ(newMetricProducers[durationMetricIndex]->getMetricId(), durationMetricId);
-    EXPECT_EQ(newMetricProducers[durationMetricIndex]->mConditionTrackerIndex, -1);
-    EXPECT_EQ(newMetricProducers[durationMetricIndex]->mCondition, ConditionState::kTrue);
-    EXPECT_EQ(newMetricProducers[eventMetricIndex]->getMetricId(), eventMetricId);
-    EXPECT_EQ(newMetricProducers[eventMetricIndex]->mConditionTrackerIndex, -1);
-    EXPECT_EQ(newMetricProducers[eventMetricIndex]->mCondition, ConditionState::kTrue);
-    EXPECT_EQ(newMetricProducers[gaugeMetricIndex]->getMetricId(), gaugeMetricId);
-    EXPECT_EQ(newMetricProducers[gaugeMetricIndex]->mConditionTrackerIndex, predicate1Index);
-    EXPECT_EQ(newMetricProducers[gaugeMetricIndex]->mCondition, ConditionState::kUnknown);
-
-    sp<ConditionWizard> newConditionWizard = newMetricProducers[0]->mWizard;
-    EXPECT_NE(newConditionWizard, oldConditionWizard);
-    EXPECT_EQ(newConditionWizard->getStrongCount(), 6);
-    oldMetricProducers.clear();
-    // Only reference to the old wizard should be the one in the test.
-    EXPECT_EQ(oldConditionWizard->getStrongCount(), 1);
-}
-
-TEST_F(ConfigUpdateTest, TestAlertPreserve) {
-    StatsdConfig config;
-    AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
-    *config.add_atom_matcher() = whatMatcher;
-
-    *config.add_count_metric() = createCountMetric("VALUE1", whatMatcher.id(), nullopt, {});
-
-    Alert alert = createAlert("Alert1", config.count_metric(0).id(), 1, 1);
-    *config.add_alert() = alert;
-    EXPECT_TRUE(initConfig(config));
-
-    UpdateStatus updateStatus = UPDATE_UNKNOWN;
-    EXPECT_TRUE(determineAlertUpdateStatus(alert, oldAlertTrackerMap, oldAnomalyTrackers,
-                                           /*replacedMetrics*/ {}, updateStatus));
-    EXPECT_EQ(updateStatus, UPDATE_PRESERVE);
-}
-
-TEST_F(ConfigUpdateTest, TestAlertMetricChanged) {
-    StatsdConfig config;
-    AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
-    *config.add_atom_matcher() = whatMatcher;
-
-    CountMetric metric = createCountMetric("VALUE1", whatMatcher.id(), nullopt, {});
-    *config.add_count_metric() = metric;
-
-    Alert alert = createAlert("Alert1", config.count_metric(0).id(), 1, 1);
-    *config.add_alert() = alert;
-    EXPECT_TRUE(initConfig(config));
-
-    UpdateStatus updateStatus = UPDATE_UNKNOWN;
-    EXPECT_TRUE(determineAlertUpdateStatus(alert, oldAlertTrackerMap, oldAnomalyTrackers,
-                                           /*replacedMetrics*/ {metric.id()}, updateStatus));
-    EXPECT_EQ(updateStatus, UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestAlertDefinitionChanged) {
-    StatsdConfig config;
-    AtomMatcher whatMatcher = CreateScreenBrightnessChangedAtomMatcher();
-    *config.add_atom_matcher() = whatMatcher;
-
-    *config.add_count_metric() = createCountMetric("VALUE1", whatMatcher.id(), nullopt, {});
-
-    Alert alert = createAlert("Alert1", config.count_metric(0).id(), 1, 1);
-    *config.add_alert() = alert;
-    EXPECT_TRUE(initConfig(config));
-
-    alert.set_num_buckets(2);
-
-    UpdateStatus updateStatus = UPDATE_UNKNOWN;
-    EXPECT_TRUE(determineAlertUpdateStatus(alert, oldAlertTrackerMap, oldAnomalyTrackers,
-                                           /*replacedMetrics*/ {}, updateStatus));
-    EXPECT_EQ(updateStatus, UPDATE_REPLACE);
-}
-
-TEST_F(ConfigUpdateTest, TestUpdateAlerts) {
-    StatsdConfig config;
-    // Add atom matchers/predicates/metrics. These are mostly needed for initStatsdConfig
-    *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
-    *config.add_predicate() = CreateScreenIsOnPredicate();
-
-    CountMetric countMetric = createCountMetric("COUNT1", config.atom_matcher(0).id(), nullopt, {});
-    int64_t countMetricId = countMetric.id();
-    *config.add_count_metric() = countMetric;
-
-    DurationMetric durationMetric =
-            createDurationMetric("DURATION1", config.predicate(0).id(), nullopt, {});
-    int64_t durationMetricId = durationMetric.id();
-    *config.add_duration_metric() = durationMetric;
-
-    // Add alerts.
-    // Preserved.
-    Alert alert1 = createAlert("Alert1", durationMetricId, /*buckets*/ 1, /*triggerSum*/ 5000);
-    int64_t alert1Id = alert1.id();
-    *config.add_alert() = alert1;
-
-    // Replaced.
-    Alert alert2 = createAlert("Alert2", countMetricId, /*buckets*/ 1, /*triggerSum*/ 2);
-    int64_t alert2Id = alert2.id();
-    *config.add_alert() = alert2;
-
-    // Replaced.
-    Alert alert3 = createAlert("Alert3", durationMetricId, /*buckets*/ 3, /*triggerSum*/ 5000);
-    int64_t alert3Id = alert3.id();
-    *config.add_alert() = alert3;
-
-    // Add Subscriptions.
-    Subscription subscription1 = createSubscription("S1", Subscription::ALERT, alert1Id);
-    *config.add_subscription() = subscription1;
-    Subscription subscription2 = createSubscription("S2", Subscription::ALERT, alert1Id);
-    *config.add_subscription() = subscription2;
-    Subscription subscription3 = createSubscription("S3", Subscription::ALERT, alert2Id);
-    *config.add_subscription() = subscription3;
-
-    EXPECT_TRUE(initConfig(config));
-
-    // Add a duration tracker to the duration metric to ensure durationTrackers are updated
-    // with the proper anomalyTrackers.
-    unique_ptr<LogEvent> event = CreateScreenStateChangedEvent(
-            timeBaseNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-    oldMetricProducers[1]->onMatchedLogEvent(0, *event.get());
-
-    // Change the count metric. Causes alert2 to be replaced.
-    config.mutable_count_metric(0)->set_bucket(ONE_DAY);
-    // Change num buckets on alert3, causing replacement.
-    alert3.set_num_buckets(5);
-
-    // New alert.
-    Alert alert4 = createAlert("Alert4", durationMetricId, /*buckets*/ 3, /*triggerSum*/ 10000);
-    int64_t alert4Id = alert4.id();
-
-    // Move subscription2 to be on alert2 and make a new subscription.
-    subscription2.set_rule_id(alert2Id);
-    Subscription subscription4 = createSubscription("S4", Subscription::ALERT, alert2Id);
-
-    // Create the new config. Modify the old one to avoid adding the matchers/predicates.
-    // Add alerts in different order so the map is changed.
-    config.clear_alert();
-    *config.add_alert() = alert4;
-    const int alert4Index = 0;
-    *config.add_alert() = alert3;
-    const int alert3Index = 1;
-    *config.add_alert() = alert1;
-    const int alert1Index = 2;
-    *config.add_alert() = alert2;
-    const int alert2Index = 3;
-
-    // Subscription3 is removed.
-    config.clear_subscription();
-    *config.add_subscription() = subscription4;
-    *config.add_subscription() = subscription2;
-    *config.add_subscription() = subscription1;
-
-    // Output data structures from update metrics. Don't care about the outputs besides
-    // replacedMetrics, but need to do this so that the metrics clear their anomaly trackers.
-    unordered_map<int64_t, int> newMetricProducerMap;
-    vector<sp<MetricProducer>> newMetricProducers;
-    unordered_map<int, vector<int>> conditionToMetricMap;
-    unordered_map<int, vector<int>> trackerToMetricMap;
-    set<int64_t> noReportMetricIds;
-    unordered_map<int, vector<int>> activationAtomTrackerToMetricMap;
-    unordered_map<int, vector<int>> deactivationAtomTrackerToMetricMap;
-    vector<int> metricsWithActivation;
-    set<int64_t> replacedMetrics;
-    EXPECT_TRUE(updateMetrics(
-            key, config, /*timeBaseNs=*/123, /*currentTimeNs=*/12345, new StatsPullerManager(),
-            oldAtomMatchingTrackerMap, oldAtomMatchingTrackerMap, /*replacedMatchers*/ {},
-            oldAtomMatchingTrackers, oldConditionTrackerMap, /*replacedConditions=*/{},
-            oldConditionTrackers, {ConditionState::kUnknown}, /*stateAtomIdMap*/ {},
-            /*allStateGroupMaps=*/{},
-            /*replacedStates=*/{}, oldMetricProducerMap, oldMetricProducers, newMetricProducerMap,
-            newMetricProducers, conditionToMetricMap, trackerToMetricMap, noReportMetricIds,
-            activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
-            metricsWithActivation, replacedMetrics));
-
-    EXPECT_EQ(replacedMetrics, set<int64_t>({countMetricId}));
-
-    unordered_map<int64_t, int> newAlertTrackerMap;
-    vector<sp<AnomalyTracker>> newAnomalyTrackers;
-    EXPECT_TRUE(updateAlerts(config, newMetricProducerMap, replacedMetrics, oldAlertTrackerMap,
-                             oldAnomalyTrackers, anomalyAlarmMonitor, newMetricProducers,
-                             newAlertTrackerMap, newAnomalyTrackers));
-
-    unordered_map<int64_t, int> expectedAlertMap = {
-            {alert1Id, alert1Index},
-            {alert2Id, alert2Index},
-            {alert3Id, alert3Index},
-            {alert4Id, alert4Index},
-    };
-    EXPECT_THAT(newAlertTrackerMap, ContainerEq(expectedAlertMap));
-
-    // Make sure preserved alerts are the same.
-    ASSERT_EQ(newAnomalyTrackers.size(), 4);
-    EXPECT_EQ(oldAnomalyTrackers[oldAlertTrackerMap.at(alert1Id)],
-              newAnomalyTrackers[newAlertTrackerMap.at(alert1Id)]);
-
-    // Make sure replaced alerts are different.
-    EXPECT_NE(oldAnomalyTrackers[oldAlertTrackerMap.at(alert2Id)],
-              newAnomalyTrackers[newAlertTrackerMap.at(alert2Id)]);
-    EXPECT_NE(oldAnomalyTrackers[oldAlertTrackerMap.at(alert3Id)],
-              newAnomalyTrackers[newAlertTrackerMap.at(alert3Id)]);
-
-    // Verify the alerts have the correct anomaly trackers.
-    ASSERT_EQ(newMetricProducers.size(), 2);
-    EXPECT_THAT(newMetricProducers[0]->mAnomalyTrackers,
-                UnorderedElementsAre(newAnomalyTrackers[alert2Index]));
-    // For durationMetric, make sure the duration trackers get the updated anomalyTrackers.
-    DurationMetricProducer* durationProducer =
-            static_cast<DurationMetricProducer*>(newMetricProducers[1].get());
-    EXPECT_THAT(
-            durationProducer->mAnomalyTrackers,
-            UnorderedElementsAre(newAnomalyTrackers[alert1Index], newAnomalyTrackers[alert3Index],
-                                 newAnomalyTrackers[alert4Index]));
-    ASSERT_EQ(durationProducer->mCurrentSlicedDurationTrackerMap.size(), 1);
-    for (const auto& durationTrackerIt : durationProducer->mCurrentSlicedDurationTrackerMap) {
-        EXPECT_EQ(durationTrackerIt.second->mAnomalyTrackers, durationProducer->mAnomalyTrackers);
-    }
-
-    // Verify alerts have the correct subscriptions. Use subscription id as proxy for equivalency.
-    vector<int64_t> alert1Subscriptions;
-    for (const Subscription& subscription : newAnomalyTrackers[alert1Index]->mSubscriptions) {
-        alert1Subscriptions.push_back(subscription.id());
-    }
-    EXPECT_THAT(alert1Subscriptions, UnorderedElementsAre(subscription1.id()));
-    vector<int64_t> alert2Subscriptions;
-    for (const Subscription& subscription : newAnomalyTrackers[alert2Index]->mSubscriptions) {
-        alert2Subscriptions.push_back(subscription.id());
-    }
-    EXPECT_THAT(alert2Subscriptions, UnorderedElementsAre(subscription2.id(), subscription4.id()));
-    EXPECT_THAT(newAnomalyTrackers[alert3Index]->mSubscriptions, IsEmpty());
-    EXPECT_THAT(newAnomalyTrackers[alert4Index]->mSubscriptions, IsEmpty());
-}
-
-TEST_F(ConfigUpdateTest, TestUpdateAlarms) {
-    StatsdConfig config;
-    // Add alarms.
-    Alarm alarm1 = createAlarm("Alarm1", /*offset*/ 1 * MS_PER_SEC, /*period*/ 50 * MS_PER_SEC);
-    int64_t alarm1Id = alarm1.id();
-    *config.add_alarm() = alarm1;
-
-    Alarm alarm2 = createAlarm("Alarm2", /*offset*/ 1 * MS_PER_SEC, /*period*/ 2000 * MS_PER_SEC);
-    int64_t alarm2Id = alarm2.id();
-    *config.add_alarm() = alarm2;
-
-    Alarm alarm3 = createAlarm("Alarm3", /*offset*/ 10 * MS_PER_SEC, /*period*/ 5000 * MS_PER_SEC);
-    int64_t alarm3Id = alarm3.id();
-    *config.add_alarm() = alarm3;
-
-    // Add Subscriptions.
-    Subscription subscription1 = createSubscription("S1", Subscription::ALARM, alarm1Id);
-    *config.add_subscription() = subscription1;
-    Subscription subscription2 = createSubscription("S2", Subscription::ALARM, alarm1Id);
-    *config.add_subscription() = subscription2;
-    Subscription subscription3 = createSubscription("S3", Subscription::ALARM, alarm2Id);
-    *config.add_subscription() = subscription3;
-
-    EXPECT_TRUE(initConfig(config));
-
-    ASSERT_EQ(oldAlarmTrackers.size(), 3);
-    // Config is created at statsd start time, so just add the offsets.
-    EXPECT_EQ(oldAlarmTrackers[0]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 1);
-    EXPECT_EQ(oldAlarmTrackers[1]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 1);
-    EXPECT_EQ(oldAlarmTrackers[2]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 10);
-
-    // Change alarm2/alarm3.
-    config.mutable_alarm(1)->set_offset_millis(5 * MS_PER_SEC);
-    config.mutable_alarm(2)->set_period_millis(10000 * MS_PER_SEC);
-
-    // Move subscription2 to be on alarm2 and make a new subscription.
-    config.mutable_subscription(1)->set_rule_id(alarm2Id);
-    Subscription subscription4 = createSubscription("S4", Subscription::ALARM, alarm1Id);
-    *config.add_subscription() = subscription4;
-
-    // Update time is 2 seconds after the base time.
-    int64_t currentTimeNs = timeBaseNs + 2 * NS_PER_SEC;
-    vector<sp<AlarmTracker>> newAlarmTrackers;
-    EXPECT_TRUE(initAlarms(config, key, periodicAlarmMonitor, timeBaseNs, currentTimeNs,
-                           newAlarmTrackers));
-
-    ASSERT_EQ(newAlarmTrackers.size(), 3);
-    // Config is updated 2 seconds after statsd start
-    // The offset has passed for alarm1, but not for alarms 2/3.
-    EXPECT_EQ(newAlarmTrackers[0]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 1 + 50);
-    EXPECT_EQ(newAlarmTrackers[1]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 5);
-    EXPECT_EQ(newAlarmTrackers[2]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 10);
-
-    // Verify alarms have the correct subscriptions. Use subscription id as proxy for equivalency.
-    vector<int64_t> alarm1Subscriptions;
-    for (const Subscription& subscription : newAlarmTrackers[0]->mSubscriptions) {
-        alarm1Subscriptions.push_back(subscription.id());
-    }
-    EXPECT_THAT(alarm1Subscriptions, UnorderedElementsAre(subscription1.id(), subscription4.id()));
-    vector<int64_t> alarm2Subscriptions;
-    for (const Subscription& subscription : newAlarmTrackers[1]->mSubscriptions) {
-        alarm2Subscriptions.push_back(subscription.id());
-    }
-    EXPECT_THAT(alarm2Subscriptions, UnorderedElementsAre(subscription2.id(), subscription3.id()));
-    EXPECT_THAT(newAlarmTrackers[2]->mSubscriptions, IsEmpty());
-
-    // Verify the alarm monitor is updated accordingly once the old alarms are removed.
-    // Alarm2 fires the earliest.
-    oldAlarmTrackers.clear();
-    EXPECT_EQ(periodicAlarmMonitor->getRegisteredAlarmTimeSec(), timeBaseNs / NS_PER_SEC + 5);
-
-    // Do another update 60 seconds after config creation time, after the offsets of each alarm.
-    currentTimeNs = timeBaseNs + 60 * NS_PER_SEC;
-    newAlarmTrackers.clear();
-    EXPECT_TRUE(initAlarms(config, key, periodicAlarmMonitor, timeBaseNs, currentTimeNs,
-                           newAlarmTrackers));
-
-    ASSERT_EQ(newAlarmTrackers.size(), 3);
-    // Config is updated one minute after statsd start.
-    // Two periods have passed for alarm 1, one has passed for alarms2/3.
-    EXPECT_EQ(newAlarmTrackers[0]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 1 + 2 * 50);
-    EXPECT_EQ(newAlarmTrackers[1]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 5 + 2000);
-    EXPECT_EQ(newAlarmTrackers[2]->getAlarmTimestampSec(), timeBaseNs / NS_PER_SEC + 10 + 10000);
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp b/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp
deleted file mode 100644
index 9ab7e47..0000000
--- a/cmds/statsd/tests/metrics/parsing_utils/metrics_manager_util_test.cpp
+++ /dev/null
@@ -1,928 +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.
-
-#include "src/metrics/parsing_utils/metrics_manager_util.h"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <private/android_filesystem_config.h>
-#include <stdio.h>
-
-#include <set>
-#include <unordered_map>
-#include <vector>
-
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "src/condition/ConditionTracker.h"
-#include "src/matchers/AtomMatchingTracker.h"
-#include "src/metrics/CountMetricProducer.h"
-#include "src/metrics/DurationMetricProducer.h"
-#include "src/metrics/GaugeMetricProducer.h"
-#include "src/metrics/MetricProducer.h"
-#include "src/metrics/ValueMetricProducer.h"
-#include "src/state/StateManager.h"
-#include "tests/metrics/metrics_test_helper.h"
-#include "tests/statsd_test_util.h"
-
-using namespace testing;
-using android::sp;
-using android::os::statsd::Predicate;
-using std::map;
-using std::set;
-using std::unordered_map;
-using std::vector;
-
-#ifdef __ANDROID__
-
-namespace android {
-namespace os {
-namespace statsd {
-
-namespace {
-const ConfigKey kConfigKey(0, 12345);
-const long kAlertId = 3;
-
-const long timeBaseSec = 1000;
-
-StatsdConfig buildGoodConfig() {
-    StatsdConfig config;
-    config.set_id(12345);
-
-    AtomMatcher* eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
-
-    SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
-    simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
-    simpleAtomMatcher->add_field_value_matcher()->set_field(
-            1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
-    simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int(
-            2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
-
-    eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_id(StringToId("SCREEN_IS_OFF"));
-
-    simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
-    simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
-    simpleAtomMatcher->add_field_value_matcher()->set_field(
-            1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
-    simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int(
-            1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/);
-
-    eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF"));
-
-    AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
-    combination->set_operation(LogicalOperation::OR);
-    combination->add_matcher(StringToId("SCREEN_IS_ON"));
-    combination->add_matcher(StringToId("SCREEN_IS_OFF"));
-
-    CountMetric* metric = config.add_count_metric();
-    metric->set_id(3);
-    metric->set_what(StringToId("SCREEN_IS_ON"));
-    metric->set_bucket(ONE_MINUTE);
-    metric->mutable_dimensions_in_what()->set_field(2 /*SCREEN_STATE_CHANGE*/);
-    metric->mutable_dimensions_in_what()->add_child()->set_field(1);
-
-    config.add_no_report_metric(3);
-
-    auto alert = config.add_alert();
-    alert->set_id(kAlertId);
-    alert->set_metric_id(3);
-    alert->set_num_buckets(10);
-    alert->set_refractory_period_secs(100);
-    alert->set_trigger_if_sum_gt(100);
-    return config;
-}
-
-StatsdConfig buildCircleMatchers() {
-    StatsdConfig config;
-    config.set_id(12345);
-
-    AtomMatcher* eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
-
-    SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
-    simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
-    simpleAtomMatcher->add_field_value_matcher()->set_field(
-            1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
-    simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int(
-            2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
-
-    eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF"));
-
-    AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
-    combination->set_operation(LogicalOperation::OR);
-    combination->add_matcher(StringToId("SCREEN_IS_ON"));
-    // Circle dependency
-    combination->add_matcher(StringToId("SCREEN_ON_OR_OFF"));
-
-    return config;
-}
-
-StatsdConfig buildAlertWithUnknownMetric() {
-    StatsdConfig config;
-    config.set_id(12345);
-
-    AtomMatcher* eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
-
-    CountMetric* metric = config.add_count_metric();
-    metric->set_id(3);
-    metric->set_what(StringToId("SCREEN_IS_ON"));
-    metric->set_bucket(ONE_MINUTE);
-    metric->mutable_dimensions_in_what()->set_field(2 /*SCREEN_STATE_CHANGE*/);
-    metric->mutable_dimensions_in_what()->add_child()->set_field(1);
-
-    auto alert = config.add_alert();
-    alert->set_id(3);
-    alert->set_metric_id(2);
-    alert->set_num_buckets(10);
-    alert->set_refractory_period_secs(100);
-    alert->set_trigger_if_sum_gt(100);
-    return config;
-}
-
-StatsdConfig buildMissingMatchers() {
-    StatsdConfig config;
-    config.set_id(12345);
-
-    AtomMatcher* eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
-
-    SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
-    simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
-    simpleAtomMatcher->add_field_value_matcher()->set_field(
-            1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
-    simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int(
-            2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
-
-    eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_id(StringToId("SCREEN_ON_OR_OFF"));
-
-    AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
-    combination->set_operation(LogicalOperation::OR);
-    combination->add_matcher(StringToId("SCREEN_IS_ON"));
-    // undefined matcher
-    combination->add_matcher(StringToId("ABC"));
-
-    return config;
-}
-
-StatsdConfig buildMissingPredicate() {
-    StatsdConfig config;
-    config.set_id(12345);
-
-    CountMetric* metric = config.add_count_metric();
-    metric->set_id(3);
-    metric->set_what(StringToId("SCREEN_EVENT"));
-    metric->set_bucket(ONE_MINUTE);
-    metric->set_condition(StringToId("SOME_CONDITION"));
-
-    AtomMatcher* eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_id(StringToId("SCREEN_EVENT"));
-
-    SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
-    simpleAtomMatcher->set_atom_id(2);
-
-    return config;
-}
-
-StatsdConfig buildDimensionMetricsWithMultiTags() {
-    StatsdConfig config;
-    config.set_id(12345);
-
-    AtomMatcher* eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_id(StringToId("BATTERY_VERY_LOW"));
-    SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
-    simpleAtomMatcher->set_atom_id(2);
-
-    eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_id(StringToId("BATTERY_VERY_VERY_LOW"));
-    simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
-    simpleAtomMatcher->set_atom_id(3);
-
-    eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_id(StringToId("BATTERY_LOW"));
-
-    AtomMatcher_Combination* combination = eventMatcher->mutable_combination();
-    combination->set_operation(LogicalOperation::OR);
-    combination->add_matcher(StringToId("BATTERY_VERY_LOW"));
-    combination->add_matcher(StringToId("BATTERY_VERY_VERY_LOW"));
-
-    // Count process state changes, slice by uid, while SCREEN_IS_OFF
-    CountMetric* metric = config.add_count_metric();
-    metric->set_id(3);
-    metric->set_what(StringToId("BATTERY_LOW"));
-    metric->set_bucket(ONE_MINUTE);
-    // This case is interesting. We want to dimension across two atoms.
-    metric->mutable_dimensions_in_what()->add_child()->set_field(1);
-
-    auto alert = config.add_alert();
-    alert->set_id(kAlertId);
-    alert->set_metric_id(3);
-    alert->set_num_buckets(10);
-    alert->set_refractory_period_secs(100);
-    alert->set_trigger_if_sum_gt(100);
-    return config;
-}
-
-StatsdConfig buildCirclePredicates() {
-    StatsdConfig config;
-    config.set_id(12345);
-
-    AtomMatcher* eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_id(StringToId("SCREEN_IS_ON"));
-
-    SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
-    simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
-    simpleAtomMatcher->add_field_value_matcher()->set_field(
-            1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
-    simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int(
-            2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
-
-    eventMatcher = config.add_atom_matcher();
-    eventMatcher->set_id(StringToId("SCREEN_IS_OFF"));
-
-    simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
-    simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/);
-    simpleAtomMatcher->add_field_value_matcher()->set_field(
-            1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
-    simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int(
-            1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/);
-
-    auto condition = config.add_predicate();
-    condition->set_id(StringToId("SCREEN_IS_ON"));
-    SimplePredicate* simplePredicate = condition->mutable_simple_predicate();
-    simplePredicate->set_start(StringToId("SCREEN_IS_ON"));
-    simplePredicate->set_stop(StringToId("SCREEN_IS_OFF"));
-
-    condition = config.add_predicate();
-    condition->set_id(StringToId("SCREEN_IS_EITHER_ON_OFF"));
-
-    Predicate_Combination* combination = condition->mutable_combination();
-    combination->set_operation(LogicalOperation::OR);
-    combination->add_predicate(StringToId("SCREEN_IS_ON"));
-    combination->add_predicate(StringToId("SCREEN_IS_EITHER_ON_OFF"));
-
-    return config;
-}
-
-StatsdConfig buildConfigWithDifferentPredicates() {
-    StatsdConfig config;
-    config.set_id(12345);
-
-    auto pulledAtomMatcher =
-            CreateSimpleAtomMatcher("SUBSYSTEM_SLEEP", util::SUBSYSTEM_SLEEP_STATE);
-    *config.add_atom_matcher() = pulledAtomMatcher;
-    auto screenOnAtomMatcher = CreateScreenTurnedOnAtomMatcher();
-    *config.add_atom_matcher() = screenOnAtomMatcher;
-    auto screenOffAtomMatcher = CreateScreenTurnedOffAtomMatcher();
-    *config.add_atom_matcher() = screenOffAtomMatcher;
-    auto batteryNoneAtomMatcher = CreateBatteryStateNoneMatcher();
-    *config.add_atom_matcher() = batteryNoneAtomMatcher;
-    auto batteryUsbAtomMatcher = CreateBatteryStateUsbMatcher();
-    *config.add_atom_matcher() = batteryUsbAtomMatcher;
-
-    // Simple condition with InitialValue set to default (unknown).
-    auto screenOnUnknownPredicate = CreateScreenIsOnPredicate();
-    *config.add_predicate() = screenOnUnknownPredicate;
-
-    // Simple condition with InitialValue set to false.
-    auto screenOnFalsePredicate = config.add_predicate();
-    screenOnFalsePredicate->set_id(StringToId("ScreenIsOnInitialFalse"));
-    SimplePredicate* simpleScreenOnFalsePredicate =
-            screenOnFalsePredicate->mutable_simple_predicate();
-    simpleScreenOnFalsePredicate->set_start(screenOnAtomMatcher.id());
-    simpleScreenOnFalsePredicate->set_stop(screenOffAtomMatcher.id());
-    simpleScreenOnFalsePredicate->set_initial_value(SimplePredicate_InitialValue_FALSE);
-
-    // Simple condition with InitialValue set to false.
-    auto onBatteryFalsePredicate = config.add_predicate();
-    onBatteryFalsePredicate->set_id(StringToId("OnBatteryInitialFalse"));
-    SimplePredicate* simpleOnBatteryFalsePredicate =
-            onBatteryFalsePredicate->mutable_simple_predicate();
-    simpleOnBatteryFalsePredicate->set_start(batteryNoneAtomMatcher.id());
-    simpleOnBatteryFalsePredicate->set_stop(batteryUsbAtomMatcher.id());
-    simpleOnBatteryFalsePredicate->set_initial_value(SimplePredicate_InitialValue_FALSE);
-
-    // Combination condition with both simple condition InitialValues set to false.
-    auto screenOnFalseOnBatteryFalsePredicate = config.add_predicate();
-    screenOnFalseOnBatteryFalsePredicate->set_id(StringToId("ScreenOnFalseOnBatteryFalse"));
-    screenOnFalseOnBatteryFalsePredicate->mutable_combination()->set_operation(
-            LogicalOperation::AND);
-    addPredicateToPredicateCombination(*screenOnFalsePredicate,
-                                       screenOnFalseOnBatteryFalsePredicate);
-    addPredicateToPredicateCombination(*onBatteryFalsePredicate,
-                                       screenOnFalseOnBatteryFalsePredicate);
-
-    // Combination condition with one simple condition InitialValue set to unknown and one set to
-    // false.
-    auto screenOnUnknownOnBatteryFalsePredicate = config.add_predicate();
-    screenOnUnknownOnBatteryFalsePredicate->set_id(StringToId("ScreenOnUnknowneOnBatteryFalse"));
-    screenOnUnknownOnBatteryFalsePredicate->mutable_combination()->set_operation(
-            LogicalOperation::AND);
-    addPredicateToPredicateCombination(screenOnUnknownPredicate,
-                                       screenOnUnknownOnBatteryFalsePredicate);
-    addPredicateToPredicateCombination(*onBatteryFalsePredicate,
-                                       screenOnUnknownOnBatteryFalsePredicate);
-
-    // Simple condition metric with initial value false.
-    ValueMetric* metric1 = config.add_value_metric();
-    metric1->set_id(StringToId("ValueSubsystemSleepWhileScreenOnInitialFalse"));
-    metric1->set_what(pulledAtomMatcher.id());
-    *metric1->mutable_value_field() =
-            CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
-    metric1->set_bucket(FIVE_MINUTES);
-    metric1->set_condition(screenOnFalsePredicate->id());
-
-    // Simple condition metric with initial value unknown.
-    ValueMetric* metric2 = config.add_value_metric();
-    metric2->set_id(StringToId("ValueSubsystemSleepWhileScreenOnInitialUnknown"));
-    metric2->set_what(pulledAtomMatcher.id());
-    *metric2->mutable_value_field() =
-            CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
-    metric2->set_bucket(FIVE_MINUTES);
-    metric2->set_condition(screenOnUnknownPredicate.id());
-
-    // Combination condition metric with initial values false and false.
-    ValueMetric* metric3 = config.add_value_metric();
-    metric3->set_id(StringToId("ValueSubsystemSleepWhileScreenOnFalseDeviceUnpluggedFalse"));
-    metric3->set_what(pulledAtomMatcher.id());
-    *metric3->mutable_value_field() =
-            CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
-    metric3->set_bucket(FIVE_MINUTES);
-    metric3->set_condition(screenOnFalseOnBatteryFalsePredicate->id());
-
-    // Combination condition metric with initial values unknown and false.
-    ValueMetric* metric4 = config.add_value_metric();
-    metric4->set_id(StringToId("ValueSubsystemSleepWhileScreenOnUnknownDeviceUnpluggedFalse"));
-    metric4->set_what(pulledAtomMatcher.id());
-    *metric4->mutable_value_field() =
-            CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
-    metric4->set_bucket(FIVE_MINUTES);
-    metric4->set_condition(screenOnUnknownOnBatteryFalsePredicate->id());
-
-    return config;
-}
-}  // anonymous namespace
-
-TEST(MetricsManagerTest, TestInitialConditions) {
-    sp<UidMap> uidMap = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> periodicAlarmMonitor;
-    StatsdConfig config = buildConfigWithDifferentPredicates();
-    set<int> allTagIds;
-    vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
-    unordered_map<int64_t, int> atomMatchingTrackerMap;
-    vector<sp<ConditionTracker>> allConditionTrackers;
-    unordered_map<int64_t, int> conditionTrackerMap;
-    vector<sp<MetricProducer>> allMetricProducers;
-    unordered_map<int64_t, int> metricProducerMap;
-    std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
-    std::vector<sp<AlarmTracker>> allAlarmTrackers;
-    unordered_map<int, std::vector<int>> conditionToMetricMap;
-    unordered_map<int, std::vector<int>> trackerToMetricMap;
-    unordered_map<int, std::vector<int>> trackerToConditionMap;
-    unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
-    unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
-    unordered_map<int64_t, int> alertTrackerMap;
-    vector<int> metricsWithActivation;
-    map<int64_t, uint64_t> stateProtoHashes;
-    std::set<int64_t> noReportMetricIds;
-
-    EXPECT_TRUE(initStatsdConfig(
-            kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
-            timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
-            allConditionTrackers, conditionTrackerMap, allMetricProducers, metricProducerMap,
-            allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, trackerToMetricMap,
-            trackerToConditionMap, activationAtomTrackerToMetricMap,
-            deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation,
-            stateProtoHashes, noReportMetricIds));
-    ASSERT_EQ(4u, allMetricProducers.size());
-    ASSERT_EQ(5u, allConditionTrackers.size());
-
-    ConditionKey queryKey;
-    vector<ConditionState> conditionCache(5, ConditionState::kNotEvaluated);
-
-    allConditionTrackers[3]->isConditionMet(queryKey, allConditionTrackers, false, conditionCache);
-    allConditionTrackers[4]->isConditionMet(queryKey, allConditionTrackers, false, conditionCache);
-    EXPECT_EQ(ConditionState::kUnknown, conditionCache[0]);
-    EXPECT_EQ(ConditionState::kFalse, conditionCache[1]);
-    EXPECT_EQ(ConditionState::kFalse, conditionCache[2]);
-    EXPECT_EQ(ConditionState::kFalse, conditionCache[3]);
-    EXPECT_EQ(ConditionState::kUnknown, conditionCache[4]);
-
-    EXPECT_EQ(ConditionState::kFalse, allMetricProducers[0]->mCondition);
-    EXPECT_EQ(ConditionState::kUnknown, allMetricProducers[1]->mCondition);
-    EXPECT_EQ(ConditionState::kFalse, allMetricProducers[2]->mCondition);
-    EXPECT_EQ(ConditionState::kUnknown, allMetricProducers[3]->mCondition);
-}
-
-TEST(MetricsManagerTest, TestGoodConfig) {
-    sp<UidMap> uidMap = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> periodicAlarmMonitor;
-    StatsdConfig config = buildGoodConfig();
-    set<int> allTagIds;
-    vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
-    unordered_map<int64_t, int> atomMatchingTrackerMap;
-    vector<sp<ConditionTracker>> allConditionTrackers;
-    unordered_map<int64_t, int> conditionTrackerMap;
-    vector<sp<MetricProducer>> allMetricProducers;
-    unordered_map<int64_t, int> metricProducerMap;
-    std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
-    std::vector<sp<AlarmTracker>> allAlarmTrackers;
-    unordered_map<int, std::vector<int>> conditionToMetricMap;
-    unordered_map<int, std::vector<int>> trackerToMetricMap;
-    unordered_map<int, std::vector<int>> trackerToConditionMap;
-    unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
-    unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
-    unordered_map<int64_t, int> alertTrackerMap;
-    vector<int> metricsWithActivation;
-    map<int64_t, uint64_t> stateProtoHashes;
-    std::set<int64_t> noReportMetricIds;
-
-    EXPECT_TRUE(initStatsdConfig(
-            kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
-            timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
-            allConditionTrackers, conditionTrackerMap, allMetricProducers, metricProducerMap,
-            allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, trackerToMetricMap,
-            trackerToConditionMap, activationAtomTrackerToMetricMap,
-            deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation,
-            stateProtoHashes, noReportMetricIds));
-    ASSERT_EQ(1u, allMetricProducers.size());
-    EXPECT_THAT(metricProducerMap, UnorderedElementsAre(Pair(config.count_metric(0).id(), 0)));
-    ASSERT_EQ(1u, allAnomalyTrackers.size());
-    ASSERT_EQ(1u, noReportMetricIds.size());
-    ASSERT_EQ(1u, alertTrackerMap.size());
-    EXPECT_NE(alertTrackerMap.find(kAlertId), alertTrackerMap.end());
-    EXPECT_EQ(alertTrackerMap.find(kAlertId)->second, 0);
-}
-
-TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) {
-    sp<UidMap> uidMap = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> periodicAlarmMonitor;
-    StatsdConfig config = buildDimensionMetricsWithMultiTags();
-    set<int> allTagIds;
-    vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
-    unordered_map<int64_t, int> atomMatchingTrackerMap;
-    vector<sp<ConditionTracker>> allConditionTrackers;
-    unordered_map<int64_t, int> conditionTrackerMap;
-    vector<sp<MetricProducer>> allMetricProducers;
-    unordered_map<int64_t, int> metricProducerMap;
-    std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
-    std::vector<sp<AlarmTracker>> allAlarmTrackers;
-    unordered_map<int, std::vector<int>> conditionToMetricMap;
-    unordered_map<int, std::vector<int>> trackerToMetricMap;
-    unordered_map<int, std::vector<int>> trackerToConditionMap;
-    unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
-    unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
-    unordered_map<int64_t, int> alertTrackerMap;
-    vector<int> metricsWithActivation;
-    map<int64_t, uint64_t> stateProtoHashes;
-    std::set<int64_t> noReportMetricIds;
-
-    EXPECT_FALSE(initStatsdConfig(
-            kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
-            timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
-            allConditionTrackers, conditionTrackerMap, allMetricProducers, metricProducerMap,
-            allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, trackerToMetricMap,
-            trackerToConditionMap, activationAtomTrackerToMetricMap,
-            deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation,
-            stateProtoHashes, noReportMetricIds));
-}
-
-TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
-    sp<UidMap> uidMap = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> periodicAlarmMonitor;
-    StatsdConfig config = buildCircleMatchers();
-    set<int> allTagIds;
-    vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
-    unordered_map<int64_t, int> atomMatchingTrackerMap;
-    vector<sp<ConditionTracker>> allConditionTrackers;
-    unordered_map<int64_t, int> conditionTrackerMap;
-    vector<sp<MetricProducer>> allMetricProducers;
-    unordered_map<int64_t, int> metricProducerMap;
-    std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
-    std::vector<sp<AlarmTracker>> allAlarmTrackers;
-    unordered_map<int, std::vector<int>> conditionToMetricMap;
-    unordered_map<int, std::vector<int>> trackerToMetricMap;
-    unordered_map<int, std::vector<int>> trackerToConditionMap;
-    unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
-    unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
-    unordered_map<int64_t, int> alertTrackerMap;
-    vector<int> metricsWithActivation;
-    map<int64_t, uint64_t> stateProtoHashes;
-    std::set<int64_t> noReportMetricIds;
-
-    EXPECT_FALSE(initStatsdConfig(
-            kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
-            timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
-            allConditionTrackers, conditionTrackerMap, allMetricProducers, metricProducerMap,
-            allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, trackerToMetricMap,
-            trackerToConditionMap, activationAtomTrackerToMetricMap,
-            deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation,
-            stateProtoHashes, noReportMetricIds));
-}
-
-TEST(MetricsManagerTest, TestMissingMatchers) {
-    sp<UidMap> uidMap = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> periodicAlarmMonitor;
-    StatsdConfig config = buildMissingMatchers();
-    set<int> allTagIds;
-    vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
-    unordered_map<int64_t, int> atomMatchingTrackerMap;
-    vector<sp<ConditionTracker>> allConditionTrackers;
-    unordered_map<int64_t, int> conditionTrackerMap;
-    vector<sp<MetricProducer>> allMetricProducers;
-    unordered_map<int64_t, int> metricProducerMap;
-    std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
-    std::vector<sp<AlarmTracker>> allAlarmTrackers;
-    unordered_map<int, std::vector<int>> conditionToMetricMap;
-    unordered_map<int, std::vector<int>> trackerToMetricMap;
-    unordered_map<int, std::vector<int>> trackerToConditionMap;
-    unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
-    unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
-    unordered_map<int64_t, int> alertTrackerMap;
-    vector<int> metricsWithActivation;
-    map<int64_t, uint64_t> stateProtoHashes;
-    std::set<int64_t> noReportMetricIds;
-    EXPECT_FALSE(initStatsdConfig(
-            kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
-            timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
-            allConditionTrackers, conditionTrackerMap, allMetricProducers, metricProducerMap,
-            allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, trackerToMetricMap,
-            trackerToConditionMap, activationAtomTrackerToMetricMap,
-            deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation,
-            stateProtoHashes, noReportMetricIds));
-}
-
-TEST(MetricsManagerTest, TestMissingPredicate) {
-    sp<UidMap> uidMap = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> periodicAlarmMonitor;
-    StatsdConfig config = buildMissingPredicate();
-    set<int> allTagIds;
-    vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
-    unordered_map<int64_t, int> atomMatchingTrackerMap;
-    vector<sp<ConditionTracker>> allConditionTrackers;
-    unordered_map<int64_t, int> conditionTrackerMap;
-    vector<sp<MetricProducer>> allMetricProducers;
-    unordered_map<int64_t, int> metricProducerMap;
-    std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
-    std::vector<sp<AlarmTracker>> allAlarmTrackers;
-    unordered_map<int, std::vector<int>> conditionToMetricMap;
-    unordered_map<int, std::vector<int>> trackerToMetricMap;
-    unordered_map<int, std::vector<int>> trackerToConditionMap;
-    unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
-    unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
-    unordered_map<int64_t, int> alertTrackerMap;
-    vector<int> metricsWithActivation;
-    map<int64_t, uint64_t> stateProtoHashes;
-    std::set<int64_t> noReportMetricIds;
-    EXPECT_FALSE(initStatsdConfig(
-            kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
-            timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
-            allConditionTrackers, conditionTrackerMap, allMetricProducers, metricProducerMap,
-            allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, trackerToMetricMap,
-            trackerToConditionMap, activationAtomTrackerToMetricMap,
-            deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation,
-            stateProtoHashes, noReportMetricIds));
-}
-
-TEST(MetricsManagerTest, TestCirclePredicateDependency) {
-    sp<UidMap> uidMap = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> periodicAlarmMonitor;
-    StatsdConfig config = buildCirclePredicates();
-    set<int> allTagIds;
-    vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
-    unordered_map<int64_t, int> atomMatchingTrackerMap;
-    vector<sp<ConditionTracker>> allConditionTrackers;
-    unordered_map<int64_t, int> conditionTrackerMap;
-    vector<sp<MetricProducer>> allMetricProducers;
-    unordered_map<int64_t, int> metricProducerMap;
-    std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
-    std::vector<sp<AlarmTracker>> allAlarmTrackers;
-    unordered_map<int, std::vector<int>> conditionToMetricMap;
-    unordered_map<int, std::vector<int>> trackerToMetricMap;
-    unordered_map<int, std::vector<int>> trackerToConditionMap;
-    unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
-    unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
-    unordered_map<int64_t, int> alertTrackerMap;
-    vector<int> metricsWithActivation;
-    map<int64_t, uint64_t> stateProtoHashes;
-    std::set<int64_t> noReportMetricIds;
-
-    EXPECT_FALSE(initStatsdConfig(
-            kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
-            timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
-            allConditionTrackers, conditionTrackerMap, allMetricProducers, metricProducerMap,
-            allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, trackerToMetricMap,
-            trackerToConditionMap, activationAtomTrackerToMetricMap,
-            deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation,
-            stateProtoHashes, noReportMetricIds));
-}
-
-TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
-    sp<UidMap> uidMap = new UidMap();
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> periodicAlarmMonitor;
-    StatsdConfig config = buildAlertWithUnknownMetric();
-    set<int> allTagIds;
-    vector<sp<AtomMatchingTracker>> allAtomMatchingTrackers;
-    unordered_map<int64_t, int> atomMatchingTrackerMap;
-    vector<sp<ConditionTracker>> allConditionTrackers;
-    unordered_map<int64_t, int> conditionTrackerMap;
-    vector<sp<MetricProducer>> allMetricProducers;
-    unordered_map<int64_t, int> metricProducerMap;
-    std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
-    std::vector<sp<AlarmTracker>> allAlarmTrackers;
-    unordered_map<int, std::vector<int>> conditionToMetricMap;
-    unordered_map<int, std::vector<int>> trackerToMetricMap;
-    unordered_map<int, std::vector<int>> trackerToConditionMap;
-    unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
-    unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
-    unordered_map<int64_t, int> alertTrackerMap;
-    vector<int> metricsWithActivation;
-    map<int64_t, uint64_t> stateProtoHashes;
-    std::set<int64_t> noReportMetricIds;
-
-    EXPECT_FALSE(initStatsdConfig(
-            kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
-            timeBaseSec, timeBaseSec, allTagIds, allAtomMatchingTrackers, atomMatchingTrackerMap,
-            allConditionTrackers, conditionTrackerMap, allMetricProducers, metricProducerMap,
-            allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap, trackerToMetricMap,
-            trackerToConditionMap, activationAtomTrackerToMetricMap,
-            deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation,
-            stateProtoHashes, noReportMetricIds));
-}
-
-TEST(MetricsManagerTest, TestCreateAtomMatchingTrackerInvalidMatcher) {
-    sp<UidMap> uidMap = new UidMap();
-    AtomMatcher matcher;
-    // Matcher has no contents_case (simple/combination), so it is invalid.
-    matcher.set_id(21);
-    EXPECT_EQ(createAtomMatchingTracker(matcher, 0, uidMap), nullptr);
-}
-
-TEST(MetricsManagerTest, TestCreateAtomMatchingTrackerSimple) {
-    int index = 1;
-    int64_t id = 123;
-    sp<UidMap> uidMap = new UidMap();
-    AtomMatcher matcher;
-    matcher.set_id(id);
-    SimpleAtomMatcher* simpleAtomMatcher = matcher.mutable_simple_atom_matcher();
-    simpleAtomMatcher->set_atom_id(util::SCREEN_STATE_CHANGED);
-    simpleAtomMatcher->add_field_value_matcher()->set_field(
-            1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
-    simpleAtomMatcher->mutable_field_value_matcher(0)->set_eq_int(
-            android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-
-    sp<AtomMatchingTracker> tracker = createAtomMatchingTracker(matcher, index, uidMap);
-    EXPECT_NE(tracker, nullptr);
-
-    EXPECT_TRUE(tracker->mInitialized);
-    EXPECT_EQ(tracker->getId(), id);
-    EXPECT_EQ(tracker->mIndex, index);
-    const set<int>& atomIds = tracker->getAtomIds();
-    ASSERT_EQ(atomIds.size(), 1);
-    EXPECT_EQ(atomIds.count(util::SCREEN_STATE_CHANGED), 1);
-}
-
-TEST(MetricsManagerTest, TestCreateAtomMatchingTrackerCombination) {
-    int index = 1;
-    int64_t id = 123;
-    sp<UidMap> uidMap = new UidMap();
-    AtomMatcher matcher;
-    matcher.set_id(id);
-    AtomMatcher_Combination* combination = matcher.mutable_combination();
-    combination->set_operation(LogicalOperation::OR);
-    combination->add_matcher(123);
-    combination->add_matcher(223);
-
-    sp<AtomMatchingTracker> tracker = createAtomMatchingTracker(matcher, index, uidMap);
-    EXPECT_NE(tracker, nullptr);
-
-    // Combination matchers need to be initialized first.
-    EXPECT_FALSE(tracker->mInitialized);
-    EXPECT_EQ(tracker->getId(), id);
-    EXPECT_EQ(tracker->mIndex, index);
-    const set<int>& atomIds = tracker->getAtomIds();
-    ASSERT_EQ(atomIds.size(), 0);
-}
-
-TEST(MetricsManagerTest, TestCreateConditionTrackerInvalid) {
-    const ConfigKey key(123, 456);
-    // Predicate has no contents_case (simple/combination), so it is invalid.
-    Predicate predicate;
-    predicate.set_id(21);
-    unordered_map<int64_t, int> atomTrackerMap;
-    EXPECT_EQ(createConditionTracker(key, predicate, 0, atomTrackerMap), nullptr);
-}
-
-TEST(MetricsManagerTest, TestCreateConditionTrackerSimple) {
-    int index = 1;
-    int64_t id = 987;
-    const ConfigKey key(123, 456);
-
-    int startMatcherIndex = 2, stopMatcherIndex = 0, stopAllMatcherIndex = 1;
-    int64_t startMatcherId = 246, stopMatcherId = 153, stopAllMatcherId = 975;
-
-    Predicate predicate;
-    predicate.set_id(id);
-    SimplePredicate* simplePredicate = predicate.mutable_simple_predicate();
-    simplePredicate->set_start(startMatcherId);
-    simplePredicate->set_stop(stopMatcherId);
-    simplePredicate->set_stop_all(stopAllMatcherId);
-
-    unordered_map<int64_t, int> atomTrackerMap;
-    atomTrackerMap[startMatcherId] = startMatcherIndex;
-    atomTrackerMap[stopMatcherId] = stopMatcherIndex;
-    atomTrackerMap[stopAllMatcherId] = stopAllMatcherIndex;
-
-    sp<ConditionTracker> tracker = createConditionTracker(key, predicate, index, atomTrackerMap);
-    EXPECT_EQ(tracker->getConditionId(), id);
-    EXPECT_EQ(tracker->isSliced(), false);
-    EXPECT_TRUE(tracker->IsSimpleCondition());
-    const set<int>& interestedMatchers = tracker->getAtomMatchingTrackerIndex();
-    ASSERT_EQ(interestedMatchers.size(), 3);
-    ASSERT_EQ(interestedMatchers.count(startMatcherIndex), 1);
-    ASSERT_EQ(interestedMatchers.count(stopMatcherIndex), 1);
-    ASSERT_EQ(interestedMatchers.count(stopAllMatcherIndex), 1);
-}
-
-TEST(MetricsManagerTest, TestCreateConditionTrackerCombination) {
-    int index = 1;
-    int64_t id = 987;
-    const ConfigKey key(123, 456);
-
-    Predicate predicate;
-    predicate.set_id(id);
-    Predicate_Combination* combinationPredicate = predicate.mutable_combination();
-    combinationPredicate->set_operation(LogicalOperation::AND);
-    combinationPredicate->add_predicate(888);
-    combinationPredicate->add_predicate(777);
-
-    // Combination conditions must be initialized to set most state.
-    unordered_map<int64_t, int> atomTrackerMap;
-    sp<ConditionTracker> tracker = createConditionTracker(key, predicate, index, atomTrackerMap);
-    EXPECT_EQ(tracker->getConditionId(), id);
-    EXPECT_FALSE(tracker->IsSimpleCondition());
-}
-
-TEST(MetricsManagerTest, TestCreateAnomalyTrackerInvalidMetric) {
-    Alert alert;
-    alert.set_id(123);
-    alert.set_metric_id(1);
-    alert.set_trigger_if_sum_gt(1);
-    alert.set_num_buckets(1);
-
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    vector<sp<MetricProducer>> metricProducers;
-    // Pass in empty metric producers, causing an error.
-    EXPECT_EQ(createAnomalyTracker(alert, anomalyAlarmMonitor, {}, metricProducers), nullopt);
-}
-
-TEST(MetricsManagerTest, TestCreateAnomalyTrackerNoThreshold) {
-    int64_t metricId = 1;
-    Alert alert;
-    alert.set_id(123);
-    alert.set_metric_id(metricId);
-    alert.set_num_buckets(1);
-
-    CountMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    vector<sp<MetricProducer>> metricProducers({new CountMetricProducer(
-            kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard, 0x0123456789, 0, 0)});
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    EXPECT_EQ(createAnomalyTracker(alert, anomalyAlarmMonitor, {{1, 0}}, metricProducers), nullopt);
-}
-
-TEST(MetricsManagerTest, TestCreateAnomalyTrackerMissingBuckets) {
-    int64_t metricId = 1;
-    Alert alert;
-    alert.set_id(123);
-    alert.set_metric_id(metricId);
-    alert.set_trigger_if_sum_gt(1);
-
-    CountMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    vector<sp<MetricProducer>> metricProducers({new CountMetricProducer(
-            kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard, 0x0123456789, 0, 0)});
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    EXPECT_EQ(createAnomalyTracker(alert, anomalyAlarmMonitor, {{1, 0}}, metricProducers), nullopt);
-}
-
-TEST(MetricsManagerTest, TestCreateAnomalyTrackerGood) {
-    int64_t metricId = 1;
-    Alert alert;
-    alert.set_id(123);
-    alert.set_metric_id(metricId);
-    alert.set_trigger_if_sum_gt(1);
-    alert.set_num_buckets(1);
-
-    CountMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    vector<sp<MetricProducer>> metricProducers({new CountMetricProducer(
-            kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard, 0x0123456789, 0, 0)});
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    EXPECT_NE(createAnomalyTracker(alert, anomalyAlarmMonitor, {{1, 0}}, metricProducers), nullopt);
-}
-
-TEST(MetricsManagerTest, TestCreateAnomalyTrackerDurationTooLong) {
-    int64_t metricId = 1;
-    Alert alert;
-    alert.set_id(123);
-    alert.set_metric_id(metricId);
-    // Impossible for alert to fire since the time is bigger than bucketSize * numBuckets
-    alert.set_trigger_if_sum_gt(MillisToNano(TimeUnitToBucketSizeInMillis(ONE_MINUTE)) + 1);
-    alert.set_num_buckets(1);
-
-    DurationMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-    FieldMatcher dimensions;
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-    vector<sp<MetricProducer>> metricProducers({new DurationMetricProducer(
-            kConfigKey, metric, -1 /*no condition*/, {}, -1 /* what index not needed*/,
-            1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
-            wizard, 0x0123456789, dimensions, 0, 0)});
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    EXPECT_EQ(createAnomalyTracker(alert, anomalyAlarmMonitor, {{1, 0}}, metricProducers), nullopt);
-}
-
-TEST(MetricsManagerTest, TestCreateDurationProducerDimensionsInWhatInvalid) {
-    StatsdConfig config;
-    config.add_allowed_log_source("AID_ROOT");
-    *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
-    *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
-    *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
-    *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
-
-    Predicate holdingWakelockPredicate = CreateHoldingWakelockPredicate();
-    // The predicate is dimensioning by first attribution node by uid.
-    FieldMatcher dimensions =
-            CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-    *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions;
-    *config.add_predicate() = holdingWakelockPredicate;
-
-    DurationMetric* durationMetric = config.add_duration_metric();
-    durationMetric->set_id(StringToId("WakelockDuration"));
-    durationMetric->set_what(holdingWakelockPredicate.id());
-    durationMetric->set_aggregation_type(DurationMetric::SUM);
-    // The metric is dimensioning by first attribution node by uid AND tag.
-    // Invalid since the predicate only dimensions by uid.
-    *durationMetric->mutable_dimensions_in_what() = CreateAttributionUidAndOtherDimensions(
-            util::WAKELOCK_STATE_CHANGED, {Position::FIRST}, {3 /* tag */});
-    durationMetric->set_bucket(FIVE_MINUTES);
-
-    ConfigKey key(123, 987);
-    uint64_t timeNs = 456;
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    sp<AlarmMonitor> anomalyAlarmMonitor;
-    sp<AlarmMonitor> periodicAlarmMonitor;
-    sp<UidMap> uidMap;
-    sp<MetricsManager> metricsManager =
-            new MetricsManager(key, config, timeNs, timeNs, uidMap, pullerManager,
-                               anomalyAlarmMonitor, periodicAlarmMonitor);
-    EXPECT_FALSE(metricsManager->isConfigValid());
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/shell/ShellSubscriber_test.cpp b/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
deleted file mode 100644
index 1ba8593..0000000
--- a/cmds/statsd/tests/shell/ShellSubscriber_test.cpp
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/shell/ShellSubscriber.h"
-
-#include <gtest/gtest.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#include <vector>
-
-#include "frameworks/base/cmds/statsd/src/shell/shell_config.pb.h"
-#include "frameworks/base/cmds/statsd/src/shell/shell_data.pb.h"
-#include "frameworks/proto_logging/stats/atoms.pb.h"
-#include "stats_event.h"
-#include "tests/metrics/metrics_test_helper.h"
-#include "tests/statsd_test_util.h"
-
-using namespace android::os::statsd;
-using android::sp;
-using std::vector;
-using testing::_;
-using testing::Invoke;
-using testing::NaggyMock;
-using testing::StrictMock;
-
-#ifdef __ANDROID__
-
-void runShellTest(ShellSubscription config, sp<MockUidMap> uidMap,
-                  sp<MockStatsPullerManager> pullerManager,
-                  const vector<std::shared_ptr<LogEvent>>& pushedEvents,
-                  const ShellData& expectedData) {
-    // set up 2 pipes for read/write config and data
-    int fds_config[2];
-    ASSERT_EQ(0, pipe(fds_config));
-
-    int fds_data[2];
-    ASSERT_EQ(0, pipe(fds_data));
-
-    size_t bufferSize = config.ByteSize();
-    // write the config to pipe, first write size of the config
-    write(fds_config[1], &bufferSize, sizeof(bufferSize));
-    // then write config itself
-    vector<uint8_t> buffer(bufferSize);
-    config.SerializeToArray(&buffer[0], bufferSize);
-    write(fds_config[1], buffer.data(), bufferSize);
-    close(fds_config[1]);
-
-    sp<ShellSubscriber> shellClient = new ShellSubscriber(uidMap, pullerManager);
-
-    // mimic a binder thread that a shell subscriber runs on. it would block.
-    std::thread reader([&shellClient, &fds_config, &fds_data] {
-        shellClient->startNewSubscription(fds_config[0], fds_data[1], /*timeoutSec=*/-1);
-    });
-    reader.detach();
-
-    // let the shell subscriber to receive the config from pipe.
-    std::this_thread::sleep_for(100ms);
-
-    if (pushedEvents.size() > 0) {
-        // send a log event that matches the config.
-        std::thread log_reader([&shellClient, &pushedEvents] {
-            for (const auto& event : pushedEvents) {
-                shellClient->onLogEvent(*event);
-            }
-        });
-
-        log_reader.detach();
-
-        if (log_reader.joinable()) {
-            log_reader.join();
-        }
-    }
-
-    // wait for the data to be written.
-    std::this_thread::sleep_for(100ms);
-
-    // Because we might receive heartbeats from statsd, consisting of data sizes
-    // of 0, encapsulate reads within a while loop.
-    bool readAtom = false;
-    while (!readAtom) {
-        // Read the atom size.
-        size_t dataSize = 0;
-        read(fds_data[0], &dataSize, sizeof(dataSize));
-        if (dataSize == 0) continue;
-        EXPECT_EQ(expectedData.ByteSize(), int(dataSize));
-
-        // Read that much data in proto binary format.
-        vector<uint8_t> dataBuffer(dataSize);
-        EXPECT_EQ((int)dataSize, read(fds_data[0], dataBuffer.data(), dataSize));
-
-        // Make sure the received bytes can be parsed to an atom.
-        ShellData receivedAtom;
-        EXPECT_TRUE(receivedAtom.ParseFromArray(dataBuffer.data(), dataSize) != 0);
-
-        // Serialize the expected atom to byte array and compare to make sure
-        // they are the same.
-        vector<uint8_t> expectedAtomBuffer(expectedData.ByteSize());
-        expectedData.SerializeToArray(expectedAtomBuffer.data(), expectedData.ByteSize());
-        EXPECT_EQ(expectedAtomBuffer, dataBuffer);
-
-        readAtom = true;
-    }
-
-    close(fds_data[0]);
-    if (reader.joinable()) {
-        reader.join();
-    }
-}
-
-TEST(ShellSubscriberTest, testPushedSubscription) {
-    sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    vector<std::shared_ptr<LogEvent>> pushedList;
-
-    // Create the LogEvent from an AStatsEvent
-    std::unique_ptr<LogEvent> logEvent = CreateScreenStateChangedEvent(
-            1000 /*timestamp*/, ::android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-    pushedList.push_back(std::move(logEvent));
-
-    // create a simple config to get screen events
-    ShellSubscription config;
-    config.add_pushed()->set_atom_id(29);
-
-    // this is the expected screen event atom.
-    ShellData shellData;
-    shellData.add_atom()->mutable_screen_state_changed()->set_state(
-            ::android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-
-    runShellTest(config, uidMap, pullerManager, pushedList, shellData);
-}
-
-namespace {
-
-int kUid1 = 1000;
-int kUid2 = 2000;
-
-int kCpuTime1 = 100;
-int kCpuTime2 = 200;
-
-ShellData getExpectedShellData() {
-    ShellData shellData;
-    auto* atom1 = shellData.add_atom()->mutable_cpu_active_time();
-    atom1->set_uid(kUid1);
-    atom1->set_time_millis(kCpuTime1);
-
-    auto* atom2 = shellData.add_atom()->mutable_cpu_active_time();
-    atom2->set_uid(kUid2);
-    atom2->set_time_millis(kCpuTime2);
-
-    return shellData;
-}
-
-ShellSubscription getPulledConfig() {
-    ShellSubscription config;
-    auto* pull_config = config.add_pulled();
-    pull_config->mutable_matcher()->set_atom_id(10016);
-    pull_config->set_freq_millis(2000);
-    return config;
-}
-
-shared_ptr<LogEvent> makeCpuActiveTimeAtom(int32_t uid, int64_t timeMillis) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, 10016);
-    AStatsEvent_overwriteTimestamp(statsEvent, 1111L);
-    AStatsEvent_writeInt32(statsEvent, uid);
-    AStatsEvent_writeInt64(statsEvent, timeMillis);
-
-    std::shared_ptr<LogEvent> logEvent = std::make_shared<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-}  // namespace
-
-TEST(ShellSubscriberTest, testPulledSubscription) {
-    sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
-
-    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    const vector<int32_t> uids = {AID_SYSTEM};
-    EXPECT_CALL(*pullerManager, Pull(10016, uids, _, _))
-            .WillRepeatedly(Invoke([](int tagId, const vector<int32_t>&, const int64_t,
-                                      vector<std::shared_ptr<LogEvent>>* data) {
-                data->clear();
-                data->push_back(makeCpuActiveTimeAtom(/*uid=*/kUid1, /*timeMillis=*/kCpuTime1));
-                data->push_back(makeCpuActiveTimeAtom(/*uid=*/kUid2, /*timeMillis=*/kCpuTime2));
-                return true;
-            }));
-    runShellTest(getPulledConfig(), uidMap, pullerManager, vector<std::shared_ptr<LogEvent>>(),
-                 getExpectedShellData());
-}
-
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/state/StateTracker_test.cpp b/cmds/statsd/tests/state/StateTracker_test.cpp
deleted file mode 100644
index 6516c15..0000000
--- a/cmds/statsd/tests/state/StateTracker_test.cpp
+++ /dev/null
@@ -1,571 +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.
- */
-#include "state/StateTracker.h"
-
-#include <gtest/gtest.h>
-#include <private/android_filesystem_config.h>
-
-#include "state/StateListener.h"
-#include "state/StateManager.h"
-#include "state/StateTracker.h"
-#include "stats_event.h"
-#include "tests/statsd_test_util.h"
-
-#ifdef __ANDROID__
-
-namespace android {
-namespace os {
-namespace statsd {
-
-const int32_t timestampNs = 1000;
-
-/**
- * Mock StateListener class for testing.
- * Stores primary key and state pairs.
- */
-class TestStateListener : public virtual StateListener {
-public:
-    TestStateListener(){};
-
-    virtual ~TestStateListener(){};
-
-    struct Update {
-        Update(const HashableDimensionKey& key, int state) : mKey(key), mState(state){};
-        HashableDimensionKey mKey;
-        int mState;
-    };
-
-    std::vector<Update> updates;
-
-    void onStateChanged(const int64_t eventTimeNs, const int32_t atomId,
-                        const HashableDimensionKey& primaryKey, const FieldValue& oldState,
-                        const FieldValue& newState) {
-        updates.emplace_back(primaryKey, newState.mValue.int_value);
-    }
-};
-
-int getStateInt(StateManager& mgr, int atomId, const HashableDimensionKey& queryKey) {
-    FieldValue output;
-    mgr.getStateValue(atomId, queryKey, &output);
-    return output.mValue.int_value;
-}
-
-// START: build event functions.
-// Incorrect event - missing fields
-std::unique_ptr<LogEvent> buildIncorrectOverlayEvent(int uid, const std::string& packageName,
-                                                     int state) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, util::OVERLAY_STATE_CHANGED);
-    AStatsEvent_overwriteTimestamp(statsEvent, 1000);
-
-    AStatsEvent_writeInt32(statsEvent, uid);
-    AStatsEvent_writeString(statsEvent, packageName.c_str());
-    // Missing field 3 - using_alert_window.
-    AStatsEvent_writeInt32(statsEvent, state);
-
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-// Incorrect event - exclusive state has wrong type
-std::unique_ptr<LogEvent> buildOverlayEventBadStateType(int uid, const std::string& packageName) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, util::OVERLAY_STATE_CHANGED);
-    AStatsEvent_overwriteTimestamp(statsEvent, 1000);
-
-    AStatsEvent_writeInt32(statsEvent, uid);
-    AStatsEvent_writeString(statsEvent, packageName.c_str());
-    AStatsEvent_writeInt32(statsEvent, true);       // using_alert_window
-    AStatsEvent_writeString(statsEvent, "string");  // exclusive state: string instead of int
-
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-// END: build event functions.
-
-TEST(StateListenerTest, TestStateListenerWeakPointer) {
-    sp<TestStateListener> listener = new TestStateListener();
-    wp<TestStateListener> wListener = listener;
-    listener = nullptr;  // let go of listener
-    EXPECT_TRUE(wListener.promote() == nullptr);
-}
-
-TEST(StateManagerTest, TestStateManagerGetInstance) {
-    sp<TestStateListener> listener1 = new TestStateListener();
-    StateManager& mgr = StateManager::getInstance();
-    mgr.clear();
-
-    mgr.registerListener(util::SCREEN_STATE_CHANGED, listener1);
-    EXPECT_EQ(1, mgr.getStateTrackersCount());
-    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-}
-
-TEST(StateManagerTest, TestOnLogEvent) {
-    sp<MockUidMap> uidMap = makeMockUidMapForPackage("com.android.systemui", {10111});
-    sp<TestStateListener> listener1 = new TestStateListener();
-    StateManager mgr;
-    mgr.updateLogSources(uidMap);
-    // Add StateTracker by registering a listener.
-    mgr.registerListener(util::SCREEN_STATE_CHANGED, listener1);
-
-    // log event using AID_ROOT
-    std::unique_ptr<LogEvent> event = CreateScreenStateChangedEvent(
-            timestampNs, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-    mgr.onLogEvent(*event);
-
-    // check StateTracker was updated by querying for state
-    HashableDimensionKey queryKey = DEFAULT_DIMENSION_KEY;
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-              getStateInt(mgr, util::SCREEN_STATE_CHANGED, queryKey));
-
-    // log event using mocked uid
-    event = CreateScreenStateChangedEvent(
-            timestampNs, android::view::DisplayStateEnum::DISPLAY_STATE_OFF, 10111);
-    mgr.onLogEvent(*event);
-
-    // check StateTracker was updated by querying for state
-    queryKey = DEFAULT_DIMENSION_KEY;
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-              getStateInt(mgr, util::SCREEN_STATE_CHANGED, queryKey));
-
-    // log event using non-whitelisted uid
-    event = CreateScreenStateChangedEvent(timestampNs,
-                                          android::view::DisplayStateEnum::DISPLAY_STATE_ON, 10112);
-    mgr.onLogEvent(*event);
-
-    // check StateTracker was NOT updated by querying for state
-    queryKey = DEFAULT_DIMENSION_KEY;
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-              getStateInt(mgr, util::SCREEN_STATE_CHANGED, queryKey));
-
-    // log event using AID_SYSTEM
-    event = CreateScreenStateChangedEvent(
-            timestampNs, android::view::DisplayStateEnum::DISPLAY_STATE_ON, AID_SYSTEM);
-    mgr.onLogEvent(*event);
-
-    // check StateTracker was updated by querying for state
-    queryKey = DEFAULT_DIMENSION_KEY;
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-              getStateInt(mgr, util::SCREEN_STATE_CHANGED, queryKey));
-}
-
-/**
- * Test registering listeners to StateTrackers
- *
- * - StateManager will create a new StateTracker if it doesn't already exist
- * and then register the listener to the StateTracker.
- * - If a listener is already registered to a StateTracker, it is not added again.
- * - StateTrackers are only created for atoms that are state atoms.
- */
-TEST(StateTrackerTest, TestRegisterListener) {
-    sp<TestStateListener> listener1 = new TestStateListener();
-    sp<TestStateListener> listener2 = new TestStateListener();
-    StateManager mgr;
-
-    // Register listener to non-existing StateTracker
-    EXPECT_EQ(0, mgr.getStateTrackersCount());
-    mgr.registerListener(util::SCREEN_STATE_CHANGED, listener1);
-    EXPECT_EQ(1, mgr.getStateTrackersCount());
-    EXPECT_EQ(1, mgr.getListenersCount(util::SCREEN_STATE_CHANGED));
-
-    // Register listener to existing StateTracker
-    mgr.registerListener(util::SCREEN_STATE_CHANGED, listener2);
-    EXPECT_EQ(1, mgr.getStateTrackersCount());
-    EXPECT_EQ(2, mgr.getListenersCount(util::SCREEN_STATE_CHANGED));
-
-    // Register already registered listener to existing StateTracker
-    mgr.registerListener(util::SCREEN_STATE_CHANGED, listener2);
-    EXPECT_EQ(1, mgr.getStateTrackersCount());
-    EXPECT_EQ(2, mgr.getListenersCount(util::SCREEN_STATE_CHANGED));
-
-    // Register listener to non-state atom
-    mgr.registerListener(util::BATTERY_LEVEL_CHANGED, listener2);
-    EXPECT_EQ(2, mgr.getStateTrackersCount());
-}
-
-/**
- * Test unregistering listeners from StateTrackers
- *
- * - StateManager will unregister listeners from a StateTracker only if the
- * StateTracker exists and the listener is registered to the StateTracker.
- * - Once all listeners are removed from a StateTracker, the StateTracker
- * is also removed.
- */
-TEST(StateTrackerTest, TestUnregisterListener) {
-    sp<TestStateListener> listener1 = new TestStateListener();
-    sp<TestStateListener> listener2 = new TestStateListener();
-    StateManager mgr;
-
-    // Unregister listener from non-existing StateTracker
-    EXPECT_EQ(0, mgr.getStateTrackersCount());
-    mgr.unregisterListener(util::SCREEN_STATE_CHANGED, listener1);
-    EXPECT_EQ(0, mgr.getStateTrackersCount());
-    EXPECT_EQ(-1, mgr.getListenersCount(util::SCREEN_STATE_CHANGED));
-
-    // Unregister non-registered listener from existing StateTracker
-    mgr.registerListener(util::SCREEN_STATE_CHANGED, listener1);
-    EXPECT_EQ(1, mgr.getStateTrackersCount());
-    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(util::SCREEN_STATE_CHANGED));
-
-    // Unregister second-to-last listener from StateTracker
-    mgr.registerListener(util::SCREEN_STATE_CHANGED, listener2);
-    mgr.unregisterListener(util::SCREEN_STATE_CHANGED, listener1);
-    EXPECT_EQ(1, mgr.getStateTrackersCount());
-    EXPECT_EQ(1, mgr.getListenersCount(util::SCREEN_STATE_CHANGED));
-
-    // Unregister last listener from StateTracker
-    mgr.unregisterListener(util::SCREEN_STATE_CHANGED, listener2);
-    EXPECT_EQ(0, mgr.getStateTrackersCount());
-    EXPECT_EQ(-1, mgr.getListenersCount(util::SCREEN_STATE_CHANGED));
-}
-
-/**
- * Test a binary state atom with nested counting.
- *
- * To go from an "ON" state to an "OFF" state with nested counting, we must see
- * an equal number of "OFF" events as "ON" events.
- * For example, ACQUIRE, ACQUIRE, RELEASE will still be in the ACQUIRE state.
- * ACQUIRE, ACQUIRE, RELEASE, RELEASE will be in the RELEASE state.
- */
-TEST(StateTrackerTest, TestStateChangeNested) {
-    sp<TestStateListener> listener = new TestStateListener();
-    StateManager mgr;
-    mgr.registerListener(util::WAKELOCK_STATE_CHANGED, listener);
-
-    std::vector<int> attributionUids1 = {1000};
-    std::vector<string> attributionTags1 = {"tag"};
-
-    std::unique_ptr<LogEvent> event1 = CreateAcquireWakelockEvent(timestampNs, attributionUids1,
-                                                                  attributionTags1, "wakelockName");
-    mgr.onLogEvent(*event1);
-    ASSERT_EQ(1, listener->updates.size());
-    EXPECT_EQ(1000, listener->updates[0].mKey.getValues()[0].mValue.int_value);
-    EXPECT_EQ(1, listener->updates[0].mState);
-    listener->updates.clear();
-
-    std::unique_ptr<LogEvent> event2 = CreateAcquireWakelockEvent(
-            timestampNs + 1000, attributionUids1, attributionTags1, "wakelockName");
-    mgr.onLogEvent(*event2);
-    ASSERT_EQ(0, listener->updates.size());
-
-    std::unique_ptr<LogEvent> event3 = CreateReleaseWakelockEvent(
-            timestampNs + 2000, attributionUids1, attributionTags1, "wakelockName");
-    mgr.onLogEvent(*event3);
-    ASSERT_EQ(0, listener->updates.size());
-
-    std::unique_ptr<LogEvent> event4 = CreateReleaseWakelockEvent(
-            timestampNs + 3000, attributionUids1, attributionTags1, "wakelockName");
-    mgr.onLogEvent(*event4);
-    ASSERT_EQ(1, listener->updates.size());
-    EXPECT_EQ(1000, listener->updates[0].mKey.getValues()[0].mValue.int_value);
-    EXPECT_EQ(0, listener->updates[0].mState);
-}
-
-/**
- * Test a state atom with a reset state.
- *
- * If the reset state value is seen, every state in the map is set to the default
- * state and every listener is notified.
- */
-TEST(StateTrackerTest, TestStateChangeReset) {
-    sp<TestStateListener> listener = new TestStateListener();
-    StateManager mgr;
-    mgr.registerListener(util::BLE_SCAN_STATE_CHANGED, listener);
-
-    std::vector<int> attributionUids1 = {1000};
-    std::vector<string> attributionTags1 = {"tag1"};
-    std::vector<int> attributionUids2 = {2000};
-
-    std::unique_ptr<LogEvent> event1 =
-            CreateBleScanStateChangedEvent(timestampNs, attributionUids1, attributionTags1,
-                                           BleScanStateChanged::ON, false, false, false);
-    mgr.onLogEvent(*event1);
-    ASSERT_EQ(1, listener->updates.size());
-    EXPECT_EQ(1000, listener->updates[0].mKey.getValues()[0].mValue.int_value);
-    EXPECT_EQ(BleScanStateChanged::ON, listener->updates[0].mState);
-    FieldValue stateFieldValue;
-    mgr.getStateValue(util::BLE_SCAN_STATE_CHANGED, listener->updates[0].mKey, &stateFieldValue);
-    EXPECT_EQ(BleScanStateChanged::ON, stateFieldValue.mValue.int_value);
-    listener->updates.clear();
-
-    std::unique_ptr<LogEvent> event2 =
-            CreateBleScanStateChangedEvent(timestampNs + 1000, attributionUids2, attributionTags1,
-                                           BleScanStateChanged::ON, false, false, false);
-    mgr.onLogEvent(*event2);
-    ASSERT_EQ(1, listener->updates.size());
-    EXPECT_EQ(2000, listener->updates[0].mKey.getValues()[0].mValue.int_value);
-    EXPECT_EQ(BleScanStateChanged::ON, listener->updates[0].mState);
-    mgr.getStateValue(util::BLE_SCAN_STATE_CHANGED, listener->updates[0].mKey, &stateFieldValue);
-    EXPECT_EQ(BleScanStateChanged::ON, stateFieldValue.mValue.int_value);
-    listener->updates.clear();
-
-    std::unique_ptr<LogEvent> event3 =
-            CreateBleScanStateChangedEvent(timestampNs + 2000, attributionUids2, attributionTags1,
-                                           BleScanStateChanged::RESET, false, false, false);
-    mgr.onLogEvent(*event3);
-    ASSERT_EQ(2, listener->updates.size());
-    for (const TestStateListener::Update& update : listener->updates) {
-        EXPECT_EQ(BleScanStateChanged::OFF, update.mState);
-
-        mgr.getStateValue(util::BLE_SCAN_STATE_CHANGED, update.mKey, &stateFieldValue);
-        EXPECT_EQ(BleScanStateChanged::OFF, stateFieldValue.mValue.int_value);
-    }
-}
-
-/**
- * Test StateManager's onLogEvent and StateListener's onStateChanged correctly
- * updates listener for states without primary keys.
- */
-TEST(StateTrackerTest, TestStateChangeNoPrimaryFields) {
-    sp<TestStateListener> listener1 = new TestStateListener();
-    StateManager mgr;
-    mgr.registerListener(util::SCREEN_STATE_CHANGED, listener1);
-
-    // log event
-    std::unique_ptr<LogEvent> event = CreateScreenStateChangedEvent(
-            timestampNs, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-    mgr.onLogEvent(*event);
-
-    // check listener was updated
-    ASSERT_EQ(1, listener1->updates.size());
-    EXPECT_EQ(DEFAULT_DIMENSION_KEY, listener1->updates[0].mKey);
-    EXPECT_EQ(2, listener1->updates[0].mState);
-
-    // check StateTracker was updated by querying for state
-    HashableDimensionKey queryKey = DEFAULT_DIMENSION_KEY;
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-              getStateInt(mgr, util::SCREEN_STATE_CHANGED, queryKey));
-}
-
-/**
- * Test StateManager's onLogEvent and StateListener's onStateChanged correctly
- * updates listener for states with one primary key.
- */
-TEST(StateTrackerTest, TestStateChangeOnePrimaryField) {
-    sp<TestStateListener> listener1 = new TestStateListener();
-    StateManager mgr;
-    mgr.registerListener(util::UID_PROCESS_STATE_CHANGED, listener1);
-
-    // log event
-    std::unique_ptr<LogEvent> event = CreateUidProcessStateChangedEvent(
-            timestampNs, 1000 /*uid*/, android::app::ProcessStateEnum::PROCESS_STATE_TOP);
-    mgr.onLogEvent(*event);
-
-    // check listener was updated
-    ASSERT_EQ(1, listener1->updates.size());
-    EXPECT_EQ(1000, listener1->updates[0].mKey.getValues()[0].mValue.int_value);
-    EXPECT_EQ(1002, listener1->updates[0].mState);
-
-    // check StateTracker was updated by querying for state
-    HashableDimensionKey queryKey;
-    getUidProcessKey(1000 /* uid */, &queryKey);
-    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_TOP,
-              getStateInt(mgr, util::UID_PROCESS_STATE_CHANGED, queryKey));
-}
-
-TEST(StateTrackerTest, TestStateChangePrimaryFieldAttrChain) {
-    sp<TestStateListener> listener1 = new TestStateListener();
-    StateManager mgr;
-    mgr.registerListener(util::WAKELOCK_STATE_CHANGED, listener1);
-
-    // Log event.
-    std::vector<int> attributionUids = {1001};
-    std::vector<string> attributionTags = {"tag1"};
-
-    std::unique_ptr<LogEvent> event = CreateAcquireWakelockEvent(timestampNs, attributionUids,
-                                                                 attributionTags, "wakelockName");
-    mgr.onLogEvent(*event);
-    EXPECT_EQ(1, mgr.getStateTrackersCount());
-    EXPECT_EQ(1, mgr.getListenersCount(util::WAKELOCK_STATE_CHANGED));
-
-    // Check listener was updated.
-    ASSERT_EQ(1, listener1->updates.size());
-    ASSERT_EQ(3, listener1->updates[0].mKey.getValues().size());
-    EXPECT_EQ(1001, listener1->updates[0].mKey.getValues()[0].mValue.int_value);
-    EXPECT_EQ(1, listener1->updates[0].mKey.getValues()[1].mValue.int_value);
-    EXPECT_EQ("wakelockName", listener1->updates[0].mKey.getValues()[2].mValue.str_value);
-    EXPECT_EQ(WakelockStateChanged::ACQUIRE, listener1->updates[0].mState);
-
-    // Check StateTracker was updated by querying for state.
-    HashableDimensionKey queryKey;
-    getPartialWakelockKey(1001 /* uid */, "wakelockName", &queryKey);
-    EXPECT_EQ(WakelockStateChanged::ACQUIRE,
-              getStateInt(mgr, util::WAKELOCK_STATE_CHANGED, queryKey));
-
-    // No state stored for this query key.
-    HashableDimensionKey queryKey2;
-    getPartialWakelockKey(1002 /* uid */, "tag1", &queryKey2);
-    EXPECT_EQ(-1 /*StateTracker::kStateUnknown*/,
-              getStateInt(mgr, util::WAKELOCK_STATE_CHANGED, queryKey2));
-
-    // Partial query fails.
-    HashableDimensionKey queryKey3;
-    getPartialWakelockKey(1001 /* uid */, &queryKey3);
-    EXPECT_EQ(-1 /*StateTracker::kStateUnknown*/,
-              getStateInt(mgr, util::WAKELOCK_STATE_CHANGED, queryKey3));
-}
-
-/**
- * Test StateManager's onLogEvent and StateListener's onStateChanged correctly
- * updates listener for states with multiple primary keys.
- */
-TEST(StateTrackerTest, TestStateChangeMultiplePrimaryFields) {
-    sp<TestStateListener> listener1 = new TestStateListener();
-    StateManager mgr;
-    mgr.registerListener(util::OVERLAY_STATE_CHANGED, listener1);
-
-    // log event
-    std::unique_ptr<LogEvent> event = CreateOverlayStateChangedEvent(
-            timestampNs, 1000 /* uid */, "package1", true /*using_alert_window*/,
-            OverlayStateChanged::ENTERED);
-    mgr.onLogEvent(*event);
-
-    // check listener was updated
-    ASSERT_EQ(1, listener1->updates.size());
-    EXPECT_EQ(1000, listener1->updates[0].mKey.getValues()[0].mValue.int_value);
-    EXPECT_EQ(1, listener1->updates[0].mState);
-
-    // check StateTracker was updated by querying for state
-    HashableDimensionKey queryKey;
-    getOverlayKey(1000 /* uid */, "package1", &queryKey);
-    EXPECT_EQ(OverlayStateChanged::ENTERED,
-              getStateInt(mgr, util::OVERLAY_STATE_CHANGED, queryKey));
-}
-
-/**
- * Test StateManager's onLogEvent and StateListener's onStateChanged
- * when there is an error extracting state from log event. Listener is not
- * updated of state change.
- */
-TEST(StateTrackerTest, TestStateChangeEventError) {
-    sp<TestStateListener> listener1 = new TestStateListener();
-    StateManager mgr;
-    mgr.registerListener(util::OVERLAY_STATE_CHANGED, listener1);
-
-    // log event
-    std::shared_ptr<LogEvent> event1 =
-            buildIncorrectOverlayEvent(1000 /* uid */, "package1", 1 /* state */);
-    std::shared_ptr<LogEvent> event2 = buildOverlayEventBadStateType(1001 /* uid */, "package2");
-
-    // check listener was updated
-    mgr.onLogEvent(*event1);
-    ASSERT_EQ(0, listener1->updates.size());
-    mgr.onLogEvent(*event2);
-    ASSERT_EQ(0, listener1->updates.size());
-}
-
-TEST(StateTrackerTest, TestStateQuery) {
-    sp<TestStateListener> listener1 = new TestStateListener();
-    sp<TestStateListener> listener2 = new TestStateListener();
-    sp<TestStateListener> listener3 = new TestStateListener();
-    sp<TestStateListener> listener4 = new TestStateListener();
-    StateManager mgr;
-    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::unique_ptr<LogEvent> event1 = CreateUidProcessStateChangedEvent(
-            timestampNs, 1000 /*uid*/,
-            android::app::ProcessStateEnum::PROCESS_STATE_TOP);  //  state value: 1002
-    std::unique_ptr<LogEvent> event2 = CreateUidProcessStateChangedEvent(
-            timestampNs + 1000, 1001 /*uid*/,
-            android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE);  //  state value:
-                                                                                //  1003
-    std::unique_ptr<LogEvent> event3 = CreateUidProcessStateChangedEvent(
-            timestampNs + 2000, 1002 /*uid*/,
-            android::app::ProcessStateEnum::PROCESS_STATE_PERSISTENT);  //  state value: 1000
-    std::unique_ptr<LogEvent> event4 = CreateUidProcessStateChangedEvent(
-            timestampNs + 3000, 1001 /*uid*/,
-            android::app::ProcessStateEnum::PROCESS_STATE_TOP);  //  state value: 1002
-    std::unique_ptr<LogEvent> event5 = CreateScreenStateChangedEvent(
-            timestampNs + 4000, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-    std::unique_ptr<LogEvent> event6 = CreateOverlayStateChangedEvent(
-            timestampNs + 5000, 1000 /*uid*/, "package1", true /*using_alert_window*/,
-            OverlayStateChanged::ENTERED);
-    std::unique_ptr<LogEvent> event7 = CreateOverlayStateChangedEvent(
-            timestampNs + 6000, 1000 /*uid*/, "package2", true /*using_alert_window*/,
-            OverlayStateChanged::EXITED);
-
-    std::vector<int> attributionUids = {1005};
-    std::vector<string> attributionTags = {"tag"};
-
-    std::unique_ptr<LogEvent> event8 = CreateAcquireWakelockEvent(
-            timestampNs + 7000, attributionUids, attributionTags, "wakelock1");
-    std::unique_ptr<LogEvent> event9 = CreateReleaseWakelockEvent(
-            timestampNs + 8000, attributionUids, attributionTags, "wakelock2");
-
-    mgr.onLogEvent(*event1);
-    mgr.onLogEvent(*event2);
-    mgr.onLogEvent(*event3);
-    mgr.onLogEvent(*event5);
-    mgr.onLogEvent(*event5);
-    mgr.onLogEvent(*event6);
-    mgr.onLogEvent(*event7);
-    mgr.onLogEvent(*event8);
-    mgr.onLogEvent(*event9);
-
-    // Query for UidProcessState of uid 1001
-    HashableDimensionKey queryKey1;
-    getUidProcessKey(1001, &queryKey1);
-    EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE,
-              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, 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, util::UID_PROCESS_STATE_CHANGED, queryKey1));
-
-    // Query for ScreenState
-    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-              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, util::OVERLAY_STATE_CHANGED, queryKey3));
-
-    // Query for WakelockState of uid 1005, tag 2
-    HashableDimensionKey queryKey4;
-    getPartialWakelockKey(1005, "wakelock2", &queryKey4);
-    EXPECT_EQ(WakelockStateChanged::RELEASE,
-              getStateInt(mgr, util::WAKELOCK_STATE_CHANGED, queryKey4));
-
-    // Query for WakelockState of uid 1005, tag 1
-    HashableDimensionKey queryKey5;
-    getPartialWakelockKey(1005, "wakelock1", &queryKey5);
-    EXPECT_EQ(WakelockStateChanged::ACQUIRE,
-              getStateInt(mgr, util::WAKELOCK_STATE_CHANGED, queryKey5));
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
deleted file mode 100644
index 153b696..0000000
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ /dev/null
@@ -1,1424 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "statsd_test_util.h"
-
-#include <aidl/android/util/StatsEventParcel.h>
-
-#include "matchers/SimpleAtomMatchingTracker.h"
-#include "stats_event.h"
-
-using aidl::android::util::StatsEventParcel;
-using std::shared_ptr;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-StatsLogReport outputStreamToProto(ProtoOutputStream* proto) {
-    vector<uint8_t> bytes;
-    bytes.resize(proto->size());
-    size_t pos = 0;
-    sp<ProtoReader> reader = proto->data();
-
-    while (reader->readBuffer() != NULL) {
-        size_t toRead = reader->currentToRead();
-        std::memcpy(&((bytes)[pos]), reader->readBuffer(), toRead);
-        pos += toRead;
-        reader->move(toRead);
-    }
-
-    StatsLogReport report;
-    report.ParseFromArray(bytes.data(), bytes.size());
-    return report;
-}
-
-AtomMatcher CreateSimpleAtomMatcher(const string& name, int atomId) {
-    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(atomId);
-    return atom_matcher;
-}
-
-AtomMatcher CreateTemperatureAtomMatcher() {
-    return CreateSimpleAtomMatcher("TemperatureMatcher", util::TEMPERATURE);
-}
-
-AtomMatcher CreateScheduledJobStateChangedAtomMatcher(const string& name,
-                                                      ScheduledJobStateChanged::State state) {
-    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(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);
-    return atom_matcher;
-}
-
-AtomMatcher CreateStartScheduledJobAtomMatcher() {
-    return CreateScheduledJobStateChangedAtomMatcher("ScheduledJobStart",
-                                                     ScheduledJobStateChanged::STARTED);
-}
-
-AtomMatcher CreateFinishScheduledJobAtomMatcher() {
-    return CreateScheduledJobStateChangedAtomMatcher("ScheduledJobFinish",
-                                                     ScheduledJobStateChanged::FINISHED);
-}
-
-AtomMatcher CreateScreenBrightnessChangedAtomMatcher() {
-    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(util::SCREEN_BRIGHTNESS_CHANGED);
-    return atom_matcher;
-}
-
-AtomMatcher CreateUidProcessStateChangedAtomMatcher() {
-    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(util::UID_PROCESS_STATE_CHANGED);
-    return atom_matcher;
-}
-
-AtomMatcher CreateWakelockStateChangedAtomMatcher(const string& name,
-                                                  WakelockStateChanged::State state) {
-    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(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);
-    return atom_matcher;
-}
-
-AtomMatcher CreateAcquireWakelockAtomMatcher() {
-    return CreateWakelockStateChangedAtomMatcher("AcquireWakelock", WakelockStateChanged::ACQUIRE);
-}
-
-AtomMatcher CreateReleaseWakelockAtomMatcher() {
-    return CreateWakelockStateChangedAtomMatcher("ReleaseWakelock", WakelockStateChanged::RELEASE);
-}
-
-AtomMatcher CreateBatterySaverModeStateChangedAtomMatcher(
-    const string& name, BatterySaverModeStateChanged::State state) {
-    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(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);
-    return atom_matcher;
-}
-
-AtomMatcher CreateBatterySaverModeStartAtomMatcher() {
-    return CreateBatterySaverModeStateChangedAtomMatcher(
-        "BatterySaverModeStart", BatterySaverModeStateChanged::ON);
-}
-
-
-AtomMatcher CreateBatterySaverModeStopAtomMatcher() {
-    return CreateBatterySaverModeStateChangedAtomMatcher(
-        "BatterySaverModeStop", BatterySaverModeStateChanged::OFF);
-}
-
-AtomMatcher CreateBatteryStateChangedAtomMatcher(const string& name,
-                                                 BatteryPluggedStateEnum state) {
-    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(util::PLUGGED_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);
-    return atom_matcher;
-}
-
-AtomMatcher CreateBatteryStateNoneMatcher() {
-    return CreateBatteryStateChangedAtomMatcher("BatteryPluggedNone",
-                                                BatteryPluggedStateEnum::BATTERY_PLUGGED_NONE);
-}
-
-AtomMatcher CreateBatteryStateUsbMatcher() {
-    return CreateBatteryStateChangedAtomMatcher("BatteryPluggedUsb",
-                                                BatteryPluggedStateEnum::BATTERY_PLUGGED_USB);
-}
-
-AtomMatcher CreateScreenStateChangedAtomMatcher(
-    const string& name, android::view::DisplayStateEnum state) {
-    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(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);
-    return atom_matcher;
-}
-
-AtomMatcher CreateScreenTurnedOnAtomMatcher() {
-    return CreateScreenStateChangedAtomMatcher("ScreenTurnedOn",
-            android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-}
-
-AtomMatcher CreateScreenTurnedOffAtomMatcher() {
-    return CreateScreenStateChangedAtomMatcher("ScreenTurnedOff",
-            ::android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
-}
-
-AtomMatcher CreateSyncStateChangedAtomMatcher(
-    const string& name, SyncStateChanged::State state) {
-    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(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);
-    return atom_matcher;
-}
-
-AtomMatcher CreateSyncStartAtomMatcher() {
-    return CreateSyncStateChangedAtomMatcher("SyncStart", SyncStateChanged::ON);
-}
-
-AtomMatcher CreateSyncEndAtomMatcher() {
-    return CreateSyncStateChangedAtomMatcher("SyncEnd", SyncStateChanged::OFF);
-}
-
-AtomMatcher CreateActivityForegroundStateChangedAtomMatcher(
-    const string& name, ActivityForegroundStateChanged::State state) {
-    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(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);
-    return atom_matcher;
-}
-
-AtomMatcher CreateMoveToBackgroundAtomMatcher() {
-    return CreateActivityForegroundStateChangedAtomMatcher(
-        "Background", ActivityForegroundStateChanged::BACKGROUND);
-}
-
-AtomMatcher CreateMoveToForegroundAtomMatcher() {
-    return CreateActivityForegroundStateChangedAtomMatcher(
-        "Foreground", ActivityForegroundStateChanged::FOREGROUND);
-}
-
-AtomMatcher CreateProcessLifeCycleStateChangedAtomMatcher(
-    const string& name, ProcessLifeCycleStateChanged::State state) {
-    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(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);
-    return atom_matcher;
-}
-
-AtomMatcher CreateProcessCrashAtomMatcher() {
-    return CreateProcessLifeCycleStateChangedAtomMatcher(
-        "Crashed", ProcessLifeCycleStateChanged::CRASHED);
-}
-
-Predicate CreateScheduledJobPredicate() {
-    Predicate predicate;
-    predicate.set_id(StringToId("ScheduledJobRunningPredicate"));
-    predicate.mutable_simple_predicate()->set_start(StringToId("ScheduledJobStart"));
-    predicate.mutable_simple_predicate()->set_stop(StringToId("ScheduledJobFinish"));
-    return predicate;
-}
-
-Predicate CreateBatterySaverModePredicate() {
-    Predicate predicate;
-    predicate.set_id(StringToId("BatterySaverIsOn"));
-    predicate.mutable_simple_predicate()->set_start(StringToId("BatterySaverModeStart"));
-    predicate.mutable_simple_predicate()->set_stop(StringToId("BatterySaverModeStop"));
-    return predicate;
-}
-
-Predicate CreateDeviceUnpluggedPredicate() {
-    Predicate predicate;
-    predicate.set_id(StringToId("DeviceUnplugged"));
-    predicate.mutable_simple_predicate()->set_start(StringToId("BatteryPluggedNone"));
-    predicate.mutable_simple_predicate()->set_stop(StringToId("BatteryPluggedUsb"));
-    return predicate;
-}
-
-Predicate CreateScreenIsOnPredicate() {
-    Predicate predicate;
-    predicate.set_id(StringToId("ScreenIsOn"));
-    predicate.mutable_simple_predicate()->set_start(StringToId("ScreenTurnedOn"));
-    predicate.mutable_simple_predicate()->set_stop(StringToId("ScreenTurnedOff"));
-    return predicate;
-}
-
-Predicate CreateScreenIsOffPredicate() {
-    Predicate predicate;
-    predicate.set_id(1111123);
-    predicate.mutable_simple_predicate()->set_start(StringToId("ScreenTurnedOff"));
-    predicate.mutable_simple_predicate()->set_stop(StringToId("ScreenTurnedOn"));
-    return predicate;
-}
-
-Predicate CreateHoldingWakelockPredicate() {
-    Predicate predicate;
-    predicate.set_id(StringToId("HoldingWakelock"));
-    predicate.mutable_simple_predicate()->set_start(StringToId("AcquireWakelock"));
-    predicate.mutable_simple_predicate()->set_stop(StringToId("ReleaseWakelock"));
-    return predicate;
-}
-
-Predicate CreateIsSyncingPredicate() {
-    Predicate predicate;
-    predicate.set_id(33333333333333);
-    predicate.mutable_simple_predicate()->set_start(StringToId("SyncStart"));
-    predicate.mutable_simple_predicate()->set_stop(StringToId("SyncEnd"));
-    return predicate;
-}
-
-Predicate CreateIsInBackgroundPredicate() {
-    Predicate predicate;
-    predicate.set_id(StringToId("IsInBackground"));
-    predicate.mutable_simple_predicate()->set_start(StringToId("Background"));
-    predicate.mutable_simple_predicate()->set_stop(StringToId("Foreground"));
-    return predicate;
-}
-
-State CreateScreenState() {
-    State state;
-    state.set_id(StringToId("ScreenState"));
-    state.set_atom_id(util::SCREEN_STATE_CHANGED);
-    return state;
-}
-
-State CreateUidProcessState() {
-    State state;
-    state.set_id(StringToId("UidProcessState"));
-    state.set_atom_id(util::UID_PROCESS_STATE_CHANGED);
-    return state;
-}
-
-State CreateOverlayState() {
-    State state;
-    state.set_id(StringToId("OverlayState"));
-    state.set_atom_id(util::OVERLAY_STATE_CHANGED);
-    return state;
-}
-
-State CreateScreenStateWithOnOffMap(int64_t screenOnId, int64_t screenOffId) {
-    State state;
-    state.set_id(StringToId("ScreenStateOnOff"));
-    state.set_atom_id(util::SCREEN_STATE_CHANGED);
-
-    auto map = CreateScreenStateOnOffMap(screenOnId, screenOffId);
-    *state.mutable_map() = map;
-
-    return state;
-}
-
-State CreateScreenStateWithSimpleOnOffMap(int64_t screenOnId, int64_t screenOffId) {
-    State state;
-    state.set_id(StringToId("ScreenStateSimpleOnOff"));
-    state.set_atom_id(util::SCREEN_STATE_CHANGED);
-
-    auto map = CreateScreenStateSimpleOnOffMap(screenOnId, screenOffId);
-    *state.mutable_map() = map;
-
-    return state;
-}
-
-StateMap_StateGroup CreateScreenStateOnGroup(int64_t screenOnId) {
-    StateMap_StateGroup group;
-    group.set_group_id(screenOnId);
-    group.add_value(android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-    group.add_value(android::view::DisplayStateEnum::DISPLAY_STATE_VR);
-    group.add_value(android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND);
-    return group;
-}
-
-StateMap_StateGroup CreateScreenStateOffGroup(int64_t screenOffId) {
-    StateMap_StateGroup group;
-    group.set_group_id(screenOffId);
-    group.add_value(android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
-    group.add_value(android::view::DisplayStateEnum::DISPLAY_STATE_DOZE);
-    group.add_value(android::view::DisplayStateEnum::DISPLAY_STATE_DOZE_SUSPEND);
-    return group;
-}
-
-StateMap_StateGroup CreateScreenStateSimpleOnGroup(int64_t screenOnId) {
-    StateMap_StateGroup group;
-    group.set_group_id(screenOnId);
-    group.add_value(android::view::DisplayStateEnum::DISPLAY_STATE_ON);
-    return group;
-}
-
-StateMap_StateGroup CreateScreenStateSimpleOffGroup(int64_t screenOffId) {
-    StateMap_StateGroup group;
-    group.set_group_id(screenOffId);
-    group.add_value(android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
-    return group;
-}
-
-StateMap CreateScreenStateOnOffMap(int64_t screenOnId, int64_t screenOffId) {
-    StateMap map;
-    *map.add_group() = CreateScreenStateOnGroup(screenOnId);
-    *map.add_group() = CreateScreenStateOffGroup(screenOffId);
-    return map;
-}
-
-StateMap CreateScreenStateSimpleOnOffMap(int64_t screenOnId, int64_t screenOffId) {
-    StateMap map;
-    *map.add_group() = CreateScreenStateSimpleOnGroup(screenOnId);
-    *map.add_group() = CreateScreenStateSimpleOffGroup(screenOffId);
-    return map;
-}
-
-void addPredicateToPredicateCombination(const Predicate& predicate,
-                                        Predicate* combinationPredicate) {
-    combinationPredicate->mutable_combination()->add_predicate(predicate.id());
-}
-
-FieldMatcher CreateAttributionUidDimensions(const int atomId,
-                                            const std::vector<Position>& positions) {
-    FieldMatcher dimensions;
-    dimensions.set_field(atomId);
-    for (const auto position : positions) {
-        auto child = dimensions.add_child();
-        child->set_field(1);
-        child->set_position(position);
-        child->add_child()->set_field(1);
-    }
-    return dimensions;
-}
-
-FieldMatcher CreateAttributionUidAndTagDimensions(const int atomId,
-                                                 const std::vector<Position>& positions) {
-    FieldMatcher dimensions;
-    dimensions.set_field(atomId);
-    for (const auto position : positions) {
-        auto child = dimensions.add_child();
-        child->set_field(1);
-        child->set_position(position);
-        child->add_child()->set_field(1);
-        child->add_child()->set_field(2);
-    }
-    return dimensions;
-}
-
-FieldMatcher CreateDimensions(const int atomId, const std::vector<int>& fields) {
-    FieldMatcher dimensions;
-    dimensions.set_field(atomId);
-    for (const int field : fields) {
-        dimensions.add_child()->set_field(field);
-    }
-    return dimensions;
-}
-
-FieldMatcher CreateAttributionUidAndOtherDimensions(const int atomId,
-                                                    const std::vector<Position>& positions,
-                                                    const std::vector<int>& fields) {
-    FieldMatcher dimensions = CreateAttributionUidDimensions(atomId, positions);
-
-    for (const int field : fields) {
-        dimensions.add_child()->set_field(field);
-    }
-    return dimensions;
-}
-
-// START: get primary key functions
-void getUidProcessKey(int uid, HashableDimensionKey* key) {
-    int pos1[] = {1, 0, 0};
-    Field field1(27 /* atom id */, pos1, 0 /* depth */);
-    Value value1((int32_t)uid);
-
-    key->addValue(FieldValue(field1, value1));
-}
-
-void getOverlayKey(int uid, string packageName, HashableDimensionKey* key) {
-    int pos1[] = {1, 0, 0};
-    int pos2[] = {2, 0, 0};
-
-    Field field1(59 /* atom id */, pos1, 0 /* depth */);
-    Field field2(59 /* atom id */, pos2, 0 /* depth */);
-
-    Value value1((int32_t)uid);
-    Value value2(packageName);
-
-    key->addValue(FieldValue(field1, value1));
-    key->addValue(FieldValue(field2, value2));
-}
-
-void getPartialWakelockKey(int uid, const std::string& tag, HashableDimensionKey* key) {
-    int pos1[] = {1, 1, 1};
-    int pos3[] = {2, 0, 0};
-    int pos4[] = {3, 0, 0};
-
-    Field field1(10 /* atom id */, pos1, 2 /* depth */);
-
-    Field field3(10 /* atom id */, pos3, 0 /* depth */);
-    Field field4(10 /* atom id */, pos4, 0 /* depth */);
-
-    Value value1((int32_t)uid);
-    Value value3((int32_t)1 /*partial*/);
-    Value value4(tag);
-
-    key->addValue(FieldValue(field1, value1));
-    key->addValue(FieldValue(field3, value3));
-    key->addValue(FieldValue(field4, value4));
-}
-
-void getPartialWakelockKey(int uid, HashableDimensionKey* key) {
-    int pos1[] = {1, 1, 1};
-    int pos3[] = {2, 0, 0};
-
-    Field field1(10 /* atom id */, pos1, 2 /* depth */);
-    Field field3(10 /* atom id */, pos3, 0 /* depth */);
-
-    Value value1((int32_t)uid);
-    Value value3((int32_t)1 /*partial*/);
-
-    key->addValue(FieldValue(field1, value1));
-    key->addValue(FieldValue(field3, value3));
-}
-// END: get primary key functions
-
-void writeAttribution(AStatsEvent* statsEvent, const vector<int>& attributionUids,
-                      const vector<string>& attributionTags) {
-    vector<const char*> cTags(attributionTags.size());
-    for (int i = 0; i < cTags.size(); i++) {
-        cTags[i] = attributionTags[i].c_str();
-    }
-
-    AStatsEvent_writeAttributionChain(statsEvent,
-                                      reinterpret_cast<const uint32_t*>(attributionUids.data()),
-                                      cTags.data(), attributionUids.size());
-}
-
-void parseStatsEventToLogEvent(AStatsEvent* statsEvent, LogEvent* logEvent) {
-    AStatsEvent_build(statsEvent);
-
-    size_t size;
-    uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
-    logEvent->parseBuffer(buf, size);
-
-    AStatsEvent_release(statsEvent);
-}
-
-void CreateTwoValueLogEvent(LogEvent* logEvent, int atomId, int64_t eventTimeNs, int32_t value1,
-                            int32_t value2) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, atomId);
-    AStatsEvent_overwriteTimestamp(statsEvent, eventTimeNs);
-
-    AStatsEvent_writeInt32(statsEvent, value1);
-    AStatsEvent_writeInt32(statsEvent, value2);
-
-    parseStatsEventToLogEvent(statsEvent, logEvent);
-}
-
-shared_ptr<LogEvent> CreateTwoValueLogEvent(int atomId, int64_t eventTimeNs, int32_t value1,
-                                            int32_t value2) {
-    shared_ptr<LogEvent> logEvent = std::make_shared<LogEvent>(/*uid=*/0, /*pid=*/0);
-    CreateTwoValueLogEvent(logEvent.get(), atomId, eventTimeNs, value1, value2);
-    return logEvent;
-}
-
-void CreateThreeValueLogEvent(LogEvent* logEvent, int atomId, int64_t eventTimeNs, int32_t value1,
-                              int32_t value2, int32_t value3) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, atomId);
-    AStatsEvent_overwriteTimestamp(statsEvent, eventTimeNs);
-
-    AStatsEvent_writeInt32(statsEvent, value1);
-    AStatsEvent_writeInt32(statsEvent, value2);
-    AStatsEvent_writeInt32(statsEvent, value3);
-
-    parseStatsEventToLogEvent(statsEvent, logEvent);
-}
-
-shared_ptr<LogEvent> CreateThreeValueLogEvent(int atomId, int64_t eventTimeNs, int32_t value1,
-                                              int32_t value2, int32_t value3) {
-    shared_ptr<LogEvent> logEvent = std::make_shared<LogEvent>(/*uid=*/0, /*pid=*/0);
-    CreateThreeValueLogEvent(logEvent.get(), atomId, eventTimeNs, value1, value2, value3);
-    return logEvent;
-}
-
-void CreateRepeatedValueLogEvent(LogEvent* logEvent, int atomId, int64_t eventTimeNs,
-                                 int32_t value) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, atomId);
-    AStatsEvent_overwriteTimestamp(statsEvent, eventTimeNs);
-
-    AStatsEvent_writeInt32(statsEvent, value);
-    AStatsEvent_writeInt32(statsEvent, value);
-
-    parseStatsEventToLogEvent(statsEvent, logEvent);
-}
-
-shared_ptr<LogEvent> CreateRepeatedValueLogEvent(int atomId, int64_t eventTimeNs, int32_t value) {
-    shared_ptr<LogEvent> logEvent = std::make_shared<LogEvent>(/*uid=*/0, /*pid=*/0);
-    CreateRepeatedValueLogEvent(logEvent.get(), atomId, eventTimeNs, value);
-    return logEvent;
-}
-
-void CreateNoValuesLogEvent(LogEvent* logEvent, int atomId, int64_t eventTimeNs) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, atomId);
-    AStatsEvent_overwriteTimestamp(statsEvent, eventTimeNs);
-
-    parseStatsEventToLogEvent(statsEvent, logEvent);
-}
-
-shared_ptr<LogEvent> CreateNoValuesLogEvent(int atomId, int64_t eventTimeNs) {
-    shared_ptr<LogEvent> logEvent = std::make_shared<LogEvent>(/*uid=*/0, /*pid=*/0);
-    CreateNoValuesLogEvent(logEvent.get(), atomId, eventTimeNs);
-    return logEvent;
-}
-
-shared_ptr<LogEvent> makeUidLogEvent(int atomId, int64_t eventTimeNs, int uid, int data1,
-                                     int data2) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, atomId);
-    AStatsEvent_overwriteTimestamp(statsEvent, eventTimeNs);
-
-    AStatsEvent_writeInt32(statsEvent, uid);
-    AStatsEvent_addBoolAnnotation(statsEvent, ANNOTATION_ID_IS_UID, true);
-    AStatsEvent_writeInt32(statsEvent, data1);
-    AStatsEvent_writeInt32(statsEvent, data2);
-
-    shared_ptr<LogEvent> logEvent = std::make_shared<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-shared_ptr<LogEvent> makeAttributionLogEvent(int atomId, int64_t eventTimeNs,
-                                             const vector<int>& uids, const vector<string>& tags,
-                                             int data1, int data2) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, atomId);
-    AStatsEvent_overwriteTimestamp(statsEvent, eventTimeNs);
-
-    writeAttribution(statsEvent, uids, tags);
-    AStatsEvent_writeInt32(statsEvent, data1);
-    AStatsEvent_writeInt32(statsEvent, data2);
-
-    shared_ptr<LogEvent> logEvent = std::make_shared<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-sp<MockUidMap> makeMockUidMapForOneHost(int hostUid, const vector<int>& isolatedUids) {
-    sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
-    EXPECT_CALL(*uidMap, getHostUidOrSelf(_)).WillRepeatedly(ReturnArg<0>());
-    for (const int isolatedUid : isolatedUids) {
-        EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid)).WillRepeatedly(Return(hostUid));
-    }
-
-    return uidMap;
-}
-
-sp<MockUidMap> makeMockUidMapForPackage(const string& pkg, const set<int32_t>& uids) {
-    sp<MockUidMap> uidMap = new StrictMock<MockUidMap>();
-    EXPECT_CALL(*uidMap, getAppUid(_)).Times(AnyNumber());
-    EXPECT_CALL(*uidMap, getAppUid(pkg)).WillRepeatedly(Return(uids));
-
-    return uidMap;
-}
-
-std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(uint64_t timestampNs,
-                                                        const android::view::DisplayStateEnum state,
-                                                        int loggerUid) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, util::SCREEN_STATE_CHANGED);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-    AStatsEvent_writeInt32(statsEvent, state);
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_EXCLUSIVE_STATE, true);
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_STATE_NESTED, false);
-
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(loggerUid, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-std::unique_ptr<LogEvent> CreateBatterySaverOnEvent(uint64_t timestampNs) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, util::BATTERY_SAVER_MODE_STATE_CHANGED);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-    AStatsEvent_writeInt32(statsEvent, BatterySaverModeStateChanged::ON);
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_EXCLUSIVE_STATE, true);
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_STATE_NESTED, false);
-
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-std::unique_ptr<LogEvent> CreateBatterySaverOffEvent(uint64_t timestampNs) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, util::BATTERY_SAVER_MODE_STATE_CHANGED);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-    AStatsEvent_writeInt32(statsEvent, BatterySaverModeStateChanged::OFF);
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_EXCLUSIVE_STATE, true);
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_STATE_NESTED, false);
-
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-std::unique_ptr<LogEvent> CreateBatteryStateChangedEvent(const uint64_t timestampNs, const BatteryPluggedStateEnum state) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, util::PLUGGED_STATE_CHANGED);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-    AStatsEvent_writeInt32(statsEvent, state);
-
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(uint64_t timestampNs, int level) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, util::SCREEN_BRIGHTNESS_CHANGED);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-    AStatsEvent_writeInt32(statsEvent, level);
-
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-std::unique_ptr<LogEvent> CreateScheduledJobStateChangedEvent(
-        const vector<int>& attributionUids, const vector<string>& attributionTags,
-        const string& jobName, const ScheduledJobStateChanged::State state, uint64_t timestampNs) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, util::SCHEDULED_JOB_STATE_CHANGED);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-
-    writeAttribution(statsEvent, attributionUids, attributionTags);
-    AStatsEvent_writeString(statsEvent, jobName.c_str());
-    AStatsEvent_writeInt32(statsEvent, state);
-
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-std::unique_ptr<LogEvent> CreateStartScheduledJobEvent(uint64_t timestampNs,
-                                                       const vector<int>& attributionUids,
-                                                       const vector<string>& attributionTags,
-                                                       const string& jobName) {
-    return CreateScheduledJobStateChangedEvent(attributionUids, attributionTags, jobName,
-                                               ScheduledJobStateChanged::STARTED, timestampNs);
-}
-
-// Create log event when scheduled job finishes.
-std::unique_ptr<LogEvent> CreateFinishScheduledJobEvent(uint64_t timestampNs,
-                                                        const vector<int>& attributionUids,
-                                                        const vector<string>& attributionTags,
-                                                        const string& jobName) {
-    return CreateScheduledJobStateChangedEvent(attributionUids, attributionTags, jobName,
-                                               ScheduledJobStateChanged::FINISHED, timestampNs);
-}
-
-std::unique_ptr<LogEvent> CreateWakelockStateChangedEvent(uint64_t timestampNs,
-                                                          const vector<int>& attributionUids,
-                                                          const vector<string>& attributionTags,
-                                                          const string& wakelockName,
-                                                          const WakelockStateChanged::State state) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, util::WAKELOCK_STATE_CHANGED);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-
-    writeAttribution(statsEvent, attributionUids, attributionTags);
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID, true);
-    AStatsEvent_writeInt32(statsEvent, android::os::WakeLockLevelEnum::PARTIAL_WAKE_LOCK);
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_PRIMARY_FIELD, true);
-    AStatsEvent_writeString(statsEvent, wakelockName.c_str());
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_PRIMARY_FIELD, true);
-    AStatsEvent_writeInt32(statsEvent, state);
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_EXCLUSIVE_STATE, true);
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_STATE_NESTED, true);
-
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-std::unique_ptr<LogEvent> CreateAcquireWakelockEvent(uint64_t timestampNs,
-                                                     const vector<int>& attributionUids,
-                                                     const vector<string>& attributionTags,
-                                                     const string& wakelockName) {
-    return CreateWakelockStateChangedEvent(timestampNs, attributionUids, attributionTags,
-                                           wakelockName, WakelockStateChanged::ACQUIRE);
-}
-
-std::unique_ptr<LogEvent> CreateReleaseWakelockEvent(uint64_t timestampNs,
-                                                     const vector<int>& attributionUids,
-                                                     const vector<string>& attributionTags,
-                                                     const string& wakelockName) {
-    return CreateWakelockStateChangedEvent(timestampNs, attributionUids, attributionTags,
-                                           wakelockName, WakelockStateChanged::RELEASE);
-}
-
-std::unique_ptr<LogEvent> CreateActivityForegroundStateChangedEvent(
-        uint64_t timestampNs, const int uid, const ActivityForegroundStateChanged::State state) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, util::ACTIVITY_FOREGROUND_STATE_CHANGED);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-
-    AStatsEvent_writeInt32(statsEvent, uid);
-    AStatsEvent_writeString(statsEvent, "pkg_name");
-    AStatsEvent_writeString(statsEvent, "class_name");
-    AStatsEvent_writeInt32(statsEvent, state);
-
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(uint64_t timestampNs, const int uid) {
-    return CreateActivityForegroundStateChangedEvent(timestampNs, uid,
-                                                     ActivityForegroundStateChanged::BACKGROUND);
-}
-
-std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(uint64_t timestampNs, const int uid) {
-    return CreateActivityForegroundStateChangedEvent(timestampNs, uid,
-                                                     ActivityForegroundStateChanged::FOREGROUND);
-}
-
-std::unique_ptr<LogEvent> CreateSyncStateChangedEvent(uint64_t timestampNs,
-                                                      const vector<int>& attributionUids,
-                                                      const vector<string>& attributionTags,
-                                                      const string& name,
-                                                      const SyncStateChanged::State state) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, util::SYNC_STATE_CHANGED);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-
-    writeAttribution(statsEvent, attributionUids, attributionTags);
-    AStatsEvent_writeString(statsEvent, name.c_str());
-    AStatsEvent_writeInt32(statsEvent, state);
-
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-std::unique_ptr<LogEvent> CreateSyncStartEvent(uint64_t timestampNs,
-                                               const vector<int>& attributionUids,
-                                               const vector<string>& attributionTags,
-                                               const string& name) {
-    return CreateSyncStateChangedEvent(timestampNs, attributionUids, attributionTags, name,
-                                       SyncStateChanged::ON);
-}
-
-std::unique_ptr<LogEvent> CreateSyncEndEvent(uint64_t timestampNs,
-                                             const vector<int>& attributionUids,
-                                             const vector<string>& attributionTags,
-                                             const string& name) {
-    return CreateSyncStateChangedEvent(timestampNs, attributionUids, attributionTags, name,
-                                       SyncStateChanged::OFF);
-}
-
-std::unique_ptr<LogEvent> CreateProcessLifeCycleStateChangedEvent(
-        uint64_t timestampNs, const int uid, const ProcessLifeCycleStateChanged::State state) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-
-    AStatsEvent_writeInt32(statsEvent, uid);
-    AStatsEvent_writeString(statsEvent, "");
-    AStatsEvent_writeInt32(statsEvent, state);
-
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-std::unique_ptr<LogEvent> CreateAppCrashEvent(uint64_t timestampNs, const int uid) {
-    return CreateProcessLifeCycleStateChangedEvent(timestampNs, uid,
-                                                   ProcessLifeCycleStateChanged::CRASHED);
-}
-
-std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(uint64_t timestampNs, const int uid) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, util::APP_CRASH_OCCURRED);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-
-    AStatsEvent_writeInt32(statsEvent, uid);
-    AStatsEvent_writeString(statsEvent, "eventType");
-    AStatsEvent_writeString(statsEvent, "processName");
-
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(uint64_t timestampNs, int hostUid,
-                                                        int isolatedUid, bool is_create) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, util::ISOLATED_UID_CHANGED);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-
-    AStatsEvent_writeInt32(statsEvent, hostUid);
-    AStatsEvent_writeInt32(statsEvent, isolatedUid);
-    AStatsEvent_writeInt32(statsEvent, is_create);
-
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent(
-        uint64_t timestampNs, int uid, const android::app::ProcessStateEnum state) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, util::UID_PROCESS_STATE_CHANGED);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-
-    AStatsEvent_writeInt32(statsEvent, uid);
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_IS_UID, true);
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_PRIMARY_FIELD, true);
-    AStatsEvent_writeInt32(statsEvent, state);
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_EXCLUSIVE_STATE, true);
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_STATE_NESTED, false);
-
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-std::unique_ptr<LogEvent> CreateBleScanStateChangedEvent(uint64_t timestampNs,
-                                                         const vector<int>& attributionUids,
-                                                         const vector<string>& attributionTags,
-                                                         const BleScanStateChanged::State state,
-                                                         const bool filtered, const bool firstMatch,
-                                                         const bool opportunistic) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, util::BLE_SCAN_STATE_CHANGED);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-
-    writeAttribution(statsEvent, attributionUids, attributionTags);
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID, true);
-    AStatsEvent_writeInt32(statsEvent, state);
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_EXCLUSIVE_STATE, true);
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_STATE_NESTED, true);
-    if (state == util::BLE_SCAN_STATE_CHANGED__STATE__RESET) {
-        AStatsEvent_addInt32Annotation(statsEvent, ANNOTATION_ID_TRIGGER_STATE_RESET,
-                                       util::BLE_SCAN_STATE_CHANGED__STATE__OFF);
-    }
-    AStatsEvent_writeBool(statsEvent, filtered);  // filtered
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_PRIMARY_FIELD, true);
-    AStatsEvent_writeBool(statsEvent, firstMatch);  // first match
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_PRIMARY_FIELD, true);
-    AStatsEvent_writeBool(statsEvent, opportunistic);  // opportunistic
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_PRIMARY_FIELD, true);
-
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-std::unique_ptr<LogEvent> CreateOverlayStateChangedEvent(int64_t timestampNs, const int32_t uid,
-                                                         const string& packageName,
-                                                         const bool usingAlertWindow,
-                                                         const OverlayStateChanged::State state) {
-    AStatsEvent* statsEvent = AStatsEvent_obtain();
-    AStatsEvent_setAtomId(statsEvent, util::OVERLAY_STATE_CHANGED);
-    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
-
-    AStatsEvent_writeInt32(statsEvent, uid);
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_IS_UID, true);
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_PRIMARY_FIELD, true);
-    AStatsEvent_writeString(statsEvent, packageName.c_str());
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_PRIMARY_FIELD, true);
-    AStatsEvent_writeBool(statsEvent, usingAlertWindow);
-    AStatsEvent_writeInt32(statsEvent, state);
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_EXCLUSIVE_STATE, true);
-    AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_STATE_NESTED, false);
-
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
-    parseStatsEventToLogEvent(statsEvent, logEvent.get());
-    return logEvent;
-}
-
-sp<StatsLogProcessor> CreateStatsLogProcessor(const int64_t timeBaseNs, const int64_t currentTimeNs,
-                                              const StatsdConfig& config, const ConfigKey& key,
-                                              const shared_ptr<IPullAtomCallback>& puller,
-                                              const int32_t atomTag, const sp<UidMap> uidMap) {
-    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-    if (puller != nullptr) {
-        pullerManager->RegisterPullAtomCallback(/*uid=*/0, atomTag, NS_PER_SEC, NS_PER_SEC * 10, {},
-                                                puller);
-    }
-    sp<AlarmMonitor> anomalyAlarmMonitor =
-        new AlarmMonitor(1,
-                         [](const shared_ptr<IStatsCompanionService>&, int64_t){},
-                         [](const shared_ptr<IStatsCompanionService>&){});
-    sp<AlarmMonitor> periodicAlarmMonitor =
-        new AlarmMonitor(1,
-                         [](const shared_ptr<IStatsCompanionService>&, int64_t){},
-                         [](const shared_ptr<IStatsCompanionService>&){});
-    sp<StatsLogProcessor> processor =
-            new StatsLogProcessor(uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
-                                  timeBaseNs, [](const ConfigKey&) { return true; },
-                                  [](const int&, const vector<int64_t>&) {return true;});
-    processor->OnConfigUpdated(currentTimeNs, key, config);
-    return processor;
-}
-
-void sortLogEventsByTimestamp(std::vector<std::unique_ptr<LogEvent>> *events) {
-  std::sort(events->begin(), events->end(),
-            [](const std::unique_ptr<LogEvent>& a, const std::unique_ptr<LogEvent>& b) {
-              return a->GetElapsedTimestampNs() < b->GetElapsedTimestampNs();
-            });
-}
-
-int64_t StringToId(const string& str) {
-    return static_cast<int64_t>(std::hash<std::string>()(str));
-}
-
-sp<EventMatcherWizard> createEventMatcherWizard(
-        int tagId, int matcherIndex, const vector<FieldValueMatcher>& fieldValueMatchers) {
-    sp<UidMap> uidMap = new UidMap();
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    for (const FieldValueMatcher& fvm : fieldValueMatchers) {
-        *atomMatcher.add_field_value_matcher() = fvm;
-    }
-    uint64_t matcherHash = 0x12345678;
-    int64_t matcherId = 678;
-    return new EventMatcherWizard({new SimpleAtomMatchingTracker(
-            matcherId, matcherIndex, matcherHash, atomMatcher, uidMap)});
-}
-
-void ValidateWakelockAttributionUidAndTagDimension(const DimensionsValue& value, const int atomId,
-                                                   const int uid, const string& tag) {
-    EXPECT_EQ(value.field(), atomId);
-    ASSERT_EQ(value.value_tuple().dimensions_value_size(), 2);
-    // Attribution field.
-    EXPECT_EQ(value.value_tuple().dimensions_value(0).field(), 1);
-    // Uid field.
-    ASSERT_EQ(value.value_tuple().dimensions_value(0).value_tuple().dimensions_value_size(), 1);
-    EXPECT_EQ(value.value_tuple().dimensions_value(0).value_tuple().dimensions_value(0).field(), 1);
-    EXPECT_EQ(value.value_tuple().dimensions_value(0).value_tuple().dimensions_value(0).value_int(),
-              uid);
-    // Tag field.
-    EXPECT_EQ(value.value_tuple().dimensions_value(1).field(), 3);
-    EXPECT_EQ(value.value_tuple().dimensions_value(1).value_str(), tag);
-}
-
-void ValidateAttributionUidDimension(const DimensionsValue& value, int atomId, int uid) {
-    EXPECT_EQ(value.field(), atomId);
-    ASSERT_EQ(value.value_tuple().dimensions_value_size(), 1);
-    // Attribution field.
-    EXPECT_EQ(value.value_tuple().dimensions_value(0).field(), 1);
-    // Uid only.
-    EXPECT_EQ(value.value_tuple().dimensions_value(0)
-        .value_tuple().dimensions_value_size(), 1);
-    EXPECT_EQ(value.value_tuple().dimensions_value(0)
-        .value_tuple().dimensions_value(0).field(), 1);
-    EXPECT_EQ(value.value_tuple().dimensions_value(0)
-        .value_tuple().dimensions_value(0).value_int(), uid);
-}
-
-void ValidateUidDimension(const DimensionsValue& value, int node_idx, int atomId, int uid) {
-    EXPECT_EQ(value.field(), atomId);
-    ASSERT_GT(value.value_tuple().dimensions_value_size(), node_idx);
-    // Attribution field.
-    EXPECT_EQ(value.value_tuple().dimensions_value(node_idx).field(), 1);
-    EXPECT_EQ(value.value_tuple().dimensions_value(node_idx)
-        .value_tuple().dimensions_value(0).field(), 1);
-    EXPECT_EQ(value.value_tuple().dimensions_value(node_idx)
-        .value_tuple().dimensions_value(0).value_int(), uid);
-}
-
-void ValidateAttributionUidAndTagDimension(
-    const DimensionsValue& value, int node_idx, int atomId, int uid, const std::string& tag) {
-    EXPECT_EQ(value.field(), atomId);
-    ASSERT_GT(value.value_tuple().dimensions_value_size(), node_idx);
-    // Attribution field.
-    EXPECT_EQ(1, value.value_tuple().dimensions_value(node_idx).field());
-    // Uid only.
-    EXPECT_EQ(2, value.value_tuple().dimensions_value(node_idx)
-        .value_tuple().dimensions_value_size());
-    EXPECT_EQ(1, value.value_tuple().dimensions_value(node_idx)
-        .value_tuple().dimensions_value(0).field());
-    EXPECT_EQ(uid, value.value_tuple().dimensions_value(node_idx)
-        .value_tuple().dimensions_value(0).value_int());
-    EXPECT_EQ(2, value.value_tuple().dimensions_value(node_idx)
-        .value_tuple().dimensions_value(1).field());
-    EXPECT_EQ(tag, value.value_tuple().dimensions_value(node_idx)
-        .value_tuple().dimensions_value(1).value_str());
-}
-
-void ValidateAttributionUidAndTagDimension(
-    const DimensionsValue& value, int atomId, int uid, const std::string& tag) {
-    EXPECT_EQ(value.field(), atomId);
-    ASSERT_EQ(1, value.value_tuple().dimensions_value_size());
-    // Attribution field.
-    EXPECT_EQ(1, value.value_tuple().dimensions_value(0).field());
-    // Uid only.
-    EXPECT_EQ(value.value_tuple().dimensions_value(0)
-        .value_tuple().dimensions_value_size(), 2);
-    EXPECT_EQ(value.value_tuple().dimensions_value(0)
-        .value_tuple().dimensions_value(0).field(), 1);
-    EXPECT_EQ(value.value_tuple().dimensions_value(0)
-        .value_tuple().dimensions_value(0).value_int(), uid);
-    EXPECT_EQ(value.value_tuple().dimensions_value(0)
-        .value_tuple().dimensions_value(1).field(), 2);
-    EXPECT_EQ(value.value_tuple().dimensions_value(0)
-        .value_tuple().dimensions_value(1).value_str(), tag);
-}
-
-void ValidateStateValue(const google::protobuf::RepeatedPtrField<StateValue>& stateValues,
-                        int atomId, int64_t value) {
-    ASSERT_EQ(stateValues.size(), 1);
-    ASSERT_EQ(stateValues[0].atom_id(), atomId);
-    switch (stateValues[0].contents_case()) {
-        case StateValue::ContentsCase::kValue:
-            EXPECT_EQ(stateValues[0].value(), (int32_t)value);
-            break;
-        case StateValue::ContentsCase::kGroupId:
-            EXPECT_EQ(stateValues[0].group_id(), value);
-            break;
-        default:
-            FAIL() << "State value should have either a value or a group id";
-    }
-}
-bool EqualsTo(const DimensionsValue& s1, const DimensionsValue& s2) {
-    if (s1.field() != s2.field()) {
-        return false;
-    }
-    if (s1.value_case() != s2.value_case()) {
-        return false;
-    }
-    switch (s1.value_case()) {
-        case DimensionsValue::ValueCase::kValueStr:
-            return (s1.value_str() == s2.value_str());
-        case DimensionsValue::ValueCase::kValueInt:
-            return s1.value_int() == s2.value_int();
-        case DimensionsValue::ValueCase::kValueLong:
-            return s1.value_long() == s2.value_long();
-        case DimensionsValue::ValueCase::kValueBool:
-            return s1.value_bool() == s2.value_bool();
-        case DimensionsValue::ValueCase::kValueFloat:
-            return s1.value_float() == s2.value_float();
-        case DimensionsValue::ValueCase::kValueTuple: {
-            if (s1.value_tuple().dimensions_value_size() !=
-                s2.value_tuple().dimensions_value_size()) {
-                return false;
-            }
-            bool allMatched = true;
-            for (int i = 0; allMatched && i < s1.value_tuple().dimensions_value_size(); ++i) {
-                allMatched &= EqualsTo(s1.value_tuple().dimensions_value(i),
-                                       s2.value_tuple().dimensions_value(i));
-            }
-            return allMatched;
-        }
-        case DimensionsValue::ValueCase::VALUE_NOT_SET:
-        default:
-            return true;
-    }
-}
-
-bool LessThan(const google::protobuf::RepeatedPtrField<StateValue>& s1,
-              const google::protobuf::RepeatedPtrField<StateValue>& s2) {
-    if (s1.size() != s2.size()) {
-        return s1.size() < s2.size();
-    }
-    for (int i = 0; i < s1.size(); i++) {
-        const StateValue& state1 = s1[i];
-        const StateValue& state2 = s2[i];
-        if (state1.atom_id() != state2.atom_id()) {
-            return state1.atom_id() < state2.atom_id();
-        }
-        if (state1.value() != state2.value()) {
-            return state1.value() < state2.value();
-        }
-        if (state1.group_id() != state2.group_id()) {
-            return state1.group_id() < state2.group_id();
-        }
-    }
-    return false;
-}
-
-bool LessThan(const DimensionsValue& s1, const DimensionsValue& s2) {
-    if (s1.field() != s2.field()) {
-        return s1.field() < s2.field();
-    }
-    if (s1.value_case() != s2.value_case()) {
-        return s1.value_case() < s2.value_case();
-    }
-    switch (s1.value_case()) {
-        case DimensionsValue::ValueCase::kValueStr:
-            return s1.value_str() < s2.value_str();
-        case DimensionsValue::ValueCase::kValueInt:
-            return s1.value_int() < s2.value_int();
-        case DimensionsValue::ValueCase::kValueLong:
-            return s1.value_long() < s2.value_long();
-        case DimensionsValue::ValueCase::kValueBool:
-            return (int)s1.value_bool() < (int)s2.value_bool();
-        case DimensionsValue::ValueCase::kValueFloat:
-            return s1.value_float() < s2.value_float();
-        case DimensionsValue::ValueCase::kValueTuple: {
-            if (s1.value_tuple().dimensions_value_size() !=
-                s2.value_tuple().dimensions_value_size()) {
-                return s1.value_tuple().dimensions_value_size() <
-                       s2.value_tuple().dimensions_value_size();
-            }
-            for (int i = 0; i < s1.value_tuple().dimensions_value_size(); ++i) {
-                if (EqualsTo(s1.value_tuple().dimensions_value(i),
-                             s2.value_tuple().dimensions_value(i))) {
-                    continue;
-                } else {
-                    return LessThan(s1.value_tuple().dimensions_value(i),
-                                    s2.value_tuple().dimensions_value(i));
-                }
-            }
-            return false;
-        }
-        case DimensionsValue::ValueCase::VALUE_NOT_SET:
-        default:
-            return false;
-    }
-}
-
-bool LessThan(const DimensionsPair& s1, const DimensionsPair& s2) {
-    if (LessThan(s1.dimInWhat, s2.dimInWhat)) {
-        return true;
-    } else if (LessThan(s2.dimInWhat, s1.dimInWhat)) {
-        return false;
-    }
-
-    return LessThan(s1.stateValues, s2.stateValues);
-}
-
-void backfillStringInDimension(const std::map<uint64_t, string>& str_map,
-                               DimensionsValue* dimension) {
-    if (dimension->has_value_str_hash()) {
-        auto it = str_map.find((uint64_t)(dimension->value_str_hash()));
-        if (it != str_map.end()) {
-            dimension->clear_value_str_hash();
-            dimension->set_value_str(it->second);
-        } else {
-            ALOGE("Can not find the string hash: %llu",
-                (unsigned long long)dimension->value_str_hash());
-        }
-    } else if (dimension->has_value_tuple()) {
-        auto value_tuple = dimension->mutable_value_tuple();
-        for (int i = 0; i < value_tuple->dimensions_value_size(); ++i) {
-            backfillStringInDimension(str_map, value_tuple->mutable_dimensions_value(i));
-        }
-    }
-}
-
-void backfillStringInReport(ConfigMetricsReport *config_report) {
-    std::map<uint64_t, string> str_map;
-    for (const auto& str : config_report->strings()) {
-        uint64_t hash = Hash64(str);
-        if (str_map.find(hash) != str_map.end()) {
-            ALOGE("String hash conflicts: %s %s", str.c_str(), str_map[hash].c_str());
-        }
-        str_map[hash] = str;
-    }
-    for (int i = 0; i < config_report->metrics_size(); ++i) {
-        auto metric_report = config_report->mutable_metrics(i);
-        if (metric_report->has_count_metrics()) {
-            backfillStringInDimension(str_map, metric_report->mutable_count_metrics());
-        } else if (metric_report->has_duration_metrics()) {
-            backfillStringInDimension(str_map, metric_report->mutable_duration_metrics());
-        } else if (metric_report->has_gauge_metrics()) {
-            backfillStringInDimension(str_map, metric_report->mutable_gauge_metrics());
-        } else if (metric_report->has_value_metrics()) {
-            backfillStringInDimension(str_map, metric_report->mutable_value_metrics());
-        }
-    }
-    // Backfill the package names.
-    for (int i = 0 ; i < config_report->uid_map().snapshots_size(); ++i) {
-        auto snapshot = config_report->mutable_uid_map()->mutable_snapshots(i);
-        for (int j = 0 ; j < snapshot->package_info_size(); ++j) {
-            auto package_info = snapshot->mutable_package_info(j);
-            if (package_info->has_name_hash()) {
-                auto it = str_map.find((uint64_t)(package_info->name_hash()));
-                if (it != str_map.end()) {
-                    package_info->clear_name_hash();
-                    package_info->set_name(it->second);
-                } else {
-                    ALOGE("Can not find the string package name hash: %llu",
-                        (unsigned long long)package_info->name_hash());
-                }
-
-            }
-        }
-    }
-    // Backfill the app name in app changes.
-    for (int i = 0 ; i < config_report->uid_map().changes_size(); ++i) {
-        auto change = config_report->mutable_uid_map()->mutable_changes(i);
-        if (change->has_app_hash()) {
-            auto it = str_map.find((uint64_t)(change->app_hash()));
-            if (it != str_map.end()) {
-                change->clear_app_hash();
-                change->set_app(it->second);
-            } else {
-                ALOGE("Can not find the string change app name hash: %llu",
-                    (unsigned long long)change->app_hash());
-            }
-        }
-    }
-}
-
-void backfillStringInReport(ConfigMetricsReportList *config_report_list) {
-    for (int i = 0; i < config_report_list->reports_size(); ++i) {
-        backfillStringInReport(config_report_list->mutable_reports(i));
-    }
-}
-
-bool backfillDimensionPath(const DimensionsValue& path,
-                           const google::protobuf::RepeatedPtrField<DimensionsValue>& leafValues,
-                           int* leafIndex,
-                           DimensionsValue* dimension) {
-    dimension->set_field(path.field());
-    if (path.has_value_tuple()) {
-        for (int i = 0; i < path.value_tuple().dimensions_value_size(); ++i) {
-            if (!backfillDimensionPath(
-                path.value_tuple().dimensions_value(i), leafValues, leafIndex,
-                dimension->mutable_value_tuple()->add_dimensions_value())) {
-                return false;
-            }
-        }
-    } else {
-        if (*leafIndex < 0 || *leafIndex >= leafValues.size()) {
-            return false;
-        }
-        dimension->MergeFrom(leafValues.Get(*leafIndex));
-        (*leafIndex)++;
-    }
-    return true;
-}
-
-bool backfillDimensionPath(const DimensionsValue& path,
-                           const google::protobuf::RepeatedPtrField<DimensionsValue>& leafValues,
-                           DimensionsValue* dimension) {
-    int leafIndex = 0;
-    return backfillDimensionPath(path, leafValues, &leafIndex, dimension);
-}
-
-void backfillDimensionPath(ConfigMetricsReportList *config_report_list) {
-    for (int i = 0; i < config_report_list->reports_size(); ++i) {
-        auto report = config_report_list->mutable_reports(i);
-        for (int j = 0; j < report->metrics_size(); ++j) {
-            auto metric_report = report->mutable_metrics(j);
-            if (metric_report->has_dimensions_path_in_what() ||
-                metric_report->has_dimensions_path_in_condition()) {
-                auto whatPath = metric_report->dimensions_path_in_what();
-                auto conditionPath = metric_report->dimensions_path_in_condition();
-                if (metric_report->has_count_metrics()) {
-                    backfillDimensionPath(whatPath, conditionPath,
-                                          metric_report->mutable_count_metrics());
-                } else if (metric_report->has_duration_metrics()) {
-                    backfillDimensionPath(whatPath, conditionPath,
-                                          metric_report->mutable_duration_metrics());
-                } else if (metric_report->has_gauge_metrics()) {
-                    backfillDimensionPath(whatPath, conditionPath,
-                                          metric_report->mutable_gauge_metrics());
-                } else if (metric_report->has_value_metrics()) {
-                    backfillDimensionPath(whatPath, conditionPath,
-                                          metric_report->mutable_value_metrics());
-                }
-                metric_report->clear_dimensions_path_in_what();
-                metric_report->clear_dimensions_path_in_condition();
-            }
-        }
-    }
-}
-
-void backfillStartEndTimestamp(StatsLogReport *report) {
-    const int64_t timeBaseNs = report->time_base_elapsed_nano_seconds();
-    const int64_t bucketSizeNs = report->bucket_size_nano_seconds();
-    if (report->has_count_metrics()) {
-        backfillStartEndTimestampForMetrics(
-            timeBaseNs, bucketSizeNs, report->mutable_count_metrics());
-    } else if (report->has_duration_metrics()) {
-        backfillStartEndTimestampForMetrics(
-            timeBaseNs, bucketSizeNs, report->mutable_duration_metrics());
-    } else if (report->has_gauge_metrics()) {
-        backfillStartEndTimestampForMetrics(
-            timeBaseNs, bucketSizeNs, report->mutable_gauge_metrics());
-        if (report->gauge_metrics().skipped_size() > 0) {
-            backfillStartEndTimestampForSkippedBuckets(
-                timeBaseNs, report->mutable_gauge_metrics());
-        }
-    } else if (report->has_value_metrics()) {
-        backfillStartEndTimestampForMetrics(
-            timeBaseNs, bucketSizeNs, report->mutable_value_metrics());
-        if (report->value_metrics().skipped_size() > 0) {
-            backfillStartEndTimestampForSkippedBuckets(
-                timeBaseNs, report->mutable_value_metrics());
-        }
-    }
-}
-
-void backfillStartEndTimestamp(ConfigMetricsReport *config_report) {
-    for (int j = 0; j < config_report->metrics_size(); ++j) {
-        backfillStartEndTimestamp(config_report->mutable_metrics(j));
-    }
-}
-
-void backfillStartEndTimestamp(ConfigMetricsReportList *config_report_list) {
-    for (int i = 0; i < config_report_list->reports_size(); ++i) {
-        backfillStartEndTimestamp(config_report_list->mutable_reports(i));
-    }
-}
-
-Status FakeSubsystemSleepCallback::onPullAtom(int atomTag,
-        const shared_ptr<IPullAtomResultReceiver>& resultReceiver) {
-    // Convert stats_events into StatsEventParcels.
-    std::vector<StatsEventParcel> parcels;
-    for (int i = 1; i < 3; i++) {
-        AStatsEvent* event = AStatsEvent_obtain();
-        AStatsEvent_setAtomId(event, atomTag);
-        std::string subsystemName = "subsystem_name_";
-        subsystemName = subsystemName + std::to_string(i);
-        AStatsEvent_writeString(event, subsystemName.c_str());
-        AStatsEvent_writeString(event, "subsystem_subname foo");
-        AStatsEvent_writeInt64(event, /*count= */ i);
-        AStatsEvent_writeInt64(event, /*time_millis= */ i * 100);
-        AStatsEvent_build(event);
-        size_t size;
-        uint8_t* buffer = AStatsEvent_getBuffer(event, &size);
-
-        StatsEventParcel p;
-        // vector.assign() creates a copy, but this is inevitable unless
-        // stats_event.h/c uses a vector as opposed to a buffer.
-        p.buffer.assign(buffer, buffer + size);
-        parcels.push_back(std::move(p));
-        AStatsEvent_release(event);
-    }
-    resultReceiver->pullFinished(atomTag, /*success=*/true, parcels);
-    return Status::ok();
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
deleted file mode 100644
index c514912..0000000
--- a/cmds/statsd/tests/statsd_test_util.h
+++ /dev/null
@@ -1,485 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include <aidl/android/os/BnPullAtomCallback.h>
-#include <aidl/android/os/IPullAtomCallback.h>
-#include <aidl/android/os/IPullAtomResultReceiver.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "src/StatsLogProcessor.h"
-#include "src/hash.h"
-#include "src/logd/LogEvent.h"
-#include "src/matchers/EventMatcherWizard.h"
-#include "src/packages/UidMap.h"
-#include "src/stats_log_util.h"
-#include "stats_event.h"
-#include "statslog_statsdtest.h"
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using namespace testing;
-using ::aidl::android::os::BnPullAtomCallback;
-using ::aidl::android::os::IPullAtomCallback;
-using ::aidl::android::os::IPullAtomResultReceiver;
-using android::util::ProtoReader;
-using google::protobuf::RepeatedPtrField;
-using Status = ::ndk::ScopedAStatus;
-
-const int SCREEN_STATE_ATOM_ID = util::SCREEN_STATE_CHANGED;
-const int UID_PROCESS_STATE_ATOM_ID = util::UID_PROCESS_STATE_CHANGED;
-
-enum BucketSplitEvent { APP_UPGRADE, BOOT_COMPLETE };
-
-class MockUidMap : public UidMap {
-public:
-    MOCK_METHOD(int, getHostUidOrSelf, (int uid), (const));
-    MOCK_METHOD(std::set<int32_t>, getAppUid, (const string& package), (const));
-};
-
-// Converts a ProtoOutputStream to a StatsLogReport proto.
-StatsLogReport outputStreamToProto(ProtoOutputStream* proto);
-
-// Create AtomMatcher proto to simply match a specific atom type.
-AtomMatcher CreateSimpleAtomMatcher(const string& name, int atomId);
-
-// Create AtomMatcher proto for temperature atom.
-AtomMatcher CreateTemperatureAtomMatcher();
-
-// Create AtomMatcher proto for scheduled job state changed.
-AtomMatcher CreateScheduledJobStateChangedAtomMatcher();
-
-// Create AtomMatcher proto for starting a scheduled job.
-AtomMatcher CreateStartScheduledJobAtomMatcher();
-
-// Create AtomMatcher proto for a scheduled job is done.
-AtomMatcher CreateFinishScheduledJobAtomMatcher();
-
-// Create AtomMatcher proto for screen brightness state changed.
-AtomMatcher CreateScreenBrightnessChangedAtomMatcher();
-
-// Create AtomMatcher proto for starting battery save mode.
-AtomMatcher CreateBatterySaverModeStartAtomMatcher();
-
-// Create AtomMatcher proto for stopping battery save mode.
-AtomMatcher CreateBatterySaverModeStopAtomMatcher();
-
-// Create AtomMatcher proto for battery state none mode.
-AtomMatcher CreateBatteryStateNoneMatcher();
-
-// Create AtomMatcher proto for battery state usb mode.
-AtomMatcher CreateBatteryStateUsbMatcher();
-
-// Create AtomMatcher proto for process state changed.
-AtomMatcher CreateUidProcessStateChangedAtomMatcher();
-
-// Create AtomMatcher proto for acquiring wakelock.
-AtomMatcher CreateAcquireWakelockAtomMatcher();
-
-// Create AtomMatcher proto for releasing wakelock.
-AtomMatcher CreateReleaseWakelockAtomMatcher() ;
-
-// Create AtomMatcher proto for screen turned on.
-AtomMatcher CreateScreenTurnedOnAtomMatcher();
-
-// Create AtomMatcher proto for screen turned off.
-AtomMatcher CreateScreenTurnedOffAtomMatcher();
-
-// Create AtomMatcher proto for app sync turned on.
-AtomMatcher CreateSyncStartAtomMatcher();
-
-// Create AtomMatcher proto for app sync turned off.
-AtomMatcher CreateSyncEndAtomMatcher();
-
-// Create AtomMatcher proto for app sync moves to background.
-AtomMatcher CreateMoveToBackgroundAtomMatcher();
-
-// Create AtomMatcher proto for app sync moves to foreground.
-AtomMatcher CreateMoveToForegroundAtomMatcher();
-
-// Create AtomMatcher proto for process crashes
-AtomMatcher CreateProcessCrashAtomMatcher() ;
-
-// Create Predicate proto for screen is on.
-Predicate CreateScreenIsOnPredicate();
-
-// Create Predicate proto for screen is off.
-Predicate CreateScreenIsOffPredicate();
-
-// Create Predicate proto for a running scheduled job.
-Predicate CreateScheduledJobPredicate();
-
-// Create Predicate proto for battery saver mode.
-Predicate CreateBatterySaverModePredicate();
-
-// Create Predicate proto for device unplogged mode.
-Predicate CreateDeviceUnpluggedPredicate();
-
-// Create Predicate proto for holding wakelock.
-Predicate CreateHoldingWakelockPredicate();
-
-// Create a Predicate proto for app syncing.
-Predicate CreateIsSyncingPredicate();
-
-// Create a Predicate proto for app is in background.
-Predicate CreateIsInBackgroundPredicate();
-
-// Create State proto for screen state atom.
-State CreateScreenState();
-
-// Create State proto for uid process state atom.
-State CreateUidProcessState();
-
-// Create State proto for overlay state atom.
-State CreateOverlayState();
-
-// Create State proto for screen state atom with on/off map.
-State CreateScreenStateWithOnOffMap(int64_t screenOnId, int64_t screenOffId);
-
-// Create State proto for screen state atom with simple on/off map.
-State CreateScreenStateWithSimpleOnOffMap(int64_t screenOnId, int64_t screenOffId);
-
-// Create StateGroup proto for ScreenState ON group
-StateMap_StateGroup CreateScreenStateOnGroup(int64_t screenOnId);
-
-// Create StateGroup proto for ScreenState OFF group
-StateMap_StateGroup CreateScreenStateOffGroup(int64_t screenOffId);
-
-// Create StateGroup proto for simple ScreenState ON group
-StateMap_StateGroup CreateScreenStateSimpleOnGroup(int64_t screenOnId);
-
-// Create StateGroup proto for simple ScreenState OFF group
-StateMap_StateGroup CreateScreenStateSimpleOffGroup(int64_t screenOffId);
-
-// Create StateMap proto for ScreenState ON/OFF map
-StateMap CreateScreenStateOnOffMap(int64_t screenOnId, int64_t screenOffId);
-
-// Create StateMap proto for simple ScreenState ON/OFF map
-StateMap CreateScreenStateSimpleOnOffMap(int64_t screenOnId, int64_t screenOffId);
-
-// Add a predicate to the predicate combination.
-void addPredicateToPredicateCombination(const Predicate& predicate, Predicate* combination);
-
-// Create dimensions from primitive fields.
-FieldMatcher CreateDimensions(const int atomId, const std::vector<int>& fields);
-
-// Create dimensions by attribution uid and tag.
-FieldMatcher CreateAttributionUidAndTagDimensions(const int atomId,
-                                                  const std::vector<Position>& positions);
-
-// Create dimensions by attribution uid only.
-FieldMatcher CreateAttributionUidDimensions(const int atomId,
-                                            const std::vector<Position>& positions);
-
-FieldMatcher CreateAttributionUidAndOtherDimensions(const int atomId,
-                                                    const std::vector<Position>& positions,
-                                                    const std::vector<int>& fields);
-
-// START: get primary key functions
-// These functions take in atom field information and create FieldValues which are stored in the
-// given HashableDimensionKey.
-void getUidProcessKey(int uid, HashableDimensionKey* key);
-
-void getOverlayKey(int uid, string packageName, HashableDimensionKey* key);
-
-void getPartialWakelockKey(int uid, const std::string& tag, HashableDimensionKey* key);
-
-void getPartialWakelockKey(int uid, HashableDimensionKey* key);
-// END: get primary key functions
-
-void writeAttribution(AStatsEvent* statsEvent, const vector<int>& attributionUids,
-                      const vector<string>& attributionTags);
-
-// Builds statsEvent to get buffer that is parsed into logEvent then releases statsEvent.
-void parseStatsEventToLogEvent(AStatsEvent* statsEvent, LogEvent* logEvent);
-
-shared_ptr<LogEvent> CreateTwoValueLogEvent(int atomId, int64_t eventTimeNs, int32_t value1,
-                                            int32_t value2);
-
-void CreateTwoValueLogEvent(LogEvent* logEvent, int atomId, int64_t eventTimeNs, int32_t value1,
-                            int32_t value2);
-
-shared_ptr<LogEvent> CreateThreeValueLogEvent(int atomId, int64_t eventTimeNs, int32_t value1,
-                                              int32_t value2, int32_t value3);
-
-void CreateThreeValueLogEvent(LogEvent* logEvent, int atomId, int64_t eventTimeNs, int32_t value1,
-                              int32_t value2, int32_t value3);
-
-// The repeated value log event helpers create a log event with two int fields, both
-// set to the same value. This is useful for testing metrics that are only interested
-// in the value of the second field but still need the first field to be populated.
-std::shared_ptr<LogEvent> CreateRepeatedValueLogEvent(int atomId, int64_t eventTimeNs,
-                                                      int32_t value);
-
-void CreateRepeatedValueLogEvent(LogEvent* logEvent, int atomId, int64_t eventTimeNs,
-                                 int32_t value);
-
-std::shared_ptr<LogEvent> CreateNoValuesLogEvent(int atomId, int64_t eventTimeNs);
-
-void CreateNoValuesLogEvent(LogEvent* logEvent, int atomId, int64_t eventTimeNs);
-
-std::shared_ptr<LogEvent> makeUidLogEvent(int atomId, int64_t eventTimeNs, int uid, int data1,
-                                          int data2);
-
-std::shared_ptr<LogEvent> makeAttributionLogEvent(int atomId, int64_t eventTimeNs,
-                                                  const vector<int>& uids,
-                                                  const vector<string>& tags, int data1, int data2);
-
-sp<MockUidMap> makeMockUidMapForOneHost(int hostUid, const vector<int>& isolatedUids);
-
-sp<MockUidMap> makeMockUidMapForPackage(const string& pkg, const set<int32_t>& uids);
-
-// Create log event for screen state changed.
-std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(uint64_t timestampNs,
-                                                        const android::view::DisplayStateEnum state,
-                                                        int loggerUid = 0);
-
-// Create log event for screen brightness state changed.
-std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(uint64_t timestampNs, int level);
-
-// Create log event when scheduled job starts.
-std::unique_ptr<LogEvent> CreateStartScheduledJobEvent(uint64_t timestampNs,
-                                                       const vector<int>& attributionUids,
-                                                       const vector<string>& attributionTags,
-                                                       const string& jobName);
-
-// Create log event when scheduled job finishes.
-std::unique_ptr<LogEvent> CreateFinishScheduledJobEvent(uint64_t timestampNs,
-                                                        const vector<int>& attributionUids,
-                                                        const vector<string>& attributionTags,
-                                                        const string& jobName);
-
-// Create log event when battery saver starts.
-std::unique_ptr<LogEvent> CreateBatterySaverOnEvent(uint64_t timestampNs);
-// Create log event when battery saver stops.
-std::unique_ptr<LogEvent> CreateBatterySaverOffEvent(uint64_t timestampNs);
-
-// Create log event when battery state changes.
-std::unique_ptr<LogEvent> CreateBatteryStateChangedEvent(const uint64_t timestampNs, const BatteryPluggedStateEnum state);
-
-// Create log event for app moving to background.
-std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(uint64_t timestampNs, const int uid);
-
-// Create log event for app moving to foreground.
-std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(uint64_t timestampNs, const int uid);
-
-// Create log event when the app sync starts.
-std::unique_ptr<LogEvent> CreateSyncStartEvent(uint64_t timestampNs, const vector<int>& uids,
-                                               const vector<string>& tags, const string& name);
-
-// Create log event when the app sync ends.
-std::unique_ptr<LogEvent> CreateSyncEndEvent(uint64_t timestampNs, const vector<int>& uids,
-                                             const vector<string>& tags, const string& name);
-
-// Create log event when the app sync ends.
-std::unique_ptr<LogEvent> CreateAppCrashEvent(uint64_t timestampNs, const int uid);
-
-// Create log event for an app crash.
-std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(uint64_t timestampNs, const int uid);
-
-// Create log event for acquiring wakelock.
-std::unique_ptr<LogEvent> CreateAcquireWakelockEvent(uint64_t timestampNs, const vector<int>& uids,
-                                                     const vector<string>& tags,
-                                                     const string& wakelockName);
-
-// Create log event for releasing wakelock.
-std::unique_ptr<LogEvent> CreateReleaseWakelockEvent(uint64_t timestampNs, const vector<int>& uids,
-                                                     const vector<string>& tags,
-                                                     const string& wakelockName);
-
-// Create log event for releasing wakelock.
-std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(uint64_t timestampNs, int hostUid,
-                                                        int isolatedUid, bool is_create);
-
-// Create log event for uid process state change.
-std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent(
-        uint64_t timestampNs, int uid, const android::app::ProcessStateEnum state);
-
-std::unique_ptr<LogEvent> CreateBleScanStateChangedEvent(uint64_t timestampNs,
-                                                         const vector<int>& attributionUids,
-                                                         const vector<string>& attributionTags,
-                                                         const BleScanStateChanged::State state,
-                                                         const bool filtered, const bool firstMatch,
-                                                         const bool opportunistic);
-
-std::unique_ptr<LogEvent> CreateOverlayStateChangedEvent(int64_t timestampNs, const int32_t uid,
-                                                         const string& packageName,
-                                                         const bool usingAlertWindow,
-                                                         const OverlayStateChanged::State state);
-
-// Create a statsd log event processor upon the start time in seconds, config and key.
-sp<StatsLogProcessor> CreateStatsLogProcessor(const int64_t timeBaseNs, const int64_t currentTimeNs,
-                                              const StatsdConfig& config, const ConfigKey& key,
-                                              const shared_ptr<IPullAtomCallback>& puller = nullptr,
-                                              const int32_t atomTag = 0 /*for puller only*/,
-                                              const sp<UidMap> = new UidMap());
-
-// Util function to sort the log events by timestamp.
-void sortLogEventsByTimestamp(std::vector<std::unique_ptr<LogEvent>> *events);
-
-int64_t StringToId(const string& str);
-
-sp<EventMatcherWizard> createEventMatcherWizard(
-        int tagId, int matcherIndex, const std::vector<FieldValueMatcher>& fieldValueMatchers = {});
-
-void ValidateWakelockAttributionUidAndTagDimension(const DimensionsValue& value, const int atomId,
-                                                   const int uid, const string& tag);
-void ValidateUidDimension(const DimensionsValue& value, int node_idx, int atomId, int uid);
-void ValidateAttributionUidDimension(const DimensionsValue& value, int atomId, int uid);
-void ValidateAttributionUidAndTagDimension(
-    const DimensionsValue& value, int atomId, int uid, const std::string& tag);
-void ValidateAttributionUidAndTagDimension(
-    const DimensionsValue& value, int node_idx, int atomId, int uid, const std::string& tag);
-void ValidateStateValue(const google::protobuf::RepeatedPtrField<StateValue>& stateValues,
-                        int atomId, int64_t value);
-
-struct DimensionsPair {
-    DimensionsPair(DimensionsValue m1, google::protobuf::RepeatedPtrField<StateValue> m2)
-        : dimInWhat(m1), stateValues(m2){};
-
-    DimensionsValue dimInWhat;
-    google::protobuf::RepeatedPtrField<StateValue> stateValues;
-};
-
-bool LessThan(const StateValue& s1, const StateValue& s2);
-bool LessThan(const DimensionsValue& s1, const DimensionsValue& s2);
-bool LessThan(const DimensionsPair& s1, const DimensionsPair& s2);
-
-
-void backfillStartEndTimestamp(ConfigMetricsReport *config_report);
-void backfillStartEndTimestamp(ConfigMetricsReportList *config_report_list);
-
-void backfillStringInReport(ConfigMetricsReportList *config_report_list);
-void backfillStringInDimension(const std::map<uint64_t, string>& str_map,
-                               DimensionsValue* dimension);
-
-template <typename T>
-void backfillStringInDimension(const std::map<uint64_t, string>& str_map,
-                               T* metrics) {
-    for (int i = 0; i < metrics->data_size(); ++i) {
-        auto data = metrics->mutable_data(i);
-        if (data->has_dimensions_in_what()) {
-            backfillStringInDimension(str_map, data->mutable_dimensions_in_what());
-        }
-        if (data->has_dimensions_in_condition()) {
-            backfillStringInDimension(str_map, data->mutable_dimensions_in_condition());
-        }
-    }
-}
-
-void backfillDimensionPath(ConfigMetricsReportList* config_report_list);
-
-bool backfillDimensionPath(const DimensionsValue& path,
-                           const google::protobuf::RepeatedPtrField<DimensionsValue>& leafValues,
-                           DimensionsValue* dimension);
-
-class FakeSubsystemSleepCallback : public BnPullAtomCallback {
-public:
-    Status onPullAtom(int atomTag,
-                      const shared_ptr<IPullAtomResultReceiver>& resultReceiver) override;
-};
-
-template <typename T>
-void backfillDimensionPath(const DimensionsValue& whatPath,
-                           const DimensionsValue& conditionPath,
-                           T* metricData) {
-    for (int i = 0; i < metricData->data_size(); ++i) {
-        auto data = metricData->mutable_data(i);
-        if (data->dimension_leaf_values_in_what_size() > 0) {
-            backfillDimensionPath(whatPath, data->dimension_leaf_values_in_what(),
-                                  data->mutable_dimensions_in_what());
-            data->clear_dimension_leaf_values_in_what();
-        }
-        if (data->dimension_leaf_values_in_condition_size() > 0) {
-            backfillDimensionPath(conditionPath, data->dimension_leaf_values_in_condition(),
-                                  data->mutable_dimensions_in_condition());
-            data->clear_dimension_leaf_values_in_condition();
-        }
-    }
-}
-
-struct DimensionCompare {
-    bool operator()(const DimensionsPair& s1, const DimensionsPair& s2) const {
-        return LessThan(s1, s2);
-    }
-};
-
-template <typename T>
-void sortMetricDataByDimensionsValue(const T& metricData, T* sortedMetricData) {
-    std::map<DimensionsPair, int, DimensionCompare> dimensionIndexMap;
-    for (int i = 0; i < metricData.data_size(); ++i) {
-        dimensionIndexMap.insert(
-                std::make_pair(DimensionsPair(metricData.data(i).dimensions_in_what(),
-                                              metricData.data(i).slice_by_state()),
-                               i));
-    }
-    for (const auto& itr : dimensionIndexMap) {
-        *sortedMetricData->add_data() = metricData.data(itr.second);
-    }
-}
-
-template <typename T>
-void backfillStartEndTimestampForFullBucket(
-    const int64_t timeBaseNs, const int64_t bucketSizeNs, T* bucket) {
-    bucket->set_start_bucket_elapsed_nanos(timeBaseNs + bucketSizeNs * bucket->bucket_num());
-    bucket->set_end_bucket_elapsed_nanos(
-        timeBaseNs + bucketSizeNs * bucket->bucket_num() + bucketSizeNs);
-    bucket->clear_bucket_num();
-}
-
-template <typename T>
-void backfillStartEndTimestampForPartialBucket(const int64_t timeBaseNs, T* bucket) {
-    if (bucket->has_start_bucket_elapsed_millis()) {
-        bucket->set_start_bucket_elapsed_nanos(
-            MillisToNano(bucket->start_bucket_elapsed_millis()));
-        bucket->clear_start_bucket_elapsed_millis();
-    }
-    if (bucket->has_end_bucket_elapsed_millis()) {
-        bucket->set_end_bucket_elapsed_nanos(
-            MillisToNano(bucket->end_bucket_elapsed_millis()));
-        bucket->clear_end_bucket_elapsed_millis();
-    }
-}
-
-template <typename T>
-void backfillStartEndTimestampForMetrics(const int64_t timeBaseNs, const int64_t bucketSizeNs,
-                                         T* metrics) {
-    for (int i = 0; i < metrics->data_size(); ++i) {
-        auto data = metrics->mutable_data(i);
-        for (int j = 0; j < data->bucket_info_size(); ++j) {
-            auto bucket = data->mutable_bucket_info(j);
-            if (bucket->has_bucket_num()) {
-                backfillStartEndTimestampForFullBucket(timeBaseNs, bucketSizeNs, bucket);
-            } else {
-                backfillStartEndTimestampForPartialBucket(timeBaseNs, bucket);
-            }
-        }
-    }
-}
-
-template <typename T>
-void backfillStartEndTimestampForSkippedBuckets(const int64_t timeBaseNs, T* metrics) {
-    for (int i = 0; i < metrics->skipped_size(); ++i) {
-        backfillStartEndTimestampForPartialBucket(timeBaseNs, metrics->mutable_skipped(i));
-    }
-}
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/tests/storage/StorageManager_test.cpp b/cmds/statsd/tests/storage/StorageManager_test.cpp
deleted file mode 100644
index 74eafbf..0000000
--- a/cmds/statsd/tests/storage/StorageManager_test.cpp
+++ /dev/null
@@ -1,204 +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.
-
-#include <android-base/unique_fd.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <stdio.h>
-#include "src/storage/StorageManager.h"
-
-#ifdef __ANDROID__
-
-namespace android {
-namespace os {
-namespace statsd {
-
-using namespace testing;
-using std::make_shared;
-using std::shared_ptr;
-using std::vector;
-using testing::Contains;
-
-TEST(StorageManagerTest, TrainInfoReadWriteTest) {
-    InstallTrainInfo trainInfo;
-    trainInfo.trainVersionCode = 12345;
-    trainInfo.trainName = "This is a train name #)$(&&$";
-    trainInfo.status = 1;
-    const char* expIds = "test_ids";
-    trainInfo.experimentIds.assign(expIds, expIds + strlen(expIds));
-
-    bool result;
-
-    result = StorageManager::writeTrainInfo(trainInfo);
-
-    EXPECT_TRUE(result);
-
-    InstallTrainInfo trainInfoResult;
-    result = StorageManager::readTrainInfo(trainInfo.trainName, trainInfoResult);
-    EXPECT_TRUE(result);
-
-    EXPECT_EQ(trainInfo.trainVersionCode, trainInfoResult.trainVersionCode);
-    ASSERT_EQ(trainInfo.trainName.size(), trainInfoResult.trainName.size());
-    EXPECT_EQ(trainInfo.trainName, trainInfoResult.trainName);
-    EXPECT_EQ(trainInfo.status, trainInfoResult.status);
-    ASSERT_EQ(trainInfo.experimentIds.size(), trainInfoResult.experimentIds.size());
-    EXPECT_EQ(trainInfo.experimentIds, trainInfoResult.experimentIds);
-}
-
-TEST(StorageManagerTest, TrainInfoReadWriteTrainNameSizeOneTest) {
-    InstallTrainInfo trainInfo;
-    trainInfo.trainVersionCode = 12345;
-    trainInfo.trainName = "{";
-    trainInfo.status = 1;
-    const char* expIds = "test_ids";
-    trainInfo.experimentIds.assign(expIds, expIds + strlen(expIds));
-
-    bool result;
-
-    result = StorageManager::writeTrainInfo(trainInfo);
-
-    EXPECT_TRUE(result);
-
-    InstallTrainInfo trainInfoResult;
-    result = StorageManager::readTrainInfo(trainInfo.trainName, trainInfoResult);
-    EXPECT_TRUE(result);
-
-    EXPECT_EQ(trainInfo.trainVersionCode, trainInfoResult.trainVersionCode);
-    ASSERT_EQ(trainInfo.trainName.size(), trainInfoResult.trainName.size());
-    EXPECT_EQ(trainInfo.trainName, trainInfoResult.trainName);
-    EXPECT_EQ(trainInfo.status, trainInfoResult.status);
-    ASSERT_EQ(trainInfo.experimentIds.size(), trainInfoResult.experimentIds.size());
-    EXPECT_EQ(trainInfo.experimentIds, trainInfoResult.experimentIds);
-}
-
-TEST(StorageManagerTest, SortFileTest) {
-    vector<StorageManager::FileInfo> list;
-    // assume now sec is 500
-    list.emplace_back("200_5000_123454", false, 20, 300);
-    list.emplace_back("300_2000_123454_history", true, 30, 200);
-    list.emplace_back("400_100009_123454_history", true, 40, 100);
-    list.emplace_back("100_2000_123454", false, 50, 400);
-
-    StorageManager::sortFiles(&list);
-    EXPECT_EQ("200_5000_123454", list[0].mFileName);
-    EXPECT_EQ("100_2000_123454", list[1].mFileName);
-    EXPECT_EQ("400_100009_123454_history", list[2].mFileName);
-    EXPECT_EQ("300_2000_123454_history", list[3].mFileName);
-}
-
-const string testDir = "/data/misc/stats-data/";
-const string file1 = testDir + "2557169347_1066_1";
-const string file2 = testDir + "2557169349_1066_1";
-const string file1_history = file1 + "_history";
-const string file2_history = file2 + "_history";
-
-bool prepareLocalHistoryTestFiles() {
-    android::base::unique_fd fd(TEMP_FAILURE_RETRY(
-            open(file1.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR)));
-    if (fd != -1) {
-        dprintf(fd, "content");
-    } else {
-        return false;
-    }
-
-    android::base::unique_fd fd2(TEMP_FAILURE_RETRY(
-            open(file2.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR)));
-    if (fd2 != -1) {
-        dprintf(fd2, "content");
-    } else {
-        return false;
-    }
-    return true;
-}
-
-void clearLocalHistoryTestFiles() {
-    TEMP_FAILURE_RETRY(remove(file1.c_str()));
-    TEMP_FAILURE_RETRY(remove(file2.c_str()));
-    TEMP_FAILURE_RETRY(remove(file1_history.c_str()));
-    TEMP_FAILURE_RETRY(remove(file2_history.c_str()));
-}
-
-bool fileExist(string name) {
-    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(name.c_str(), O_RDONLY | O_CLOEXEC)));
-    return fd != -1;
-}
-
-/* The following AppendConfigReportTests test the 4 combinations of [whether erase data] [whether
- * the caller is adb] */
-TEST(StorageManagerTest, AppendConfigReportTest1) {
-    EXPECT_TRUE(prepareLocalHistoryTestFiles());
-
-    ProtoOutputStream out;
-    StorageManager::appendConfigMetricsReport(ConfigKey(1066, 1), &out, false /*erase?*/,
-                                              false /*isAdb?*/);
-
-    EXPECT_FALSE(fileExist(file1));
-    EXPECT_FALSE(fileExist(file2));
-
-    EXPECT_TRUE(fileExist(file1_history));
-    EXPECT_TRUE(fileExist(file2_history));
-    clearLocalHistoryTestFiles();
-}
-
-TEST(StorageManagerTest, AppendConfigReportTest2) {
-    EXPECT_TRUE(prepareLocalHistoryTestFiles());
-
-    ProtoOutputStream out;
-    StorageManager::appendConfigMetricsReport(ConfigKey(1066, 1), &out, true /*erase?*/,
-                                              false /*isAdb?*/);
-
-    EXPECT_FALSE(fileExist(file1));
-    EXPECT_FALSE(fileExist(file2));
-    EXPECT_FALSE(fileExist(file1_history));
-    EXPECT_FALSE(fileExist(file2_history));
-
-    clearLocalHistoryTestFiles();
-}
-
-TEST(StorageManagerTest, AppendConfigReportTest3) {
-    EXPECT_TRUE(prepareLocalHistoryTestFiles());
-
-    ProtoOutputStream out;
-    StorageManager::appendConfigMetricsReport(ConfigKey(1066, 1), &out, false /*erase?*/,
-                                              true /*isAdb?*/);
-
-    EXPECT_TRUE(fileExist(file1));
-    EXPECT_TRUE(fileExist(file2));
-    EXPECT_FALSE(fileExist(file1_history));
-    EXPECT_FALSE(fileExist(file2_history));
-
-    clearLocalHistoryTestFiles();
-}
-
-TEST(StorageManagerTest, AppendConfigReportTest4) {
-    EXPECT_TRUE(prepareLocalHistoryTestFiles());
-
-    ProtoOutputStream out;
-    StorageManager::appendConfigMetricsReport(ConfigKey(1066, 1), &out, true /*erase?*/,
-                                              true /*isAdb?*/);
-
-    EXPECT_FALSE(fileExist(file1));
-    EXPECT_FALSE(fileExist(file2));
-    EXPECT_FALSE(fileExist(file1_history));
-    EXPECT_FALSE(fileExist(file2_history));
-
-    clearLocalHistoryTestFiles();
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tests/utils/MultiConditionTrigger_test.cpp b/cmds/statsd/tests/utils/MultiConditionTrigger_test.cpp
deleted file mode 100644
index 32cecd3..0000000
--- a/cmds/statsd/tests/utils/MultiConditionTrigger_test.cpp
+++ /dev/null
@@ -1,174 +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.
- */
-#include "utils/MultiConditionTrigger.h"
-
-#include <gtest/gtest.h>
-
-#include <chrono>
-#include <set>
-#include <thread>
-#include <vector>
-
-#ifdef __ANDROID__
-
-using namespace std;
-using std::this_thread::sleep_for;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-TEST(MultiConditionTrigger, TestMultipleConditions) {
-    int numConditions = 5;
-    string t1 = "t1", t2 = "t2", t3 = "t3", t4 = "t4", t5 = "t5";
-    set<string> conditionNames = {t1, t2, t3, t4, t5};
-
-    mutex lock;
-    condition_variable cv;
-    bool triggerCalled = false;
-
-    // Mark done as true and notify in the done.
-    MultiConditionTrigger trigger(conditionNames, [&lock, &cv, &triggerCalled] {
-        {
-            lock_guard lg(lock);
-            triggerCalled = true;
-        }
-        cv.notify_all();
-    });
-
-    vector<thread> threads;
-    vector<int> done(numConditions, 0);
-
-    int i = 0;
-    for (const string& conditionName : conditionNames) {
-        threads.emplace_back([&done, &conditionName, &trigger, i] {
-            sleep_for(chrono::milliseconds(3));
-            done[i] = 1;
-            trigger.markComplete(conditionName);
-        });
-        i++;
-    }
-
-    unique_lock<mutex> unique_lk(lock);
-    cv.wait(unique_lk, [&triggerCalled] {
-        return triggerCalled;
-    });
-
-    for (i = 0; i < numConditions; i++) {
-        EXPECT_EQ(done[i], 1);
-    }
-
-    for (i = 0; i < numConditions; i++) {
-        threads[i].join();
-    }
-}
-
-TEST(MultiConditionTrigger, TestNoConditions) {
-    mutex lock;
-    condition_variable cv;
-    bool triggerCalled = false;
-
-    MultiConditionTrigger trigger({}, [&lock, &cv, &triggerCalled] {
-        {
-            lock_guard lg(lock);
-            triggerCalled = true;
-        }
-        cv.notify_all();
-    });
-
-    unique_lock<mutex> unique_lk(lock);
-    cv.wait(unique_lk, [&triggerCalled] { return triggerCalled; });
-    EXPECT_TRUE(triggerCalled);
-    // Ensure that trigger occurs immediately if no events need to be completed.
-}
-
-TEST(MultiConditionTrigger, TestMarkCompleteCalledBySameCondition) {
-    string t1 = "t1", t2 = "t2";
-    set<string> conditionNames = {t1, t2};
-
-    mutex lock;
-    condition_variable cv;
-    bool triggerCalled = false;
-
-    MultiConditionTrigger trigger(conditionNames, [&lock, &cv, &triggerCalled] {
-        {
-            lock_guard lg(lock);
-            triggerCalled = true;
-        }
-        cv.notify_all();
-    });
-
-    trigger.markComplete(t1);
-    trigger.markComplete(t1);
-
-    // Ensure that the trigger still hasn't fired.
-    {
-        lock_guard lg(lock);
-        EXPECT_FALSE(triggerCalled);
-    }
-
-    trigger.markComplete(t2);
-    unique_lock<mutex> unique_lk(lock);
-    cv.wait(unique_lk, [&triggerCalled] { return triggerCalled; });
-    EXPECT_TRUE(triggerCalled);
-}
-
-TEST(MultiConditionTrigger, TestTriggerOnlyCalledOnce) {
-    string t1 = "t1";
-    set<string> conditionNames = {t1};
-
-    mutex lock;
-    condition_variable cv;
-    bool triggerCalled = false;
-    int triggerCount = 0;
-
-    MultiConditionTrigger trigger(conditionNames, [&lock, &cv, &triggerCalled, &triggerCount] {
-        {
-            lock_guard lg(lock);
-            triggerCount++;
-            triggerCalled = true;
-        }
-        cv.notify_all();
-    });
-
-    trigger.markComplete(t1);
-
-    // Ensure that the trigger fired.
-    {
-        unique_lock<mutex> unique_lk(lock);
-        cv.wait(unique_lk, [&triggerCalled] { return triggerCalled; });
-        EXPECT_TRUE(triggerCalled);
-        EXPECT_EQ(triggerCount, 1);
-        triggerCalled = false;
-    }
-
-    trigger.markComplete(t1);
-
-    // Ensure that the trigger does not fire again.
-    {
-        unique_lock<mutex> unique_lk(lock);
-        cv.wait_for(unique_lk, chrono::milliseconds(5), [&triggerCalled] { return triggerCalled; });
-        EXPECT_FALSE(triggerCalled);
-        EXPECT_EQ(triggerCount, 1);
-    }
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-#else
-GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
diff --git a/cmds/statsd/tools/localtools/Android.bp b/cmds/statsd/tools/localtools/Android.bp
deleted file mode 100644
index 69a43a8..0000000
--- a/cmds/statsd/tools/localtools/Android.bp
+++ /dev/null
@@ -1,46 +0,0 @@
-java_binary_host {
-    name: "statsd_localdrive",
-    manifest: "localdrive_manifest.txt",
-    srcs: [
-        "src/com/android/statsd/shelltools/localdrive/*.java",
-        "src/com/android/statsd/shelltools/Utils.java",
-    ],
-    static_libs: [
-        "platformprotos",
-        "guava",
-    ],
-}
-
-java_library_host {
-    name: "statsd_testdrive_lib",
-    srcs: [
-        "src/com/android/statsd/shelltools/testdrive/*.java",
-        "src/com/android/statsd/shelltools/Utils.java",
-    ],
-    static_libs: [
-        "platformprotos",
-        "guava",
-    ],
-}
-
-
-java_binary_host {
-    name: "statsd_testdrive",
-    manifest: "testdrive_manifest.txt",
-    static_libs: [
-        "statsd_testdrive_lib",
-    ],
-}
-
-java_test_host {
-    name: "statsd_testdrive_test",
-    test_suites: ["general-tests"],
-    srcs: ["test/com/android/statsd/shelltools/testdrive/*.java"],
-    static_libs: [
-        "statsd_testdrive_lib",
-        "junit",
-        "platformprotos",
-        "guava",
-    ],
-}
-
diff --git a/cmds/statsd/tools/localtools/TEST_MAPPING b/cmds/statsd/tools/localtools/TEST_MAPPING
deleted file mode 100644
index 7c8a3db..0000000
--- a/cmds/statsd/tools/localtools/TEST_MAPPING
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "presubmit": [
-    {
-      "name": "statsd_testdrive_test",
-      "host": true
-    }
-  ]
-}
diff --git a/cmds/statsd/tools/localtools/localdrive_manifest.txt b/cmds/statsd/tools/localtools/localdrive_manifest.txt
deleted file mode 100644
index 035cea1..0000000
--- a/cmds/statsd/tools/localtools/localdrive_manifest.txt
+++ /dev/null
@@ -1 +0,0 @@
-Main-class: com.android.statsd.shelltools.localdrive.LocalDrive
diff --git a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/Utils.java b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/Utils.java
deleted file mode 100644
index 6a74480..0000000
--- a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/Utils.java
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.statsd.shelltools;
-
-import com.android.os.StatsLog.ConfigMetricsReportList;
-
-import com.google.common.io.Files;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.logging.ConsoleHandler;
-import java.util.logging.Formatter;
-import java.util.logging.Level;
-import java.util.logging.LogRecord;
-import java.util.logging.Logger;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Utilities for local use of statsd.
- */
-public class Utils {
-
-    public static final String CMD_DUMP_REPORT = "cmd stats dump-report";
-    public static final String CMD_LOG_APP_BREADCRUMB = "cmd stats log-app-breadcrumb";
-    public static final String CMD_REMOVE_CONFIG = "cmd stats config remove";
-    public static final String CMD_UPDATE_CONFIG = "cmd stats config update";
-
-    public static final String SHELL_UID = "2000"; // Use shell, even if rooted.
-
-    /**
-     * Runs adb shell command with output directed to outputFile if non-null.
-     */
-    public static void runCommand(File outputFile, Logger logger, String... commands)
-            throws IOException, InterruptedException {
-        ProcessBuilder pb = new ProcessBuilder(commands);
-        if (outputFile != null && outputFile.exists() && outputFile.canWrite()) {
-            pb.redirectOutput(outputFile);
-        }
-        Process process = pb.start();
-
-        // Capture any errors
-        StringBuilder err = new StringBuilder();
-        BufferedReader br = new BufferedReader(new InputStreamReader(process.getErrorStream()));
-        for (String line = br.readLine(); line != null; line = br.readLine()) {
-            err.append(line).append('\n');
-        }
-        logger.severe(err.toString());
-
-        // Check result
-        if (process.waitFor() == 0) {
-            logger.fine("Adb command successful.");
-        } else {
-            logger.severe("Abnormal adb shell termination for: " + String.join(",", commands));
-            throw new RuntimeException("Error running adb command: " + err.toString());
-        }
-    }
-
-    /**
-     * Dumps the report from the device and converts it to a ConfigMetricsReportList.
-     * Erases the data if clearData is true.
-     * @param configId id of the config
-     * @param clearData whether to erase the report data from statsd after getting the report.
-     * @param useShellUid Pulls data for the {@link SHELL_UID} instead of the caller's uid.
-     * @param logger Logger to log error messages
-     * @return
-     * @throws IOException
-     * @throws InterruptedException
-     */
-    public static ConfigMetricsReportList getReportList(long configId, boolean clearData,
-            boolean useShellUid, Logger logger, String deviceSerial)
-            throws IOException, InterruptedException {
-        try {
-            File outputFile = File.createTempFile("statsdret", ".bin");
-            outputFile.deleteOnExit();
-            runCommand(
-                    outputFile,
-                    logger,
-                    "adb",
-                    "-s",
-                    deviceSerial,
-                    "shell",
-                    CMD_DUMP_REPORT,
-                    useShellUid ? SHELL_UID : "",
-                    String.valueOf(configId),
-                    clearData ? "" : "--keep_data",
-                    "--include_current_bucket",
-                    "--proto");
-            ConfigMetricsReportList reportList =
-                    ConfigMetricsReportList.parseFrom(new FileInputStream(outputFile));
-            return reportList;
-        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
-            logger.severe("Failed to fetch and parse the statsd output report. "
-                            + "Perhaps there is not a valid statsd config for the requested "
-                            + (useShellUid ? ("uid=" + SHELL_UID + ", ") : "")
-                            + "configId=" + configId
-                            + ".");
-            throw (e);
-        }
-    }
-
-    /**
-     * Logs an AppBreadcrumbReported atom.
-     * @param label which label to log for the app breadcrumb atom.
-     * @param state which state to log for the app breadcrumb atom.
-     * @param logger Logger to log error messages
-     *
-     * @throws IOException
-     * @throws InterruptedException
-     */
-    public static void logAppBreadcrumb(int label, int state, Logger logger, String deviceSerial)
-            throws IOException, InterruptedException {
-        runCommand(
-                null,
-                logger,
-                "adb",
-                "-s",
-                deviceSerial,
-                "shell",
-                CMD_LOG_APP_BREADCRUMB,
-                String.valueOf(label),
-                String.valueOf(state));
-    }
-    public static void setUpLogger(Logger logger, boolean debug) {
-        ConsoleHandler handler = new ConsoleHandler();
-        handler.setFormatter(new LocalToolsFormatter());
-        logger.setUseParentHandlers(false);
-        if (debug) {
-            handler.setLevel(Level.ALL);
-            logger.setLevel(Level.ALL);
-        }
-        logger.addHandler(handler);
-    }
-
-    /**
-     * Attempt to determine whether tool will work with this statsd, i.e. whether statsd is
-     * minCodename or higher.
-     * Algorithm: true if (sdk >= minSdk) || (sdk == minSdk-1 && codeName.startsWith(minCodeName))
-     * If all else fails, assume it will work (letting future commands deal with any errors).
-     */
-    public static boolean isAcceptableStatsd(Logger logger, int minSdk, String minCodename,
-            String deviceSerial) {
-        BufferedReader in = null;
-        try {
-            File outFileSdk = File.createTempFile("shelltools_sdk", "tmp");
-            outFileSdk.deleteOnExit();
-            runCommand(outFileSdk, logger,
-                    "adb", "-s", deviceSerial, "shell", "getprop", "ro.build.version.sdk");
-            in = new BufferedReader(new InputStreamReader(new FileInputStream(outFileSdk)));
-            // If NullPointerException/NumberFormatException/etc., just catch and return true.
-            int sdk = Integer.parseInt(in.readLine().trim());
-            if (sdk >= minSdk) {
-                return true;
-            } else if (sdk == minSdk - 1) { // Could be minSdk-1, or could be minSdk development.
-                in.close();
-                File outFileCode = File.createTempFile("shelltools_codename", "tmp");
-                outFileCode.deleteOnExit();
-                runCommand(outFileCode, logger,
-                        "adb", "-s", deviceSerial, "shell", "getprop", "ro.build.version.codename");
-                in = new BufferedReader(new InputStreamReader(new FileInputStream(outFileCode)));
-                return in.readLine().startsWith(minCodename);
-            } else {
-                return false;
-            }
-        } catch (Exception e) {
-            logger.fine("Could not determine whether statsd version is compatibile "
-                    + "with tool: " + e.toString());
-        } finally {
-            try {
-                if (in != null) {
-                    in.close();
-                }
-            } catch (IOException e) {
-                logger.fine("Could not close temporary file: " + e.toString());
-            }
-        }
-        // Could not determine whether statsd is acceptable version.
-        // Just assume it is; if it isn't, we'll just get future errors via adb and deal with them.
-        return true;
-    }
-
-    public static class LocalToolsFormatter extends Formatter {
-        public String format(LogRecord record) {
-            return record.getMessage() + "\n";
-        }
-    }
-
-    /**
-     * Parse the result of "adb devices" to return the list of connected devices.
-     * @param logger Logger to log error messages
-     * @return List of the serial numbers of the connected devices.
-     */
-    public static List<String> getDeviceSerials(Logger logger) {
-        try {
-            ArrayList<String> devices = new ArrayList<>();
-            File outFile = File.createTempFile("device_serial", "tmp");
-            outFile.deleteOnExit();
-            Utils.runCommand(outFile, logger, "adb", "devices");
-            List<String> outputLines = Files.readLines(outFile, Charset.defaultCharset());
-            Pattern regex = Pattern.compile("^(.*)\tdevice$");
-            for (String line : outputLines) {
-                Matcher m = regex.matcher(line);
-                if (m.find()) {
-                    devices.add(m.group(1));
-                }
-            }
-            return devices;
-        } catch (Exception ex) {
-            logger.log(Level.SEVERE, "Failed to list connected devices: " + ex.getMessage());
-        }
-        return null;
-    }
-
-    /**
-     * Returns ANDROID_SERIAL environment variable, or null if that is undefined or unavailable.
-     * @param logger Destination of error messages.
-     * @return String value of ANDROID_SERIAL environment variable, or null.
-     */
-    public static String getDefaultDevice(Logger logger) {
-        try {
-            return System.getenv("ANDROID_SERIAL");
-        } catch (Exception ex) {
-            logger.log(Level.SEVERE, "Failed to check ANDROID_SERIAL environment variable.",
-                    ex);
-        }
-        return null;
-    }
-
-    /**
-     * Returns the device to use if one can be deduced, or null.
-     * @param device Command-line specified device, or null.
-     * @param connectedDevices List of all connected devices.
-     * @param defaultDevice Environment-variable specified device, or null.
-     * @param logger Destination of error messages.
-     * @return Device to use, or null.
-     */
-    public static String chooseDevice(String device, List<String> connectedDevices,
-            String defaultDevice, Logger logger) {
-        if (connectedDevices == null || connectedDevices.isEmpty()) {
-            logger.severe("No connected device.");
-            return null;
-        }
-        if (device != null) {
-            if (connectedDevices.contains(device)) {
-                return device;
-            }
-            logger.severe("Device not connected: " + device);
-            return null;
-        }
-        if (connectedDevices.size() == 1) {
-            return connectedDevices.get(0);
-        }
-        if (defaultDevice != null) {
-            if (connectedDevices.contains(defaultDevice)) {
-                return defaultDevice;
-            } else {
-                logger.severe("ANDROID_SERIAL device is not connected: " + defaultDevice);
-                return null;
-            }
-        }
-        logger.severe("More than one device is connected. Choose one"
-                + " with -s DEVICE_SERIAL or environment variable ANDROID_SERIAL.");
-        return null;
-    }
-}
diff --git a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/localdrive/LocalDrive.java b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/localdrive/LocalDrive.java
deleted file mode 100644
index ec3c7df..0000000
--- a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/localdrive/LocalDrive.java
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.statsd.shelltools.localdrive;
-
-import com.android.internal.os.StatsdConfigProto.StatsdConfig;
-import com.android.os.StatsLog.ConfigMetricsReport;
-import com.android.os.StatsLog.ConfigMetricsReportList;
-import com.android.statsd.shelltools.Utils;
-
-import com.google.common.io.Files;
-import com.google.protobuf.TextFormat;
-
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.util.List;
-import java.util.logging.Logger;
-
-/**
- * Tool for using statsd locally. Can upload a config and get the data. Handles
- * both binary and human-readable protos.
- * To make: make statsd_localdrive
- * To run: statsd_localdrive     (i.e.  ./out/host/linux-x86/bin/statsd_localdrive)
- */
-public class LocalDrive {
-    private static final boolean DEBUG = false;
-
-    public static final int MIN_SDK = 29;
-    public static final String MIN_CODENAME = "Q";
-
-    public static final long DEFAULT_CONFIG_ID = 56789;
-
-    public static final String BINARY_FLAG = "--binary";
-    public static final String CLEAR_DATA = "--clear";
-    public static final String NO_UID_MAP_FLAG = "--no-uid-map";
-
-    public static final String HELP_STRING =
-        "Usage:\n\n" +
-
-        "statsd_localdrive [-s DEVICE_SERIAL] upload CONFIG_FILE [CONFIG_ID] [--binary]\n" +
-        "  Uploads the given statsd config file (in binary or human-readable-text format).\n" +
-        "  If a config with this id already exists, removes it first.\n" +
-        "    CONFIG_FILE    Location of config file on host.\n" +
-        "    CONFIG_ID      Long ID to associate with this config. If absent, uses "
-                                                                + DEFAULT_CONFIG_ID + ".\n" +
-        "    --binary       Config is in binary format; otherwise, assumed human-readable text.\n" +
-        // Similar to: adb shell cmd stats config update SHELL_UID CONFIG_ID
-        "\n" +
-
-        "statsd_localdrive [-s DEVICE_SERIAL] update CONFIG_FILE [CONFIG_ID] [--binary]\n" +
-        "  Same as upload, but does not remove the old config first (if it already exists).\n" +
-        // Similar to: adb shell cmd stats config update SHELL_UID CONFIG_ID
-        "\n" +
-
-        "statsd_localdrive [-s DEVICE_SERIAL] get-data [CONFIG_ID] [--clear] [--binary] [--no-uid-map]\n" +
-        "  Prints the output statslog data (in binary or human-readable-text format).\n" +
-        "    CONFIG_ID      Long ID of the config. If absent, uses " + DEFAULT_CONFIG_ID + ".\n" +
-        "    --binary       Output should be in binary, instead of default human-readable text.\n" +
-        "                       Binary output can be redirected as usual (e.g. > FILENAME).\n" +
-        "    --no-uid-map   Do not include the uid-map (the very lengthy uid<-->pkgName map).\n" +
-        "    --clear        Erase the data from statsd afterwards. Does not remove the config.\n" +
-        // Similar to: adb shell cmd stats dump-report SHELL_UID CONFIG_ID [--keep_data]
-        //                                                      --include_current_bucket --proto
-        "\n" +
-
-        "statsd_localdrive [-s DEVICE_SERIAL] remove [CONFIG_ID]\n" +
-        "  Removes the config.\n" +
-        "    CONFIG_ID      Long ID of the config. If absent, uses " + DEFAULT_CONFIG_ID + ".\n" +
-        // Equivalent to: adb shell cmd stats config remove SHELL_UID CONFIG_ID
-        "\n" +
-
-        "statsd_localdrive [-s DEVICE_SERIAL] clear [CONFIG_ID]\n" +
-        "  Clears the data associated with the config.\n" +
-        "    CONFIG_ID      Long ID of the config. If absent, uses " + DEFAULT_CONFIG_ID + ".\n" +
-        // Similar to: adb shell cmd stats dump-report SHELL_UID CONFIG_ID
-        //                                                      --include_current_bucket --proto
-        "";
-
-
-    private static final Logger sLogger = Logger.getLogger(LocalDrive.class.getName());
-
-    /** Usage: make statsd_localdrive && statsd_localdrive */
-    public static void main(String[] args) {
-        Utils.setUpLogger(sLogger, DEBUG);
-        if (args.length == 0) {
-            printHelp();
-            return;
-        }
-
-        int remainingArgsLength = args.length;
-        String deviceSerial = null;
-        if (args[0].equals("-s")) {
-            if (args.length == 1) {
-                printHelp();
-            }
-            deviceSerial = args[1];
-            remainingArgsLength -= 2;
-        }
-
-        List<String> connectedDevices = Utils.getDeviceSerials(sLogger);
-        deviceSerial = Utils.chooseDevice(deviceSerial, connectedDevices,
-                Utils.getDefaultDevice(sLogger), sLogger);
-        if (deviceSerial == null) {
-            return;
-        }
-
-        if (!Utils.isAcceptableStatsd(sLogger, MIN_SDK, MIN_CODENAME, deviceSerial)) {
-            sLogger.severe("LocalDrive only works with statsd versions for Android "
-                    + MIN_CODENAME + " or higher.");
-            return;
-        }
-
-        int idx = args.length - remainingArgsLength;
-        if (remainingArgsLength > 0) {
-            switch (args[idx]) {
-                case "clear":
-                    cmdClear(args, idx, deviceSerial);
-                    return;
-                case "get-data":
-                    cmdGetData(args, idx, deviceSerial);
-                    return;
-                case "remove":
-                    cmdRemove(args, idx);
-                    return;
-                case "update":
-                    cmdUpdate(args, idx, deviceSerial);
-                    return;
-                case "upload":
-                    cmdUpload(args, idx, deviceSerial);
-                    return;
-            }
-        }
-        printHelp();
-    }
-
-    private static void printHelp() {
-        sLogger.info(HELP_STRING);
-    }
-
-    // upload CONFIG_FILE [CONFIG_ID] [--binary]
-    private static boolean cmdUpload(String[] args, int idx, String deviceSerial) {
-        return updateConfig(args, idx, true, deviceSerial);
-    }
-
-    // update CONFIG_FILE [CONFIG_ID] [--binary]
-    private static boolean cmdUpdate(String[] args, int idx, String deviceSerial) {
-        return updateConfig(args, idx, false, deviceSerial);
-    }
-
-    private static boolean updateConfig(String[] args, int idx, boolean removeOldConfig,
-            String deviceSerial) {
-        int argCount = args.length - 1 - idx; // Used up one for upload/update.
-
-        // Get CONFIG_FILE
-        if (argCount < 1) {
-            sLogger.severe("No config file provided.");
-            printHelp();
-            return false;
-        }
-        final String origConfigLocation = args[idx + 1];
-        if (!new File(origConfigLocation).exists()) {
-            sLogger.severe("Error - Cannot find the provided config file: " + origConfigLocation);
-            return false;
-        }
-        argCount--;
-
-        // Get --binary
-        boolean binary = contains(args, idx + 2, BINARY_FLAG);
-        if (binary) argCount --;
-
-        // Get CONFIG_ID
-        long configId;
-        try {
-            configId = getConfigId(argCount < 1, args, idx + 2);
-        } catch (NumberFormatException e) {
-            sLogger.severe("Invalid config id provided.");
-            printHelp();
-            return false;
-        }
-        sLogger.fine(String.format("updateConfig with %s %d %b %b",
-                origConfigLocation, configId, binary, removeOldConfig));
-
-        // Remove the old config.
-        if (removeOldConfig) {
-            try {
-                Utils.runCommand(null, sLogger, "adb", "shell", Utils.CMD_REMOVE_CONFIG,
-                        Utils.SHELL_UID, String.valueOf(configId));
-                Utils.getReportList(configId, true /* clearData */, true /* SHELL_UID */, sLogger,
-                        deviceSerial);
-            } catch (InterruptedException | IOException e) {
-                sLogger.severe("Failed to remove config: " + e.getMessage());
-                return false;
-            }
-        }
-
-        // Upload the config.
-        String configLocation;
-        if (binary) {
-            configLocation = origConfigLocation;
-        } else {
-            StatsdConfig.Builder builder = StatsdConfig.newBuilder();
-            try {
-                TextFormat.merge(new FileReader(origConfigLocation), builder);
-            } catch (IOException e) {
-                sLogger.severe("Failed to read config file " + origConfigLocation + ": "
-                        + e.getMessage());
-                return false;
-            }
-
-            try {
-                File tempConfigFile = File.createTempFile("statsdconfig", ".config");
-                tempConfigFile.deleteOnExit();
-                Files.write(builder.build().toByteArray(), tempConfigFile);
-                configLocation = tempConfigFile.getAbsolutePath();
-            } catch (IOException e) {
-                sLogger.severe("Failed to write temp config file: " + e.getMessage());
-                return false;
-            }
-        }
-        String remotePath = "/data/local/tmp/statsdconfig.config";
-        try {
-            Utils.runCommand(null, sLogger, "adb", "push", configLocation, remotePath);
-            Utils.runCommand(null, sLogger, "adb", "shell", "cat", remotePath, "|",
-                    Utils.CMD_UPDATE_CONFIG, Utils.SHELL_UID, String.valueOf(configId));
-        } catch (InterruptedException | IOException e) {
-            sLogger.severe("Failed to update config: " + e.getMessage());
-            return false;
-        }
-        return true;
-    }
-
-    // get-data [CONFIG_ID] [--clear] [--binary] [--no-uid-map]
-    private static boolean cmdGetData(String[] args, int idx, String deviceSerial) {
-        boolean binary = contains(args, idx + 1, BINARY_FLAG);
-        boolean noUidMap = contains(args, idx + 1, NO_UID_MAP_FLAG);
-        boolean clearData = contains(args, idx + 1, CLEAR_DATA);
-
-        // Get CONFIG_ID
-        int argCount = args.length - 1 - idx; // Used up one for get-data.
-        if (binary) argCount--;
-        if (noUidMap) argCount--;
-        if (clearData) argCount--;
-        long configId;
-        try {
-            configId = getConfigId(argCount < 1, args, idx + 1);
-        } catch (NumberFormatException e) {
-            sLogger.severe("Invalid config id provided.");
-            printHelp();
-            return false;
-        }
-        sLogger.fine(String.format("cmdGetData with %d %b %b %b",
-                configId, clearData, binary, noUidMap));
-
-        // Get the StatsLog
-        // Even if the args request no modifications, we still parse it to make sure it's valid.
-        ConfigMetricsReportList reportList;
-        try {
-            reportList = Utils.getReportList(configId, clearData, true /* SHELL_UID */, sLogger,
-                    deviceSerial);
-        } catch (IOException | InterruptedException e) {
-            sLogger.severe("Failed to get report list: " + e.getMessage());
-            return false;
-        }
-        if (noUidMap) {
-            ConfigMetricsReportList.Builder builder
-                    = ConfigMetricsReportList.newBuilder(reportList);
-            // Clear the reports, then add them back without their UidMap.
-            builder.clearReports();
-            for (ConfigMetricsReport report : reportList.getReportsList()) {
-                builder.addReports(ConfigMetricsReport.newBuilder(report).clearUidMap());
-            }
-            reportList = builder.build();
-        }
-
-        if (!binary) {
-            sLogger.info(reportList.toString());
-        } else {
-            try {
-                System.out.write(reportList.toByteArray());
-            } catch (IOException e) {
-                sLogger.severe("Failed to output binary statslog proto: "
-                        + e.getMessage());
-                return false;
-            }
-        }
-        return true;
-    }
-
-    // clear [CONFIG_ID]
-    private static boolean cmdClear(String[] args, int idx, String deviceSerial) {
-        // Get CONFIG_ID
-        long configId;
-        try {
-            configId = getConfigId(false, args, idx + 1);
-        } catch (NumberFormatException e) {
-            sLogger.severe("Invalid config id provided.");
-            printHelp();
-            return false;
-        }
-        sLogger.fine(String.format("cmdClear with %d", configId));
-
-        try {
-            Utils.getReportList(configId, true /* clearData */, true /* SHELL_UID */, sLogger,
-                    deviceSerial);
-        } catch (IOException | InterruptedException e) {
-            sLogger.severe("Failed to get report list: " + e.getMessage());
-            return false;
-        }
-        return true;
-    }
-
-    // remove [CONFIG_ID]
-    private static boolean cmdRemove(String[] args, int idx) {
-        // Get CONFIG_ID
-        long configId;
-        try {
-            configId = getConfigId(false, args, idx + 1);
-        } catch (NumberFormatException e) {
-            sLogger.severe("Invalid config id provided.");
-            printHelp();
-            return false;
-        }
-        sLogger.fine(String.format("cmdRemove with %d", configId));
-
-        try {
-            Utils.runCommand(null, sLogger, "adb", "shell", Utils.CMD_REMOVE_CONFIG,
-                    Utils.SHELL_UID, String.valueOf(configId));
-        } catch (InterruptedException | IOException e) {
-            sLogger.severe("Failed to remove config: " + e.getMessage());
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Searches through the array to see if it contains (precisely) the given value, starting
-     * at the given firstIdx.
-     */
-    private static boolean contains(String[] array, int firstIdx, String value) {
-        if (value == null) return false;
-        if (firstIdx < 0) return false;
-        for (int i = firstIdx; i < array.length; i++) {
-            if (value.equals(array[i])) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Gets the config id from args[idx], or returns DEFAULT_CONFIG_ID if args[idx] does not exist.
-     * If justUseDefault, overrides and just uses DEFAULT_CONFIG_ID instead.
-     */
-    private static long getConfigId(boolean justUseDefault, String[] args, int idx)
-            throws NumberFormatException {
-        if (justUseDefault || args.length <= idx || idx < 0) {
-            return DEFAULT_CONFIG_ID;
-        }
-        try {
-            return Long.valueOf(args[idx]);
-        } catch (NumberFormatException e) {
-            sLogger.severe("Bad config id provided: " + args[idx]);
-            throw e;
-        }
-    }
-}
diff --git a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
deleted file mode 100644
index 51bcad1..0000000
--- a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.statsd.shelltools.testdrive;
-
-import com.android.internal.os.StatsdConfigProto;
-import com.android.internal.os.StatsdConfigProto.AtomMatcher;
-import com.android.internal.os.StatsdConfigProto.EventMetric;
-import com.android.internal.os.StatsdConfigProto.FieldFilter;
-import com.android.internal.os.StatsdConfigProto.GaugeMetric;
-import com.android.internal.os.StatsdConfigProto.PullAtomPackages;
-import com.android.internal.os.StatsdConfigProto.SimpleAtomMatcher;
-import com.android.internal.os.StatsdConfigProto.StatsdConfig;
-import com.android.internal.os.StatsdConfigProto.TimeUnit;
-import com.android.os.AtomsProto.Atom;
-import com.android.os.StatsLog;
-import com.android.os.StatsLog.ConfigMetricsReport;
-import com.android.os.StatsLog.ConfigMetricsReportList;
-import com.android.os.StatsLog.StatsLogReport;
-import com.android.statsd.shelltools.Utils;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.io.Files;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-public class TestDrive {
-
-    private static final int METRIC_ID_BASE = 1111;
-    private static final long ATOM_MATCHER_ID_BASE = 1234567;
-    private static final long APP_BREADCRUMB_MATCHER_ID = 1111111;
-    private static final int PULL_ATOM_START = 10000;
-    private static final int MAX_PLATFORM_ATOM_TAG = 100000;
-    private static final int VENDOR_PULLED_ATOM_START_TAG = 150000;
-    private static final long CONFIG_ID = 54321;
-    private static final String[] ALLOWED_LOG_SOURCES = {
-            "AID_GRAPHICS",
-            "AID_INCIDENTD",
-            "AID_STATSD",
-            "AID_RADIO",
-            "com.android.systemui",
-            "com.android.vending",
-            "AID_SYSTEM",
-            "AID_ROOT",
-            "AID_BLUETOOTH",
-            "AID_LMKD",
-            "com.android.managedprovisioning",
-            "AID_MEDIA",
-            "AID_NETWORK_STACK",
-            "com.google.android.providers.media.module",
-    };
-    private static final String[] DEFAULT_PULL_SOURCES = {
-            "AID_SYSTEM",
-            "AID_RADIO"
-    };
-    private static final Logger LOGGER = Logger.getLogger(TestDrive.class.getName());
-
-    @VisibleForTesting
-    String mDeviceSerial = null;
-    @VisibleForTesting
-    Dumper mDumper = new BasicDumper();
-
-    public static void main(String[] args) {
-        final Configuration configuration = new Configuration();
-        final TestDrive testDrive = new TestDrive();
-        Utils.setUpLogger(LOGGER, false);
-
-        if (!testDrive.processArgs(configuration, args,
-                Utils.getDeviceSerials(LOGGER), Utils.getDefaultDevice(LOGGER))) {
-            return;
-        }
-
-        final ConfigMetricsReportList reports = testDrive.testDriveAndGetReports(
-                configuration.createConfig(), configuration.hasPulledAtoms(),
-                configuration.hasPushedAtoms());
-        if (reports != null) {
-            configuration.dumpMetrics(reports, testDrive.mDumper);
-        }
-    }
-
-    boolean processArgs(Configuration configuration, String[] args, List<String> connectedDevices,
-            String defaultDevice) {
-        if (args.length < 1) {
-            LOGGER.severe("Usage: ./test_drive [-one] "
-                    + "[-p additional_allowed_package] "
-                    + "[-s DEVICE_SERIAL_NUMBER] "
-                    + "<atomId1> <atomId2> ... <atomIdN>");
-            return false;
-        }
-
-        int first_arg = 0;
-        // Consume all flags, which must precede all atoms
-        for (; first_arg < args.length; ++first_arg) {
-            String arg = args[first_arg];
-            int remaining_args = args.length - first_arg;
-            if (remaining_args >= 2 && arg.equals("-one")) {
-                LOGGER.info("Creating one event metric to catch all pushed atoms.");
-                configuration.mOnePushedAtomEvent = true;
-            } else if (remaining_args >= 2 && arg.equals("-terse")) {
-                LOGGER.info("Terse output format.");
-                mDumper = new TerseDumper();
-            } else if (remaining_args >= 3 && arg.equals("-p")) {
-                configuration.mAdditionalAllowedPackage = args[++first_arg];
-            } else if (remaining_args >= 3 && arg.equals("-s")) {
-                mDeviceSerial = args[++first_arg];
-            } else {
-                break;  // Found the atom list
-            }
-        }
-
-        mDeviceSerial = Utils.chooseDevice(mDeviceSerial, connectedDevices, defaultDevice, LOGGER);
-        if (mDeviceSerial == null) {
-            return false;
-        }
-
-        for ( ; first_arg < args.length; ++first_arg) {
-            String atom = args[first_arg];
-            try {
-                configuration.addAtom(Integer.valueOf(atom));
-            } catch (NumberFormatException e) {
-                LOGGER.severe("Bad atom id provided: " + atom);
-            }
-        }
-
-        return configuration.hasPulledAtoms() || configuration.hasPushedAtoms();
-    }
-
-    private ConfigMetricsReportList testDriveAndGetReports(StatsdConfig config,
-            boolean hasPulledAtoms, boolean hasPushedAtoms) {
-        if (config == null) {
-            LOGGER.severe("Failed to create valid config.");
-            return null;
-        }
-
-        String remoteConfigPath = null;
-        try {
-            remoteConfigPath = pushConfig(config, mDeviceSerial);
-            LOGGER.info("Pushed the following config to statsd on device '" + mDeviceSerial
-                    + "':");
-            LOGGER.info(config.toString());
-            if (hasPushedAtoms) {
-                LOGGER.info("Now please play with the device to trigger the event.");
-            }
-            if (!hasPulledAtoms) {
-                LOGGER.info(
-                        "All events should be dumped after 1 min ...");
-                Thread.sleep(60_000);
-            } else {
-                LOGGER.info("All events should be dumped after 1.5 minutes ...");
-                Thread.sleep(15_000);
-                Utils.logAppBreadcrumb(0, 0, LOGGER, mDeviceSerial);
-                Thread.sleep(75_000);
-            }
-            return Utils.getReportList(CONFIG_ID, true, false, LOGGER,
-                    mDeviceSerial);
-        } catch (Exception e) {
-            LOGGER.log(Level.SEVERE, "Failed to test drive: " + e.getMessage(), e);
-        } finally {
-            removeConfig(mDeviceSerial);
-            if (remoteConfigPath != null) {
-                try {
-                    Utils.runCommand(null, LOGGER,
-                            "adb", "-s", mDeviceSerial, "shell", "rm",
-                            remoteConfigPath);
-                } catch (Exception e) {
-                    LOGGER.log(Level.WARNING,
-                            "Unable to remove remote config file: " + remoteConfigPath, e);
-                }
-            }
-        }
-        return null;
-    }
-
-    static class Configuration {
-        boolean mOnePushedAtomEvent = false;
-        @VisibleForTesting
-        Set<Integer> mPushedAtoms = new TreeSet<>();
-        @VisibleForTesting
-        Set<Integer> mPulledAtoms = new TreeSet<>();
-        @VisibleForTesting
-        String mAdditionalAllowedPackage = null;
-        private final Set<Long> mTrackedMetrics = new HashSet<>();
-
-        private void dumpMetrics(ConfigMetricsReportList reportList, Dumper dumper) {
-            // We may get multiple reports. Take the last one.
-            ConfigMetricsReport report = reportList.getReports(reportList.getReportsCount() - 1);
-            for (StatsLogReport statsLog : report.getMetricsList()) {
-                if (isTrackedMetric(statsLog.getMetricId())) {
-                    dumper.dump(statsLog);
-                }
-            }
-        }
-
-        boolean isTrackedMetric(long metricId) {
-            return mTrackedMetrics.contains(metricId);
-        }
-
-        static boolean isPulledAtom(int atomId) {
-            return atomId >= PULL_ATOM_START && atomId <= MAX_PLATFORM_ATOM_TAG
-                    || atomId >= VENDOR_PULLED_ATOM_START_TAG;
-        }
-
-        void addAtom(Integer atom) {
-            if (Atom.getDescriptor().findFieldByNumber(atom) == null) {
-                LOGGER.severe("No such atom found: " + atom);
-                return;
-            }
-            if (isPulledAtom(atom)) {
-                mPulledAtoms.add(atom);
-            } else {
-                mPushedAtoms.add(atom);
-            }
-        }
-
-        private boolean hasPulledAtoms() {
-            return !mPulledAtoms.isEmpty();
-        }
-
-        private boolean hasPushedAtoms() {
-            return !mPushedAtoms.isEmpty();
-        }
-
-        StatsdConfig createConfig() {
-            long metricId = METRIC_ID_BASE;
-            long atomMatcherId = ATOM_MATCHER_ID_BASE;
-
-            StatsdConfig.Builder builder = baseBuilder();
-
-            if (hasPulledAtoms()) {
-                builder.addAtomMatcher(
-                        createAtomMatcher(
-                                Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER,
-                                APP_BREADCRUMB_MATCHER_ID));
-            }
-
-            for (int atomId : mPulledAtoms) {
-                builder.addAtomMatcher(createAtomMatcher(atomId, atomMatcherId));
-                GaugeMetric.Builder gaugeMetricBuilder = GaugeMetric.newBuilder();
-                gaugeMetricBuilder
-                        .setId(metricId)
-                        .setWhat(atomMatcherId)
-                        .setTriggerEvent(APP_BREADCRUMB_MATCHER_ID)
-                        .setGaugeFieldsFilter(FieldFilter.newBuilder().setIncludeAll(true).build())
-                        .setBucket(TimeUnit.ONE_MINUTE)
-                        .setSamplingType(GaugeMetric.SamplingType.FIRST_N_SAMPLES)
-                        .setMaxNumGaugeAtomsPerBucket(100);
-                builder.addGaugeMetric(gaugeMetricBuilder.build());
-                atomMatcherId++;
-                mTrackedMetrics.add(metricId++);
-            }
-
-            // A simple atom matcher for each pushed atom.
-            List<AtomMatcher> simpleAtomMatchers = new ArrayList<>();
-            for (int atomId : mPushedAtoms) {
-                final AtomMatcher atomMatcher = createAtomMatcher(atomId, atomMatcherId++);
-                simpleAtomMatchers.add(atomMatcher);
-                builder.addAtomMatcher(atomMatcher);
-            }
-
-            if (mOnePushedAtomEvent) {
-                // Create a union event metric, using an matcher that matches all pulled atoms.
-                AtomMatcher unionAtomMatcher = createUnionMatcher(simpleAtomMatchers,
-                        atomMatcherId);
-                builder.addAtomMatcher(unionAtomMatcher);
-                EventMetric.Builder eventMetricBuilder = EventMetric.newBuilder();
-                eventMetricBuilder.setId(metricId).setWhat(unionAtomMatcher.getId());
-                builder.addEventMetric(eventMetricBuilder.build());
-                mTrackedMetrics.add(metricId++);
-            } else {
-                // Create multiple event metrics, one per pulled atom.
-                for (AtomMatcher atomMatcher : simpleAtomMatchers) {
-                    EventMetric.Builder eventMetricBuilder = EventMetric.newBuilder();
-                    eventMetricBuilder
-                            .setId(metricId)
-                            .setWhat(atomMatcher.getId());
-                    builder.addEventMetric(eventMetricBuilder.build());
-                    mTrackedMetrics.add(metricId++);
-                }
-            }
-
-            return builder.build();
-        }
-
-        private static AtomMatcher createAtomMatcher(int atomId, long matcherId) {
-            AtomMatcher.Builder atomMatcherBuilder = AtomMatcher.newBuilder();
-            atomMatcherBuilder
-                    .setId(matcherId)
-                    .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder().setAtomId(atomId));
-            return atomMatcherBuilder.build();
-        }
-
-        private AtomMatcher createUnionMatcher(List<AtomMatcher> simpleAtomMatchers,
-                long atomMatcherId) {
-            AtomMatcher.Combination.Builder combinationBuilder =
-                    AtomMatcher.Combination.newBuilder();
-            combinationBuilder.setOperation(StatsdConfigProto.LogicalOperation.OR);
-            for (AtomMatcher matcher : simpleAtomMatchers) {
-                combinationBuilder.addMatcher(matcher.getId());
-            }
-            AtomMatcher.Builder atomMatcherBuilder = AtomMatcher.newBuilder();
-            atomMatcherBuilder.setId(atomMatcherId).setCombination(combinationBuilder.build());
-            return atomMatcherBuilder.build();
-        }
-
-        private StatsdConfig.Builder baseBuilder() {
-            ArrayList<String> allowedSources = new ArrayList<>();
-            Collections.addAll(allowedSources, ALLOWED_LOG_SOURCES);
-            if (mAdditionalAllowedPackage != null) {
-                allowedSources.add(mAdditionalAllowedPackage);
-            }
-            return StatsdConfig.newBuilder()
-                    .addAllAllowedLogSource(allowedSources)
-                    .addAllDefaultPullPackages(Arrays.asList(DEFAULT_PULL_SOURCES))
-                    .addPullAtomPackages(PullAtomPackages.newBuilder()
-                            .setAtomId(Atom.GPU_STATS_GLOBAL_INFO_FIELD_NUMBER)
-                            .addPackages("AID_GPU_SERVICE"))
-                    .addPullAtomPackages(PullAtomPackages.newBuilder()
-                            .setAtomId(Atom.GPU_STATS_APP_INFO_FIELD_NUMBER)
-                            .addPackages("AID_GPU_SERVICE"))
-                    .addPullAtomPackages(PullAtomPackages.newBuilder()
-                            .setAtomId(Atom.TRAIN_INFO_FIELD_NUMBER)
-                            .addPackages("AID_STATSD"))
-                    .addPullAtomPackages(PullAtomPackages.newBuilder()
-                            .setAtomId(Atom.GENERAL_EXTERNAL_STORAGE_ACCESS_STATS_FIELD_NUMBER)
-                            .addPackages("com.google.android.providers.media.module"))
-                    .setHashStringsInMetricReport(false);
-        }
-    }
-
-    interface Dumper {
-        void dump(StatsLogReport report);
-    }
-
-    static class BasicDumper implements Dumper {
-        @Override
-        public void dump(StatsLogReport report) {
-            System.out.println(report.toString());
-        }
-    }
-
-    static class TerseDumper extends BasicDumper {
-        @Override
-        public void dump(StatsLogReport report) {
-            if (report.hasGaugeMetrics()) {
-                dumpGaugeMetrics(report);
-            }
-            if (report.hasEventMetrics()) {
-                dumpEventMetrics(report);
-            }
-        }
-        void dumpEventMetrics(StatsLogReport report) {
-            final List<StatsLog.EventMetricData> data = report.getEventMetrics().getDataList();
-            if (data.isEmpty()) {
-                return;
-            }
-            long firstTimestampNanos = data.get(0).getElapsedTimestampNanos();
-            for (StatsLog.EventMetricData event : data) {
-                final double deltaSec = (event.getElapsedTimestampNanos() - firstTimestampNanos)
-                        / 1e9;
-                System.out.println(
-                        String.format("+%.3fs: %s", deltaSec, event.getAtom().toString()));
-            }
-        }
-        void dumpGaugeMetrics(StatsLogReport report) {
-            final List<StatsLog.GaugeMetricData> data = report.getGaugeMetrics().getDataList();
-            if (data.isEmpty()) {
-                return;
-            }
-            for (StatsLog.GaugeMetricData gauge : data) {
-                System.out.println(gauge.toString());
-            }
-        }
-    }
-
-    private static String pushConfig(StatsdConfig config, String deviceSerial)
-            throws IOException, InterruptedException {
-        File configFile = File.createTempFile("statsdconfig", ".config");
-        configFile.deleteOnExit();
-        Files.write(config.toByteArray(), configFile);
-        String remotePath = "/data/local/tmp/" + configFile.getName();
-        Utils.runCommand(null, LOGGER, "adb", "-s", deviceSerial,
-                "push", configFile.getAbsolutePath(), remotePath);
-        Utils.runCommand(null, LOGGER, "adb", "-s", deviceSerial,
-                "shell", "cat", remotePath, "|", Utils.CMD_UPDATE_CONFIG,
-                String.valueOf(CONFIG_ID));
-        return remotePath;
-    }
-
-    private static void removeConfig(String deviceSerial) {
-        try {
-            Utils.runCommand(null, LOGGER, "adb", "-s", deviceSerial,
-                    "shell", Utils.CMD_REMOVE_CONFIG, String.valueOf(CONFIG_ID));
-        } catch (Exception e) {
-            LOGGER.severe("Failed to remove config: " + e.getMessage());
-        }
-    }
-}
diff --git a/cmds/statsd/tools/localtools/test/com/android/statsd/shelltools/testdrive/ConfigurationTest.java b/cmds/statsd/tools/localtools/test/com/android/statsd/shelltools/testdrive/ConfigurationTest.java
deleted file mode 100644
index b1cc60f..0000000
--- a/cmds/statsd/tools/localtools/test/com/android/statsd/shelltools/testdrive/ConfigurationTest.java
+++ /dev/null
@@ -1,326 +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 com.android.statsd.shelltools.testdrive;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import com.android.internal.os.StatsdConfigProto;
-import com.android.internal.os.StatsdConfigProto.StatsdConfig;
-import com.android.os.AtomsProto;
-
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Tests for {@link TestDrive}
- */
-public class ConfigurationTest {
-
-    private StatsdConfigProto.AtomMatcher findAndRemoveAtomMatcherById(
-            List<StatsdConfigProto.AtomMatcher> atomMatchers, long id) {
-        int numMatches = 0;
-        StatsdConfigProto.AtomMatcher match = null;
-        for (StatsdConfigProto.AtomMatcher atomMatcher : atomMatchers) {
-            if (id == atomMatcher.getId()) {
-                ++numMatches;
-                match = atomMatcher;
-            }
-        }
-        if (numMatches == 1) {
-            atomMatchers.remove(match);
-            return match;
-        }
-        return null;  // Too many, or not found
-    }
-
-    private final TestDrive.Configuration mConfiguration = new TestDrive.Configuration();
-
-    @Test
-    public void testOnePushed() {
-        final int atom = 90;
-        assertFalse(TestDrive.Configuration.isPulledAtom(atom));
-        mConfiguration.addAtom(atom);
-        StatsdConfig config = mConfiguration.createConfig();
-
-        //event_metric {
-        //  id: 1111
-        //  what: 1234567
-        //}
-        //atom_matcher {
-        //  id: 1234567
-        //  simple_atom_matcher {
-        //    atom_id: 90
-        //  }
-        //}
-
-        assertEquals(1, config.getEventMetricCount());
-        assertEquals(0, config.getGaugeMetricCount());
-
-        assertTrue(mConfiguration.isTrackedMetric(config.getEventMetric(0).getId()));
-
-        final List<StatsdConfigProto.AtomMatcher> atomMatchers =
-                new ArrayList<>(config.getAtomMatcherList());
-        assertEquals(atom,
-                findAndRemoveAtomMatcherById(atomMatchers, config.getEventMetric(0).getWhat())
-                        .getSimpleAtomMatcher().getAtomId());
-        assertEquals(0, atomMatchers.size());
-    }
-
-    @Test
-    public void testOnePulled() {
-        final int atom = 10022;
-        assertTrue(TestDrive.Configuration.isPulledAtom(atom));
-        mConfiguration.addAtom(atom);
-        StatsdConfig config = mConfiguration.createConfig();
-
-        //gauge_metric {
-        //  id: 1111
-        //  what: 1234567
-        //  gauge_fields_filter {
-        //    include_all: true
-        //  }
-        //  bucket: ONE_MINUTE
-        //  sampling_type: FIRST_N_SAMPLES
-        //  max_num_gauge_atoms_per_bucket: 100
-        //  trigger_event: 1111111
-        //}
-        //atom_matcher {
-        //  id: 1111111
-        //  simple_atom_matcher {
-        //    atom_id: 47
-        //  }
-        //}
-        //atom_matcher {
-        //  id: 1234567
-        //  simple_atom_matcher {
-        //    atom_id: 10022
-        //  }
-        //}
-
-        assertEquals(0, config.getEventMetricCount());
-        assertEquals(1, config.getGaugeMetricCount());
-
-        assertTrue(mConfiguration.isTrackedMetric(config.getGaugeMetric(0).getId()));
-
-        final StatsdConfigProto.GaugeMetric gaugeMetric = config.getGaugeMetric(0);
-        assertTrue(gaugeMetric.getGaugeFieldsFilter().getIncludeAll());
-
-        final List<StatsdConfigProto.AtomMatcher> atomMatchers =
-                new ArrayList<>(config.getAtomMatcherList());
-        assertEquals(atom,
-                findAndRemoveAtomMatcherById(atomMatchers, gaugeMetric.getWhat())
-                        .getSimpleAtomMatcher().getAtomId());
-        assertEquals(AtomsProto.Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER,
-                findAndRemoveAtomMatcherById(atomMatchers, gaugeMetric.getTriggerEvent())
-                        .getSimpleAtomMatcher().getAtomId());
-        assertEquals(0, atomMatchers.size());
-    }
-
-    @Test
-    public void testOnePulledTwoPushed() {
-        final int pulledAtom = 10022;
-        assertTrue(TestDrive.Configuration.isPulledAtom(pulledAtom));
-        mConfiguration.addAtom(pulledAtom);
-
-        Integer[] pushedAtoms = new Integer[]{244, 245};
-        for (int atom : pushedAtoms) {
-            assertFalse(TestDrive.Configuration.isPulledAtom(atom));
-            mConfiguration.addAtom(atom);
-        }
-        StatsdConfig config = mConfiguration.createConfig();
-
-        //  event_metric {
-        //    id: 1111
-        //    what: 1234567
-        //  }
-        //  event_metric {
-        //    id: 1112
-        //    what: 1234568
-        //  }
-        //  gauge_metric {
-        //    id: 1114
-        //    what: 1234570
-        //    gauge_fields_filter {
-        //      include_all: true
-        //    }
-        //    bucket: ONE_MINUTE
-        //    sampling_type: FIRST_N_SAMPLES
-        //    max_num_gauge_atoms_per_bucket: 100
-        //    trigger_event: 1111111
-        //  }
-        //  atom_matcher {
-        //    id: 1111111
-        //    simple_atom_matcher {
-        //      atom_id: 47
-        //    }
-        //  }
-        //  atom_matcher {
-        //    id: 1234567
-        //    simple_atom_matcher {
-        //      atom_id: 244
-        //    }
-        //  }
-        //  atom_matcher {
-        //    id: 1234568
-        //    simple_atom_matcher {
-        //      atom_id: 245
-        //    }
-        //  }
-        //  atom_matcher {
-        //    id: 1234570
-        //    simple_atom_matcher {
-        //      atom_id: 10022
-        //    }
-        //  }
-
-        assertEquals(2, config.getEventMetricCount());
-        assertEquals(1, config.getGaugeMetricCount());
-
-        final StatsdConfigProto.GaugeMetric gaugeMetric = config.getGaugeMetric(0);
-        assertTrue(mConfiguration.isTrackedMetric(gaugeMetric.getId()));
-        assertTrue(gaugeMetric.getGaugeFieldsFilter().getIncludeAll());
-        for (StatsdConfigProto.EventMetric eventMetric : config.getEventMetricList()) {
-            assertTrue(mConfiguration.isTrackedMetric(eventMetric.getId()));
-        }
-
-        final List<StatsdConfigProto.AtomMatcher> atomMatchers =
-                new ArrayList<>(config.getAtomMatcherList());
-
-        assertEquals(pulledAtom, findAndRemoveAtomMatcherById(atomMatchers, gaugeMetric.getWhat())
-                .getSimpleAtomMatcher().getAtomId());
-        assertEquals(AtomsProto.Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER,
-                findAndRemoveAtomMatcherById(atomMatchers, gaugeMetric.getTriggerEvent())
-                        .getSimpleAtomMatcher().getAtomId());
-
-        Integer[] actualAtoms = new Integer[]{
-                findAndRemoveAtomMatcherById(atomMatchers, config.getEventMetric(0).getWhat())
-                        .getSimpleAtomMatcher().getAtomId(),
-                findAndRemoveAtomMatcherById(atomMatchers, config.getEventMetric(1).getWhat())
-                        .getSimpleAtomMatcher().getAtomId()};
-        Arrays.sort(actualAtoms);
-        assertArrayEquals(pushedAtoms, actualAtoms);
-
-        assertEquals(0, atomMatchers.size());
-    }
-
-    @Test
-    public void testOnePulledTwoPushedTogether() {
-        mConfiguration.mOnePushedAtomEvent = true;  // Use one event grabbing all pushed atoms
-
-        final int pulledAtom = 10022;
-        assertTrue(TestDrive.Configuration.isPulledAtom(pulledAtom));
-        mConfiguration.addAtom(pulledAtom);
-
-        Integer[] pushedAtoms = new Integer[]{244, 245};
-        for (int atom : pushedAtoms) {
-            assertFalse(TestDrive.Configuration.isPulledAtom(atom));
-            mConfiguration.addAtom(atom);
-        }
-        StatsdConfig config = mConfiguration.createConfig();
-
-        //    event_metric {
-        //      id: 1112
-        //      what: 1234570
-        //    }
-        //    gauge_metric {
-        //      id: 1111
-        //      what: 1234567
-        //      gauge_fields_filter {
-        //        include_all: true
-        //      }
-        //      bucket: ONE_MINUTE
-        //      sampling_type: FIRST_N_SAMPLES
-        //      max_num_gauge_atoms_per_bucket: 100
-        //      trigger_event: 1111111
-        //    }
-        //    atom_matcher {
-        //      id: 1111111
-        //      simple_atom_matcher {
-        //        atom_id: 47
-        //      }
-        //    }
-        //    atom_matcher {
-        //      id: 1234567
-        //      simple_atom_matcher {
-        //        atom_id: 10022
-        //      }
-        //    }
-        //    atom_matcher {
-        //      id: 1234568
-        //      simple_atom_matcher {
-        //        atom_id: 244
-        //      }
-        //    }
-        //    atom_matcher {
-        //      id: 1234569
-        //      simple_atom_matcher {
-        //        atom_id: 245
-        //      }
-        //    }
-        //    atom_matcher {
-        //      id: 1234570
-        //      combination {
-        //        operation: OR
-        //        matcher: 1234568
-        //        matcher: 1234569
-        //      }
-        //    }
-
-        assertEquals(1, config.getEventMetricCount());
-        assertEquals(1, config.getGaugeMetricCount());
-
-        final StatsdConfigProto.GaugeMetric gaugeMetric = config.getGaugeMetric(0);
-        assertTrue(mConfiguration.isTrackedMetric(gaugeMetric.getId()));
-        assertTrue(gaugeMetric.getGaugeFieldsFilter().getIncludeAll());
-
-        StatsdConfigProto.EventMetric eventMetric = config.getEventMetric(0);
-        assertTrue(mConfiguration.isTrackedMetric(eventMetric.getId()));
-
-        final List<StatsdConfigProto.AtomMatcher> atomMatchers =
-                new ArrayList<>(config.getAtomMatcherList());
-
-        assertEquals(pulledAtom, findAndRemoveAtomMatcherById(atomMatchers, gaugeMetric.getWhat())
-                .getSimpleAtomMatcher().getAtomId());
-        assertEquals(AtomsProto.Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER,
-                findAndRemoveAtomMatcherById(atomMatchers, gaugeMetric.getTriggerEvent())
-                        .getSimpleAtomMatcher().getAtomId());
-
-        StatsdConfigProto.AtomMatcher unionMatcher = findAndRemoveAtomMatcherById(atomMatchers,
-                eventMetric.getWhat());
-        assertNotNull(unionMatcher.getCombination());
-        assertEquals(2, unionMatcher.getCombination().getMatcherCount());
-
-        Integer[] actualAtoms = new Integer[]{
-              findAndRemoveAtomMatcherById(atomMatchers,
-                      unionMatcher.getCombination().getMatcher(0))
-                      .getSimpleAtomMatcher().getAtomId(),
-                findAndRemoveAtomMatcherById(atomMatchers,
-                        unionMatcher.getCombination().getMatcher(1))
-                        .getSimpleAtomMatcher().getAtomId()};
-        Arrays.sort(actualAtoms);
-        assertArrayEquals(pushedAtoms, actualAtoms);
-
-        assertEquals(0, atomMatchers.size());
-    }
-}
diff --git a/cmds/statsd/tools/localtools/test/com/android/statsd/shelltools/testdrive/TestDriveTest.java b/cmds/statsd/tools/localtools/test/com/android/statsd/shelltools/testdrive/TestDriveTest.java
deleted file mode 100644
index 363fac0..0000000
--- a/cmds/statsd/tools/localtools/test/com/android/statsd/shelltools/testdrive/TestDriveTest.java
+++ /dev/null
@@ -1,195 +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 com.android.statsd.shelltools.testdrive;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Tests for {@link TestDrive}
- */
-@RunWith(Parameterized.class)
-public class TestDriveTest {
-    /**
-     * Expected results of a single iteration of the paramerized test.
-     */
-    static class Expect {
-        public boolean success;
-        public Integer[] atoms;
-        public boolean onePushedAtomEvent = false;
-        public String extraPackage = null;
-        public String target;
-        public boolean terse = false;
-
-        static Expect success(Integer... atoms) {
-            return new Expect(true, atoms,
-                    TARGET);
-        }
-        Expect(boolean success, Integer[] atoms, String target) {
-            this.success = success;
-            this.atoms = atoms;
-            this.target = target;
-        }
-        static final Expect FAILURE = new Expect(false, null, null);
-        Expect onePushedAtomEvent() {
-            this.onePushedAtomEvent = true;
-            return this;
-        }
-        Expect extraPackage() {
-            this.extraPackage = TestDriveTest.PACKAGE;
-            return this;
-        }
-        Expect terse() {
-            this.terse = true;
-            return this;
-        }
-    }
-
-    @Parameterized.Parameter(0)
-    public String[] mArgs;
-
-    @Parameterized.Parameter(1)
-    public List<String> mConnectedDevices;
-
-    @Parameterized.Parameter(2)
-    public String mDefaultDevice;
-
-    @Parameterized.Parameter(3)
-    public Expect mExpect;
-
-    private static final String TARGET = "target";
-    private static final List<String> TARGET_AND_OTHER = Arrays.asList("otherDevice",
-            TARGET);
-    private static final List<String> TWO_OTHER_DEVICES = Arrays.asList(
-            "other1", "other2");
-    private static final List<String> TARGET_ONLY = Collections.singletonList(TARGET);
-    private static final List<String> NOT_TARGET = Collections.singletonList("other");
-    private static final List<String> NO_DEVICES = Collections.emptyList();
-    private static final String PACKAGE = "extraPackage";
-
-    @Parameterized.Parameters
-    public static Collection<Object[]> data() {
-        return Arrays.asList(
-                new Object[]{new String[]{}, null, null,
-                        Expect.FAILURE},  // Usage explanation
-                new Object[]{new String[]{"244", "245"}, null, null,
-                        Expect.FAILURE},  // Failure looking up connected devices
-                new Object[]{new String[]{"244", "245"}, NO_DEVICES, null,
-                        Expect.FAILURE},  // No connected devices
-                new Object[]{new String[]{"-s", TARGET, "244", "245"}, NOT_TARGET, null,
-                        Expect.FAILURE},  // Wrong device connected
-                new Object[]{new String[]{"244", "245"}, TWO_OTHER_DEVICES, null,
-                        Expect.FAILURE},  // Wrong devices connected
-                new Object[]{new String[]{"244", "245"}, TARGET_ONLY, null,
-                        Expect.success(244, 245)},  // If only one device connected, guess that one
-                new Object[]{new String[]{"244", "not_an_atom"}, TARGET_ONLY, null,
-                        Expect.success(244)},  // Ignore non-atoms
-                new Object[]{new String[]{"not_an_atom"}, TARGET_ONLY, null,
-                        Expect.FAILURE},  // Require at least one atom
-                new Object[]{new String[]{"244", "245"}, TWO_OTHER_DEVICES, TARGET,
-                        Expect.FAILURE},  // ANDROID_SERIAL specifies non-connected target
-                new Object[]{new String[]{"244", "245"}, TARGET_AND_OTHER, TARGET,
-                        Expect.success(244, 245)},  // ANDROID_SERIAL specifies a valid target
-                new Object[]{new String[]{"244", "245"}, TARGET_AND_OTHER, null,
-                        Expect.FAILURE},  // Two connected devices, no indication of which to use
-                new Object[]{new String[]{"-one", "244", "245"}, TARGET_ONLY, null,
-                        Expect.success(244, 245).onePushedAtomEvent()},
-                new Object[]{new String[]{"-terse", "-one", "244", "245"}, TARGET_ONLY, null,
-                        Expect.success(244, 245).onePushedAtomEvent().terse()},
-                new Object[]{new String[]{"-one", "-terse", "244", "245"}, TARGET_ONLY, null,
-                        Expect.success(244, 245).onePushedAtomEvent().terse()},
-                new Object[]{new String[]{"-p", PACKAGE, "244", "245"}, TARGET_ONLY, null,
-                        Expect.success(244, 245).extraPackage()},
-                new Object[]{new String[]{"-p", PACKAGE, "-one", "244", "245"}, TARGET_ONLY, null,
-                        Expect.success(244, 245).extraPackage().onePushedAtomEvent()},
-                new Object[]{new String[]{"-one", "-p", PACKAGE, "244", "245"}, TARGET_ONLY, null,
-                        Expect.success(244, 245).extraPackage().onePushedAtomEvent()},
-                new Object[]{new String[]{"-s", TARGET, "-one", "-p", PACKAGE, "244", "245"},
-                        TARGET_AND_OTHER, null,
-                        Expect.success(244, 245).extraPackage().onePushedAtomEvent()},
-                new Object[]{new String[]{"-one", "-s", TARGET, "-p", PACKAGE, "244", "245"},
-                        TARGET_AND_OTHER, null,
-                        Expect.success(244, 245).extraPackage().onePushedAtomEvent()},
-                new Object[]{new String[]{"-one", "-p", PACKAGE, "-s", TARGET, "244", "245"},
-                        TARGET_AND_OTHER, null,
-                        Expect.success(244, 245).extraPackage().onePushedAtomEvent()},
-                new Object[]{new String[]{"-terse", "-one", "-p", PACKAGE, "-s", TARGET,
-                        "244", "245"},
-                        TARGET_AND_OTHER, null,
-                        Expect.success(244, 245).extraPackage().onePushedAtomEvent().terse()},
-                new Object[]{new String[]{"-one", "-terse", "-p", PACKAGE, "-s", TARGET,
-                        "244", "245"},
-                        TARGET_AND_OTHER, null,
-                        Expect.success(244, 245).extraPackage().onePushedAtomEvent().terse()},
-                new Object[]{new String[]{"-one", "-p", PACKAGE, "-terse", "-s", TARGET,
-                        "244", "245"},
-                        TARGET_AND_OTHER, null,
-                        Expect.success(244, 245).extraPackage().onePushedAtomEvent().terse()},
-                new Object[]{new String[]{"-one", "-p", PACKAGE, "-s", TARGET, "-terse",
-                        "244", "245"},
-                        TARGET_AND_OTHER, null,
-                        Expect.success(244, 245).extraPackage().onePushedAtomEvent().terse()}
-        );
-    }
-
-    private final TestDrive.Configuration mConfiguration = new TestDrive.Configuration();
-    private final TestDrive mTestDrive = new TestDrive();
-
-    private static Integer[] collectAtoms(TestDrive.Configuration configuration) {
-        Integer[] result = new Integer[configuration.mPulledAtoms.size()
-                + configuration.mPushedAtoms.size()];
-        int result_index = 0;
-        for (Integer atom : configuration.mPushedAtoms) {
-            result[result_index++] = atom;
-        }
-        for (Integer atom : configuration.mPulledAtoms) {
-            result[result_index++] = atom;
-        }
-        Arrays.sort(result);
-        return result;
-    }
-
-    @Test
-    public void testProcessArgs() {
-        boolean result = mTestDrive.processArgs(mConfiguration, mArgs, mConnectedDevices,
-                mDefaultDevice);
-        if (mExpect.success) {
-            assertTrue(result);
-            assertArrayEquals(mExpect.atoms, collectAtoms(mConfiguration));
-            assertEquals(mExpect.onePushedAtomEvent, mConfiguration.mOnePushedAtomEvent);
-            assertEquals(mExpect.target, mTestDrive.mDeviceSerial);
-            if (mExpect.terse) {
-                assertEquals(TestDrive.TerseDumper.class, mTestDrive.mDumper.getClass());
-            } else {
-                assertEquals(TestDrive.BasicDumper.class, mTestDrive.mDumper.getClass());
-            }
-        } else {
-            assertFalse(result);
-        }
-    }
-}
diff --git a/cmds/statsd/tools/localtools/testdrive_manifest.txt b/cmds/statsd/tools/localtools/testdrive_manifest.txt
deleted file mode 100644
index 625ebfa..0000000
--- a/cmds/statsd/tools/localtools/testdrive_manifest.txt
+++ /dev/null
@@ -1 +0,0 @@
-Main-class: com.android.statsd.shelltools.testdrive.TestDrive
diff --git a/cmds/telecom/OWNERS b/cmds/telecom/OWNERS
new file mode 100644
index 0000000..2f813e6
--- /dev/null
+++ b/cmds/telecom/OWNERS
@@ -0,0 +1 @@
+include /telecomm/OWNERS
diff --git a/cmds/uinput/OWNERS b/cmds/uinput/OWNERS
new file mode 100644
index 0000000..d701f23
--- /dev/null
+++ b/cmds/uinput/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/hardware/input/OWNERS
diff --git a/cmds/wm/OWNERS b/cmds/wm/OWNERS
new file mode 100644
index 0000000..0862c05
--- /dev/null
+++ b/cmds/wm/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/config/OWNERS b/config/OWNERS
index 3d4924d..d59c6f2 100644
--- a/config/OWNERS
+++ b/config/OWNERS
@@ -1,4 +1,7 @@
+include /ZYGOTE_OWNERS
+
 # compat-team@ for changes to hiddenapi files
+
 per-file hiddenapi-* = andreionea@google.com, mathewi@google.com, satayev@google.com
 
 # Escalations:
diff --git a/core/api/OWNERS b/core/api/OWNERS
new file mode 100644
index 0000000..0b95c51
--- /dev/null
+++ b/core/api/OWNERS
@@ -0,0 +1,2 @@
+# API changes are managed via Prolog rules, not OWNERS
+*
diff --git a/core/api/current.txt b/core/api/current.txt
index ed92c29..8a6430f 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -2883,6 +2883,7 @@
     method protected void onServiceConnected();
     method public void onSystemActionsChanged();
     method public final boolean performGlobalAction(int);
+    method public void setAccessibilityFocusAppearance(int, @ColorInt int);
     method public void setGestureDetectionPassthroughRegion(int, @NonNull android.graphics.Region);
     method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
     method public void setTouchExplorationPassthroughRegion(int, @NonNull android.graphics.Region);
@@ -7150,6 +7151,7 @@
     field @RequiresPermission(android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY) public static final String EXTRA_PASSWORD_COMPLEXITY = "android.app.extra.PASSWORD_COMPLEXITY";
     field public static final String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE";
     field public static final String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE";
+    field public static final String EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES = "android.app.extra.PROVISIONING_ALLOWED_PROVISIONING_MODES";
     field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME";
     field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE = "android.app.extra.PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE";
     field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
@@ -7254,6 +7256,7 @@
     field public static final int PRIVATE_DNS_SET_NO_ERROR = 0; // 0x0
     field public static final int PROVISIONING_MODE_FULLY_MANAGED_DEVICE = 1; // 0x1
     field public static final int PROVISIONING_MODE_MANAGED_PROFILE = 2; // 0x2
+    field public static final int PROVISIONING_MODE_MANAGED_PROFILE_ON_PERSONAL_DEVICE = 3; // 0x3
     field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2
     field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
     field public static final int SKIP_SETUP_WIZARD = 1; // 0x1
@@ -7686,6 +7689,7 @@
     method public long getTriggerContentMaxDelay();
     method public long getTriggerContentUpdateDelay();
     method @Nullable public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
+    method public boolean isForegroundJob();
     method public boolean isImportantWhileForeground();
     method public boolean isPeriodic();
     method public boolean isPersisted();
@@ -7717,7 +7721,8 @@
     method public android.app.job.JobInfo.Builder setClipData(@Nullable android.content.ClipData, int);
     method public android.app.job.JobInfo.Builder setEstimatedNetworkBytes(long, long);
     method public android.app.job.JobInfo.Builder setExtras(@NonNull android.os.PersistableBundle);
-    method public android.app.job.JobInfo.Builder setImportantWhileForeground(boolean);
+    method @NonNull public android.app.job.JobInfo.Builder setForeground(boolean);
+    method @Deprecated public android.app.job.JobInfo.Builder setImportantWhileForeground(boolean);
     method public android.app.job.JobInfo.Builder setMinimumLatency(long);
     method public android.app.job.JobInfo.Builder setOverrideDeadline(long);
     method public android.app.job.JobInfo.Builder setPeriodic(long);
@@ -7757,6 +7762,7 @@
     method @NonNull public android.os.Bundle getTransientExtras();
     method @Nullable public String[] getTriggeredContentAuthorities();
     method @Nullable public android.net.Uri[] getTriggeredContentUris();
+    method public boolean isForegroundJob();
     method public boolean isOverrideDeadlineExpired();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.job.JobParameters> CREATOR;
@@ -34856,6 +34862,27 @@
     method public void onCancel();
   }
 
+  public abstract class CombinedVibrationEffect implements android.os.Parcelable {
+    method @NonNull public static android.os.CombinedVibrationEffect createSynced(@NonNull android.os.VibrationEffect);
+    method public int describeContents();
+    method @NonNull public static android.os.CombinedVibrationEffect.SequentialCombination startSequential();
+    method @NonNull public static android.os.CombinedVibrationEffect.SyncedCombination startSynced();
+    field @NonNull public static final android.os.Parcelable.Creator<android.os.CombinedVibrationEffect> CREATOR;
+  }
+
+  public static final class CombinedVibrationEffect.SequentialCombination {
+    method @NonNull public android.os.CombinedVibrationEffect.SequentialCombination addNext(int, @NonNull android.os.VibrationEffect);
+    method @NonNull public android.os.CombinedVibrationEffect.SequentialCombination addNext(int, @NonNull android.os.VibrationEffect, int);
+    method @NonNull public android.os.CombinedVibrationEffect.SequentialCombination addNext(@NonNull android.os.CombinedVibrationEffect);
+    method @NonNull public android.os.CombinedVibrationEffect.SequentialCombination addNext(@NonNull android.os.CombinedVibrationEffect, int);
+    method @NonNull public android.os.CombinedVibrationEffect combine();
+  }
+
+  public static final class CombinedVibrationEffect.SyncedCombination {
+    method @NonNull public android.os.CombinedVibrationEffect.SyncedCombination addVibrator(int, @NonNull android.os.VibrationEffect);
+    method @NonNull public android.os.CombinedVibrationEffect combine();
+  }
+
   public class ConditionVariable {
     ctor public ConditionVariable();
     ctor public ConditionVariable(boolean);
@@ -36082,6 +36109,13 @@
     field public static final int VIBRATION_EFFECT_SUPPORT_YES = 1; // 0x1
   }
 
+  public abstract class VibratorManager {
+    method @NonNull public abstract android.os.Vibrator getDefaultVibrator();
+    method @NonNull public abstract android.os.Vibrator getVibrator(int);
+    method @NonNull public abstract int[] getVibratorIds();
+    method public abstract void vibrate(@NonNull android.os.CombinedVibrationEffect);
+  }
+
   public class WorkSource implements android.os.Parcelable {
     ctor public WorkSource();
     ctor public WorkSource(android.os.WorkSource);
@@ -38699,6 +38733,25 @@
     field public static final String UNGROUPED_WITH_PHONES = "summ_phones";
   }
 
+  public static final class ContactsContract.SimAccount implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public String getAccountName();
+    method @NonNull public String getAccountType();
+    method public int getEfType();
+    method public int getSimSlotIndex();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int ADN_EF_TYPE = 1; // 0x1
+    field @NonNull public static final android.os.Parcelable.Creator<android.provider.ContactsContract.SimAccount> CREATOR;
+    field public static final int FDN_EF_TYPE = 3; // 0x3
+    field public static final int SDN_EF_TYPE = 2; // 0x2
+    field public static final int UNKNOWN_EF_TYPE = 0; // 0x0
+  }
+
+  public static final class ContactsContract.SimContacts {
+    method @NonNull public static java.util.List<android.provider.ContactsContract.SimAccount> getSimAccounts(@NonNull android.content.ContentResolver);
+    field public static final String ACTION_SIM_ACCOUNTS_CHANGED = "android.provider.action.SIM_ACCOUNTS_CHANGED";
+  }
+
   protected static interface ContactsContract.StatusColumns {
     field public static final int AVAILABLE = 5; // 0x5
     field public static final int AWAY = 2; // 0x2
@@ -42438,6 +42491,7 @@
     method public CharSequence getImportanceExplanation();
     method public String getKey();
     method public long getLastAudiblyAlertedMillis();
+    method public int getLockscreenVisibilityOverride();
     method public String getOverrideGroupKey();
     method public int getRank();
     method @NonNull public java.util.List<android.app.Notification.Action> getSmartActions();
@@ -42451,6 +42505,7 @@
     field public static final int USER_SENTIMENT_NEGATIVE = -1; // 0xffffffff
     field public static final int USER_SENTIMENT_NEUTRAL = 0; // 0x0
     field public static final int USER_SENTIMENT_POSITIVE = 1; // 0x1
+    field public static final int VISIBILITY_NO_OVERRIDE = -1000; // 0xfffffc18
   }
 
   public static class NotificationListenerService.RankingMap implements android.os.Parcelable {
@@ -44838,14 +44893,19 @@
     field public static final String EXTRA_DEFAULT_CALL_SCREENING_APP_COMPONENT_NAME = "android.telecom.extra.DEFAULT_CALL_SCREENING_APP_COMPONENT_NAME";
     field public static final String EXTRA_DISCONNECT_CAUSE = "android.telecom.extra.DISCONNECT_CAUSE";
     field public static final String EXTRA_HANDLE = "android.telecom.extra.HANDLE";
+    field public static final String EXTRA_HAS_PICTURE = "android.telecom.extra.HAS_PICTURE";
     field public static final String EXTRA_INCOMING_CALL_ADDRESS = "android.telecom.extra.INCOMING_CALL_ADDRESS";
     field public static final String EXTRA_INCOMING_CALL_EXTRAS = "android.telecom.extra.INCOMING_CALL_EXTRAS";
+    field public static final String EXTRA_INCOMING_PICTURE = "android.telecom.extra.INCOMING_PICTURE";
     field public static final String EXTRA_INCOMING_VIDEO_STATE = "android.telecom.extra.INCOMING_VIDEO_STATE";
     field public static final String EXTRA_IS_DEFAULT_CALL_SCREENING_APP = "android.telecom.extra.IS_DEFAULT_CALL_SCREENING_APP";
+    field public static final String EXTRA_LOCATION = "android.telecom.extra.LOCATION";
     field public static final String EXTRA_NOTIFICATION_COUNT = "android.telecom.extra.NOTIFICATION_COUNT";
     field public static final String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
     field public static final String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
+    field public static final String EXTRA_OUTGOING_PICTURE = "android.telecom.extra.OUTGOING_PICTURE";
     field public static final String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
+    field public static final String EXTRA_PRIORITY = "android.telecom.extra.PRIORITY";
     field public static final String EXTRA_START_CALL_WITH_RTT = "android.telecom.extra.START_CALL_WITH_RTT";
     field public static final String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
     field public static final String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
@@ -44861,6 +44921,8 @@
     field public static final int PRESENTATION_PAYPHONE = 4; // 0x4
     field public static final int PRESENTATION_RESTRICTED = 2; // 0x2
     field public static final int PRESENTATION_UNKNOWN = 3; // 0x3
+    field public static final int PRIORITY_NORMAL = 0; // 0x0
+    field public static final int PRIORITY_URGENT = 1; // 0x1
   }
 
   public class VideoProfile implements android.os.Parcelable {
@@ -46250,6 +46312,12 @@
     field public static final int SCAN_TYPE_PERIODIC = 1; // 0x1
   }
 
+  public final class PhoneCapability implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PhoneCapability> CREATOR;
+  }
+
   public class PhoneNumberFormattingTextWatcher implements android.text.TextWatcher {
     ctor public PhoneNumberFormattingTextWatcher();
     ctor public PhoneNumberFormattingTextWatcher(String);
@@ -46318,10 +46386,10 @@
 
   public class PhoneStateListener {
     ctor public PhoneStateListener();
-    ctor public PhoneStateListener(@NonNull java.util.concurrent.Executor);
+    ctor @Deprecated public PhoneStateListener(@NonNull java.util.concurrent.Executor);
     method public void onActiveDataSubscriptionIdChanged(int);
     method public void onBarringInfoChanged(@NonNull android.telephony.BarringInfo);
-    method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onCallDisconnectCauseChanged(int, int);
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallDisconnectCauseChanged(int, int);
     method public void onCallForwardingIndicatorChanged(boolean);
     method public void onCallStateChanged(int, String);
     method public void onCellInfoChanged(java.util.List<android.telephony.CellInfo>);
@@ -46329,36 +46397,140 @@
     method public void onDataActivity(int);
     method public void onDataConnectionStateChanged(int);
     method public void onDataConnectionStateChanged(int, int);
-    method @RequiresPermission("android.permission.READ_PHONE_STATE") public void onDisplayInfoChanged(@NonNull android.telephony.TelephonyDisplayInfo);
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onDisplayInfoChanged(@NonNull android.telephony.TelephonyDisplayInfo);
     method public void onEmergencyNumberListChanged(@NonNull java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>>);
-    method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo);
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo);
     method public void onMessageWaitingIndicatorChanged(boolean);
-    method @RequiresPermission("android.permission.MODIFY_PHONE_STATE") public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState);
     method public void onRegistrationFailed(@NonNull android.telephony.CellIdentity, @NonNull String, int, int, int);
     method public void onServiceStateChanged(android.telephony.ServiceState);
     method @Deprecated public void onSignalStrengthChanged(int);
     method public void onSignalStrengthsChanged(android.telephony.SignalStrength);
     method public void onUserMobileDataStateChanged(boolean);
-    field public static final int LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE = 4194304; // 0x400000
-    field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_BARRING_INFO = -2147483648; // 0x80000000
-    field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_CALL_DISCONNECT_CAUSES = 33554432; // 0x2000000
-    field public static final int LISTEN_CALL_FORWARDING_INDICATOR = 8; // 0x8
-    field public static final int LISTEN_CALL_STATE = 32; // 0x20
-    field public static final int LISTEN_CELL_INFO = 1024; // 0x400
-    field public static final int LISTEN_CELL_LOCATION = 16; // 0x10
-    field public static final int LISTEN_DATA_ACTIVITY = 128; // 0x80
-    field public static final int LISTEN_DATA_CONNECTION_STATE = 64; // 0x40
-    field public static final int LISTEN_DISPLAY_INFO_CHANGED = 1048576; // 0x100000
-    field public static final int LISTEN_EMERGENCY_NUMBER_LIST = 16777216; // 0x1000000
-    field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_IMS_CALL_DISCONNECT_CAUSES = 134217728; // 0x8000000
-    field public static final int LISTEN_MESSAGE_WAITING_INDICATOR = 4; // 0x4
+    field @Deprecated public static final int LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE = 4194304; // 0x400000
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_BARRING_INFO = -2147483648; // 0x80000000
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_CALL_DISCONNECT_CAUSES = 33554432; // 0x2000000
+    field @Deprecated public static final int LISTEN_CALL_FORWARDING_INDICATOR = 8; // 0x8
+    field @Deprecated public static final int LISTEN_CALL_STATE = 32; // 0x20
+    field @Deprecated public static final int LISTEN_CELL_INFO = 1024; // 0x400
+    field @Deprecated public static final int LISTEN_CELL_LOCATION = 16; // 0x10
+    field @Deprecated public static final int LISTEN_DATA_ACTIVITY = 128; // 0x80
+    field @Deprecated public static final int LISTEN_DATA_CONNECTION_STATE = 64; // 0x40
+    field @Deprecated public static final int LISTEN_DISPLAY_INFO_CHANGED = 1048576; // 0x100000
+    field @Deprecated public static final int LISTEN_EMERGENCY_NUMBER_LIST = 16777216; // 0x1000000
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_IMS_CALL_DISCONNECT_CAUSES = 134217728; // 0x8000000
+    field @Deprecated public static final int LISTEN_MESSAGE_WAITING_INDICATOR = 4; // 0x4
     field public static final int LISTEN_NONE = 0; // 0x0
-    field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 4096; // 0x1000
-    field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_REGISTRATION_FAILURE = 1073741824; // 0x40000000
-    field public static final int LISTEN_SERVICE_STATE = 1; // 0x1
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 4096; // 0x1000
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_REGISTRATION_FAILURE = 1073741824; // 0x40000000
+    field @Deprecated public static final int LISTEN_SERVICE_STATE = 1; // 0x1
     field @Deprecated public static final int LISTEN_SIGNAL_STRENGTH = 2; // 0x2
-    field public static final int LISTEN_SIGNAL_STRENGTHS = 256; // 0x100
-    field public static final int LISTEN_USER_MOBILE_DATA_STATE = 524288; // 0x80000
+    field @Deprecated public static final int LISTEN_SIGNAL_STRENGTHS = 256; // 0x100
+    field @Deprecated public static final int LISTEN_USER_MOBILE_DATA_STATE = 524288; // 0x80000
+  }
+
+  public static interface PhoneStateListener.ActiveDataSubscriptionIdChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onActiveDataSubscriptionIdChanged(int);
+  }
+
+  public static interface PhoneStateListener.AlwaysReportedSignalStrengthChangedListener {
+    method @RequiresPermission("android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH") public void onSignalStrengthsChanged(@NonNull android.telephony.SignalStrength);
+  }
+
+  public static interface PhoneStateListener.BarringInfoChangedListener {
+    method @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void onBarringInfoChanged(@NonNull android.telephony.BarringInfo);
+  }
+
+  public static interface PhoneStateListener.CallDisconnectCauseChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallDisconnectCauseChanged(int, int);
+  }
+
+  public static interface PhoneStateListener.CallForwardingIndicatorChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onCallForwardingIndicatorChanged(boolean);
+  }
+
+  public static interface PhoneStateListener.CallStateChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_CALL_LOG) public void onCallStateChanged(int, @Nullable String);
+  }
+
+  public static interface PhoneStateListener.CarrierNetworkChangeListener {
+    method public void onCarrierNetworkChange(boolean);
+  }
+
+  public static interface PhoneStateListener.CellInfoChangedListener {
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void onCellInfoChanged(@NonNull java.util.List<android.telephony.CellInfo>);
+  }
+
+  public static interface PhoneStateListener.CellLocationChangedListener {
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void onCellLocationChanged(@NonNull android.telephony.CellLocation);
+  }
+
+  public static interface PhoneStateListener.DataActivationStateChangedListener {
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onDataActivationStateChanged(int);
+  }
+
+  public static interface PhoneStateListener.DataActivityListener {
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onDataActivity(int);
+  }
+
+  public static interface PhoneStateListener.DataConnectionStateChangedListener {
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onDataConnectionStateChanged(int, int);
+  }
+
+  public static interface PhoneStateListener.DisplayInfoChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onDisplayInfoChanged(@NonNull android.telephony.TelephonyDisplayInfo);
+  }
+
+  public static interface PhoneStateListener.EmergencyNumberListChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onEmergencyNumberListChanged(@NonNull java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>>);
+  }
+
+  public static interface PhoneStateListener.ImsCallDisconnectCauseChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo);
+  }
+
+  public static interface PhoneStateListener.MessageWaitingIndicatorChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void onMessageWaitingIndicatorChanged(boolean);
+  }
+
+  public static interface PhoneStateListener.PhoneCapabilityChangedListener {
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onPhoneCapabilityChanged(@NonNull android.telephony.PhoneCapability);
+  }
+
+  public static interface PhoneStateListener.PreciseDataConnectionStateChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState);
+  }
+
+  public static interface PhoneStateListener.RegistrationFailedListener {
+    method @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void onRegistrationFailed(@NonNull android.telephony.CellIdentity, @NonNull String, int, int, int);
+  }
+
+  public static interface PhoneStateListener.ServiceStateChangedListener {
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onServiceStateChanged(@NonNull android.telephony.ServiceState);
+  }
+
+  public static interface PhoneStateListener.SignalStrengthsChangedListener {
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onSignalStrengthsChanged(@NonNull android.telephony.SignalStrength);
+  }
+
+  public static interface PhoneStateListener.UserMobileDataStateChangedListener {
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onUserMobileDataStateChanged(boolean);
+  }
+
+  public final class PhysicalChannelConfig implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getCellBandwidthDownlink();
+    method public int getChannelNumber();
+    method public int getConnectionStatus();
+    method public int getNetworkType();
+    method @IntRange(from=0, to=1007) public int getPhysicalCellId();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int CHANNEL_NUMBER_UNKNOWN = -1; // 0xffffffff
+    field public static final int CONNECTION_PRIMARY_SERVING = 1; // 0x1
+    field public static final int CONNECTION_SECONDARY_SERVING = 2; // 0x2
+    field public static final int CONNECTION_UNKNOWN = -1; // 0xffffffff
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PhysicalChannelConfig> CREATOR;
+    field public static final int PHYSICAL_CELL_ID_UNKNOWN = -1; // 0xffffffff
   }
 
   public final class PreciseDataConnectionState implements android.os.Parcelable {
@@ -46870,7 +47042,8 @@
     method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle);
     method public boolean isWorldPhone();
     method @Deprecated public void listen(android.telephony.PhoneStateListener, int);
-    method public void listen(long, @NonNull android.telephony.PhoneStateListener);
+    method @Deprecated public void listen(long, @NonNull android.telephony.PhoneStateListener);
+    method public void registerPhoneStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.PhoneStateListener);
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void requestCellInfoUpdate(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
     method @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, java.util.concurrent.Executor, android.telephony.TelephonyScanManager.NetworkScanCallback);
     method public void sendDialerSpecialCode(String);
@@ -46892,6 +47065,7 @@
     method @Deprecated public void setVoicemailRingtoneUri(android.telecom.PhoneAccountHandle, android.net.Uri);
     method @Deprecated public void setVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle, boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void switchMultiSimConfig(int);
+    method public void unregisterPhoneStateListener(@NonNull android.telephony.PhoneStateListener);
     method public void updateAvailableNetworks(@NonNull java.util.List<android.telephony.AvailableNetworkInfo>, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
     field public static final String ACTION_CARRIER_MESSAGING_CLIENT_SERVICE = "android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE";
     field public static final String ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE = "android.telephony.action.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE";
@@ -47638,6 +47812,7 @@
     field public static final int CODE_WIFI_LOST = 1407; // 0x57f
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsReasonInfo> CREATOR;
     field public static final int EXTRA_CODE_CALL_RETRY_BY_SETTINGS = 3; // 0x3
+    field public static final int EXTRA_CODE_CALL_RETRY_EMERGENCY = 4; // 0x4
     field public static final int EXTRA_CODE_CALL_RETRY_NORMAL = 1; // 0x1
     field public static final int EXTRA_CODE_CALL_RETRY_SILENT_REDIAL = 2; // 0x2
   }
@@ -50871,7 +51046,7 @@
     method public int getFlags();
     method @Nullable public android.net.Uri getLinkUri();
     method public int getSource();
-    method @NonNull public java.util.Map<java.lang.Boolean,android.view.ContentInfo> partition(@NonNull java.util.function.Predicate<android.content.ClipData.Item>);
+    method @NonNull public android.util.Pair<android.view.ContentInfo,android.view.ContentInfo> partition(@NonNull java.util.function.Predicate<android.content.ClipData.Item>);
     field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
     field public static final int SOURCE_APP = 0; // 0x0
     field public static final int SOURCE_AUTOFILL = 4; // 0x4
@@ -51190,6 +51365,7 @@
     method public int getSources();
     method public int getVendorId();
     method public android.os.Vibrator getVibrator();
+    method @NonNull public android.os.VibratorManager getVibratorManager();
     method public boolean[] hasKeys(int...);
     method public boolean hasMicrophone();
     method public boolean isEnabled();
@@ -54589,6 +54765,8 @@
     method public void addAccessibilityStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener, @Nullable android.os.Handler);
     method public boolean addTouchExplorationStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener);
     method public void addTouchExplorationStateChangeListener(@NonNull android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener, @Nullable android.os.Handler);
+    method @ColorInt public int getAccessibilityFocusColor();
+    method public int getAccessibilityFocusStrokeWidth();
     method @Deprecated public java.util.List<android.content.pm.ServiceInfo> getAccessibilityServiceList();
     method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int);
     method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList();
@@ -56542,6 +56720,7 @@
     method @Nullable public String getId();
     method public int getSelectionEndIndex();
     method public int getSelectionStartIndex();
+    method @Nullable public android.view.textclassifier.TextClassification getTextClassification();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.view.textclassifier.TextSelection> CREATOR;
   }
@@ -56552,6 +56731,7 @@
     method @NonNull public android.view.textclassifier.TextSelection.Builder setEntityType(@NonNull String, @FloatRange(from=0.0, to=1.0) float);
     method @NonNull public android.view.textclassifier.TextSelection.Builder setExtras(@Nullable android.os.Bundle);
     method @NonNull public android.view.textclassifier.TextSelection.Builder setId(@Nullable String);
+    method @NonNull public android.view.textclassifier.TextSelection.Builder setTextClassification(@Nullable android.view.textclassifier.TextClassification);
   }
 
   public static final class TextSelection.Request implements android.os.Parcelable {
@@ -56562,6 +56742,7 @@
     method @NonNull public android.os.Bundle getExtras();
     method @IntRange(from=0) public int getStartIndex();
     method @NonNull public CharSequence getText();
+    method public boolean shouldIncludeTextClassification();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.view.textclassifier.TextSelection.Request> CREATOR;
   }
@@ -56571,6 +56752,7 @@
     method @NonNull public android.view.textclassifier.TextSelection.Request build();
     method @NonNull public android.view.textclassifier.TextSelection.Request.Builder setDefaultLocales(@Nullable android.os.LocaleList);
     method @NonNull public android.view.textclassifier.TextSelection.Request.Builder setExtras(@Nullable android.os.Bundle);
+    method @NonNull public android.view.textclassifier.TextSelection.Request.Builder setIncludeTextClassification(boolean);
   }
 
 }
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 8eb1b5f..66d29d3 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -607,7 +607,10 @@
     method @RequiresPermission(android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND) public void setBackgroundActivityStartsAllowed(boolean);
     method public void setDontSendToRestrictedApps(boolean);
     method @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppWhitelistDuration(long);
+    method @RequiresPermission(anyOf={android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND}) public void setTemporaryAppWhitelistDuration(int, long);
     method public android.os.Bundle toBundle();
+    field public static final int TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED = 0; // 0x0
+    field public static final int TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED = 1; // 0x1
   }
 
   public class DownloadManager {
@@ -878,11 +881,13 @@
     field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI";
     field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL";
     field public static final String EXTRA_PROVISIONING_ORGANIZATION_NAME = "android.app.extra.PROVISIONING_ORGANIZATION_NAME";
+    field public static final String EXTRA_PROVISIONING_SUPPORTED_MODES = "android.app.extra.PROVISIONING_SUPPORTED_MODES";
     field public static final String EXTRA_PROVISIONING_SUPPORT_URL = "android.app.extra.PROVISIONING_SUPPORT_URL";
     field public static final String EXTRA_PROVISIONING_TRIGGER = "android.app.extra.PROVISIONING_TRIGGER";
     field public static final String EXTRA_RESTRICTION = "android.app.extra.RESTRICTION";
     field public static final int PROVISIONING_TRIGGER_CLOUD_ENROLLMENT = 1; // 0x1
-    field public static final int PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER = 3; // 0x3
+    field public static final int PROVISIONING_TRIGGER_MANAGED_ACCOUNT = 4; // 0x4
+    field @Deprecated public static final int PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER = 3; // 0x3
     field public static final int PROVISIONING_TRIGGER_QR_CODE = 2; // 0x2
     field public static final int PROVISIONING_TRIGGER_UNSPECIFIED = 0; // 0x0
     field public static final int STATE_USER_PROFILE_COMPLETE = 4; // 0x4
@@ -891,6 +896,9 @@
     field public static final int STATE_USER_SETUP_FINALIZED = 3; // 0x3
     field public static final int STATE_USER_SETUP_INCOMPLETE = 1; // 0x1
     field public static final int STATE_USER_UNMANAGED = 0; // 0x0
+    field public static final int SUPPORTED_MODES_ORGANIZATION_AND_PERSONALLY_OWNED = 3; // 0x3
+    field public static final int SUPPORTED_MODES_ORGANIZATION_OWNED = 1; // 0x1
+    field public static final int SUPPORTED_MODES_PERSONALLY_OWNED = 2; // 0x2
   }
 
   public final class SystemUpdatePolicy implements android.os.Parcelable {
@@ -4111,6 +4119,22 @@
     method @Deprecated public void onStatusChanged(int);
   }
 
+  public final class LastLocationRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method public boolean isHiddenFromAppOps();
+    method public boolean isLocationSettingsIgnored();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.LastLocationRequest> CREATOR;
+  }
+
+  public static final class LastLocationRequest.Builder {
+    ctor public LastLocationRequest.Builder();
+    ctor public LastLocationRequest.Builder(@NonNull android.location.LastLocationRequest);
+    method @NonNull public android.location.LastLocationRequest build();
+    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LastLocationRequest.Builder setHiddenFromAppOps(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LastLocationRequest.Builder setLocationSettingsIgnored(boolean);
+  }
+
   public class Location implements android.os.Parcelable {
     method public boolean isComplete();
     method public void makeComplete();
@@ -4123,6 +4147,7 @@
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
     method @Nullable public String getExtraLocationControllerPackage();
     method @Deprecated public int getGnssBatchSize();
+    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.location.Location getLastKnownLocation(@NonNull String, @NonNull android.location.LastLocationRequest);
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void injectGnssMeasurementCorrections(@NonNull android.location.GnssMeasurementCorrections);
     method public boolean isExtraLocationControllerPackageEnabled();
     method public boolean isLocationEnabledForUser(@NonNull android.os.UserHandle);
@@ -4345,6 +4370,7 @@
     field public static final int PLAYER_STATE_STARTED = 2; // 0x2
     field public static final int PLAYER_STATE_STOPPED = 4; // 0x4
     field public static final int PLAYER_STATE_UNKNOWN = -1; // 0xffffffff
+    field public static final int PLAYER_TYPE_AAUDIO = 13; // 0xd
     field public static final int PLAYER_TYPE_JAM_AUDIOTRACK = 1; // 0x1
     field public static final int PLAYER_TYPE_JAM_MEDIAPLAYER = 2; // 0x2
     field public static final int PLAYER_TYPE_JAM_SOUNDPOOL = 3; // 0x3
@@ -4991,6 +5017,7 @@
   public class Descrambler implements java.lang.AutoCloseable {
     method public int addPid(int, int, @Nullable android.media.tv.tuner.filter.Filter);
     method public void close();
+    method public static boolean isValidKeyToken(@NonNull byte[]);
     method public int removePid(int, int, @Nullable android.media.tv.tuner.filter.Filter);
     method public int setKeyToken(@NonNull byte[]);
     field public static final int PID_TYPE_MMTP = 2; // 0x2
@@ -5065,7 +5092,6 @@
     field public static final int INVALID_FIRST_MACROBLOCK_IN_SLICE = -1; // 0xffffffff
     field public static final int INVALID_FRONTEND_ID = -1; // 0xffffffff
     field public static final int INVALID_FRONTEND_SETTING_FREQUENCY = -1; // 0xffffffff
-    field @NonNull public static final byte[] INVALID_KEYTOKEN;
     field public static final int INVALID_LTS_ID = -1; // 0xffffffff
     field public static final int INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM = -1; // 0xffffffff
     field public static final int INVALID_STREAM_ID = 65535; // 0xffff
@@ -5081,6 +5107,7 @@
     field public static final int SCAN_TYPE_AUTO = 1; // 0x1
     field public static final int SCAN_TYPE_BLIND = 2; // 0x2
     field public static final int SCAN_TYPE_UNDEFINED = 0; // 0x0
+    field @NonNull public static final byte[] VOID_KEYTOKEN;
   }
 
   public static interface Tuner.OnResourceLostListener {
@@ -5885,8 +5912,8 @@
 
   public class DvbsFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
     method @NonNull public static android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder builder();
+    method public boolean canHandleDiseqcRxMessage();
     method @Nullable public android.media.tv.tuner.frontend.DvbsCodeRate getCodeRate();
-    method public boolean getCouldHandleDiseqcRxMessage();
     method public int getInputStreamId();
     method public int getModulation();
     method public int getPilot();
@@ -5938,8 +5965,8 @@
 
   public static class DvbsFrontendSettings.Builder {
     method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings build();
+    method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setCanHandleDiseqcRxMessage(boolean);
     method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setCodeRate(@Nullable android.media.tv.tuner.frontend.DvbsCodeRate);
-    method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setCouldHandleDiseqcRxMessage(boolean);
     method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setFrequency(int);
     method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setInputStreamId(int);
     method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setModulation(int);
@@ -7813,7 +7840,7 @@
     method @Nullable public <T extends android.os.Parcelable> T getParcelable(@NonNull Class<T>);
     method public int getStability();
     method public void readFromParcel(@NonNull android.os.Parcel);
-    method public boolean setParcelable(@Nullable android.os.Parcelable);
+    method public void setParcelable(@Nullable android.os.Parcelable);
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.os.ParcelableHolder> CREATOR;
   }
@@ -8383,6 +8410,11 @@
     field @Deprecated public static final String STATE = "state";
   }
 
+  public static final class ContactsContract.SimContacts {
+    method @RequiresPermission("android.contacts.permission.MANAGE_SIM_ACCOUNTS") public static void addSimAccount(@NonNull android.content.ContentResolver, @NonNull String, @NonNull String, int, int);
+    method @RequiresPermission("android.contacts.permission.MANAGE_SIM_ACCOUNTS") public static void removeSimAccounts(@NonNull android.content.ContentResolver, int);
+  }
+
   public final class DeviceConfig {
     method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static void addOnPropertiesChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertiesChangedListener);
     method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static boolean getBoolean(@NonNull String, @NonNull String, boolean);
@@ -8401,6 +8433,7 @@
     field public static final String NAMESPACE_APP_COMPAT = "app_compat";
     field public static final String NAMESPACE_ATTENTION_MANAGER_SERVICE = "attention_manager_service";
     field public static final String NAMESPACE_AUTOFILL = "autofill";
+    field public static final String NAMESPACE_BATTERY_SAVER = "battery_saver";
     field public static final String NAMESPACE_BIOMETRICS = "biometrics";
     field public static final String NAMESPACE_BLOBSTORE = "blobstore";
     field public static final String NAMESPACE_BLUETOOTH = "bluetooth";
@@ -9088,6 +9121,26 @@
     method @NonNull @WorkerThread public abstract java.util.List<android.content.ContentValues> onRestoreApns(int);
   }
 
+  public final class CarrierMessagingServiceWrapper {
+    ctor public CarrierMessagingServiceWrapper();
+    method public boolean bindToCarrierMessagingService(@NonNull android.content.Context, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull Runnable);
+    method public void disposeConnection(@NonNull android.content.Context);
+    method public void downloadMms(@NonNull android.net.Uri, int, @NonNull android.net.Uri, @NonNull java.util.concurrent.Executor, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallback);
+    method public void receiveSms(@NonNull android.service.carrier.MessagePdu, @NonNull String, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallback);
+    method public void sendDataSms(@NonNull byte[], int, @NonNull String, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallback);
+    method public void sendMms(@NonNull android.net.Uri, int, @NonNull android.net.Uri, @NonNull java.util.concurrent.Executor, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallback);
+    method public void sendMultipartTextSms(@NonNull java.util.List<java.lang.String>, int, @NonNull String, int, @NonNull java.util.concurrent.Executor, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallback);
+    method public void sendTextSms(@NonNull String, int, @NonNull String, int, @NonNull java.util.concurrent.Executor, @NonNull android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallback);
+  }
+
+  public static interface CarrierMessagingServiceWrapper.CarrierMessagingCallback {
+    method public default void onDownloadMmsComplete(int);
+    method public default void onReceiveSmsComplete(int);
+    method public default void onSendMmsComplete(int, @Nullable byte[]);
+    method public default void onSendMultipartSmsComplete(int, @Nullable int[]);
+    method public default void onSendSmsComplete(int, int);
+  }
+
 }
 
 package android.service.contentcapture {
@@ -10402,35 +10455,87 @@
     method public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber, int);
     method @Deprecated public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber);
     method public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber, int);
-    method public void onPhysicalChannelConfigurationChanged(@NonNull java.util.List<android.telephony.PhysicalChannelConfig>);
-    method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState);
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState);
     method public void onRadioPowerStateChanged(int);
     method public void onSrvccStateChanged(int);
     method public void onVoiceActivationStateChanged(int);
-    field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 67108864; // 0x4000000
-    field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_CALL = 268435456; // 0x10000000
-    field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_SMS = 536870912; // 0x20000000
-    field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final long LISTEN_PHYSICAL_CHANNEL_CONFIGURATION = 4294967296L; // 0x100000000L
-    field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_PRECISE_CALL_STATE = 2048; // 0x800
-    field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 8388608; // 0x800000
-    field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_SRVCC_STATE_CHANGED = 16384; // 0x4000
-    field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_VOICE_ACTIVATION_STATE = 131072; // 0x20000
+    field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED = 23; // 0x17
+    field @RequiresPermission("android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH") public static final int EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED = 10; // 0xa
+    field @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static final int EVENT_BARRING_INFO_CHANGED = 32; // 0x20
+    field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_CALL_ATTRIBUTES_CHANGED = 27; // 0x1b
+    field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_CALL_DISCONNECT_CAUSE_CHANGED = 26; // 0x1a
+    field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_CALL_FORWARDING_INDICATOR_CHANGED = 4; // 0x4
+    field @RequiresPermission(android.Manifest.permission.READ_CALL_LOG) public static final int EVENT_CALL_STATE_CHANGED = 6; // 0x6
+    field public static final int EVENT_CARRIER_NETWORK_CHANGED = 17; // 0x11
+    field @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static final int EVENT_CELL_INFO_CHANGED = 11; // 0xb
+    field @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static final int EVENT_CELL_LOCATION_CHANGED = 5; // 0x5
+    field public static final int EVENT_DATA_ACTIVATION_STATE_CHANGED = 19; // 0x13
+    field public static final int EVENT_DATA_ACTIVITY_CHANGED = 8; // 0x8
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED = 14; // 0xe
+    field public static final int EVENT_DATA_CONNECTION_STATE_CHANGED = 7; // 0x7
+    field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_DATA_ENABLED_CHANGED = 34; // 0x22
+    field public static final int EVENT_DISPLAY_INFO_CHANGED = 21; // 0x15
+    field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_EMERGENCY_NUMBER_LIST_CHANGED = 25; // 0x19
+    field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED = 28; // 0x1c
+    field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_MESSAGE_WAITING_INDICATOR_CHANGED = 3; // 0x3
+    field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_OEM_HOOK_RAW = 15; // 0xf
+    field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int EVENT_OUTGOING_EMERGENCY_CALL = 29; // 0x1d
+    field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int EVENT_OUTGOING_EMERGENCY_SMS = 30; // 0x1e
+    field public static final int EVENT_PHONE_CAPABILITY_CHANGED = 22; // 0x16
+    field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 33; // 0x21
+    field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_PRECISE_CALL_STATE_CHANGED = 12; // 0xc
+    field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED = 13; // 0xd
+    field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_RADIO_POWER_STATE_CHANGED = 24; // 0x18
+    field @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static final int EVENT_REGISTRATION_FAILURE = 31; // 0x1f
+    field public static final int EVENT_SERVICE_STATE_CHANGED = 1; // 0x1
+    field public static final int EVENT_SIGNAL_STRENGTHS_CHANGED = 9; // 0x9
+    field public static final int EVENT_SIGNAL_STRENGTH_CHANGED = 2; // 0x2
+    field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_SRVCC_STATE_CHANGED = 16; // 0x10
+    field public static final int EVENT_USER_MOBILE_DATA_STATE_CHANGED = 20; // 0x14
+    field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_VOICE_ACTIVATION_STATE_CHANGED = 18; // 0x12
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 67108864; // 0x4000000
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_CALL = 268435456; // 0x10000000
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_SMS = 536870912; // 0x20000000
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int LISTEN_PRECISE_CALL_STATE = 2048; // 0x800
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 8388608; // 0x800000
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_SRVCC_STATE_CHANGED = 16384; // 0x4000
+    field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_VOICE_ACTIVATION_STATE = 131072; // 0x20000
   }
 
-  public final class PhysicalChannelConfig implements android.os.Parcelable {
-    method public int describeContents();
-    method public int getCellBandwidthDownlink();
-    method public int getChannelNumber();
-    method public int getConnectionStatus();
-    method public int getNetworkType();
-    method @IntRange(from=0, to=1007) public int getPhysicalCellId();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final int CHANNEL_NUMBER_UNKNOWN = -1; // 0xffffffff
-    field public static final int CONNECTION_PRIMARY_SERVING = 1; // 0x1
-    field public static final int CONNECTION_SECONDARY_SERVING = 2; // 0x2
-    field public static final int CONNECTION_UNKNOWN = -1; // 0xffffffff
-    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PhysicalChannelConfig> CREATOR;
-    field public static final int PHYSICAL_CELL_ID_UNKNOWN = -1; // 0xffffffff
+  public static interface PhoneStateListener.CallAttributesChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes);
+  }
+
+  public static interface PhoneStateListener.DataEnabledChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onDataEnabledChanged(boolean, int);
+  }
+
+  public static interface PhoneStateListener.OutgoingEmergencyCallListener {
+    method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber, int);
+  }
+
+  public static interface PhoneStateListener.OutgoingEmergencySmsListener {
+    method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber, int);
+  }
+
+  public static interface PhoneStateListener.PhysicalChannelConfigChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPhysicalChannelConfigChanged(@NonNull java.util.List<android.telephony.PhysicalChannelConfig>);
+  }
+
+  public static interface PhoneStateListener.PreciseCallStateChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState);
+  }
+
+  public static interface PhoneStateListener.RadioPowerStateChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onRadioPowerStateChanged(int);
+  }
+
+  public static interface PhoneStateListener.SrvccStateChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onSrvccStateChanged(int);
+  }
+
+  public static interface PhoneStateListener.VoiceActivationStateChangedListener {
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onVoiceActivationStateChanged(int);
   }
 
   public final class PinResult implements android.os.Parcelable {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 51edd03..ffb31c9 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -272,6 +272,7 @@
     method public void allowAssistantAdjustment(String);
     method public void disallowAssistantAdjustment(String);
     method public android.content.ComponentName getEffectsSuppressor();
+    method public boolean isNotificationPolicyAccessGrantedForPackage(@NonNull String);
     method public boolean matchesCallFilter(android.os.Bundle);
     method @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS) public void setNotificationListenerAccessGranted(@NonNull android.content.ComponentName, boolean, boolean);
     method public void updateNotificationChannel(@NonNull String, int, @NonNull android.app.NotificationChannel);
@@ -372,8 +373,15 @@
     method public java.util.List<java.lang.String> getOwnerInstalledCaCerts(@NonNull android.os.UserHandle);
     method public boolean isCurrentInputMethodSetByOwner();
     method public boolean isFactoryResetProtectionPolicySupported();
+    method @NonNull public static String operationToString(int);
+    method @RequiresPermission("android.permission.MANAGE_DEVICE_ADMINS") public void setNextOperationSafety(int, boolean);
     field public static final String ACTION_DATA_SHARING_RESTRICTION_APPLIED = "android.app.action.DATA_SHARING_RESTRICTION_APPLIED";
+    field public static final int OPERATION_CREATE_AND_MANAGE_USER = 5; // 0x5
     field public static final int OPERATION_LOCK_NOW = 1; // 0x1
+    field public static final int OPERATION_REMOVE_USER = 6; // 0x6
+    field public static final int OPERATION_START_USER_IN_BACKGROUND = 3; // 0x3
+    field public static final int OPERATION_STOP_USER = 4; // 0x4
+    field public static final int OPERATION_SWITCH_USER = 2; // 0x2
   }
 
   public static final class SecurityLog.SecurityEvent implements android.os.Parcelable {
@@ -987,9 +995,9 @@
   }
 
   public class AudioSystem {
-    method public static float getMasterBalance();
+    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS) public static float getMasterBalance();
     method public static final int getNumStreamTypes();
-    method public static int setMasterBalance(float);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS) public static int setMasterBalance(float);
     field public static final int DEVICE_ROLE_DISABLED = 2; // 0x2
     field public static final int DEVICE_ROLE_NONE = 0; // 0x0
     field public static final int DEVICE_ROLE_PREFERRED = 1; // 0x1
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 0ad9e44..8e50184 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -18,6 +18,7 @@
 
 import android.accessibilityservice.GestureDescription.MotionEventGenerator;
 import android.annotation.CallbackExecutor;
+import android.annotation.ColorInt;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -2118,6 +2119,27 @@
     }
 
     /**
+     * Sets the strokeWidth and color of the accessibility focus rectangle.
+     *
+     * @param strokeWidth The stroke width of the rectangle in pixels.
+     *                    Setting this value to zero results in no focus rectangle being drawn.
+     * @param color The color of the rectangle.
+     */
+    public void setAccessibilityFocusAppearance(int strokeWidth, @ColorInt int color) {
+        IAccessibilityServiceConnection connection =
+                AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
+        if (connection != null) {
+            try {
+                connection.setFocusAppearance(strokeWidth, color);
+            } catch (RemoteException re) {
+                Log.w(LOG_TAG, "Error while setting the strokeWidth and color of the "
+                        + "accessibility focus rectangle", re);
+                re.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
      * Implement to return the implementation of the internal accessibility
      * service interface.
      */
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 0b3b9b2..ab21dc9 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -115,4 +115,6 @@
     void setGestureDetectionPassthroughRegion(int displayId, in Region region);
 
     void setTouchExplorationPassthroughRegion(int displayId, in Region region);
+
+    void setFocusAppearance(int strokeWidth, int color);
 }
diff --git a/core/java/android/animation/OWNERS b/core/java/android/animation/OWNERS
new file mode 100644
index 0000000..822a35c
--- /dev/null
+++ b/core/java/android/animation/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 47085
+
+romainguy@google.com
+tianliu@google.com
+alanv@google.com
+adamp@google.com
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 5ee5597..f92768a 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -963,8 +963,8 @@
          * @hide
          */
         @Override
-        public void toggleFreeformWindowingMode() throws RemoteException {
-            ActivityTaskManager.getService().toggleFreeformWindowingMode(mToken);
+        public void toggleFreeformWindowingMode() {
+            ActivityClient.getInstance().toggleFreeformWindowingMode(mToken);
         }
 
         /**
@@ -981,11 +981,8 @@
 
         @Override
         public boolean isTaskRoot() {
-            try {
-                return ActivityTaskManager.getService().getTaskForActivity(mToken, true) >= 0;
-            } catch (RemoteException e) {
-                return false;
-            }
+            return ActivityClient.getInstance().getTaskForActivity(
+                    mToken, true /* onlyRoot */) >= 0;
         }
 
         /**
@@ -2052,12 +2049,8 @@
      * {@link #isVoiceInteractionRoot()} return {@code false} in this case.
      */
     public boolean isVoiceInteractionRoot() {
-        try {
-            return mVoiceInteractor != null
-                    && ActivityTaskManager.getService().isRootVoiceInteraction(mToken);
-        } catch (RemoteException e) {
-        }
-        return false;
+        return mVoiceInteractor != null
+                && ActivityClient.getInstance().isRootVoiceInteraction(mToken);
     }
 
     /**
@@ -2090,10 +2083,7 @@
      * @param privateOptions a Bundle of private arguments to the current voice interaction service
      */
     public void startLocalVoiceInteraction(Bundle privateOptions) {
-        try {
-            ActivityTaskManager.getService().startLocalVoiceInteraction(mToken, privateOptions);
-        } catch (RemoteException re) {
-        }
+        ActivityClient.getInstance().startLocalVoiceInteraction(mToken, privateOptions);
     }
 
     /**
@@ -2119,10 +2109,7 @@
      * terminated, {@link #onLocalVoiceInteractionStopped()} will be called.
      */
     public void stopLocalVoiceInteraction() {
-        try {
-            ActivityTaskManager.getService().stopLocalVoiceInteraction(mToken);
-        } catch (RemoteException re) {
-        }
+        ActivityClient.getInstance().stopLocalVoiceInteraction(mToken);
     }
 
     /**
@@ -2564,11 +2551,7 @@
      * false will be returned if the caller is not the current top activity.
      */
     public boolean showAssist(Bundle args) {
-        try {
-            return ActivityTaskManager.getService().showAssistFromActivity(mToken, args);
-        } catch (RemoteException e) {
-        }
-        return false;
+        return ActivityClient.getInstance().showAssistFromActivity(mToken, args);
     }
 
     /**
@@ -2708,10 +2691,9 @@
             }
             mDoReportFullyDrawn = false;
             try {
-                ActivityTaskManager.getService().reportActivityFullyDrawn(
+                ActivityClient.getInstance().reportActivityFullyDrawn(
                         mToken, mRestoredFromBundle);
                 VMRuntime.getRuntime().notifyStartupCompleted();
-            } catch (RemoteException e) {
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
             }
@@ -2841,27 +2823,23 @@
      * does not support picture-in-picture, return false.
      */
     public boolean enterPictureInPictureMode(@NonNull PictureInPictureParams params) {
-        try {
-            if (!deviceSupportsPictureInPictureMode()) {
-                return false;
-            }
-            if (params == null) {
-                throw new IllegalArgumentException("Expected non-null picture-in-picture params");
-            }
-            if (!mCanEnterPictureInPicture) {
-                throw new IllegalStateException("Activity must be resumed to enter"
-                        + " picture-in-picture");
-            }
-            // Set mIsInPictureInPictureMode earlier and don't wait for
-            // onPictureInPictureModeChanged callback here. This is to ensure that
-            // isInPictureInPictureMode returns true in the following onPause callback.
-            // See https://developer.android.com/guide/topics/ui/picture-in-picture for guidance.
-            mIsInPictureInPictureMode = ActivityTaskManager.getService().enterPictureInPictureMode(
-                    mToken, params);
-            return mIsInPictureInPictureMode;
-        } catch (RemoteException e) {
+        if (!deviceSupportsPictureInPictureMode()) {
             return false;
         }
+        if (params == null) {
+            throw new IllegalArgumentException("Expected non-null picture-in-picture params");
+        }
+        if (!mCanEnterPictureInPicture) {
+            throw new IllegalStateException("Activity must be resumed to enter"
+                    + " picture-in-picture");
+        }
+        // Set mIsInPictureInPictureMode earlier and don't wait for
+        // onPictureInPictureModeChanged callback here. This is to ensure that
+        // isInPictureInPictureMode returns true in the following onPause callback.
+        // See https://developer.android.com/guide/topics/ui/picture-in-picture for guidance.
+        mIsInPictureInPictureMode = ActivityClient.getInstance().enterPictureInPictureMode(
+                mToken, params);
+        return mIsInPictureInPictureMode;
     }
 
     /**
@@ -2871,16 +2849,13 @@
      * @param params the new parameters for the picture-in-picture.
      */
     public void setPictureInPictureParams(@NonNull PictureInPictureParams params) {
-        try {
-            if (!deviceSupportsPictureInPictureMode()) {
-                return;
-            }
-            if (params == null) {
-                throw new IllegalArgumentException("Expected non-null picture-in-picture params");
-            }
-            ActivityTaskManager.getService().setPictureInPictureParams(mToken, params);
-        } catch (RemoteException e) {
+        if (!deviceSupportsPictureInPictureMode()) {
+            return;
         }
+        if (params == null) {
+            throw new IllegalArgumentException("Expected non-null picture-in-picture params");
+        }
+        ActivityClient.getInstance().setPictureInPictureParams(mToken, params);
     }
 
     /**
@@ -3822,14 +3797,10 @@
             finishAfterTransition();
             return;
         }
-        try {
-            // Inform activity task manager that the activity received a back press
-            // while at the root of the task. This call allows ActivityTaskManager
-            // to intercept or move the task to the back.
-            ActivityTaskManager.getService().onBackPressedOnTaskRoot(mToken);
-        } catch (RemoteException e) {
-            finishAfterTransition();
-        }
+        // Inform activity task manager that the activity received a back press while at the
+        // root of the task. This call allows ActivityTaskManager to intercept or move the task
+        // to the back.
+        ActivityClient.getInstance().onBackPressedOnTaskRoot(mToken);
 
         // Activity was launched when user tapped a link in the Autofill Save UI - Save UI must
         // be restored now.
@@ -6114,11 +6085,8 @@
      * the outgoing activity.  Use 0 for no animation.
      */
     public void overridePendingTransition(int enterAnim, int exitAnim) {
-        try {
-            ActivityTaskManager.getService().overridePendingTransition(
-                    mToken, getPackageName(), enterAnim, exitAnim);
-        } catch (RemoteException e) {
-        }
+        ActivityClient.getInstance().overridePendingTransition(mToken, getPackageName(),
+                enterAnim, exitAnim);
     }
 
     /**
@@ -6239,11 +6207,7 @@
      */
     @Nullable
     public String getCallingPackage() {
-        try {
-            return ActivityTaskManager.getService().getCallingPackage(mToken);
-        } catch (RemoteException e) {
-            return null;
-        }
+        return ActivityClient.getInstance().getCallingPackage(mToken);
     }
 
     /**
@@ -6262,11 +6226,7 @@
      */
     @Nullable
     public ComponentName getCallingActivity() {
-        try {
-            return ActivityTaskManager.getService().getCallingActivity(mToken);
-        } catch (RemoteException e) {
-            return null;
-        }
+        return ActivityClient.getInstance().getCallingActivity(mToken);
     }
 
     /**
@@ -6364,16 +6324,12 @@
                 resultData = mResultData;
             }
             if (false) Log.v(TAG, "Finishing self: token=" + mToken);
-            try {
-                if (resultData != null) {
-                    resultData.prepareToLeaveProcess(this);
-                }
-                if (ActivityTaskManager.getService()
-                        .finishActivity(mToken, resultCode, resultData, finishTask)) {
-                    mFinished = true;
-                }
-            } catch (RemoteException e) {
-                // Empty
+            if (resultData != null) {
+                resultData.prepareToLeaveProcess(this);
+            }
+            if (ActivityClient.getInstance().finishActivity(mToken, resultCode, resultData,
+                    finishTask)) {
+                mFinished = true;
             }
         } else {
             mParent.finishFromChild(this);
@@ -6429,12 +6385,8 @@
         if (mResultCode != RESULT_CANCELED || mResultData != null) {
             throw new IllegalStateException("Can not be called to deliver a result");
         }
-        try {
-            if (ActivityTaskManager.getService().finishActivityAffinity(mToken)) {
-                mFinished = true;
-            }
-        } catch (RemoteException e) {
-            // Empty
+        if (ActivityClient.getInstance().finishActivityAffinity(mToken)) {
+            mFinished = true;
         }
     }
 
@@ -6477,12 +6429,7 @@
      */
     public void finishActivity(int requestCode) {
         if (mParent == null) {
-            try {
-                ActivityTaskManager.getService()
-                    .finishSubActivity(mToken, mEmbeddedID, requestCode);
-            } catch (RemoteException e) {
-                // Empty
-            }
+            ActivityClient.getInstance().finishSubActivity(mToken, mEmbeddedID, requestCode);
         } else {
             mParent.finishActivityFromChild(this, requestCode);
         }
@@ -6499,12 +6446,7 @@
      */
     @Deprecated
     public void finishActivityFromChild(@NonNull Activity child, int requestCode) {
-        try {
-            ActivityTaskManager.getService()
-                .finishSubActivity(mToken, child.mEmbeddedID, requestCode);
-        } catch (RemoteException e) {
-            // Empty
-        }
+        ActivityClient.getInstance().finishSubActivity(mToken, child.mEmbeddedID, requestCode);
     }
 
     /**
@@ -6527,12 +6469,7 @@
      * being finished, it hasn't yet saved its state, etc.
      */
     public boolean releaseInstance() {
-        try {
-            return ActivityTaskManager.getService().releaseActivityInstance(mToken);
-        } catch (RemoteException e) {
-            // Empty
-        }
-        return false;
+        return ActivityClient.getInstance().releaseActivityInstance(mToken);
     }
 
     /**
@@ -6644,12 +6581,7 @@
      */
     public void setRequestedOrientation(@ActivityInfo.ScreenOrientation int requestedOrientation) {
         if (mParent == null) {
-            try {
-                ActivityTaskManager.getService().setRequestedOrientation(
-                        mToken, requestedOrientation);
-            } catch (RemoteException e) {
-                // Empty
-            }
+            ActivityClient.getInstance().setRequestedOrientation(mToken, requestedOrientation);
         } else {
             mParent.setRequestedOrientation(requestedOrientation);
         }
@@ -6667,16 +6599,10 @@
     @ActivityInfo.ScreenOrientation
     public int getRequestedOrientation() {
         if (mParent == null) {
-            try {
-                return ActivityTaskManager.getService()
-                        .getRequestedOrientation(mToken);
-            } catch (RemoteException e) {
-                // Empty
-            }
+            return ActivityClient.getInstance().getRequestedOrientation(mToken);
         } else {
             return mParent.getRequestedOrientation();
         }
-        return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
     }
 
     /**
@@ -6686,11 +6612,7 @@
      * @return Task identifier, an opaque integer.
      */
     public int getTaskId() {
-        try {
-            return ActivityTaskManager.getService().getTaskForActivity(mToken, false);
-        } catch (RemoteException e) {
-            return -1;
-        }
+        return ActivityClient.getInstance().getTaskForActivity(mToken, false /* onlyRoot */);
     }
 
     /**
@@ -6715,12 +6637,7 @@
      *         back) true is returned, else false.
      */
     public boolean moveTaskToBack(boolean nonRoot) {
-        try {
-            return ActivityTaskManager.getService().moveActivityTaskToBack(mToken, nonRoot);
-        } catch (RemoteException e) {
-            // Empty
-        }
-        return false;
+        return ActivityClient.getInstance().moveActivityTaskToBack(mToken, nonRoot);
     }
 
     /**
@@ -6896,10 +6813,7 @@
                 mTaskDescription.setIcon(Icon.createWithBitmap(icon));
             }
         }
-        try {
-            ActivityTaskManager.getService().setTaskDescription(mToken, mTaskDescription);
-        } catch (RemoteException e) {
-        }
+        ActivityClient.getInstance().setTaskDescription(mToken, mTaskDescription);
     }
 
     /**
@@ -7210,11 +7124,7 @@
      * @see android.content.pm.ActivityInfo#FLAG_IMMERSIVE
      */
     public boolean isImmersive() {
-        try {
-            return ActivityTaskManager.getService().isImmersive(mToken);
-        } catch (RemoteException e) {
-            return false;
-        }
+        return ActivityClient.getInstance().isImmersive(mToken);
     }
 
     /**
@@ -7228,11 +7138,7 @@
         if (mToken == null || mWindow == null) {
             return false;
         }
-        try {
-            return ActivityTaskManager.getService().isTopOfTask(getActivityToken());
-        } catch (RemoteException e) {
-            return false;
-        }
+        return ActivityClient.getInstance().isTopOfTask(getActivityToken());
     }
 
     /**
@@ -7271,14 +7177,10 @@
     }
 
     private boolean convertFromTranslucentInternal() {
-        try {
-            mTranslucentCallback = null;
-            if (ActivityTaskManager.getService().convertFromTranslucent(mToken)) {
-                WindowManagerGlobal.getInstance().changeCanvasOpacity(mToken, true);
-                return true;
-            }
-        } catch (RemoteException e) {
-            // pass
+        mTranslucentCallback = null;
+        if (ActivityClient.getInstance().convertFromTranslucent(mToken)) {
+            WindowManagerGlobal.getInstance().changeCanvasOpacity(mToken, true /* opaque */);
+            return true;
         }
         return false;
     }
@@ -7307,21 +7209,14 @@
     @SystemApi
     public boolean convertToTranslucent(TranslucentConversionListener callback,
             ActivityOptions options) {
-        boolean drawComplete;
-        try {
-            mTranslucentCallback = callback;
-            mChangeCanvasToTranslucent = ActivityTaskManager.getService().convertToTranslucent(
-                    mToken, options == null ? null : options.toBundle());
-            WindowManagerGlobal.getInstance().changeCanvasOpacity(mToken, false);
-            drawComplete = true;
-        } catch (RemoteException e) {
-            // Make callback return as though it timed out.
-            mChangeCanvasToTranslucent = false;
-            drawComplete = false;
-        }
+        mTranslucentCallback = callback;
+        mChangeCanvasToTranslucent = ActivityClient.getInstance().convertToTranslucent(
+                mToken, options == null ? null : options.toBundle());
+        WindowManagerGlobal.getInstance().changeCanvasOpacity(mToken, false);
+
         if (!mChangeCanvasToTranslucent && mTranslucentCallback != null) {
             // Window is already translucent.
-            mTranslucentCallback.onTranslucentConversionComplete(drawComplete);
+            mTranslucentCallback.onTranslucentConversionComplete(true /* drawComplete */);
         }
         return mChangeCanvasToTranslucent;
     }
@@ -7355,12 +7250,7 @@
      */
     @UnsupportedAppUsage
     ActivityOptions getActivityOptions() {
-        try {
-            return ActivityOptions.fromBundle(
-                    ActivityTaskManager.getService().getActivityOptions(mToken));
-        } catch (RemoteException e) {
-        }
-        return null;
+        return ActivityOptions.fromBundle(ActivityClient.getInstance().getActivityOptions(mToken));
     }
 
     /**
@@ -7504,11 +7394,7 @@
      * @see android.content.pm.ActivityInfo#FLAG_IMMERSIVE
      */
     public void setImmersive(boolean i) {
-        try {
-            ActivityTaskManager.getService().setImmersive(mToken, i);
-        } catch (RemoteException e) {
-            // pass
-        }
+        ActivityClient.getInstance().setImmersive(mToken, i);
     }
 
     /**
@@ -7567,14 +7453,8 @@
      */
     public void setVrModeEnabled(boolean enabled, @NonNull ComponentName requestedComponent)
           throws PackageManager.NameNotFoundException {
-        try {
-            if (ActivityTaskManager.getService().setVrMode(mToken, enabled, requestedComponent)
-                    != 0) {
-                throw new PackageManager.NameNotFoundException(
-                        requestedComponent.flattenToString());
-            }
-        } catch (RemoteException e) {
-            // pass
+        if (ActivityClient.getInstance().setVrMode(mToken, enabled, requestedComponent) != 0) {
+            throw new PackageManager.NameNotFoundException(requestedComponent.flattenToString());
         }
     }
 
@@ -7689,9 +7569,7 @@
             if (info.taskAffinity == null) {
                 return false;
             }
-            return ActivityTaskManager.getService().shouldUpRecreateTask(mToken, info.taskAffinity);
-        } catch (RemoteException e) {
-            return false;
+            return ActivityClient.getInstance().shouldUpRecreateTask(mToken, info.taskAffinity);
         } catch (NameNotFoundException e) {
             return false;
         }
@@ -7739,13 +7617,9 @@
             if (resultData != null) {
                 resultData.prepareToLeaveProcess(this);
             }
-            try {
-                upIntent.prepareToLeaveProcess(this);
-                return ActivityTaskManager.getService().navigateUpTo(mToken, upIntent,
-                        resultCode, resultData);
-            } catch (RemoteException e) {
-                return false;
-            }
+            upIntent.prepareToLeaveProcess(this);
+            return ActivityClient.getInstance().navigateUpTo(mToken, upIntent, resultCode,
+                    resultData);
         } else {
             return mParent.navigateUpToFromChild(this, upIntent);
         }
@@ -8361,10 +8235,7 @@
      * @see android.R.attr#lockTaskMode
      */
     public void startLockTask() {
-        try {
-            ActivityTaskManager.getService().startLockTaskModeByToken(mToken);
-        } catch (RemoteException e) {
-        }
+        ActivityClient.getInstance().startLockTaskModeByToken(mToken);
     }
 
     /**
@@ -8384,10 +8255,7 @@
      * @see ActivityManager#getLockTaskModeState()
      */
     public void stopLockTask() {
-        try {
-            ActivityTaskManager.getService().stopLockTaskModeByToken(mToken);
-        } catch (RemoteException e) {
-        }
+        ActivityClient.getInstance().stopLockTaskModeByToken(mToken);
     }
 
     /**
@@ -8396,10 +8264,7 @@
      * of this call for the message to be displayed.
      */
     public void showLockTaskEscapeMessage() {
-        try {
-            ActivityTaskManager.getService().showLockTaskEscapeMessage(mToken);
-        } catch (RemoteException e) {
-        }
+        ActivityClient.getInstance().showLockTaskEscapeMessage(mToken);
     }
 
     /**
@@ -8667,11 +8532,7 @@
      */
     @UnsupportedAppUsage
     public void setDisablePreviewScreenshots(boolean disable) {
-        try {
-            ActivityTaskManager.getService().setDisablePreviewScreenshots(mToken, disable);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        ActivityClient.getInstance().setDisablePreviewScreenshots(mToken, disable);
     }
 
     /**
@@ -8688,11 +8549,7 @@
      * @see android.R.attr#showWhenLocked
      */
     public void setShowWhenLocked(boolean showWhenLocked) {
-        try {
-            ActivityTaskManager.getService().setShowWhenLocked(mToken, showWhenLocked);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        ActivityClient.getInstance().setShowWhenLocked(mToken, showWhenLocked);
     }
 
     /**
@@ -8711,12 +8568,7 @@
      * @see android.R.attr#inheritShowWhenLocked
      */
     public void setInheritShowWhenLocked(boolean inheritShowWhenLocked) {
-        try {
-            ActivityTaskManager.getService().setInheritShowWhenLocked(
-                    mToken, inheritShowWhenLocked);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        ActivityClient.getInstance().setInheritShowWhenLocked(mToken, inheritShowWhenLocked);
     }
 
     /**
@@ -8741,11 +8593,7 @@
      * @see KeyguardManager#isDeviceSecure()
      */
     public void setTurnScreenOn(boolean turnScreenOn) {
-        try {
-            ActivityTaskManager.getService().setTurnScreenOn(mToken, turnScreenOn);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        ActivityClient.getInstance().setTurnScreenOn(mToken, turnScreenOn);
     }
 
     /**
@@ -8757,11 +8605,7 @@
      */
     @RequiresPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS)
     public void registerRemoteAnimations(RemoteAnimationDefinition definition) {
-        try {
-            ActivityTaskManager.getService().registerRemoteAnimations(mToken, definition);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        ActivityClient.getInstance().registerRemoteAnimations(mToken, definition);
     }
 
     /**
@@ -8771,11 +8615,7 @@
      */
     @RequiresPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS)
     public void unregisterRemoteAnimations() {
-        try {
-            ActivityTaskManager.getService().unregisterRemoteAnimations(mToken);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        ActivityClient.getInstance().unregisterRemoteAnimations(mToken);
     }
 
     class HostCallbacks extends FragmentHostCallback<Activity> {
diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java
new file mode 100644
index 0000000..84ecd24
--- /dev/null
+++ b/core/java/android/app/ActivityClient.java
@@ -0,0 +1,476 @@
+/*
+ * 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.content.ComponentName;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.PersistableBundle;
+import android.os.RemoteException;
+import android.util.Singleton;
+import android.view.RemoteAnimationDefinition;
+
+/**
+ * Provides the activity associated operations that communicate with system.
+ *
+ * @hide
+ */
+public class ActivityClient {
+    private ActivityClient() {}
+
+    /** Reports the main thread is idle after the activity is resumed. */
+    public void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
+        try {
+            getActivityClientController().activityIdle(token, config, stopProfiling);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /** Reports {@link Activity#onResume()} is done. */
+    public void activityResumed(IBinder token) {
+        try {
+            getActivityClientController().activityResumed(token);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Reports after {@link Activity#onTopResumedActivityChanged(boolean)} is called for losing the
+     * top most position.
+     */
+    public void activityTopResumedStateLost() {
+        try {
+            getActivityClientController().activityTopResumedStateLost();
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /** Reports {@link Activity#onPause()} is done. */
+    public void activityPaused(IBinder token) {
+        try {
+            getActivityClientController().activityPaused(token);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /** Reports {@link Activity#onStop()} is done. */
+    public void activityStopped(IBinder token, Bundle state, PersistableBundle persistentState,
+            CharSequence description) {
+        try {
+            getActivityClientController().activityStopped(token, state, persistentState,
+                    description);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /** Reports {@link Activity#onDestroy()} is done. */
+    public void activityDestroyed(IBinder token) {
+        try {
+            getActivityClientController().activityDestroyed(token);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /** Reports the activity has completed relaunched. */
+    public void activityRelaunched(IBinder token) {
+        try {
+            getActivityClientController().activityRelaunched(token);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    void reportSizeConfigurations(IBinder token, int[] horizontalSizeConfiguration,
+            int[] verticalSizeConfigurations, int[] smallestSizeConfigurations) {
+        try {
+            getActivityClientController().reportSizeConfigurations(token,
+                    horizontalSizeConfiguration, verticalSizeConfigurations,
+                    smallestSizeConfigurations);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
+        try {
+            return getActivityClientController().moveActivityTaskToBack(token, nonRoot);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    boolean shouldUpRecreateTask(IBinder token, String destAffinity) {
+        try {
+            return getActivityClientController().shouldUpRecreateTask(token, destAffinity);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    boolean navigateUpTo(IBinder token, Intent destIntent, int resultCode,
+            Intent resultData) {
+        try {
+            return getActivityClientController().navigateUpTo(token, destIntent, resultCode,
+                    resultData);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    boolean releaseActivityInstance(IBinder token) {
+        try {
+            return getActivityClientController().releaseActivityInstance(token);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    public boolean finishActivity(IBinder token, int resultCode, Intent resultData,
+            int finishTask) {
+        try {
+            return getActivityClientController().finishActivity(token, resultCode, resultData,
+                    finishTask);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    boolean finishActivityAffinity(IBinder token) {
+        try {
+            return getActivityClientController().finishActivityAffinity(token);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    void finishSubActivity(IBinder token, String resultWho, int requestCode) {
+        try {
+            getActivityClientController().finishSubActivity(token, resultWho, requestCode);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    public boolean isTopOfTask(IBinder token) {
+        try {
+            return getActivityClientController().isTopOfTask(token);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    boolean willActivityBeVisible(IBinder token) {
+        try {
+            return getActivityClientController().willActivityBeVisible(token);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    public int getDisplayId(IBinder token) {
+        try {
+            return getActivityClientController().getDisplayId(token);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    public int getTaskForActivity(IBinder token, boolean onlyRoot) {
+        try {
+            return getActivityClientController().getTaskForActivity(token, onlyRoot);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    ComponentName getCallingActivity(IBinder token) {
+        try {
+            return getActivityClientController().getCallingActivity(token);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    String getCallingPackage(IBinder token) {
+        try {
+            return getActivityClientController().getCallingPackage(token);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    Bundle getActivityOptions(IBinder token) {
+        try {
+            return getActivityClientController().getActivityOptions(token);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    public void setRequestedOrientation(IBinder token, int requestedOrientation) {
+        try {
+            getActivityClientController().setRequestedOrientation(token, requestedOrientation);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    int getRequestedOrientation(IBinder token) {
+        try {
+            return getActivityClientController().getRequestedOrientation(token);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    boolean convertFromTranslucent(IBinder token) {
+        try {
+            return getActivityClientController().convertFromTranslucent(token);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    boolean convertToTranslucent(IBinder token, Bundle options) {
+        try {
+            return getActivityClientController().convertToTranslucent(token, options);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    void reportActivityFullyDrawn(IBinder token, boolean restoredFromBundle) {
+        try {
+            getActivityClientController().reportActivityFullyDrawn(token, restoredFromBundle);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    boolean isImmersive(IBinder token) {
+        try {
+            return getActivityClientController().isImmersive(token);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    void setImmersive(IBinder token, boolean immersive) {
+        try {
+            getActivityClientController().setImmersive(token, immersive);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    boolean enterPictureInPictureMode(IBinder token, PictureInPictureParams params) {
+        try {
+            return getActivityClientController().enterPictureInPictureMode(token, params);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    void setPictureInPictureParams(IBinder token, PictureInPictureParams params) {
+        try {
+            getActivityClientController().setPictureInPictureParams(token, params);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    void toggleFreeformWindowingMode(IBinder token) {
+        try {
+            getActivityClientController().toggleFreeformWindowingMode(token);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    void startLockTaskModeByToken(IBinder token) {
+        try {
+            getActivityClientController().startLockTaskModeByToken(token);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    void stopLockTaskModeByToken(IBinder token) {
+        try {
+            getActivityClientController().stopLockTaskModeByToken(token);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    void showLockTaskEscapeMessage(IBinder token) {
+        try {
+            getActivityClientController().showLockTaskEscapeMessage(token);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    void setTaskDescription(IBinder token, ActivityManager.TaskDescription td) {
+        try {
+            getActivityClientController().setTaskDescription(token, td);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    boolean showAssistFromActivity(IBinder token, Bundle args) {
+        try {
+            return getActivityClientController().showAssistFromActivity(token, args);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    boolean isRootVoiceInteraction(IBinder token) {
+        try {
+            return getActivityClientController().isRootVoiceInteraction(token);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    void startLocalVoiceInteraction(IBinder callingActivity, Bundle options) {
+        try {
+            getActivityClientController().startLocalVoiceInteraction(callingActivity, options);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    void stopLocalVoiceInteraction(IBinder callingActivity) {
+        try {
+            getActivityClientController().stopLocalVoiceInteraction(callingActivity);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    void setShowWhenLocked(IBinder token, boolean showWhenLocked) {
+        try {
+            getActivityClientController().setShowWhenLocked(token, showWhenLocked);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    void setInheritShowWhenLocked(IBinder token, boolean inheritShowWhenLocked) {
+        try {
+            getActivityClientController().setInheritShowWhenLocked(token, inheritShowWhenLocked);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    void setTurnScreenOn(IBinder token, boolean turnScreenOn) {
+        try {
+            getActivityClientController().setTurnScreenOn(token, turnScreenOn);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    int setVrMode(IBinder token, boolean enabled, ComponentName packageName) {
+        try {
+            return getActivityClientController().setVrMode(token, enabled, packageName);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    void overridePendingTransition(IBinder token, String packageName,
+            int enterAnim, int exitAnim) {
+        try {
+            getActivityClientController().overridePendingTransition(token, packageName,
+                    enterAnim, exitAnim);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    void setDisablePreviewScreenshots(IBinder token, boolean disable) {
+        try {
+            getActivityClientController().setDisablePreviewScreenshots(token, disable);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    void registerRemoteAnimations(IBinder token, RemoteAnimationDefinition definition) {
+        try {
+            getActivityClientController().registerRemoteAnimations(token, definition);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    void unregisterRemoteAnimations(IBinder token) {
+        try {
+            getActivityClientController().unregisterRemoteAnimations(token);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    void onBackPressedOnTaskRoot(IBinder token) {
+        try {
+            getActivityClientController().onBackPressedOnTaskRoot(token);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    public static ActivityClient getInstance() {
+        return sInstance.get();
+    }
+
+    private static IActivityClientController getActivityClientController() {
+        return sActivityClientController.get();
+    }
+
+    private static final Singleton<ActivityClient> sInstance = new Singleton<ActivityClient>() {
+        @Override
+        protected ActivityClient create() {
+            return new ActivityClient();
+        }
+    };
+
+    private static final Singleton<IActivityClientController> sActivityClientController =
+            new Singleton<IActivityClientController>() {
+        @Override
+        protected IActivityClientController create() {
+            try {
+                return ActivityTaskManager.getService().getActivityClientController();
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+    };
+}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index e3048df..38a22d8 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -77,6 +77,8 @@
 import android.util.DisplayMetrics;
 import android.util.Singleton;
 import android.util.Size;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.view.Surface;
 import android.view.WindowInsetsController.Appearance;
 
@@ -1502,57 +1504,54 @@
         }
 
         /** @hide */
-        public void saveToXml(XmlSerializer out) throws IOException {
+        public void saveToXml(TypedXmlSerializer out) throws IOException {
             if (mLabel != null) {
                 out.attribute(null, ATTR_TASKDESCRIPTIONLABEL, mLabel);
             }
             if (mColorPrimary != 0) {
-                out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR_PRIMARY,
-                        Integer.toHexString(mColorPrimary));
+                out.attributeIntHex(null, ATTR_TASKDESCRIPTIONCOLOR_PRIMARY, mColorPrimary);
             }
             if (mColorBackground != 0) {
-                out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR_BACKGROUND,
-                        Integer.toHexString(mColorBackground));
+                out.attributeIntHex(null, ATTR_TASKDESCRIPTIONCOLOR_BACKGROUND, mColorBackground);
             }
             if (mIconFilename != null) {
                 out.attribute(null, ATTR_TASKDESCRIPTIONICON_FILENAME, mIconFilename);
             }
             if (mIcon != null && mIcon.getType() == Icon.TYPE_RESOURCE) {
-                out.attribute(null, ATTR_TASKDESCRIPTIONICON_RESOURCE,
-                        Integer.toString(mIcon.getResId()));
+                out.attributeInt(null, ATTR_TASKDESCRIPTIONICON_RESOURCE, mIcon.getResId());
                 out.attribute(null, ATTR_TASKDESCRIPTIONICON_RESOURCE_PACKAGE,
                         mIcon.getResPackage());
             }
         }
 
         /** @hide */
-        public void restoreFromXml(XmlPullParser in) {
+        public void restoreFromXml(TypedXmlPullParser in) {
             final String label = in.getAttributeValue(null, ATTR_TASKDESCRIPTIONLABEL);
             if (label != null) {
                 setLabel(label);
             }
-            final String colorPrimary = in.getAttributeValue(null,
-                    ATTR_TASKDESCRIPTIONCOLOR_PRIMARY);
-            if (colorPrimary != null) {
-                setPrimaryColor((int) Long.parseLong(colorPrimary, 16));
+            final int colorPrimary = in.getAttributeIntHex(null,
+                    ATTR_TASKDESCRIPTIONCOLOR_PRIMARY, 0);
+            if (colorPrimary != 0) {
+                setPrimaryColor(colorPrimary);
             }
-            final String colorBackground = in.getAttributeValue(null,
-                    ATTR_TASKDESCRIPTIONCOLOR_BACKGROUND);
-            if (colorBackground != null) {
-                setBackgroundColor((int) Long.parseLong(colorBackground, 16));
+            final int colorBackground = in.getAttributeIntHex(null,
+                    ATTR_TASKDESCRIPTIONCOLOR_BACKGROUND, 0);
+            if (colorBackground != 0) {
+                setBackgroundColor(colorBackground);
             }
             final String iconFilename = in.getAttributeValue(null,
                     ATTR_TASKDESCRIPTIONICON_FILENAME);
             if (iconFilename != null) {
                 setIconFilename(iconFilename);
             }
-            final String iconResourceId = in.getAttributeValue(null,
-                    ATTR_TASKDESCRIPTIONICON_RESOURCE);
+            final int iconResourceId = in.getAttributeInt(null,
+                    ATTR_TASKDESCRIPTIONICON_RESOURCE, Resources.ID_NULL);
             final String iconResourcePackage = in.getAttributeValue(null,
                     ATTR_TASKDESCRIPTIONICON_RESOURCE_PACKAGE);
-            if (iconResourceId != null && iconResourcePackage != null) {
+            if (iconResourceId != Resources.ID_NULL && iconResourcePackage != null) {
                 setIcon(Icon.createWithResource(iconResourcePackage,
-                        Integer.parseInt(iconResourceId, 10)));
+                        iconResourceId));
             }
         }
 
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 2e08fc8..ed6dea8 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -85,6 +85,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.HardwareRenderer;
+import android.graphics.Rect;
 import android.graphics.Typeface;
 import android.hardware.display.DisplayManagerGlobal;
 import android.inputmethodservice.InputMethodService;
@@ -2154,7 +2155,7 @@
             }
             if (a != null) {
                 mNewActivities = null;
-                IActivityTaskManager am = ActivityTaskManager.getService();
+                final ActivityClient ac = ActivityClient.getInstance();
                 ActivityClientRecord prev;
                 do {
                     if (localLOGV) Slog.v(
@@ -2162,12 +2163,8 @@
                         " finished=" +
                         (a.activity != null && a.activity.mFinished));
                     if (a.activity != null && !a.activity.mFinished) {
-                        try {
-                            am.activityIdle(a.token, a.createdConfig, stopProfiling);
-                            a.createdConfig = null;
-                        } catch (RemoteException ex) {
-                            throw ex.rethrowFromSystemServer();
-                        }
+                        ac.activityIdle(a.token, a.createdConfig, stopProfiling);
+                        a.createdConfig = null;
                     }
                     prev = a;
                     a = a.nextIdle;
@@ -3576,13 +3573,7 @@
     }
 
     private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
-        final int displayId;
-        try {
-            displayId = ActivityTaskManager.getService().getDisplayId(r.token);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-
+        final int displayId = ActivityClient.getInstance().getDisplayId(r.token);
         ContextImpl appContext = ContextImpl.createActivityContext(
                 this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
 
@@ -3669,13 +3660,8 @@
             }
         } else {
             // If there was an error, for any reason, tell the activity manager to stop us.
-            try {
-                ActivityTaskManager.getService()
-                        .finishActivity(r.token, Activity.RESULT_CANCELED, null,
-                                Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
-            } catch (RemoteException ex) {
-                throw ex.rethrowFromSystemServer();
-            }
+            ActivityClient.getInstance().finishActivity(r.token, Activity.RESULT_CANCELED,
+                    null /* resultData */, Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
         }
 
         return a;
@@ -3705,12 +3691,8 @@
                 smallest.put(config.smallestScreenWidthDp, 0);
             }
         }
-        try {
-            ActivityTaskManager.getService().reportSizeConfigurations(r.token,
-                    horizontal.copyKeys(), vertical.copyKeys(), smallest.copyKeys());
-        } catch (RemoteException ex) {
-            throw ex.rethrowFromSystemServer();
-        }
+        ActivityClient.getInstance().reportSizeConfigurations(r.token, horizontal.copyKeys(),
+                vertical.copyKeys(), smallest.copyKeys());
     }
 
     private void deliverNewIntents(ActivityClientRecord r, List<ReferrerIntent> intents) {
@@ -4559,12 +4541,8 @@
         // then go ahead and add the window.
         boolean willBeVisible = !a.mStartedActivity;
         if (!willBeVisible) {
-            try {
-                willBeVisible = ActivityTaskManager.getService().willActivityBeVisible(
-                        a.getActivityToken());
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
+            willBeVisible = ActivityClient.getInstance().willActivityBeVisible(
+                    a.getActivityToken());
         }
         if (r.window == null && !a.mFinished && willBeVisible) {
             r.window = r.activity.getWindow();
@@ -5209,11 +5187,7 @@
             ((ContextImpl) c).scheduleFinalCleanup(r.activity.getClass().getName(), "Activity");
         }
         if (finishing) {
-            try {
-                ActivityTaskManager.getService().activityDestroyed(r.token);
-            } catch (RemoteException ex) {
-                throw ex.rethrowFromSystemServer();
-            }
+            ActivityClient.getInstance().activityDestroyed(r.token);
         }
         mSomeActivitiesChanged = true;
     }
@@ -5477,13 +5451,9 @@
 
     @Override
     public void reportRelaunch(ActivityClientRecord r, PendingTransactionActions pendingActions) {
-        try {
-            ActivityTaskManager.getService().activityRelaunched(r.token);
-            if (pendingActions.shouldReportRelaunchToWindowManager() && r.window != null) {
-                r.window.reportActivityRelaunched();
-            }
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+        ActivityClient.getInstance().activityRelaunched(r.token);
+        if (pendingActions.shouldReportRelaunchToWindowManager() && r.window != null) {
+            r.window.reportActivityRelaunched();
         }
     }
 
@@ -5623,10 +5593,13 @@
             // If the new config is the same as the config this Activity is already running with and
             // the override config also didn't change, then don't bother calling
             // onConfigurationChanged.
+            // TODO(b/173090263): Use diff instead after the improvement of AssetManager and
+            // ResourcesImpl constructions.
             final int diff = activity.mCurrentConfig.diffPublicOnly(newConfig);
-            if (diff == 0 && !movedToDifferentDisplay
-                    && mResourcesManager.isSameResourcesOverrideConfig(activityToken,
-                    amOverrideConfig)) {
+
+            if (diff == 0 && !shouldUpdateWindowMetricsBounds(activity.mCurrentConfig, newConfig)
+                    && !movedToDifferentDisplay && mResourcesManager.isSameResourcesOverrideConfig(
+                            activityToken, amOverrideConfig)) {
                 // Nothing significant, don't proceed with updating and reporting.
                 return null;
             } else if ((~activity.mActivityInfo.getRealConfigChanged() & diff) == 0) {
@@ -5678,6 +5651,26 @@
         return configToReport;
     }
 
+    // TODO(b/173090263): Remove this method after the improvement of AssetManager and ResourcesImpl
+    // constructions.
+    /**
+     * Returns {@code true} if the metrics reported by {@link android.view.WindowMetrics} APIs
+     * should be updated.
+     *
+     * @see WindowManager#getCurrentWindowMetrics()
+     * @see WindowManager#getMaximumWindowMetrics()
+     */
+    private static boolean shouldUpdateWindowMetricsBounds(@NonNull Configuration currentConfig,
+            @NonNull Configuration newConfig) {
+        final Rect currentBounds = currentConfig.windowConfiguration.getBounds();
+        final Rect newBounds = newConfig.windowConfiguration.getBounds();
+
+        final Rect currentMaxBounds = currentConfig.windowConfiguration.getMaxBounds();
+        final Rect newMaxBounds = newConfig.windowConfiguration.getMaxBounds();
+
+        return !currentBounds.equals(newBounds) || !currentMaxBounds.equals(newMaxBounds);
+    }
+
     public final void applyConfigurationToResources(Configuration config) {
         synchronized (mResourcesManager) {
             mResourcesManager.applyConfigurationToResourcesLocked(config, null);
@@ -5912,7 +5905,7 @@
     /**
      * Sets the supplied {@code overrideConfig} as pending for the {@code activityToken}. Calling
      * this method prevents any calls to
-     * {@link #handleActivityConfigurationChanged(IBinder, Configuration, int, boolean)} from
+     * {@link #handleActivityConfigurationChanged(ActivityClientRecord, Configuration, int)} from
      * processing any configurations older than {@code overrideConfig}.
      */
     @Override
@@ -5934,8 +5927,8 @@
 
     /**
      * Handle new activity configuration and/or move to a different display. This method is a noop
-     * if {@link #updatePendingActivityConfiguration(IBinder, Configuration)} has been called with
-     * a newer config than {@code overrideConfig}.
+     * if {@link #updatePendingActivityConfiguration(ActivityClientRecord, Configuration)} has been
+     * called with a newer config than {@code overrideConfig}.
      *
      * @param r Target activity record.
      * @param overrideConfig Activity override config.
@@ -6000,7 +5993,7 @@
 
     /**
      * Checks if the display id of activity is different from the given one. Note that
-     * {@link #INVALID_DISPLAY} means no difference.
+     * {@link Display#INVALID_DISPLAY} means no difference.
      */
     private static boolean isDifferentDisplay(@NonNull Activity activity, int displayId) {
         return displayId != INVALID_DISPLAY && displayId != activity.getDisplayId();
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 34437af..3642d31 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -30,6 +30,7 @@
 import android.annotation.StringRes;
 import android.annotation.UserIdInt;
 import android.annotation.XmlRes;
+import android.app.role.RoleManager;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -2306,20 +2307,14 @@
 
     @Override
     public String getDefaultBrowserPackageNameAsUser(int userId) {
-        try {
-            return mPermissionManager.getDefaultBrowser(userId);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        RoleManager roleManager = mContext.getSystemService(RoleManager.class);
+        return roleManager.getBrowserRoleHolder(userId);
     }
 
     @Override
     public boolean setDefaultBrowserPackageNameAsUser(String packageName, int userId) {
-        try {
-            return mPermissionManager.setDefaultBrowser(packageName, userId);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        RoleManager roleManager = mContext.getSystemService(RoleManager.class);
+        return roleManager.setBrowserRoleHolder(packageName, userId);
     }
 
     @Override
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index 298c455..a16f6a8 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -16,11 +16,15 @@
 
 package android.app;
 
+import android.annotation.IntDef;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.os.Build;
 import android.os.Bundle;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Helper class for building an options Bundle that can be used with
  * {@link android.content.Context#sendBroadcast(android.content.Intent)
@@ -30,6 +34,7 @@
 @SystemApi
 public class BroadcastOptions {
     private long mTemporaryAppWhitelistDuration;
+    private @TempAllowListType int mTemporaryAppWhitelistType;
     private int mMinManifestReceiverApiLevel = 0;
     private int mMaxManifestReceiverApiLevel = Build.VERSION_CODES.CUR_DEVELOPMENT;
     private boolean mDontSendToRestrictedApps = false;
@@ -42,6 +47,9 @@
     static final String KEY_TEMPORARY_APP_WHITELIST_DURATION
             = "android:broadcast.temporaryAppWhitelistDuration";
 
+    static final String KEY_TEMPORARY_APP_WHITELIST_TYPE
+            = "android:broadcast.temporaryAppWhitelistType";
+
     /**
      * Corresponds to {@link #setMinManifestReceiverApiLevel}.
      */
@@ -66,6 +74,27 @@
     static final String KEY_ALLOW_BACKGROUND_ACTIVITY_STARTS =
             "android:broadcast.allowBackgroundActivityStarts";
 
+    /**
+     * Allow the temp allowlist behavior, plus allow foreground service start from background.
+     */
+    public static final int TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED = 0;
+    /**
+     * Only allow the temp allowlist behavior, not allow foreground service start from
+     * background.
+     */
+    public static final int TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED = 1;
+
+    /**
+     * The list of temp allowlist types.
+     * @hide
+     */
+    @IntDef(flag = true, prefix = { "TEMPORARY_WHITELIST_TYPE_" }, value = {
+            TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+            TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface TempAllowListType {}
+
     public static BroadcastOptions makeBasic() {
         BroadcastOptions opts = new BroadcastOptions();
         return opts;
@@ -77,6 +106,7 @@
     /** @hide */
     public BroadcastOptions(Bundle opts) {
         mTemporaryAppWhitelistDuration = opts.getLong(KEY_TEMPORARY_APP_WHITELIST_DURATION);
+        mTemporaryAppWhitelistType = opts.getInt(KEY_TEMPORARY_APP_WHITELIST_TYPE);
         mMinManifestReceiverApiLevel = opts.getInt(KEY_MIN_MANIFEST_RECEIVER_API_LEVEL, 0);
         mMaxManifestReceiverApiLevel = opts.getInt(KEY_MAX_MANIFEST_RECEIVER_API_LEVEL,
                 Build.VERSION_CODES.CUR_DEVELOPMENT);
@@ -95,6 +125,22 @@
             android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND})
     public void setTemporaryAppWhitelistDuration(long duration) {
         mTemporaryAppWhitelistDuration = duration;
+        mTemporaryAppWhitelistType = TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
+    }
+
+    /**
+     * Set a duration for which the system should temporary place an application on the
+     * power allowlist when this broadcast is being delivered to it, specify the temp allowlist
+     * type.
+     * @param type one of {@link TempAllowListType}
+     * @param duration the duration in milliseconds; 0 means to not place on allowlist.
+     */
+    @RequiresPermission(anyOf = {android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
+            android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
+            android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND})
+    public void setTemporaryAppWhitelistDuration(@TempAllowListType int type, long duration) {
+        mTemporaryAppWhitelistDuration = duration;
+        mTemporaryAppWhitelistType = type;
     }
 
     /**
@@ -106,6 +152,14 @@
     }
 
     /**
+     * Return {@link #mTemporaryAppWhitelistType}.
+     * @hide
+     */
+    public @TempAllowListType int getTemporaryAppWhitelistType() {
+        return mTemporaryAppWhitelistType;
+    }
+
+    /**
      * Set the minimum target API level of receivers of the broadcast.  If an application
      * is targeting an API level less than this, the broadcast will not be delivered to
      * them.  This only applies to receivers declared in the app's AndroidManifest.xml.
@@ -190,6 +244,9 @@
         if (mTemporaryAppWhitelistDuration > 0) {
             b.putLong(KEY_TEMPORARY_APP_WHITELIST_DURATION, mTemporaryAppWhitelistDuration);
         }
+        if (mTemporaryAppWhitelistType != 0) {
+            b.putInt(KEY_TEMPORARY_APP_WHITELIST_TYPE, mTemporaryAppWhitelistType);
+        }
         if (mMinManifestReceiverApiLevel != 0) {
             b.putInt(KEY_MIN_MANIFEST_RECEIVER_API_LEVEL, mMinManifestReceiverApiLevel);
         }
diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl
new file mode 100644
index 0000000..f9449f2
--- /dev/null
+++ b/core/java/android/app/IActivityClientController.aidl
@@ -0,0 +1,108 @@
+/*
+ * 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.app.ActivityManager;
+import android.app.PictureInPictureParams;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.PersistableBundle;
+import android.view.RemoteAnimationDefinition;
+
+/**
+ * Interface for the callback and request from an activity to system.
+ *
+ * {@hide}
+ */
+interface IActivityClientController {
+    oneway void activityIdle(in IBinder token, in Configuration config, in boolean stopProfiling);
+    void activityResumed(in IBinder token);
+    void activityTopResumedStateLost();
+    void activityPaused(in IBinder token);
+    void activityStopped(in IBinder token, in Bundle state, in PersistableBundle persistentState,
+            in CharSequence description);
+    oneway void activityDestroyed(in IBinder token);
+    void activityRelaunched(in IBinder token);
+
+    void reportSizeConfigurations(in IBinder token, in int[] horizontalSizeConfiguration,
+            in int[] verticalSizeConfigurations, in int[] smallestWidthConfigurations);
+    boolean moveActivityTaskToBack(in IBinder token, boolean nonRoot);
+    boolean shouldUpRecreateTask(in IBinder token, in String destAffinity);
+    boolean navigateUpTo(in IBinder token, in Intent target, int resultCode,
+            in Intent resultData);
+    boolean releaseActivityInstance(in IBinder token);
+    boolean finishActivity(in IBinder token, int code, in Intent data, int finishTask);
+    boolean finishActivityAffinity(in IBinder token);
+    /** Finish all activities that were started for result from the specified activity. */
+    void finishSubActivity(in IBinder token, in String resultWho, int requestCode);
+
+    boolean isTopOfTask(in IBinder token);
+    boolean willActivityBeVisible(in IBinder token);
+    int getDisplayId(in IBinder activityToken);
+    int getTaskForActivity(in IBinder token, in boolean onlyRoot);
+    ComponentName getCallingActivity(in IBinder token);
+    String getCallingPackage(in IBinder token);
+    Bundle getActivityOptions(in IBinder token);
+
+    void setRequestedOrientation(in IBinder token, int requestedOrientation);
+    int getRequestedOrientation(in IBinder token);
+
+    boolean convertFromTranslucent(in IBinder token);
+    boolean convertToTranslucent(in IBinder token, in Bundle options);
+
+    boolean isImmersive(in IBinder token);
+    void setImmersive(in IBinder token, boolean immersive);
+
+    boolean enterPictureInPictureMode(in IBinder token, in PictureInPictureParams params);
+    void setPictureInPictureParams(in IBinder token, in PictureInPictureParams params);
+    void toggleFreeformWindowingMode(in IBinder token);
+
+    void startLockTaskModeByToken(in IBinder token);
+    void stopLockTaskModeByToken(in IBinder token);
+    oneway void showLockTaskEscapeMessage(in IBinder token);
+    void setTaskDescription(in IBinder token, in ActivityManager.TaskDescription values);
+
+    boolean showAssistFromActivity(in IBinder token, in Bundle args);
+    boolean isRootVoiceInteraction(in IBinder token);
+    void startLocalVoiceInteraction(in IBinder token, in Bundle options);
+    void stopLocalVoiceInteraction(in IBinder token);
+
+    void setShowWhenLocked(in IBinder token, boolean showWhenLocked);
+    void setInheritShowWhenLocked(in IBinder token, boolean setInheritShownWhenLocked);
+    void setTurnScreenOn(in IBinder token, boolean turnScreenOn);
+    void reportActivityFullyDrawn(in IBinder token, boolean restoredFromBundle);
+    void overridePendingTransition(in IBinder token, in String packageName,
+            int enterAnim, int exitAnim);
+    int setVrMode(in IBinder token, boolean enabled, in ComponentName packageName);
+
+    /** See {@link android.app.Activity#setDisablePreviewScreenshots}. */
+    void setDisablePreviewScreenshots(in IBinder token, boolean disable);
+
+    /** Registers remote animations for a specific activity. */
+    void registerRemoteAnimations(in IBinder token, in RemoteAnimationDefinition definition);
+
+    /** Unregisters all remote animations for a specific activity. */
+    void unregisterRemoteAnimations(in IBinder token);
+
+    /**
+     * Reports that an Activity received a back key press when there were no additional activities
+     * on the back stack.
+     */
+    void onBackPressedOnTaskRoot(in IBinder token);
+}
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index ab48bae..4b25573 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -22,6 +22,7 @@
 import android.app.ContentProviderHolder;
 import android.app.GrantedUriPermission;
 import android.app.IApplicationThread;
+import android.app.IActivityClientController;
 import android.app.IActivityController;
 import android.app.IAppTask;
 import android.app.IAssistDataReceiver;
@@ -35,7 +36,6 @@
 import android.app.IUserSwitchObserver;
 import android.app.Notification;
 import android.app.PendingIntent;
-import android.app.PictureInPictureParams;
 import android.app.ProfilerInfo;
 import android.app.WaitResult;
 import android.app.assist.AssistContent;
@@ -63,7 +63,6 @@
 import android.os.IBinder;
 import android.os.IProgressListener;
 import android.os.ParcelFileDescriptor;
-import android.os.PersistableBundle;
 import android.os.StrictMode;
 import android.os.WorkSource;
 import android.service.voice.IVoiceInteractionSession;
@@ -144,54 +143,25 @@
             int userId);
 
     void unhandledBack();
-    boolean finishActivity(in IBinder token, int code, in Intent data, int finishTask);
-    boolean finishActivityAffinity(in IBinder token);
 
-    oneway void activityIdle(in IBinder token, in Configuration config,
-            in boolean stopProfiling);
-    void activityResumed(in IBinder token);
-    void activityTopResumedStateLost();
-    void activityPaused(in IBinder token);
-    void activityStopped(in IBinder token, in Bundle state,
-            in PersistableBundle persistentState, in CharSequence description);
-    oneway void activityDestroyed(in IBinder token);
-    void activityRelaunched(in IBinder token);
+    /** Returns an interface to control the activity related operations. */
+    IActivityClientController getActivityClientController();
+
     int getFrontActivityScreenCompatMode();
     void setFrontActivityScreenCompatMode(int mode);
-    String getCallingPackage(in IBinder token);
-    ComponentName getCallingActivity(in IBinder token);
     void setFocusedTask(int taskId);
     boolean removeTask(int taskId);
     void removeAllVisibleRecentTasks();
     List<ActivityManager.RunningTaskInfo> getTasks(int maxNum, boolean filterOnlyVisibleRecents);
-    boolean shouldUpRecreateTask(in IBinder token, in String destAffinity);
-    boolean navigateUpTo(in IBinder token, in Intent target, int resultCode,
-            in Intent resultData);
     void moveTaskToFront(in IApplicationThread app, in String callingPackage, int task,
             int flags, in Bundle options);
-    int getTaskForActivity(in IBinder token, in boolean onlyRoot);
-    /** Finish all activities that were started for result from the specified activity. */
-    void finishSubActivity(in IBinder token, in String resultWho, int requestCode);
     ParceledListSlice<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum, int flags,
             int userId);
-    boolean willActivityBeVisible(in IBinder token);
-    void setRequestedOrientation(in IBinder token, int requestedOrientation);
-    int getRequestedOrientation(in IBinder token);
-    boolean convertFromTranslucent(in IBinder token);
-    boolean convertToTranslucent(in IBinder token, in Bundle options);
-    void notifyActivityDrawn(in IBinder token);
-    void reportActivityFullyDrawn(in IBinder token, boolean restoredFromBundle);
-    int getDisplayId(in IBinder activityToken);
-    boolean isImmersive(in IBinder token);
-    void setImmersive(in IBinder token, boolean immersive);
     boolean isTopActivityImmersive();
-    boolean moveActivityTaskToBack(in IBinder token, boolean nonRoot);
     ActivityManager.TaskDescription getTaskDescription(int taskId);
-    void overridePendingTransition(in IBinder token, in String packageName,
-            int enterAnim, int exitAnim);
     int getLaunchedFromUid(in IBinder activityToken);
     String getLaunchedFromPackage(in IBinder activityToken);
-    void reportAssistContextExtras(in IBinder token, in Bundle extras,
+    void reportAssistContextExtras(in IBinder assistToken, in Bundle extras,
             in AssistStructure structure, in AssistContent content, in Uri referrer);
 
     void setFocusedRootTask(int taskId);
@@ -199,24 +169,16 @@
     Rect getTaskBounds(int taskId);
 
     void cancelRecentsAnimation(boolean restoreHomeRootTaskPosition);
-    void startLockTaskModeByToken(in IBinder token);
-    void stopLockTaskModeByToken(in IBinder token);
     void updateLockTaskPackages(int userId, in String[] packages);
     boolean isInLockTaskMode();
     int getLockTaskModeState();
-    void setTaskDescription(in IBinder token, in ActivityManager.TaskDescription values);
-    Bundle getActivityOptions(in IBinder token);
     List<IBinder> getAppTasks(in String callingPackage);
     void startSystemLockTaskMode(int taskId);
     void stopSystemLockTaskMode();
     void finishVoiceTask(in IVoiceInteractionSession session);
-    boolean isTopOfTask(in IBinder token);
-    void notifyLaunchTaskBehindComplete(in IBinder token);
-    void notifyEnterAnimationComplete(in IBinder token);
     int addAppTask(in IBinder activityToken, in Intent intent,
             in ActivityManager.TaskDescription description, in Bitmap thumbnail);
     Point getAppTaskThumbnailSize();
-    boolean releaseActivityInstance(in IBinder token);
     /**
      * Only callable from the system. This token grants a temporary permission to call
      * #startActivityAsCallerWithToken. The token will time out after
@@ -236,7 +198,6 @@
     void registerTaskStackListener(in ITaskStackListener listener);
     void unregisterTaskStackListener(in ITaskStackListener listener);
     void setTaskResizeable(int taskId, int resizeableMode);
-    void toggleFreeformWindowingMode(in IBinder token);
 
     /**
      * Resize the task with given bounds
@@ -287,9 +248,6 @@
     boolean requestAutofillData(in IAssistDataReceiver receiver, in Bundle receiverExtras,
             in IBinder activityToken, int flags);
     boolean isAssistDataAllowedOnCurrentActivity();
-    boolean showAssistFromActivity(in IBinder token, in Bundle args);
-    boolean isRootVoiceInteraction(in IBinder token);
-    oneway void showLockTaskEscapeMessage(in IBinder token);
 
     /**
      * Notify the system that the keyguard is going away.
@@ -302,15 +260,9 @@
     ComponentName getActivityClassForToken(in IBinder token);
     String getPackageForToken(in IBinder token);
 
-    void reportSizeConfigurations(in IBinder token, in int[] horizontalSizeConfiguration,
-            in int[] verticalSizeConfigurations, in int[] smallestWidthConfigurations);
-
     void suppressResizeConfigChanges(boolean suppress);
     boolean moveTopActivityToPinnedRootTask(int rootTaskId, in Rect bounds);
-    boolean enterPictureInPictureMode(in IBinder token, in PictureInPictureParams params);
-    void setPictureInPictureParams(in IBinder token, in PictureInPictureParams params);
     void requestPictureInPictureMode(in IBinder token);
-    IBinder getUriPermissionOwnerForActivity(in IBinder activityToken);
 
     /**
      * Resizes the docked stack, and all other stacks as the result of the dock stack bounds change.
@@ -343,9 +295,6 @@
      * are changing the docked stack size.
      */
     void setSplitScreenResizing(boolean resizing);
-    int setVrMode(in IBinder token, boolean enabled, in ComponentName packageName);
-    void startLocalVoiceInteraction(in IBinder token, in Bundle options);
-    void stopLocalVoiceInteraction(in IBinder token);
     boolean supportsLocalVoiceInteraction();
 
     // Get device configuration
@@ -366,11 +315,6 @@
     ActivityManager.TaskSnapshot getTaskSnapshot(int taskId, boolean isLowResolution);
 
     /**
-     * See {@link android.app.Activity#setDisablePreviewScreenshots}
-     */
-    void setDisablePreviewScreenshots(IBinder token, boolean disable);
-
-    /**
      * It should only be called from home activity to remove its outdated snapshot. The home
      * snapshot is used to speed up entering home from screen off. If the content of home activity
      * is significantly different from before taking the snapshot, then the home activity can use
@@ -393,20 +337,6 @@
     boolean updateConfiguration(in Configuration values);
     void updateLockTaskFeatures(int userId, int flags);
 
-    void setShowWhenLocked(in IBinder token, boolean showWhenLocked);
-    void setInheritShowWhenLocked(in IBinder token, boolean setInheritShownWhenLocked);
-    void setTurnScreenOn(in IBinder token, boolean turnScreenOn);
-
-    /**
-     * Registers remote animations for a specific activity.
-     */
-    void registerRemoteAnimations(in IBinder token, in RemoteAnimationDefinition definition);
-
-    /**
-     * Unregisters all remote animations for a specific activity.
-     */
-    void unregisterRemoteAnimations(in IBinder token);
-
     /**
      * Registers a remote animation to be run for all activity starts from a certain package during
      * a short predefined amount of time.
@@ -448,10 +378,4 @@
      * @param activityToken The token of the target activity to restart.
      */
     void restartActivityProcessIfVisible(in IBinder activityToken);
-
-    /**
-     * Reports that an Activity received a back key press when there were no additional activities
-     * on the back stack.
-     */
-    void onBackPressedOnTaskRoot(in IBinder activityToken);
 }
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 6535387a..99785e1 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1284,7 +1284,7 @@
                 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                 throw new RuntimeException(
                     "Unable to instantiate application " + appClass
-                    + ": " + e.toString(), e);
+                    + " package " + mPackageName + ": " + e.toString(), e);
             }
         }
         mActivityThread.mAllApplications.add(app);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index a113580..82f61a4 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -83,6 +83,7 @@
 import android.util.Pair;
 import android.util.SparseArray;
 import android.util.proto.ProtoOutputStream;
+import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
@@ -6120,8 +6121,11 @@
             int defaultColor = mInNightMode ? Color.BLACK : Color.WHITE;
             Resources.Theme theme = mContext.getTheme();
             if (theme == null) {
+                // Running unit tests with mocked context
                 return defaultColor;
             }
+            theme = new ContextThemeWrapper(mContext, R.style.Theme_DeviceDefault_DayNight)
+                    .getTheme();
             TypedArray ta = theme.obtainStyledAttributes(new int[]{R.attr.colorBackground});
             if (ta == null) {
                 return defaultColor;
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 080aac9..b1a8f9b 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -32,9 +32,12 @@
 import android.provider.Settings;
 import android.service.notification.NotificationListenerService;
 import android.text.TextUtils;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.util.Preconditions;
+import com.android.internal.util.XmlUtils;
 
 import org.json.JSONException;
 import org.json.JSONObject;
@@ -869,7 +872,7 @@
      * @hide
      */
     public void populateFromXmlForRestore(XmlPullParser parser, Context context) {
-        populateFromXml(parser, true, context);
+        populateFromXml(XmlUtils.makeTyped(parser), true, context);
     }
 
     /**
@@ -877,13 +880,13 @@
      */
     @SystemApi
     public void populateFromXml(XmlPullParser parser) {
-        populateFromXml(parser, false, null);
+        populateFromXml(XmlUtils.makeTyped(parser), false, null);
     }
 
     /**
      * If {@param forRestore} is true, {@param Context} MUST be non-null.
      */
-    private void populateFromXml(XmlPullParser parser, boolean forRestore,
+    private void populateFromXml(TypedXmlPullParser parser, boolean forRestore,
             @Nullable Context context) {
         Preconditions.checkArgument(!forRestore || context != null,
                 "forRestore is true but got null context");
@@ -941,14 +944,14 @@
      */
     @SystemApi
     public void writeXml(XmlSerializer out) throws IOException {
-        writeXml(out, false, null);
+        writeXml(XmlUtils.makeTyped(out), false, null);
     }
 
     /**
      * @hide
      */
     public void writeXmlForBackup(XmlSerializer out, Context context) throws IOException {
-        writeXml(out, true, context);
+        writeXml(XmlUtils.makeTyped(out), true, context);
     }
 
     private Uri getSoundForBackup(Context context) {
@@ -967,7 +970,7 @@
     /**
      * If {@param forBackup} is true, {@param Context} MUST be non-null.
      */
-    private void writeXml(XmlSerializer out, boolean forBackup, @Nullable Context context)
+    private void writeXml(TypedXmlSerializer out, boolean forBackup, @Nullable Context context)
             throws IOException {
         Preconditions.checkArgument(!forBackup || context != null,
                 "forBackup is true but got null context");
@@ -980,62 +983,58 @@
             out.attribute(null, ATT_DESC, getDescription());
         }
         if (getImportance() != DEFAULT_IMPORTANCE) {
-            out.attribute(
-                    null, ATT_IMPORTANCE, Integer.toString(getImportance()));
+            out.attributeInt(null, ATT_IMPORTANCE, getImportance());
         }
         if (canBypassDnd()) {
-            out.attribute(
-                    null, ATT_PRIORITY, Integer.toString(Notification.PRIORITY_MAX));
+            out.attributeInt(null, ATT_PRIORITY, Notification.PRIORITY_MAX);
         }
         if (getLockscreenVisibility() != DEFAULT_VISIBILITY) {
-            out.attribute(null, ATT_VISIBILITY,
-                    Integer.toString(getLockscreenVisibility()));
+            out.attributeInt(null, ATT_VISIBILITY, getLockscreenVisibility());
         }
         Uri sound = forBackup ? getSoundForBackup(context) : getSound();
         if (sound != null) {
             out.attribute(null, ATT_SOUND, sound.toString());
         }
         if (getAudioAttributes() != null) {
-            out.attribute(null, ATT_USAGE, Integer.toString(getAudioAttributes().getUsage()));
-            out.attribute(null, ATT_CONTENT_TYPE,
-                    Integer.toString(getAudioAttributes().getContentType()));
-            out.attribute(null, ATT_FLAGS, Integer.toString(getAudioAttributes().getFlags()));
+            out.attributeInt(null, ATT_USAGE, getAudioAttributes().getUsage());
+            out.attributeInt(null, ATT_CONTENT_TYPE, getAudioAttributes().getContentType());
+            out.attributeInt(null, ATT_FLAGS, getAudioAttributes().getFlags());
         }
         if (shouldShowLights()) {
-            out.attribute(null, ATT_LIGHTS, Boolean.toString(shouldShowLights()));
+            out.attributeBoolean(null, ATT_LIGHTS, shouldShowLights());
         }
         if (getLightColor() != DEFAULT_LIGHT_COLOR) {
-            out.attribute(null, ATT_LIGHT_COLOR, Integer.toString(getLightColor()));
+            out.attributeInt(null, ATT_LIGHT_COLOR, getLightColor());
         }
         if (shouldVibrate()) {
-            out.attribute(null, ATT_VIBRATION_ENABLED, Boolean.toString(shouldVibrate()));
+            out.attributeBoolean(null, ATT_VIBRATION_ENABLED, shouldVibrate());
         }
         if (getVibrationPattern() != null) {
             out.attribute(null, ATT_VIBRATION, longArrayToString(getVibrationPattern()));
         }
         if (getUserLockedFields() != 0) {
-            out.attribute(null, ATT_USER_LOCKED, Integer.toString(getUserLockedFields()));
+            out.attributeInt(null, ATT_USER_LOCKED, getUserLockedFields());
         }
         if (isFgServiceShown()) {
-            out.attribute(null, ATT_FG_SERVICE_SHOWN, Boolean.toString(isFgServiceShown()));
+            out.attributeBoolean(null, ATT_FG_SERVICE_SHOWN, isFgServiceShown());
         }
         if (canShowBadge()) {
-            out.attribute(null, ATT_SHOW_BADGE, Boolean.toString(canShowBadge()));
+            out.attributeBoolean(null, ATT_SHOW_BADGE, canShowBadge());
         }
         if (isDeleted()) {
-            out.attribute(null, ATT_DELETED, Boolean.toString(isDeleted()));
+            out.attributeBoolean(null, ATT_DELETED, isDeleted());
         }
         if (getGroup() != null) {
             out.attribute(null, ATT_GROUP, getGroup());
         }
         if (isBlockable()) {
-            out.attribute(null, ATT_BLOCKABLE_SYSTEM, Boolean.toString(isBlockable()));
+            out.attributeBoolean(null, ATT_BLOCKABLE_SYSTEM, isBlockable());
         }
         if (getAllowBubbles() != DEFAULT_ALLOW_BUBBLE) {
-            out.attribute(null, ATT_ALLOW_BUBBLE, Integer.toString(getAllowBubbles()));
+            out.attributeInt(null, ATT_ALLOW_BUBBLE, getAllowBubbles());
         }
         if (getOriginalImportance() != DEFAULT_IMPORTANCE) {
-            out.attribute(null, ATT_ORIG_IMP, Integer.toString(getOriginalImportance()));
+            out.attributeInt(null, ATT_ORIG_IMP, getOriginalImportance());
         }
         if (getParentChannelId() != null) {
             out.attribute(null, ATT_PARENT_CHANNEL, getParentChannelId());
@@ -1044,10 +1043,10 @@
             out.attribute(null, ATT_CONVERSATION_ID, getConversationId());
         }
         if (isDemoted()) {
-            out.attribute(null, ATT_DEMOTE, Boolean.toString(isDemoted()));
+            out.attributeBoolean(null, ATT_DEMOTE, isDemoted());
         }
         if (isImportantConversation()) {
-            out.attribute(null, ATT_IMP_CONVERSATION, Boolean.toString(isImportantConversation()));
+            out.attributeBoolean(null, ATT_IMP_CONVERSATION, isImportantConversation());
         }
 
         // mImportanceLockedDefaultApp and mImportanceLockedByOEM have a different source of
@@ -1099,7 +1098,7 @@
         return record;
     }
 
-    private static AudioAttributes safeAudioAttributes(XmlPullParser parser) {
+    private static AudioAttributes safeAudioAttributes(TypedXmlPullParser parser) {
         int usage = safeInt(parser, ATT_USAGE, AudioAttributes.USAGE_NOTIFICATION);
         int contentType = safeInt(parser, ATT_CONTENT_TYPE,
                 AudioAttributes.CONTENT_TYPE_SONIFICATION);
@@ -1111,32 +1110,20 @@
                 .build();
     }
 
-    private static Uri safeUri(XmlPullParser parser, String att) {
+    private static Uri safeUri(TypedXmlPullParser parser, String att) {
         final String val = parser.getAttributeValue(null, att);
         return val == null ? null : Uri.parse(val);
     }
 
-    private static int safeInt(XmlPullParser parser, String att, int defValue) {
-        final String val = parser.getAttributeValue(null, att);
-        return tryParseInt(val, defValue);
+    private static int safeInt(TypedXmlPullParser parser, String att, int defValue) {
+        return parser.getAttributeInt(null, att, defValue);
     }
 
-    private static int tryParseInt(String value, int defValue) {
-        if (TextUtils.isEmpty(value)) return defValue;
-        try {
-            return Integer.parseInt(value);
-        } catch (NumberFormatException e) {
-            return defValue;
-        }
+    private static boolean safeBool(TypedXmlPullParser parser, String att, boolean defValue) {
+        return parser.getAttributeBoolean(null, att, defValue);
     }
 
-    private static boolean safeBool(XmlPullParser parser, String att, boolean defValue) {
-        final String value = parser.getAttributeValue(null, att);
-        if (TextUtils.isEmpty(value)) return defValue;
-        return Boolean.parseBoolean(value);
-    }
-
-    private static long[] safeLongArray(XmlPullParser parser, String att, long[] defValue) {
+    private static long[] safeLongArray(TypedXmlPullParser parser, String att, long[] defValue) {
         final String attributeValue = parser.getAttributeValue(null, att);
         if (TextUtils.isEmpty(attributeValue)) return defValue;
         String[] values = attributeValue.split(DELIMITER);
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
index ec7fa33..cd6df0b 100644
--- a/core/java/android/app/NotificationChannelGroup.java
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -23,12 +23,12 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.proto.ProtoOutputStream;
 
 import org.json.JSONException;
 import org.json.JSONObject;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -228,22 +228,16 @@
     /**
      * @hide
      */
-    public void populateFromXml(XmlPullParser parser) {
+    public void populateFromXml(TypedXmlPullParser parser) {
         // Name, id, and importance are set in the constructor.
         setDescription(parser.getAttributeValue(null, ATT_DESC));
-        setBlocked(safeBool(parser, ATT_BLOCKED, false));
-    }
-
-    private static boolean safeBool(XmlPullParser parser, String att, boolean defValue) {
-        final String value = parser.getAttributeValue(null, att);
-        if (TextUtils.isEmpty(value)) return defValue;
-        return Boolean.parseBoolean(value);
+        setBlocked(parser.getAttributeBoolean(null, ATT_BLOCKED, false));
     }
 
     /**
      * @hide
      */
-    public void writeXml(XmlSerializer out) throws IOException {
+    public void writeXml(TypedXmlSerializer out) throws IOException {
         out.startTag(null, TAG_GROUP);
 
         out.attribute(null, ATT_ID, getId());
@@ -253,8 +247,8 @@
         if (getDescription() != null) {
             out.attribute(null, ATT_DESC, getDescription().toString());
         }
-        out.attribute(null, ATT_BLOCKED, Boolean.toString(isBlocked()));
-        out.attribute(null, ATT_USER_LOCKED, Integer.toString(mUserLockedFields));
+        out.attributeBoolean(null, ATT_BLOCKED, isBlocked());
+        out.attributeInt(null, ATT_USER_LOCKED, mUserLockedFields);
 
         out.endTag(null, TAG_GROUP);
     }
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 12460ba..da7a29f 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1501,7 +1501,8 @@
     }
 
     /** @hide */
-    public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {
+    @TestApi
+    public boolean isNotificationPolicyAccessGrantedForPackage(@NonNull String pkg) {
         INotificationManager service = getService();
         try {
             return service.isNotificationPolicyAccessGrantedForPackage(pkg);
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
new file mode 100644
index 0000000..633d093
--- /dev/null
+++ b/core/java/android/app/OWNERS
@@ -0,0 +1 @@
+per-file *Zygote* = file:/ZYGOTE_OWNERS
diff --git a/core/java/android/app/PictureInPictureParams.java b/core/java/android/app/PictureInPictureParams.java
index 32252a3f..29c9c67 100644
--- a/core/java/android/app/PictureInPictureParams.java
+++ b/core/java/android/app/PictureInPictureParams.java
@@ -26,6 +26,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Represents a set of parameters used to initialize and update an Activity in picture-in-picture
@@ -194,6 +195,16 @@
     }
 
     /**
+     * Makes a copy from the other picture-in-picture args.
+     * @hide
+     */
+    public PictureInPictureParams(PictureInPictureParams other) {
+        this(other.mAspectRatio, other.mUserActions,
+                other.hasSourceBoundsHint() ? new Rect(other.getSourceRectHint()) : null,
+                other.mAutoEnterEnabled);
+    }
+
+    /**
      * Copies the set parameters from the other picture-in-picture args.
      * @hide
      */
@@ -297,6 +308,22 @@
     }
 
     @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof PictureInPictureParams)) return false;
+        PictureInPictureParams that = (PictureInPictureParams) o;
+        return mAutoEnterEnabled == that.mAutoEnterEnabled
+                && Objects.equals(mAspectRatio, that.mAspectRatio)
+                && Objects.equals(mUserActions, that.mUserActions)
+                && Objects.equals(mSourceRectHint, that.mSourceRectHint);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mAspectRatio, mUserActions, mSourceRectHint, mAutoEnterEnabled);
+    }
+
+    @Override
     public int describeContents() {
         return 0;
     }
diff --git a/core/java/android/app/RemoteAction.java b/core/java/android/app/RemoteAction.java
index 5a4244f..26f324b 100644
--- a/core/java/android/app/RemoteAction.java
+++ b/core/java/android/app/RemoteAction.java
@@ -23,6 +23,7 @@
 import android.text.TextUtils;
 
 import java.io.PrintWriter;
+import java.util.Objects;
 
 /**
  * Represents a remote action that can be called from another process.  The action can have an
@@ -127,6 +128,25 @@
     }
 
     @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof RemoteAction)) return false;
+        RemoteAction that = (RemoteAction) o;
+        return mEnabled == that.mEnabled
+                && mShouldShowIcon == that.mShouldShowIcon
+                && mIcon.equals(that.mIcon)
+                && mTitle.equals(that.mTitle)
+                && mContentDescription.equals(that.mContentDescription)
+                && mActionIntent.equals(that.mActionIntent);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mIcon, mTitle, mContentDescription, mActionIntent, mEnabled,
+                mShouldShowIcon);
+    }
+
+    @Override
     public int describeContents() {
         return 0;
     }
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 36d5b5e..772833cc 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -1178,6 +1178,8 @@
                         continue;
                     }
 
+                    // TODO(b/173090263): Improve the performance of AssetManager & ResourcesImpl
+                    // constructions.
                     final ResourcesImpl resourcesImpl =
                             findOrCreateResourcesImplForKeyLocked(newKey);
                     if (resourcesImpl != null && resourcesImpl != resources.getImpl()) {
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index 36241a8..61e93f7 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -70,6 +70,18 @@
             "name": "CtsAutoFillServiceTestCases",
             "options": [
                 {
+                    "include-filter": "android.autofillservice.cts.saveui.AutofillSaveDialogTest"
+                },
+                {
+                    "exclude-annotation": "androidx.test.filters.FlakyTest"
+                }
+            ],
+            "file_patterns": ["(/|^)Activity.java"]
+        },
+        {
+            "name": "CtsAutoFillServiceTestCases",
+            "options": [
+                {
                     "include-filter": "android.autofillservice.cts.saveui.PreSimpleSaveActivityTest"
                 },
                 {
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 1a8a4b7..8367bde 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -313,7 +313,7 @@
                 && isResizeable == that.isResizeable
                 && Objects.equals(positionInParent, that.positionInParent)
                 && equalsLetterboxParams(that)
-                && pictureInPictureParams == that.pictureInPictureParams
+                && Objects.equals(pictureInPictureParams, that.pictureInPictureParams)
                 && getWindowingMode() == that.getWindowingMode()
                 && Objects.equals(taskDescription, that.taskDescription)
                 && isFocused == that.isFocused
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index 1ee8e4f..41256d0 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -37,11 +37,12 @@
 import android.util.Log;
 import android.util.Printer;
 import android.util.SparseArray;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -472,16 +473,15 @@
     }
 
     /** @hide */
-    public void writePoliciesToXml(XmlSerializer out)
+    public void writePoliciesToXml(TypedXmlSerializer out)
             throws IllegalArgumentException, IllegalStateException, IOException {
-        out.attribute(null, "flags", Integer.toString(mUsesPolicies));
+        out.attributeInt(null, "flags", mUsesPolicies);
     }
 
     /** @hide */
-    public void readPoliciesFromXml(XmlPullParser parser)
+    public void readPoliciesFromXml(TypedXmlPullParser parser)
             throws XmlPullParserException, IOException {
-        mUsesPolicies = Integer.parseInt(
-                parser.getAttributeValue(null, "flags"));
+        mUsesPolicies = parser.getAttributeInt(null, "flags");
     }
 
     public void dump(Printer pw, String prefix) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 5eb1922..4095acc 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -39,6 +39,7 @@
 import android.app.Activity;
 import android.app.IServiceConnection;
 import android.app.KeyguardManager;
+import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
 import android.app.admin.SecurityLog.SecurityEvent;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
@@ -1206,7 +1207,7 @@
      * <ul>
      * <li>By the admin app when performing the admin-integrated
      * provisioning flow as a result of the {@link #ACTION_GET_PROVISIONING_MODE} activity</li>
-     * <li>With intent action {@link #ACTION_PROVISION_MANAGED_DEVICE}</li>
+     * <li>For managed account enrollment</li>
      * </ul>
      *
      * <p>If the education screens are skipped, it is the admin application's responsibility
@@ -1229,9 +1230,37 @@
             "android.app.extra.PROVISIONING_USE_MOBILE_DATA";
 
     /**
+     * Possible values for {@link #EXTRA_PROVISIONING_TRIGGER}.
+     *
+     * @hide
+     */
+    @IntDef(prefix = { "PROVISIONING_TRIGGER_" }, value = {
+            PROVISIONING_TRIGGER_UNSPECIFIED,
+            PROVISIONING_TRIGGER_CLOUD_ENROLLMENT,
+            PROVISIONING_TRIGGER_QR_CODE,
+            PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER,
+            PROVISIONING_TRIGGER_MANAGED_ACCOUNT
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ProvisioningTrigger {}
+
+    /**
+     * Possible values for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES}.
+     *
+     * @hide
+     */
+    @IntDef(prefix = { "SUPPORTED_MODES_" }, value = {
+            SUPPORTED_MODES_ORGANIZATION_OWNED,
+            SUPPORTED_MODES_PERSONALLY_OWNED,
+            SUPPORTED_MODES_ORGANIZATION_AND_PERSONALLY_OWNED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ProvisioningConfiguration {}
+
+    /**
      * A String extra holding the provisioning trigger. It could be one of
      * {@link #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT}, {@link #PROVISIONING_TRIGGER_QR_CODE},
-     * {@link #PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER} or {@link
+     * {@link #PROVISIONING_TRIGGER_MANAGED_ACCOUNT} or {@link
      * #PROVISIONING_TRIGGER_UNSPECIFIED}.
      *
      * <p>Use in an intent with action {@link
@@ -1247,7 +1276,7 @@
      * trigger has not been specified.
      * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT
      * @see #PROVISIONING_TRIGGER_QR_CODE
-     * @see #PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER
+     * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT
      * @hide
      */
     @SystemApi
@@ -1257,7 +1286,7 @@
      * A value for {@link #EXTRA_PROVISIONING_TRIGGER} indicating that the provisioning
      * trigger is cloud enrollment.
      * @see #PROVISIONING_TRIGGER_QR_CODE
-     * @see #PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER
+     * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT
      * @see #PROVISIONING_TRIGGER_UNSPECIFIED
      * @hide
      */
@@ -1268,7 +1297,7 @@
      * A value for {@link #EXTRA_PROVISIONING_TRIGGER} indicating that the provisioning
      * trigger is the QR code scanner.
      * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT
-     * @see #PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER
+     * @see #PROVISIONING_TRIGGER_MANAGED_ACCOUNT
      * @see #PROVISIONING_TRIGGER_UNSPECIFIED
      * @hide
      */
@@ -1278,15 +1307,78 @@
     /**
      * A value for {@link #EXTRA_PROVISIONING_TRIGGER} indicating that the provisioning
      * trigger is persistent device owner enrollment.
+     * @deprecated Use the broader {@link #PROVISIONING_TRIGGER_MANAGED_ACCOUNT} instead
      * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT
      * @see #PROVISIONING_TRIGGER_QR_CODE
      * @see #PROVISIONING_TRIGGER_UNSPECIFIED
      * @hide
      */
     @SystemApi
+    @Deprecated
     public static final int PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER = 3;
 
     /**
+     * A value for {@link #EXTRA_PROVISIONING_TRIGGER} indicating that the provisioning
+     * trigger is managed account enrollment.
+     * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT
+     * @see #PROVISIONING_TRIGGER_QR_CODE
+     * @see #PROVISIONING_TRIGGER_UNSPECIFIED
+     * @hide
+     */
+    @SystemApi
+    public static final int PROVISIONING_TRIGGER_MANAGED_ACCOUNT = 4;
+
+    /**
+     * A value for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that provisioning is
+     * organization-owned.
+     *
+     * <p>Using this value will cause the admin app's {@link #ACTION_GET_PROVISIONING_MODE}
+     * activity to have the {@link #EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES} array extra
+     * contain {@link #PROVISIONING_MODE_MANAGED_PROFILE} and {@link
+     * #PROVISIONING_MODE_FULLY_MANAGED_DEVICE}.
+     *
+     * <p>Also, if this value is set, the admin app's {@link #ACTION_GET_PROVISIONING_MODE} activity
+     * will not receive the {@link #EXTRA_PROVISIONING_IMEI} and {@link
+     * #EXTRA_PROVISIONING_SERIAL_NUMBER} extras.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int SUPPORTED_MODES_ORGANIZATION_OWNED = 1;
+
+    /**
+     * A value for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that provisioning is
+     * personally-owned.
+     *
+     * <p>Using this value will cause the admin app's {@link #ACTION_GET_PROVISIONING_MODE}
+     * activity to have the {@link #EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES} array extra
+     * contain only {@link #PROVISIONING_MODE_MANAGED_PROFILE}.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int SUPPORTED_MODES_PERSONALLY_OWNED = 2;
+
+    /**
+     * A value for {@link #EXTRA_PROVISIONING_SUPPORTED_MODES} indicating that provisioning could
+     * be organization-owned or personally-owned.
+     *
+     * <p>Using this value will cause the admin app's {@link #ACTION_GET_PROVISIONING_MODE}
+     * activity to have the {@link #EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES} array extra
+     * contain {@link
+     * #PROVISIONING_MODE_MANAGED_PROFILE}, {@link #PROVISIONING_MODE_FULLY_MANAGED_DEVICE} and
+     * {@link #PROVISIONING_MODE_MANAGED_PROFILE_ON_PERSONAL_DEVICE}.
+     *
+     * <p>Also, if this value is set, the admin app's {@link #ACTION_GET_PROVISIONING_MODE} activity
+     * will not receive the {@link #EXTRA_PROVISIONING_IMEI} and {@link
+     * #EXTRA_PROVISIONING_SERIAL_NUMBER} extras.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int SUPPORTED_MODES_ORGANIZATION_AND_PERSONALLY_OWNED = 3;
+
+    /**
      * This MIME type is used for starting the device owner provisioning.
      *
      * <p>During device owner provisioning a device admin app is set as the owner of the device.
@@ -2379,16 +2471,57 @@
 
     /**
      * An intent extra holding the provisioning mode returned by the administrator.
-     * The value for this extra should be one of the following:
-     * <ul>
-     *     <li>{@link #PROVISIONING_MODE_FULLY_MANAGED_DEVICE}</li>
-     *     <li>{@link #PROVISIONING_MODE_MANAGED_PROFILE}</li>
-     * </ul>
+     * The value of this extra must be one of the values provided in {@link
+     * #EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES}, which is provided as an intent extra to
+     * the admin app's {@link #ACTION_GET_PROVISIONING_MODE} activity.
+     *
+     * @see #PROVISIONING_MODE_FULLY_MANAGED_DEVICE
+     * @see #PROVISIONING_MODE_MANAGED_PROFILE
      */
     public static final String EXTRA_PROVISIONING_MODE =
             "android.app.extra.PROVISIONING_MODE";
 
     /**
+     * An integer extra indication what provisioning modes should be available for the admin app
+     * to pick.
+     *
+     * <p>The default value is {@link #SUPPORTED_MODES_ORGANIZATION_OWNED}.
+     *
+     * <p>The value of this extra will determine the contents of the {@link
+     * #EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES} array that is passed to the admin app as an
+     * extra to its {@link #ACTION_GET_PROVISIONING_MODE} activity.
+     *
+     * <p>If one of the possible admin app choices is a personally-owned work profile, then the
+     * IMEI and serial number will not be passed to the admin app's {@link
+     * #ACTION_GET_PROVISIONING_MODE} activity via the {@link #EXTRA_PROVISIONING_IMEI} and {@link
+     * #EXTRA_PROVISIONING_SERIAL_NUMBER} respectively.
+     *
+     * <p>This extra is only respected when provided alongside the {@link
+     * #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE} intent action.
+     *
+     * @see #SUPPORTED_MODES_ORGANIZATION_OWNED
+     * @see #SUPPORTED_MODES_PERSONALLY_OWNED
+     * @see #SUPPORTED_MODES_ORGANIZATION_AND_PERSONALLY_OWNED
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_PROVISIONING_SUPPORTED_MODES =
+            "android.app.extra.PROVISIONING_SUPPORTED_MODES";
+
+    /**
+     * An {@link ArrayList} of {@link Integer} extra specifying the allowed provisioning modes.
+     * <p>This extra will be passed to the admin app's {@link #ACTION_GET_PROVISIONING_MODE}
+     * activity, whose result intent must contain {@link #EXTRA_PROVISIONING_MODE} set to one of
+     * the values in this array.
+     * <p>If the value set to {@link #EXTRA_PROVISIONING_MODE} is not in the array,
+     * provisioning will fail.
+     * @see #PROVISIONING_MODE_MANAGED_PROFILE
+     * @see #PROVISIONING_MODE_FULLY_MANAGED_DEVICE
+     */
+    public static final String EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES =
+            "android.app.extra.PROVISIONING_ALLOWED_PROVISIONING_MODES";
+
+    /**
      * The provisioning mode for fully managed device.
      */
     public static final int PROVISIONING_MODE_FULLY_MANAGED_DEVICE = 1;
@@ -2399,6 +2532,11 @@
     public static final int PROVISIONING_MODE_MANAGED_PROFILE = 2;
 
     /**
+     * The provisioning mode for a work profile on a personal device.
+     */
+    public static final int PROVISIONING_MODE_MANAGED_PROFILE_ON_PERSONAL_DEVICE = 3;
+
+    /**
      * Activity action: Starts the administrator to show policy compliance for the provisioning.
      * This action is used any time that the administrator has an opportunity to show policy
      * compliance before the end of setup wizard. This could happen as part of the admin-integrated
@@ -2454,27 +2592,27 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface PersonalAppsSuspensionReason {}
 
-    // TODO(b/172376923) - make all (or none) @TestApi
-
     /** @hide */
     @TestApi
     public static final int OPERATION_LOCK_NOW = 1;
-
     /** @hide */
+    @TestApi
     public static final int OPERATION_SWITCH_USER = 2;
     /** @hide */
+    @TestApi
     public static final int OPERATION_START_USER_IN_BACKGROUND = 3;
     /** @hide */
+    @TestApi
     public static final int OPERATION_STOP_USER = 4;
     /** @hide */
+    @TestApi
     public static final int OPERATION_CREATE_AND_MANAGE_USER = 5;
     /** @hide */
+    @TestApi
     public static final int OPERATION_REMOVE_USER = 6;
 
     private static final String PREFIX_OPERATION = "OPERATION_";
 
-
-    // TODO(b/172376923) - add all operations
     /** @hide */
     @IntDef(prefix = PREFIX_OPERATION, value = {
             OPERATION_LOCK_NOW,
@@ -2489,6 +2627,8 @@
     }
 
     /** @hide */
+    @TestApi
+    @NonNull
     public static String operationToString(@DevicePolicyOperation int operation) {
         return DebugUtils.constantToString(DevicePolicyManager.class, PREFIX_OPERATION, operation);
     }
@@ -12397,4 +12537,21 @@
         }
         return false;
     }
+
+    /**
+     * Used by CTS to set the result of the next safety operation check.
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS)
+    public void setNextOperationSafety(@DevicePolicyOperation int operation, boolean safe) {
+        if (mService != null) {
+            try {
+                mService.setNextOperationSafety(operation, safe);
+            } catch (RemoteException re) {
+                throw re.rethrowFromSystemServer();
+            }
+        }
+    }
 }
diff --git a/core/java/android/app/admin/FactoryResetProtectionPolicy.java b/core/java/android/app/admin/FactoryResetProtectionPolicy.java
index aa94e81..40ae1f0 100644
--- a/core/java/android/app/admin/FactoryResetProtectionPolicy.java
+++ b/core/java/android/app/admin/FactoryResetProtectionPolicy.java
@@ -26,10 +26,10 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 
-import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -201,10 +201,10 @@
      * @hide
      */
     @Nullable
-    public static FactoryResetProtectionPolicy readFromXml(@NonNull XmlPullParser parser) {
+    public static FactoryResetProtectionPolicy readFromXml(@NonNull TypedXmlPullParser parser) {
         try {
-            boolean factoryResetProtectionEnabled = Boolean.parseBoolean(
-                    parser.getAttributeValue(null, KEY_FACTORY_RESET_PROTECTION_ENABLED));
+            boolean factoryResetProtectionEnabled = parser.getAttributeBoolean(null,
+                    KEY_FACTORY_RESET_PROTECTION_ENABLED, false);
 
             List<String> factoryResetProtectionAccounts = new ArrayList<>();
             int outerDepth = parser.getDepth();
@@ -232,9 +232,9 @@
     /**
      * @hide
      */
-    public void writeToXml(@NonNull XmlSerializer out) throws IOException {
-        out.attribute(null, KEY_FACTORY_RESET_PROTECTION_ENABLED,
-                Boolean.toString(mFactoryResetProtectionEnabled));
+    public void writeToXml(@NonNull TypedXmlSerializer out) throws IOException {
+        out.attributeBoolean(null, KEY_FACTORY_RESET_PROTECTION_ENABLED,
+                mFactoryResetProtectionEnabled);
         for (String account : mFactoryResetProtectionAccounts) {
             out.startTag(null, KEY_FACTORY_RESET_PROTECTION_ACCOUNT);
             out.attribute(null, ATTR_VALUE, account);
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 8be3cdc..e21fee2 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -484,5 +484,7 @@
 
     long getManagedProfileMaximumTimeOff(in ComponentName admin);
     void setManagedProfileMaximumTimeOff(in ComponentName admin, long timeoutMs);
-    boolean canProfileOwnerResetPasswordWhenLocked(in int userId);
+    boolean canProfileOwnerResetPasswordWhenLocked(int userId);
+
+    void setNextOperationSafety(int operation, boolean safe);
 }
diff --git a/core/java/android/app/admin/OWNERS b/core/java/android/app/admin/OWNERS
new file mode 100644
index 0000000..64a1d27
--- /dev/null
+++ b/core/java/android/app/admin/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 142675
+
+yamasani@google.com
+rubinxu@google.com
diff --git a/core/java/android/app/admin/SystemUpdateInfo.java b/core/java/android/app/admin/SystemUpdateInfo.java
index 53b2386..b88bf76 100644
--- a/core/java/android/app/admin/SystemUpdateInfo.java
+++ b/core/java/android/app/admin/SystemUpdateInfo.java
@@ -21,9 +21,11 @@
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.Log;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlSerializer;
+import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
 import java.lang.annotation.Retention;
@@ -34,6 +36,7 @@
  * A class containing information about a pending system update.
  */
 public final class SystemUpdateInfo implements Parcelable {
+    private static final String TAG = "SystemUpdateInfo";
 
     /**
      * Represents it is unknown whether the system update is a security patch.
@@ -125,27 +128,32 @@
             };
 
     /** @hide */
-    public void writeToXml(XmlSerializer out, String tag) throws IOException {
+    public void writeToXml(TypedXmlSerializer out, String tag) throws IOException {
         out.startTag(null, tag);
-        out.attribute(null, ATTR_RECEIVED_TIME, String.valueOf(mReceivedTime));
-        out.attribute(null, ATTR_SECURITY_PATCH_STATE, String.valueOf(mSecurityPatchState));
+        out.attributeLong(null, ATTR_RECEIVED_TIME, mReceivedTime);
+        out.attributeInt(null, ATTR_SECURITY_PATCH_STATE, mSecurityPatchState);
         out.attribute(null, ATTR_ORIGINAL_BUILD , Build.FINGERPRINT);
         out.endTag(null, tag);
     }
 
     /** @hide */
     @Nullable
-    public static SystemUpdateInfo readFromXml(XmlPullParser parser) {
+    public static SystemUpdateInfo readFromXml(TypedXmlPullParser parser) {
         // If an OTA has been applied (build fingerprint has changed), discard stale info.
         final String buildFingerprint = parser.getAttributeValue(null, ATTR_ORIGINAL_BUILD );
         if (!Build.FINGERPRINT.equals(buildFingerprint)) {
             return null;
         }
-        final long receivedTime =
-                Long.parseLong(parser.getAttributeValue(null, ATTR_RECEIVED_TIME));
-        final int securityPatchState =
-                Integer.parseInt(parser.getAttributeValue(null, ATTR_SECURITY_PATCH_STATE));
-        return new SystemUpdateInfo(receivedTime, securityPatchState);
+        try {
+            final long receivedTime =
+                    parser.getAttributeLong(null, ATTR_RECEIVED_TIME);
+            final int securityPatchState =
+                    parser.getAttributeInt(null, ATTR_SECURITY_PATCH_STATE);
+            return new SystemUpdateInfo(receivedTime, securityPatchState);
+        } catch (XmlPullParserException e) {
+            Log.w(TAG, "Load xml failed", e);
+            return null;
+        }
     }
 
     @Override
diff --git a/core/java/android/app/admin/SystemUpdatePolicy.java b/core/java/android/app/admin/SystemUpdatePolicy.java
index 2ba2c04..68ac4cc 100644
--- a/core/java/android/app/admin/SystemUpdatePolicy.java
+++ b/core/java/android/app/admin/SystemUpdatePolicy.java
@@ -26,10 +26,10 @@
 import android.os.Parcelable;
 import android.util.Log;
 import android.util.Pair;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 
-import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
 import java.lang.annotation.Retention;
@@ -741,38 +741,31 @@
      * system server from a validated policy object previously.
      * @hide
      */
-    public static SystemUpdatePolicy restoreFromXml(XmlPullParser parser) {
+    public static SystemUpdatePolicy restoreFromXml(TypedXmlPullParser parser) {
         try {
             SystemUpdatePolicy policy = new SystemUpdatePolicy();
-            String value = parser.getAttributeValue(null, KEY_POLICY_TYPE);
-            if (value != null) {
-                policy.mPolicyType = Integer.parseInt(value);
+            policy.mPolicyType =
+                    parser.getAttributeInt(null, KEY_POLICY_TYPE, TYPE_UNKNOWN);
+            policy.mMaintenanceWindowStart =
+                    parser.getAttributeInt(null, KEY_INSTALL_WINDOW_START, 0);
+            policy.mMaintenanceWindowEnd =
+                    parser.getAttributeInt(null, KEY_INSTALL_WINDOW_END, 0);
 
-                value = parser.getAttributeValue(null, KEY_INSTALL_WINDOW_START);
-                if (value != null) {
-                    policy.mMaintenanceWindowStart = Integer.parseInt(value);
+            int outerDepth = parser.getDepth();
+            int type;
+            while ((type = parser.next()) != END_DOCUMENT
+                    && (type != END_TAG || parser.getDepth() > outerDepth)) {
+                if (type == END_TAG || type == TEXT) {
+                    continue;
                 }
-                value = parser.getAttributeValue(null, KEY_INSTALL_WINDOW_END);
-                if (value != null) {
-                    policy.mMaintenanceWindowEnd = Integer.parseInt(value);
+                if (!parser.getName().equals(KEY_FREEZE_TAG)) {
+                    continue;
                 }
-
-                int outerDepth = parser.getDepth();
-                int type;
-                while ((type = parser.next()) != END_DOCUMENT
-                        && (type != END_TAG || parser.getDepth() > outerDepth)) {
-                    if (type == END_TAG || type == TEXT) {
-                        continue;
-                    }
-                    if (!parser.getName().equals(KEY_FREEZE_TAG)) {
-                        continue;
-                    }
-                    policy.mFreezePeriods.add(new FreezePeriod(
-                            MonthDay.parse(parser.getAttributeValue(null, KEY_FREEZE_START)),
-                            MonthDay.parse(parser.getAttributeValue(null, KEY_FREEZE_END))));
-                }
-                return policy;
+                policy.mFreezePeriods.add(new FreezePeriod(
+                        MonthDay.parse(parser.getAttributeValue(null, KEY_FREEZE_START)),
+                        MonthDay.parse(parser.getAttributeValue(null, KEY_FREEZE_END))));
             }
+            return policy;
         } catch (NumberFormatException | XmlPullParserException | IOException e) {
             // Fail through
             Log.w(TAG, "Load xml failed", e);
@@ -783,10 +776,10 @@
     /**
      * @hide
      */
-    public void saveToXml(XmlSerializer out) throws IOException {
-        out.attribute(null, KEY_POLICY_TYPE, Integer.toString(mPolicyType));
-        out.attribute(null, KEY_INSTALL_WINDOW_START, Integer.toString(mMaintenanceWindowStart));
-        out.attribute(null, KEY_INSTALL_WINDOW_END, Integer.toString(mMaintenanceWindowEnd));
+    public void saveToXml(TypedXmlSerializer out) throws IOException {
+        out.attributeInt(null, KEY_POLICY_TYPE, mPolicyType);
+        out.attributeInt(null, KEY_INSTALL_WINDOW_START, mMaintenanceWindowStart);
+        out.attributeInt(null, KEY_INSTALL_WINDOW_END, mMaintenanceWindowEnd);
         for (int i = 0; i < mFreezePeriods.size(); i++) {
             FreezePeriod interval = mFreezePeriods.get(i);
             out.startTag(null, KEY_FREEZE_TAG);
diff --git a/core/java/android/app/assist/OWNERS b/core/java/android/app/assist/OWNERS
new file mode 100644
index 0000000..46b5ea0
--- /dev/null
+++ b/core/java/android/app/assist/OWNERS
@@ -0,0 +1,7 @@
+joannechung@google.com
+adamhe@google.com
+tymtsai@google.com
+lpeter@google.com
+augale@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 44a4b78..673de8f 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -205,13 +205,16 @@
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({
         OperationType.BACKUP,
-        OperationType.MIGRATION
+        OperationType.MIGRATION,
+        OperationType.ADB_BACKUP,
     })
     public @interface OperationType {
-        // A regular backup / restore operation.
+        // A backup / restore to / from an off-device location, e.g. cloud.
         int BACKUP = 0;
-        // A full migration: all app data for non-system apps is eligible.
+        // A direct transfer to another device.
         int MIGRATION = 1;
+        // Backup via adb, data saved on the host machine.
+        int ADB_BACKUP = 3;
     }
 
     private Context mContext;
diff --git a/core/java/android/app/contentsuggestions/OWNERS b/core/java/android/app/contentsuggestions/OWNERS
new file mode 100644
index 0000000..482abb2
--- /dev/null
+++ b/core/java/android/app/contentsuggestions/OWNERS
@@ -0,0 +1,9 @@
+# Bug component: 643919
+
+joannechung@google.com
+adamhe@google.com
+tymtsai@google.com
+lpeter@google.com
+augale@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
diff --git a/core/java/android/app/prediction/OWNERS b/core/java/android/app/prediction/OWNERS
new file mode 100644
index 0000000..fe012da
--- /dev/null
+++ b/core/java/android/app/prediction/OWNERS
@@ -0,0 +1,2 @@
+adamcohen@google.com
+sunnygoyal@google.com
diff --git a/core/java/android/app/role/IRoleManager.aidl b/core/java/android/app/role/IRoleManager.aidl
index 6d790b3..5fc25f0 100644
--- a/core/java/android/app/role/IRoleManager.aidl
+++ b/core/java/android/app/role/IRoleManager.aidl
@@ -53,5 +53,9 @@
 
     List<String> getHeldRolesFromController(in String packageName);
 
-    String getDefaultSmsPackage(int userId);
+    String getBrowserRoleHolder(int userId);
+
+    boolean setBrowserRoleHolder(String packageName, int userId);
+
+    String getSmsRoleHolder(int userId);
 }
diff --git a/core/java/android/app/role/OWNERS b/core/java/android/app/role/OWNERS
index b94d988..b8076366 100644
--- a/core/java/android/app/role/OWNERS
+++ b/core/java/android/app/role/OWNERS
@@ -1,6 +1,4 @@
-svetoslavganov@google.com
-moltmann@google.com
+# Bug component: 137825
+
 zhanghai@google.com
-evanseverson@google.com
-eugenesusla@google.com
-ntmyren@google.com
+moltmann@google.com
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index 408ce0f..8b2e07b 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -613,12 +613,56 @@
     }
 
     /**
-     * Allows getting the role holder for {@link #ROLE_SMS} without
-     * {@link Manifest.permission#OBSERVE_ROLE_HOLDERS}, as required by
-     * {@link android.provider.Telephony.Sms#getDefaultSmsPackage(Context)}
+     * Get the role holder of {@link #ROLE_BROWSER} without requiring
+     * {@link Manifest.permission#OBSERVE_ROLE_HOLDERS}, as in
+     * {@link android.content.pm.PackageManager#getDefaultBrowserPackageNameAsUser(int)}
      *
-     * @param userId The user ID to get the default SMS package for.
-     * @return the package name of the default SMS app, or {@code null} if not configured.
+     * @param userId the user ID
+     * @return the package name of the default browser, or {@code null} if none
+     *
+     * @hide
+     */
+    @Nullable
+    //@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public String getBrowserRoleHolder(@UserIdInt int userId) {
+        try {
+            return mService.getBrowserRoleHolder(userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Set the role holder of {@link #ROLE_BROWSER} requiring
+     * {@link Manifest.permission.SET_PREFERRED_APPLICATIONS} instead of
+     * {@link Manifest.permission#MANAGE_ROLE_HOLDERS}, as in
+     * {@link android.content.pm.PackageManager#setDefaultBrowserPackageNameAsUser(String, int)}
+     *
+     * @param packageName the package name of the default browser, or {@code null} if none
+     * @param userId the user ID
+     * @return whether the default browser was set successfully
+     *
+     * @hide
+     */
+    @Nullable
+    @RequiresPermission(Manifest.permission.SET_PREFERRED_APPLICATIONS)
+    //@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public boolean setBrowserRoleHolder(@Nullable String packageName, @UserIdInt int userId) {
+        try {
+            return mService.setBrowserRoleHolder(packageName, userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Allows getting the role holder for {@link #ROLE_SMS} without requiring
+     * {@link Manifest.permission#OBSERVE_ROLE_HOLDERS}, as in
+     * {@link android.provider.Telephony.Sms#getDefaultSmsPackage(Context)}.
+     *
+     * @param userId the user ID to get the default SMS package for
+     * @return the package name of the default SMS app, or {@code null} if none
+     *
      * @hide
      */
     @Nullable
@@ -626,7 +670,7 @@
     @TestApi
     public String getSmsRoleHolder(@UserIdInt int userId) {
         try {
-            return mService.getDefaultSmsPackage(userId);
+            return mService.getSmsRoleHolder(userId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/servertransaction/OWNERS b/core/java/android/app/servertransaction/OWNERS
new file mode 100644
index 0000000..aa6248e
--- /dev/null
+++ b/core/java/android/app/servertransaction/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 316125
+
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/core/java/android/app/servertransaction/PauseActivityItem.java b/core/java/android/app/servertransaction/PauseActivityItem.java
index f7c645e..813e0f9 100644
--- a/core/java/android/app/servertransaction/PauseActivityItem.java
+++ b/core/java/android/app/servertransaction/PauseActivityItem.java
@@ -20,12 +20,11 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.ActivityTaskManager;
+import android.app.ActivityClient;
 import android.app.ActivityThread.ActivityClientRecord;
 import android.app.ClientTransactionHandler;
 import android.os.IBinder;
 import android.os.Parcel;
-import android.os.RemoteException;
 import android.os.Trace;
 
 /**
@@ -61,12 +60,8 @@
         if (mDontReport) {
             return;
         }
-        try {
-            // TODO(lifecycler): Use interface callback instead of AMS.
-            ActivityTaskManager.getService().activityPaused(token);
-        } catch (RemoteException ex) {
-            throw ex.rethrowFromSystemServer();
-        }
+        // TODO(lifecycler): Use interface callback instead of actual implementation.
+        ActivityClient.getInstance().activityPaused(token);
     }
 
 
diff --git a/core/java/android/app/servertransaction/PendingTransactionActions.java b/core/java/android/app/servertransaction/PendingTransactionActions.java
index 52ba8fb..a47fe82 100644
--- a/core/java/android/app/servertransaction/PendingTransactionActions.java
+++ b/core/java/android/app/servertransaction/PendingTransactionActions.java
@@ -18,13 +18,11 @@
 
 import static android.app.ActivityThread.DEBUG_MEMORY_TRIM;
 
-import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
+import android.app.ActivityClient;
 import android.app.ActivityThread.ActivityClientRecord;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.PersistableBundle;
-import android.os.RemoteException;
 import android.os.TransactionTooLargeException;
 import android.util.Log;
 import android.util.LogWriter;
@@ -142,9 +140,9 @@
             try {
                 if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Reporting activity stopped: " + mActivity);
                 // TODO(lifecycler): Use interface callback instead of AMS.
-                ActivityTaskManager.getService().activityStopped(
+                ActivityClient.getInstance().activityStopped(
                         mActivity.token, mState, mPersistentState, mDescription);
-            } catch (RemoteException ex) {
+            } catch (RuntimeException ex) {
                 // Dump statistics about bundle to help developers debug
                 final LogWriter writer = new LogWriter(Log.WARN, TAG);
                 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
@@ -153,12 +151,12 @@
                 pw.println("PersistableBundle stats:");
                 Bundle.dumpStats(pw, mPersistentState);
 
-                if (ex instanceof TransactionTooLargeException
+                if (ex.getCause() instanceof TransactionTooLargeException
                         && mActivity.packageInfo.getTargetSdkVersion() < Build.VERSION_CODES.N) {
                     Log.e(TAG, "App sent too much data in instance state, so it was ignored", ex);
                     return;
                 }
-                throw ex.rethrowFromSystemServer();
+                throw ex;
             }
         }
     }
diff --git a/core/java/android/app/servertransaction/ResumeActivityItem.java b/core/java/android/app/servertransaction/ResumeActivityItem.java
index b4523f5..d451599 100644
--- a/core/java/android/app/servertransaction/ResumeActivityItem.java
+++ b/core/java/android/app/servertransaction/ResumeActivityItem.java
@@ -20,13 +20,12 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityClient;
 import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
 import android.app.ActivityThread.ActivityClientRecord;
 import android.app.ClientTransactionHandler;
 import android.os.IBinder;
 import android.os.Parcel;
-import android.os.RemoteException;
 import android.os.Trace;
 
 /**
@@ -60,12 +59,8 @@
     @Override
     public void postExecute(ClientTransactionHandler client, IBinder token,
             PendingTransactionActions pendingActions) {
-        try {
-            // TODO(lifecycler): Use interface callback instead of AMS.
-            ActivityTaskManager.getService().activityResumed(token);
-        } catch (RemoteException ex) {
-            throw ex.rethrowFromSystemServer();
-        }
+        // TODO(lifecycler): Use interface callback instead of actual implementation.
+        ActivityClient.getInstance().activityResumed(token);
     }
 
     @Override
diff --git a/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java b/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java
index 2b0c1b9..5cd3d68f 100644
--- a/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java
+++ b/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java
@@ -19,12 +19,11 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.ActivityTaskManager;
+import android.app.ActivityClient;
 import android.app.ActivityThread.ActivityClientRecord;
 import android.app.ClientTransactionHandler;
 import android.os.IBinder;
 import android.os.Parcel;
-import android.os.RemoteException;
 import android.os.Trace;
 
 /**
@@ -56,11 +55,7 @@
         // 2. Activity wasn't RESUMED yet, which means that it didn't receive the top state yet.
         // 3. Activity is PAUSED or in other lifecycle state after PAUSED. In this case top resumed
         // state loss was already called right before pausing.
-        try {
-            ActivityTaskManager.getService().activityTopResumedStateLost();
-        } catch (RemoteException ex) {
-            throw ex.rethrowFromSystemServer();
-        }
+        ActivityClient.getInstance().activityTopResumedStateLost();
     }
 
 
diff --git a/core/java/android/app/slice/OWNERS b/core/java/android/app/slice/OWNERS
new file mode 100644
index 0000000..b0a44fb
--- /dev/null
+++ b/core/java/android/app/slice/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 342804
+
+sunnygoyal@google.com
+dsandler@android.com
+dsandler@google.com
+adamcohen@google.com
diff --git a/core/java/android/app/timedetector/OWNERS b/core/java/android/app/timedetector/OWNERS
new file mode 100644
index 0000000..8c11324
--- /dev/null
+++ b/core/java/android/app/timedetector/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 847766
+
+narayan@google.com
+nfuller@google.com
diff --git a/core/java/android/app/timezone/OWNERS b/core/java/android/app/timezone/OWNERS
new file mode 100644
index 0000000..8c11324
--- /dev/null
+++ b/core/java/android/app/timezone/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 847766
+
+narayan@google.com
+nfuller@google.com
diff --git a/core/java/android/app/usage/OWNERS b/core/java/android/app/usage/OWNERS
new file mode 100644
index 0000000..a33d0ad
--- /dev/null
+++ b/core/java/android/app/usage/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 532296
+
+yamasani@google.com
+mwachens@google.com
+varunshah@google.com
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 3522b1b..081f4fd 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -383,6 +383,10 @@
         public int mClassToken = UNASSIGNED_TOKEN;
 
         /**
+         * Uniquely identifies an activity. It's possible for two activities with the same
+         * pkg/class name to be in lifecycle at the same time. The mInstanceId is guaranteed to be
+         * unique per activity across all apps (not just within a single app).
+         *
          * {@hide}
          */
         public int mInstanceId;
diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java
index 130a20d..c4333ac 100644
--- a/core/java/android/appwidget/AppWidgetProviderInfo.java
+++ b/core/java/android/appwidget/AppWidgetProviderInfo.java
@@ -68,6 +68,9 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface ResizeModeFlags {}
 
+    /** {@hide} */
+    public static final int WIDGET_CATEGORY_UNKNOWN = -1;
+
     /**
      * Indicates that the widget can be displayed on the home screen. This is the default value.
      */
diff --git a/core/java/android/attention/OWNERS b/core/java/android/attention/OWNERS
new file mode 100644
index 0000000..dd579b6
--- /dev/null
+++ b/core/java/android/attention/OWNERS
@@ -0,0 +1 @@
+asalo@google.com
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index c07cd52..1713a0c 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -3689,7 +3689,7 @@
      *
      * @hide
      */
-    public abstract class BluetoothConnectionCallback {
+    public abstract static class BluetoothConnectionCallback {
         /**
          * Callback triggered when a bluetooth device (classic or BLE) is connected
          * @param device is the connected bluetooth device
diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java
index 603a7ff..7fe18a0 100755
--- a/core/java/android/bluetooth/BluetoothClass.java
+++ b/core/java/android/bluetooth/BluetoothClass.java
@@ -426,13 +426,13 @@
                     return false;
             }
         } else if (profile == PROFILE_HID) {
-            return (getDeviceClass() & Device.Major.PERIPHERAL) == Device.Major.PERIPHERAL;
+            return getMajorDeviceClass() == Device.Major.PERIPHERAL;
         } else if (profile == PROFILE_PANU || profile == PROFILE_NAP) {
             // No good way to distinguish between the two, based on class bits.
             if (hasService(Service.NETWORKING)) {
                 return true;
             }
-            return (getDeviceClass() & Device.Major.NETWORKING) == Device.Major.NETWORKING;
+            return getMajorDeviceClass() == Device.Major.NETWORKING;
         } else {
             return false;
         }
diff --git a/core/java/android/bluetooth/OWNERS b/core/java/android/bluetooth/OWNERS
new file mode 100644
index 0000000..3523ee0
--- /dev/null
+++ b/core/java/android/bluetooth/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 27441
+
+zachoverflow@google.com
+siyuanh@google.com
diff --git a/core/java/android/bluetooth/le/OWNERS b/core/java/android/bluetooth/le/OWNERS
new file mode 100644
index 0000000..3523ee0
--- /dev/null
+++ b/core/java/android/bluetooth/le/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 27441
+
+zachoverflow@google.com
+siyuanh@google.com
diff --git a/core/java/android/companion/Association.java b/core/java/android/companion/Association.java
index 06a3f2f..17bf11b 100644
--- a/core/java/android/companion/Association.java
+++ b/core/java/android/companion/Association.java
@@ -37,6 +37,8 @@
     private final @UserIdInt int mUserId;
     private final @NonNull String mDeviceMacAddress;
     private final @NonNull String mPackageName;
+    private final @Nullable String mDeviceProfile;
+    private final boolean mKeepProfilePrivilegesWhenDeviceAway;
 
     /** @hide */
     public int getUserId() {
@@ -45,7 +47,7 @@
 
 
 
-    // Code below generated by codegen v1.0.15.
+    // Code below generated by codegen v1.0.21.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -67,7 +69,9 @@
     public Association(
             @UserIdInt int userId,
             @NonNull String deviceMacAddress,
-            @NonNull String packageName) {
+            @NonNull String packageName,
+            @Nullable String deviceProfile,
+            boolean keepProfilePrivilegesWhenDeviceAway) {
         this.mUserId = userId;
         com.android.internal.util.AnnotationValidations.validate(
                 UserIdInt.class, null, mUserId);
@@ -77,6 +81,8 @@
         this.mPackageName = packageName;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mPackageName);
+        this.mDeviceProfile = deviceProfile;
+        this.mKeepProfilePrivilegesWhenDeviceAway = keepProfilePrivilegesWhenDeviceAway;
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -91,6 +97,16 @@
         return mPackageName;
     }
 
+    @DataClass.Generated.Member
+    public @Nullable String getDeviceProfile() {
+        return mDeviceProfile;
+    }
+
+    @DataClass.Generated.Member
+    public boolean isKeepProfilePrivilegesWhenDeviceAway() {
+        return mKeepProfilePrivilegesWhenDeviceAway;
+    }
+
     @Override
     @DataClass.Generated.Member
     public String toString() {
@@ -100,7 +116,9 @@
         return "Association { " +
                 "userId = " + mUserId + ", " +
                 "deviceMacAddress = " + mDeviceMacAddress + ", " +
-                "packageName = " + mPackageName +
+                "packageName = " + mPackageName + ", " +
+                "deviceProfile = " + mDeviceProfile + ", " +
+                "keepProfilePrivilegesWhenDeviceAway = " + mKeepProfilePrivilegesWhenDeviceAway +
         " }";
     }
 
@@ -119,7 +137,9 @@
         return true
                 && mUserId == that.mUserId
                 && Objects.equals(mDeviceMacAddress, that.mDeviceMacAddress)
-                && Objects.equals(mPackageName, that.mPackageName);
+                && Objects.equals(mPackageName, that.mPackageName)
+                && Objects.equals(mDeviceProfile, that.mDeviceProfile)
+                && mKeepProfilePrivilegesWhenDeviceAway == that.mKeepProfilePrivilegesWhenDeviceAway;
     }
 
     @Override
@@ -132,6 +152,8 @@
         _hash = 31 * _hash + mUserId;
         _hash = 31 * _hash + Objects.hashCode(mDeviceMacAddress);
         _hash = 31 * _hash + Objects.hashCode(mPackageName);
+        _hash = 31 * _hash + Objects.hashCode(mDeviceProfile);
+        _hash = 31 * _hash + Boolean.hashCode(mKeepProfilePrivilegesWhenDeviceAway);
         return _hash;
     }
 
@@ -141,9 +163,14 @@
         // You can override field parcelling by defining methods like:
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
+        byte flg = 0;
+        if (mKeepProfilePrivilegesWhenDeviceAway) flg |= 0x10;
+        if (mDeviceProfile != null) flg |= 0x8;
+        dest.writeByte(flg);
         dest.writeInt(mUserId);
         dest.writeString(mDeviceMacAddress);
         dest.writeString(mPackageName);
+        if (mDeviceProfile != null) dest.writeString(mDeviceProfile);
     }
 
     @Override
@@ -157,9 +184,12 @@
         // You can override field unparcelling by defining methods like:
         // static FieldType unparcelFieldName(Parcel in) { ... }
 
+        byte flg = in.readByte();
+        boolean keepProfilePrivilegesWhenDeviceAway = (flg & 0x10) != 0;
         int userId = in.readInt();
         String deviceMacAddress = in.readString();
         String packageName = in.readString();
+        String deviceProfile = (flg & 0x8) == 0 ? null : in.readString();
 
         this.mUserId = userId;
         com.android.internal.util.AnnotationValidations.validate(
@@ -170,6 +200,8 @@
         this.mPackageName = packageName;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mPackageName);
+        this.mDeviceProfile = deviceProfile;
+        this.mKeepProfilePrivilegesWhenDeviceAway = keepProfilePrivilegesWhenDeviceAway;
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -189,10 +221,10 @@
     };
 
     @DataClass.Generated(
-            time = 1599083149942L,
-            codegenVersion = "1.0.15",
+            time = 1606940835778L,
+            codegenVersion = "1.0.21",
             sourceFile = "frameworks/base/core/java/android/companion/Association.java",
-            inputSignatures = "private final @android.annotation.UserIdInt int mUserId\nprivate final @android.annotation.NonNull java.lang.String mDeviceMacAddress\nprivate final @android.annotation.NonNull java.lang.String mPackageName\npublic  int getUserId()\nclass Association extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstructor=true)")
+            inputSignatures = "private final @android.annotation.UserIdInt int mUserId\nprivate final @android.annotation.NonNull java.lang.String mDeviceMacAddress\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mDeviceProfile\nprivate final  boolean mKeepProfilePrivilegesWhenDeviceAway\npublic  int getUserId()\nclass Association extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstructor=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/content/SyncAdaptersCache.java b/core/java/android/content/SyncAdaptersCache.java
index 58445a7..495f94f 100644
--- a/core/java/android/content/SyncAdaptersCache.java
+++ b/core/java/android/content/SyncAdaptersCache.java
@@ -25,12 +25,12 @@
 import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.SparseArray;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 
 import com.android.internal.annotations.GuardedBy;
 
-import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -142,12 +142,12 @@
     }
 
     static class MySerializer implements XmlSerializerAndParser<SyncAdapterType> {
-        public void writeAsXml(SyncAdapterType item, XmlSerializer out) throws IOException {
+        public void writeAsXml(SyncAdapterType item, TypedXmlSerializer out) throws IOException {
             out.attribute(null, "authority", item.authority);
             out.attribute(null, "accountType", item.accountType);
         }
 
-        public SyncAdapterType createFromXml(XmlPullParser parser)
+        public SyncAdapterType createFromXml(TypedXmlPullParser parser)
                 throws IOException, XmlPullParserException {
             final String authority = parser.getAttributeValue(null, "authority");
             final String accountType = parser.getAttributeValue(null, "accountType");
diff --git a/core/java/android/content/om/OWNERS b/core/java/android/content/om/OWNERS
new file mode 100644
index 0000000..91a0abf
--- /dev/null
+++ b/core/java/android/content/om/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 568631
+
+toddke@android.com
+toddke@google.com
+patb@google.com
+rtmitchell@google.com
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index 6ccbc36..9a73be9 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -33,6 +33,7 @@
     ParcelFileDescriptor openRead(String name);
 
     void write(String name, long offsetBytes, long lengthBytes, in ParcelFileDescriptor fd);
+    void stageViaHardLink(String target);
 
     void addChecksums(String name, in Checksum[] checksums);
 
diff --git a/core/java/android/content/pm/IntentFilterVerificationInfo.java b/core/java/android/content/pm/IntentFilterVerificationInfo.java
index 0a913ac..56b8bd8 100644
--- a/core/java/android/content/pm/IntentFilterVerificationInfo.java
+++ b/core/java/android/content/pm/IntentFilterVerificationInfo.java
@@ -16,11 +16,11 @@
 
 package android.content.pm;
 
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
 
 import android.annotation.SystemApi;
 import android.os.Parcel;
@@ -28,12 +28,13 @@
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 
 import com.android.internal.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -72,7 +73,7 @@
     }
 
     /** @hide */
-    public IntentFilterVerificationInfo(XmlPullParser parser)
+    public IntentFilterVerificationInfo(TypedXmlPullParser parser)
             throws IOException, XmlPullParserException {
         readFromXml(parser);
     }
@@ -121,7 +122,7 @@
         return sb.toString();
     }
 
-    String getStringFromXml(XmlPullParser parser, String attribute, String defaultValue) {
+    String getStringFromXml(TypedXmlPullParser parser, String attribute, String defaultValue) {
         String value = parser.getAttributeValue(null, attribute);
         if (value == null) {
             String msg = "Missing element under " + TAG +": " + attribute + " at " +
@@ -133,20 +134,12 @@
         }
     }
 
-    int getIntFromXml(XmlPullParser parser, String attribute, int defaultValue) {
-        String value = parser.getAttributeValue(null, attribute);
-        if (TextUtils.isEmpty(value)) {
-            String msg = "Missing element under " + TAG +": " + attribute + " at " +
-                    parser.getPositionDescription();
-            Log.w(TAG, msg);
-            return defaultValue;
-        } else {
-            return Integer.parseInt(value);
-        }
+    int getIntFromXml(TypedXmlPullParser parser, String attribute, int defaultValue) {
+        return parser.getAttributeInt(null, attribute, defaultValue);
     }
 
     /** @hide */
-    public void readFromXml(XmlPullParser parser) throws XmlPullParserException,
+    public void readFromXml(TypedXmlPullParser parser) throws XmlPullParserException,
             IOException {
         mPackageName = getStringFromXml(parser, ATTR_PACKAGE_NAME, null);
         if (mPackageName == null) {
@@ -182,9 +175,9 @@
     }
 
     /** @hide */
-    public void writeToXml(XmlSerializer serializer) throws IOException {
+    public void writeToXml(TypedXmlSerializer serializer) throws IOException {
         serializer.attribute(null, ATTR_PACKAGE_NAME, mPackageName);
-        serializer.attribute(null, ATTR_STATUS, String.valueOf(mStatus));
+        serializer.attributeInt(null, ATTR_STATUS, mStatus);
         for (String str : mDomains) {
             serializer.startTag(null, TAG_DOMAIN);
             serializer.attribute(null, ATTR_DOMAIN_NAME, str);
diff --git a/core/java/android/content/pm/OWNERS b/core/java/android/content/pm/OWNERS
index a16bb4f..3a590da 100644
--- a/core/java/android/content/pm/OWNERS
+++ b/core/java/android/content/pm/OWNERS
@@ -1 +1,7 @@
+# Bug component: 36137
+
+toddke@android.com
+toddke@google.com
+patb@google.com
+
 per-file PackageParser.java = chiuwinson@google.com
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 0dcfd38..4347f99 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -37,6 +37,7 @@
 import android.content.IntentSender;
 import android.content.pm.PackageManager.DeleteFlags;
 import android.content.pm.PackageManager.InstallReason;
+import android.content.pm.PackageManager.InstallScenario;
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.Build;
@@ -1049,6 +1050,31 @@
         }
 
         /**
+         * Populate an APK file by creating a hard link to avoid the need to copy.
+         * <p>
+         * Note this API is used by RollbackManager only and can only be called from system_server.
+         * {@code target} will be relabeled if link is created successfully. RollbackManager has
+         * to delete {@code target} when the session is committed successfully to avoid SELinux
+         * label conflicts.
+         * <p>
+         * Note No more bytes should be written to the file once the link is created successfully.
+         *
+         * @param target the path of the link target
+         *
+         * @hide
+         */
+        public void stageViaHardLink(String target) throws IOException {
+            try {
+                mSession.stageViaHardLink(target);
+            } catch (RuntimeException e) {
+                ExceptionUtils.maybeUnwrapIOException(e);
+                throw e;
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        /**
          * Ensure that any outstanding data for given stream has been committed
          * to disk. This is only valid for streams returned from
          * {@link #openWrite(String, long, long)}.
@@ -1500,6 +1526,14 @@
         public int installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
         /** {@hide} */
         public @InstallReason int installReason = PackageManager.INSTALL_REASON_UNKNOWN;
+        /**
+         * {@hide}
+         *
+         * This flag indicates which installation scenario best describes this session.  The system
+         * may use this value when making decisions about how to handle the installation, such as
+         * prioritizing system health or user experience.
+         */
+        public @InstallScenario int installScenario = PackageManager.INSTALL_SCENARIO_DEFAULT;
         /** {@hide} */
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
         public long sizeBytes = -1;
@@ -1563,6 +1597,7 @@
             installFlags = source.readInt();
             installLocation = source.readInt();
             installReason = source.readInt();
+            installScenario = source.readInt();
             sizeBytes = source.readLong();
             appPackageName = source.readString();
             appIcon = source.readParcelable(null);
@@ -1594,6 +1629,7 @@
             ret.installFlags = installFlags;
             ret.installLocation = installLocation;
             ret.installReason = installReason;
+            ret.installScenario = installScenario;
             ret.sizeBytes = sizeBytes;
             ret.appPackageName = appPackageName;
             ret.appIcon = appIcon;  // not a copy.
@@ -2019,6 +2055,8 @@
             pw.printPair("mode", mode);
             pw.printHexPair("installFlags", installFlags);
             pw.printPair("installLocation", installLocation);
+            pw.printPair("installReason", installReason);
+            pw.printPair("installScenario", installScenario);
             pw.printPair("sizeBytes", sizeBytes);
             pw.printPair("appPackageName", appPackageName);
             pw.printPair("appIcon", (appIcon != null));
@@ -2052,6 +2090,7 @@
             dest.writeInt(installFlags);
             dest.writeInt(installLocation);
             dest.writeInt(installReason);
+            dest.writeInt(installScenario);
             dest.writeLong(sizeBytes);
             dest.writeString(appPackageName);
             dest.writeParcelable(appIcon, flags);
@@ -2170,6 +2209,8 @@
         /** {@hide} */
         public @InstallReason int installReason;
         /** {@hide} */
+        public @InstallReason int installScenario;
+        /** {@hide} */
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public long sizeBytes;
         /** {@hide} */
@@ -2248,6 +2289,7 @@
 
             mode = source.readInt();
             installReason = source.readInt();
+            installScenario = source.readInt();
             sizeBytes = source.readLong();
             appPackageName = source.readString();
             appIcon = source.readParcelable(null);
@@ -2795,6 +2837,7 @@
 
             dest.writeInt(mode);
             dest.writeInt(installReason);
+            dest.writeInt(installScenario);
             dest.writeLong(sizeBytes);
             dest.writeString(appPackageName);
             dest.writeParcelable(appIcon, flags);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 19e4d14..cf3f706 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1323,6 +1323,60 @@
     public static final int INSTALL_REASON_ROLLBACK = 5;
 
     /** @hide */
+    @IntDef(prefix = { "INSTALL_SCENARIO_" }, value = {
+            INSTALL_SCENARIO_DEFAULT,
+            INSTALL_SCENARIO_FAST,
+            INSTALL_SCENARIO_BULK,
+            INSTALL_SCENARIO_BULK_SECONDARY,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface InstallScenario {}
+
+    /**
+     * A value to indicate the lack of CUJ information, disabling all installation scenario logic.
+     *
+     * @hide
+     */
+    public static final int INSTALL_SCENARIO_DEFAULT = 0;
+
+    /**
+     * Installation scenario providing the fastest “install button to launch" experience possible.
+     *
+     * @hide
+     */
+    public static final int INSTALL_SCENARIO_FAST = 1;
+
+    /**
+     * Installation scenario indicating a bulk operation with the desired result of a fully
+     * optimized application.  If the system is busy or resources are scarce the system will
+     * perform less work to avoid impacting system health.
+     *
+     * Examples of bulk installation scenarios might include device restore, background updates of
+     * multiple applications, or user-triggered updates for all applications.
+     *
+     * The decision to use BULK or BULK_SECONDARY should be based on the desired user experience.
+     * BULK_SECONDARY operations may take less time to complete but, when they do, will produce
+     * less optimized applications.  The device state (e.g. memory usage or battery status) should
+     * not be considered when making this decision as those factors are taken into account by the
+     * Package Manager when acting on the installation scenario.
+     *
+     * @hide
+     */
+    public static final int INSTALL_SCENARIO_BULK = 2;
+
+    /**
+     * Installation scenario indicating a bulk operation that prioritizes minimal system health
+     * impact over application optimization.  The application may undergo additional optimization
+     * if the system is idle and system resources are abundant.  The more elements of a bulk
+     * operation that are marked BULK_SECONDARY, the faster the entire bulk operation will be.
+     *
+     * See the comments for INSTALL_SCENARIO_BULK for more information.
+     *
+     * @hide
+     */
+    public static final int INSTALL_SCENARIO_BULK_SECONDARY = 3;
+
+    /** @hide */
     @IntDef(prefix = { "UNINSTALL_REASON_" }, value = {
             UNINSTALL_REASON_UNKNOWN,
             UNINSTALL_REASON_USER_TYPE,
@@ -4131,6 +4185,14 @@
      */
     public static final int UNSTARTABLE_REASON_INSUFFICIENT_STORAGE = 2;
 
+    /**
+     * A manifest property to control app's participation in {@code adb backup}. Should only
+     * be used by system / privileged apps.
+     *
+     * @hide
+     */
+    public static final String PROPERTY_ALLOW_ADB_BACKUP = "android.backup.ALLOW_ADB_BACKUP";
+
     /** {@hide} */
     public int getUserId() {
         return UserHandle.myUserId();
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index cb0decf..4dfbd75 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -406,9 +406,15 @@
         public final boolean extractNativeLibs;
         public final boolean isolatedSplits;
 
-        public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
-                boolean[] isFeatureSplits, String[] usesSplitNames, String[] configForSplit,
-                String[] splitCodePaths, int[] splitRevisionCodes) {
+        // This does not represent the actual manifest structure since the 'profilable' tag
+        // could be used with attributes other than 'shell'. Extend if necessary.
+        public final boolean profilableByShell;
+        public final boolean isSplitRequired;
+        public final boolean useEmbeddedDex;
+
+        public PackageLite(String codePath, String baseCodePath, ApkLite baseApk,
+                String[] splitNames, boolean[] isFeatureSplits, String[] usesSplitNames,
+                String[] configForSplit, String[] splitCodePaths, int[] splitRevisionCodes) {
             this.packageName = baseApk.packageName;
             this.versionCode = baseApk.versionCode;
             this.versionCodeMajor = baseApk.versionCodeMajor;
@@ -418,8 +424,10 @@
             this.isFeatureSplits = isFeatureSplits;
             this.usesSplitNames = usesSplitNames;
             this.configForSplit = configForSplit;
+            // The following paths may be different from the path in ApkLite because we
+            // move or rename the APK files. Use parameters to indicate the correct paths.
             this.codePath = codePath;
-            this.baseCodePath = baseApk.codePath;
+            this.baseCodePath = baseCodePath;
             this.splitCodePaths = splitCodePaths;
             this.baseRevisionCode = baseApk.revisionCode;
             this.splitRevisionCodes = splitRevisionCodes;
@@ -429,6 +437,9 @@
             this.use32bitAbi = baseApk.use32bitAbi;
             this.extractNativeLibs = baseApk.extractNativeLibs;
             this.isolatedSplits = baseApk.isolatedSplits;
+            this.useEmbeddedDex = baseApk.useEmbeddedDex;
+            this.isSplitRequired = baseApk.isSplitRequired;
+            this.profilableByShell = baseApk.profilableByShell;
         }
 
         public List<String> getAllCodePaths() {
@@ -439,6 +450,10 @@
             }
             return paths;
         }
+
+        public long getLongVersionCode() {
+            return PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode);
+        }
     }
 
     /**
@@ -941,7 +956,8 @@
         final ApkLite baseApk = parseApkLite(packageFile, flags);
         final String packagePath = packageFile.getAbsolutePath();
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-        return new PackageLite(packagePath, baseApk, null, null, null, null, null, null);
+        return new PackageLite(packagePath, baseApk.codePath, baseApk, null, null, null, null, null,
+                null);
     }
 
     static PackageLite parseClusterPackageLite(File packageDir, int flags)
@@ -1031,8 +1047,8 @@
         }
 
         final String codePath = packageDir.getAbsolutePath();
-        return new PackageLite(codePath, baseApk, splitNames, isFeatureSplits, usesSplitNames,
-                configForSplits, splitCodePaths, splitRevisionCodes);
+        return new PackageLite(codePath, baseApk.codePath, baseApk, splitNames, isFeatureSplits,
+                usesSplitNames, configForSplits, splitCodePaths, splitRevisionCodes);
     }
 
     /**
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 2fca980..9925871 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -41,6 +41,8 @@
 import android.util.DebugUtils;
 import android.util.Pair;
 import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
@@ -560,7 +562,7 @@
          * @param out the {@link XmlSerializer} object
          * @throws IOException
          */
-        public void saveToXml(XmlSerializer out) throws IOException {
+        public void saveToXml(TypedXmlSerializer out) throws IOException {
             if (dialogInfo != null) {
                 out.startTag(null, TAG_DIALOG_INFO);
                 dialogInfo.saveToXml(out);
@@ -594,7 +596,7 @@
          * @param in the reader
          * @return
          */
-        public static SuspendParams restoreFromXml(XmlPullParser in) throws IOException {
+        public static SuspendParams restoreFromXml(TypedXmlPullParser in) throws IOException {
             SuspendDialogInfo readDialogInfo = null;
             PersistableBundle readAppExtras = null;
             PersistableBundle readLauncherExtras = null;
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 192470e..7ecb112 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -36,21 +36,21 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.FastXmlSerializer;
+
+import libcore.io.IoUtils;
 
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 
-import libcore.io.IoUtils;
-
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -58,7 +58,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -672,8 +671,7 @@
      */
     private void readPersistentServicesLocked(InputStream is)
             throws XmlPullParserException, IOException {
-        XmlPullParser parser = Xml.newPullParser();
-        parser.setInput(is, StandardCharsets.UTF_8.name());
+        TypedXmlPullParser parser = Xml.resolvePullParser(is);
         int eventType = parser.getEventType();
         while (eventType != XmlPullParser.START_TAG
                 && eventType != XmlPullParser.END_DOCUMENT) {
@@ -690,8 +688,7 @@
                         if (service == null) {
                             break;
                         }
-                        String uidString = parser.getAttributeValue(null, "uid");
-                        final int uid = Integer.parseInt(uidString);
+                        final int uid = parser.getAttributeInt(null, "uid");
                         final int userId = UserHandle.getUserId(uid);
                         final UserServices<V> user = findOrCreateUserLocked(userId,
                                 false /*loadFromFileIfNew*/) ;
@@ -762,14 +759,13 @@
         FileOutputStream fos = null;
         try {
             fos = atomicFile.startWrite();
-            XmlSerializer out = new FastXmlSerializer();
-            out.setOutput(fos, StandardCharsets.UTF_8.name());
+            TypedXmlSerializer out = Xml.resolveSerializer(fos);
             out.startDocument(null, true);
             out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
             out.startTag(null, "services");
             for (Map.Entry<V, Integer> service : user.persistentServices.entrySet()) {
                 out.startTag(null, "service");
-                out.attribute(null, "uid", Integer.toString(service.getValue()));
+                out.attributeInt(null, "uid", service.getValue());
                 mSerializerAndParser.writeAsXml(service.getKey(), out);
                 out.endTag(null, "service");
             }
diff --git a/core/java/android/content/pm/SuspendDialogInfo.java b/core/java/android/content/pm/SuspendDialogInfo.java
index 851a081..60f3218 100644
--- a/core/java/android/content/pm/SuspendDialogInfo.java
+++ b/core/java/android/content/pm/SuspendDialogInfo.java
@@ -29,13 +29,12 @@
 import android.os.Parcelable;
 import android.os.PersistableBundle;
 import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlSerializer;
-
 import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -169,38 +168,38 @@
     /**
      * @hide
      */
-    public void saveToXml(XmlSerializer out) throws IOException {
+    public void saveToXml(TypedXmlSerializer out) throws IOException {
         if (mIconResId != ID_NULL) {
-            XmlUtils.writeIntAttribute(out, XML_ATTR_ICON_RES_ID, mIconResId);
+            out.attributeInt(null, XML_ATTR_ICON_RES_ID, mIconResId);
         }
         if (mTitleResId != ID_NULL) {
-            XmlUtils.writeIntAttribute(out, XML_ATTR_TITLE_RES_ID, mTitleResId);
+            out.attributeInt(null, XML_ATTR_TITLE_RES_ID, mTitleResId);
         }
         if (mDialogMessageResId != ID_NULL) {
-            XmlUtils.writeIntAttribute(out, XML_ATTR_DIALOG_MESSAGE_RES_ID, mDialogMessageResId);
+            out.attributeInt(null, XML_ATTR_DIALOG_MESSAGE_RES_ID, mDialogMessageResId);
         } else {
             XmlUtils.writeStringAttribute(out, XML_ATTR_DIALOG_MESSAGE, mDialogMessage);
         }
         if (mNeutralButtonTextResId != ID_NULL) {
-            XmlUtils.writeIntAttribute(out, XML_ATTR_BUTTON_TEXT_RES_ID, mNeutralButtonTextResId);
+            out.attributeInt(null, XML_ATTR_BUTTON_TEXT_RES_ID, mNeutralButtonTextResId);
         }
-        XmlUtils.writeIntAttribute(out, XML_ATTR_BUTTON_ACTION, mNeutralButtonAction);
+        out.attributeInt(null, XML_ATTR_BUTTON_ACTION, mNeutralButtonAction);
     }
 
     /**
      * @hide
      */
-    public static SuspendDialogInfo restoreFromXml(XmlPullParser in) {
+    public static SuspendDialogInfo restoreFromXml(TypedXmlPullParser in) {
         final SuspendDialogInfo.Builder dialogInfoBuilder = new SuspendDialogInfo.Builder();
         try {
-            final int iconId = XmlUtils.readIntAttribute(in, XML_ATTR_ICON_RES_ID, ID_NULL);
-            final int titleId = XmlUtils.readIntAttribute(in, XML_ATTR_TITLE_RES_ID, ID_NULL);
-            final int buttonTextId = XmlUtils.readIntAttribute(in, XML_ATTR_BUTTON_TEXT_RES_ID,
-                    ID_NULL);
-            final int buttonAction = XmlUtils.readIntAttribute(in, XML_ATTR_BUTTON_ACTION,
-                    BUTTON_ACTION_MORE_DETAILS);
-            final int dialogMessageResId = XmlUtils.readIntAttribute(
-                    in, XML_ATTR_DIALOG_MESSAGE_RES_ID, ID_NULL);
+            final int iconId = in.getAttributeInt(null, XML_ATTR_ICON_RES_ID, ID_NULL);
+            final int titleId = in.getAttributeInt(null, XML_ATTR_TITLE_RES_ID, ID_NULL);
+            final int buttonTextId =
+                    in.getAttributeInt(null, XML_ATTR_BUTTON_TEXT_RES_ID, ID_NULL);
+            final int buttonAction =
+                    in.getAttributeInt(null, XML_ATTR_BUTTON_ACTION, BUTTON_ACTION_MORE_DETAILS);
+            final int dialogMessageResId =
+                    in.getAttributeInt(null, XML_ATTR_DIALOG_MESSAGE_RES_ID, ID_NULL);
             final String dialogMessage = XmlUtils.readStringAttribute(in, XML_ATTR_DIALOG_MESSAGE);
 
             if (iconId != ID_NULL) {
diff --git a/core/java/android/content/pm/XmlSerializerAndParser.java b/core/java/android/content/pm/XmlSerializerAndParser.java
index 5dce839..51cd6ca 100644
--- a/core/java/android/content/pm/XmlSerializerAndParser.java
+++ b/core/java/android/content/pm/XmlSerializerAndParser.java
@@ -17,6 +17,10 @@
 package android.content.pm;
 
 import android.compat.annotation.UnsupportedAppUsage;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
+
+import com.android.internal.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -26,8 +30,16 @@
 
 /** @hide */
 public interface XmlSerializerAndParser<T> {
+    void writeAsXml(T item, TypedXmlSerializer out) throws IOException;
+    T createFromXml(TypedXmlPullParser parser) throws IOException, XmlPullParserException;
+
     @UnsupportedAppUsage
-    void writeAsXml(T item, XmlSerializer out) throws IOException;
+    default void writeAsXml(T item, XmlSerializer out) throws IOException {
+        writeAsXml(item, XmlUtils.makeTyped(out));
+    }
+
     @UnsupportedAppUsage
-    T createFromXml(XmlPullParser parser) throws IOException, XmlPullParserException;
+    default T createFromXml(XmlPullParser parser) throws IOException, XmlPullParserException {
+        return createFromXml(XmlUtils.makeTyped(parser));
+    }
 }
diff --git a/core/java/android/content/pm/dex/OWNERS b/core/java/android/content/pm/dex/OWNERS
new file mode 100644
index 0000000..267e5d58
--- /dev/null
+++ b/core/java/android/content/pm/dex/OWNERS
@@ -0,0 +1,7 @@
+# Bug component: 86431
+
+toddke@android.com
+toddke@google.com
+patb@google.com
+calin@google.com
+ngeoffray@google.com
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index 72a66ed..f583e25 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -18,9 +18,11 @@
 
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+import static android.content.pm.PackageParser.APK_FILE_EXTENSION;
 import static android.content.pm.parsing.ParsingPackageUtils.validateName;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 
+import android.annotation.NonNull;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
@@ -50,6 +52,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
 
 /** @hide */
 public class ApkLiteParseUtils {
@@ -95,8 +98,8 @@
             final PackageParser.ApkLite baseApk = result.getResult();
             final String packagePath = packageFile.getAbsolutePath();
             return input.success(
-                    new PackageParser.PackageLite(packagePath, baseApk, null, null, null, null,
-                            null, null));
+                    new PackageParser.PackageLite(packagePath, baseApk.codePath, baseApk, null,
+                            null, null, null, null, null));
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
@@ -159,13 +162,43 @@
         }
 
         final PackageParser.ApkLite baseApk = apks.remove(null);
+        return composePackageLiteFromApks(input, packageDir, baseApk, apks);
+    }
+
+    /**
+     * Utility method that retrieves lightweight details about the package by given location,
+     * base APK, and split APKs.
+     *
+     * @param packageDir Path to the package
+     * @param baseApk Parsed base APK
+     * @param splitApks Parsed split APKs
+     * @return PackageLite
+     */
+    public static ParseResult<PackageParser.PackageLite> composePackageLiteFromApks(
+            ParseInput input, File packageDir, PackageParser.ApkLite baseApk,
+            ArrayMap<String, PackageParser.ApkLite> splitApks) {
+        return composePackageLiteFromApks(input, packageDir, baseApk, splitApks, false);
+    }
+
+    /**
+     * Utility method that retrieves lightweight details about the package by given location,
+     * base APK, and split APKs.
+     *
+     * @param packageDir Path to the package
+     * @param baseApk Parsed base APK
+     * @param splitApks Parsed split APKs
+     * @param apkRenamed Indicate whether the APKs are renamed after parsed.
+     * @return PackageLite
+     */
+    public static ParseResult<PackageParser.PackageLite> composePackageLiteFromApks(
+            ParseInput input, File packageDir, PackageParser.ApkLite baseApk,
+            ArrayMap<String, PackageParser.ApkLite> splitApks, boolean apkRenamed) {
         if (baseApk == null) {
             return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
                     "Missing base APK in " + packageDir);
         }
-
         // Always apply deterministic ordering based on splitName
-        final int size = apks.size();
+        final int size = ArrayUtils.size(splitApks);
 
         String[] splitNames = null;
         boolean[] isFeatureSplits = null;
@@ -181,23 +214,39 @@
             splitCodePaths = new String[size];
             splitRevisionCodes = new int[size];
 
-            splitNames = apks.keySet().toArray(splitNames);
+            splitNames = splitApks.keySet().toArray(splitNames);
             Arrays.sort(splitNames, PackageParser.sSplitNameComparator);
 
             for (int i = 0; i < size; i++) {
-                final PackageParser.ApkLite apk = apks.get(splitNames[i]);
+                final PackageParser.ApkLite apk = splitApks.get(splitNames[i]);
                 usesSplitNames[i] = apk.usesSplitName;
                 isFeatureSplits[i] = apk.isFeatureSplit;
                 configForSplits[i] = apk.configForSplit;
-                splitCodePaths[i] = apk.codePath;
+                splitCodePaths[i] = apkRenamed ? new File(packageDir,
+                        splitNameToFileName(apk)).getAbsolutePath() : apk.codePath;
                 splitRevisionCodes[i] = apk.revisionCode;
             }
         }
 
         final String codePath = packageDir.getAbsolutePath();
-        return input.success(new PackageParser.PackageLite(codePath, baseApk, splitNames,
-                isFeatureSplits, usesSplitNames, configForSplits, splitCodePaths,
-                splitRevisionCodes));
+        final String baseCodePath = apkRenamed ? new File(packageDir,
+                splitNameToFileName(baseApk)).getAbsolutePath() : baseApk.codePath;
+        return input.success(
+                new PackageParser.PackageLite(codePath, baseCodePath, baseApk, splitNames,
+                        isFeatureSplits, usesSplitNames, configForSplits, splitCodePaths,
+                        splitRevisionCodes));
+    }
+
+    /**
+     * Utility method that retrieves canonical file name by given split name from parsed APK.
+     *
+     * @param apk Parsed APK
+     * @return The canonical file name
+     */
+    public static String splitNameToFileName(@NonNull PackageParser.ApkLite apk) {
+        Objects.requireNonNull(apk);
+        final String fileName = apk.splitName == null ? "base" : "split_" + apk.splitName;
+        return fileName + APK_FILE_EXTENSION;
     }
 
     /**
diff --git a/core/java/android/content/pm/permission/OWNERS b/core/java/android/content/pm/permission/OWNERS
new file mode 100644
index 0000000..cde7b2a
--- /dev/null
+++ b/core/java/android/content/pm/permission/OWNERS
@@ -0,0 +1,11 @@
+# Bug component: 137825
+
+toddke@android.com
+toddke@google.com
+patb@google.com
+moltmann@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
+zhanghai@google.com
+evanseverson@google.com
+ntmyren@google.com
diff --git a/core/java/android/content/pm/split/OWNERS b/core/java/android/content/pm/split/OWNERS
new file mode 100644
index 0000000..3d126d2
--- /dev/null
+++ b/core/java/android/content/pm/split/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 36137
+
+toddke@android.com
+toddke@google.com
+patb@google.com
diff --git a/core/java/android/content/res/OWNERS b/core/java/android/content/res/OWNERS
new file mode 100644
index 0000000..bc2355c
--- /dev/null
+++ b/core/java/android/content/res/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 568761
+
+toddke@android.com
+toddke@google.com
+patb@google.com
+rtmitchell@google.com
diff --git a/core/java/android/content/rollback/OWNERS b/core/java/android/content/rollback/OWNERS
new file mode 100644
index 0000000..3093fd6
--- /dev/null
+++ b/core/java/android/content/rollback/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 557916
+
+narayan@google.com
+nandana@google.com
+olilan@google.com
diff --git a/core/java/android/database/OWNERS b/core/java/android/database/OWNERS
index 7e19942..1734cfc 100644
--- a/core/java/android/database/OWNERS
+++ b/core/java/android/database/OWNERS
@@ -1,3 +1,3 @@
 omakoto@google.com
-jsharkey@android.com
+jsharkey@google.com
 yamasani@google.com
diff --git a/core/java/android/gesture/OWNERS b/core/java/android/gesture/OWNERS
new file mode 100644
index 0000000..b3b8775
--- /dev/null
+++ b/core/java/android/gesture/OWNERS
@@ -0,0 +1,8 @@
+# Bug component: 25700
+
+romainguy@google.com
+alanv@google.com
+adamp@google.com
+aurimas@google.com
+nduca@google.com
+sumir@google.com
diff --git a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
index cb43943..cc12125 100644
--- a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
@@ -36,7 +36,7 @@
     // Retrieve static sensor properties
     SensorPropertiesInternal getSensorProperties(String opPackageName);
 
-    // Requests a proto dump of the service. See biometrics.proto
+    // Requests a proto dump of the sensor. See biometrics.proto
     byte[] dumpSensorServiceStateProto();
 
     // This method prepares the service to start authenticating, but doesn't start authentication.
diff --git a/core/java/android/hardware/biometrics/OWNERS b/core/java/android/hardware/biometrics/OWNERS
new file mode 100644
index 0000000..33527f8
--- /dev/null
+++ b/core/java/android/hardware/biometrics/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 879035
+
+jaggies@google.com
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 232056c..0f595b7 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1467,12 +1467,13 @@
      * to any real physical measurement, but <code>0.0f</code> still represents farthest
      * focus, and {@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance} represents the
      * nearest focus the device can achieve.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED UNCALIBRATED}</li>
      *   <li>{@link #LENS_INFO_FOCUS_DISTANCE_CALIBRATION_APPROXIMATE APPROXIMATE}</li>
      *   <li>{@link #LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED CALIBRATED}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * <p><b>Limited capability</b> -
      * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
@@ -1495,12 +1496,13 @@
     /**
      * <p>Direction the camera faces relative to
      * device screen.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #LENS_FACING_FRONT FRONT}</li>
      *   <li>{@link #LENS_FACING_BACK BACK}</li>
      *   <li>{@link #LENS_FACING_EXTERNAL EXTERNAL}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p>This key is available on all devices.</p>
      * @see #LENS_FACING_FRONT
      * @see #LENS_FACING_BACK
@@ -1726,12 +1728,13 @@
      * {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation} and {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}.</p>
      * <p>Different calibration methods and use cases can produce better or worse results
      * depending on the selected coordinate origin.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #LENS_POSE_REFERENCE_PRIMARY_CAMERA PRIMARY_CAMERA}</li>
      *   <li>{@link #LENS_POSE_REFERENCE_GYROSCOPE GYROSCOPE}</li>
      *   <li>{@link #LENS_POSE_REFERENCE_UNDEFINED UNDEFINED}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
@@ -2057,7 +2060,7 @@
      * </ul>
      * <p>Other capabilities may be available on either FULL or LIMITED
      * devices, but the application should query this key to be sure.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE BACKWARD_COMPATIBLE}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR MANUAL_SENSOR}</li>
@@ -2075,7 +2078,8 @@
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA SECURE_IMAGE_DATA}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA SYSTEM_CAMERA}</li>
      *   <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING OFFLINE_PROCESSING}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p>This key is available on all devices.</p>
      *
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
@@ -2772,14 +2776,17 @@
      * </ol>
      * </li>
      * <li>Setting {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} to values different than 1.0 and
-     * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to be windowboxing at the same time is undefined behavior.</li>
+     * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to be windowboxing at the same time are not supported. In this
+     * case, the camera framework will override the {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to be the active
+     * array.</li>
      * </ul>
      * <p>LEGACY capability devices will only support CENTER_ONLY cropping.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #SCALER_CROPPING_TYPE_CENTER_ONLY CENTER_ONLY}</li>
      *   <li>{@link #SCALER_CROPPING_TYPE_FREEFORM FREEFORM}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p>This key is available on all devices.</p>
      *
      * @see CaptureRequest#CONTROL_ZOOM_RATIO
@@ -2964,7 +2971,7 @@
      * represents the colors in the top-left 2x2 section of
      * the sensor, in reading order, for a Bayer camera, or the
      * light spectrum it captures for MONOCHROME camera.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB RGGB}</li>
      *   <li>{@link #SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG GRBG}</li>
@@ -2973,7 +2980,8 @@
      *   <li>{@link #SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB RGB}</li>
      *   <li>{@link #SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_MONO MONO}</li>
      *   <li>{@link #SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_NIR NIR}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
      * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
@@ -3115,11 +3123,12 @@
      * may not based on a time source that can be compared to other system time sources.</p>
      * <p>This characteristic defines the source for the timestamps, and therefore whether they
      * can be compared against other system time sources/timestamps.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN UNKNOWN}</li>
      *   <li>{@link #SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME REALTIME}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p>This key is available on all devices.</p>
      * @see #SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN
      * @see #SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME
@@ -3229,7 +3238,7 @@
      * {@link CameraCharacteristics#SENSOR_REFERENCE_ILLUMINANT2 android.sensor.referenceIlluminant2} and its corresponding matrices.</p>
      * <p>Starting from Android Q, this key will not be present for a MONOCHROME camera, even if
      * the camera device has RAW capability.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT DAYLIGHT}</li>
      *   <li>{@link #SENSOR_REFERENCE_ILLUMINANT1_FLUORESCENT FLUORESCENT}</li>
@@ -3250,7 +3259,8 @@
      *   <li>{@link #SENSOR_REFERENCE_ILLUMINANT1_D75 D75}</li>
      *   <li>{@link #SENSOR_REFERENCE_ILLUMINANT1_D50 D50}</li>
      *   <li>{@link #SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN ISO_STUDIO_TUNGSTEN}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p>
      *
@@ -3725,10 +3735,11 @@
 
     /**
      * <p>A list of camera LEDs that are available on this system.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #LED_AVAILABLE_LEDS_TRANSMIT TRANSMIT}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * @see #LED_AVAILABLE_LEDS_TRANSMIT
      * @hide
@@ -3797,14 +3808,15 @@
      *   ({@link CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION android.lens.info.availableOpticalStabilization},
      *    {@link CameraCharacteristics#CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES android.control.availableVideoStabilizationModes})</li>
      * </ul>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED}</li>
      *   <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}</li>
      *   <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY}</li>
      *   <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_3 3}</li>
      *   <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL EXTERNAL}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p>This key is available on all devices.</p>
      *
      * @see CameraCharacteristics#CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES
@@ -3848,11 +3860,12 @@
      * must occur before the camera device knows for a fact that the new
      * submitted camera settings have been applied in outgoing frames.</p>
      * <p><b>Units</b>: Frame counts</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #SYNC_MAX_LATENCY_PER_FRAME_CONTROL PER_FRAME_CONTROL}</li>
      *   <li>{@link #SYNC_MAX_LATENCY_UNKNOWN UNKNOWN}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * A positive value, PER_FRAME_CONTROL, or UNKNOWN.</p>
      * <p>This key is available on all devices.</p>
@@ -4100,11 +4113,12 @@
      * onCaptureStarted callback.</p>
      * <p>This tag is only applicable if the logical camera device supports concurrent physical
      * streams from different physical cameras.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE APPROXIMATE}</li>
      *   <li>{@link #LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED CALIBRATED}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * <p><b>Limited capability</b> -
      * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index d931789..d7aee10 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1028,12 +1028,13 @@
      * </code></pre>
      * <p>Both the input and output value ranges must match. Overflow/underflow
      * values are clipped to fit within the range.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #COLOR_CORRECTION_MODE_TRANSFORM_MATRIX TRANSFORM_MATRIX}</li>
      *   <li>{@link #COLOR_CORRECTION_MODE_FAST FAST}</li>
      *   <li>{@link #COLOR_CORRECTION_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
      * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
@@ -1121,12 +1122,13 @@
      * capture rate. FAST means the camera device will not slow down capture rate when
      * applying aberration correction.</p>
      * <p>LEGACY devices will always be in FAST mode.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #COLOR_CORRECTION_ABERRATION_MODE_OFF OFF}</li>
      *   <li>{@link #COLOR_CORRECTION_ABERRATION_MODE_FAST FAST}</li>
      *   <li>{@link #COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES android.colorCorrection.availableAberrationModes}</p>
      * <p>This key is available on all devices.</p>
@@ -1173,13 +1175,14 @@
      * ensure it selects exposure times that do not cause banding
      * issues. The {@link CaptureResult#STATISTICS_SCENE_FLICKER android.statistics.sceneFlicker} key can assist
      * the application in this.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_AE_ANTIBANDING_MODE_OFF OFF}</li>
      *   <li>{@link #CONTROL_AE_ANTIBANDING_MODE_50HZ 50HZ}</li>
      *   <li>{@link #CONTROL_AE_ANTIBANDING_MODE_60HZ 60HZ}</li>
      *   <li>{@link #CONTROL_AE_ANTIBANDING_MODE_AUTO AUTO}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br></p>
      * <p>{@link CameraCharacteristics#CONTROL_AE_AVAILABLE_ANTIBANDING_MODES android.control.aeAvailableAntibandingModes}</p>
      * <p>This key is available on all devices.</p>
@@ -1304,7 +1307,7 @@
      * camera device auto-exposure routine for the overridden
      * fields for a given capture will be available in its
      * CaptureResult.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_AE_MODE_OFF OFF}</li>
      *   <li>{@link #CONTROL_AE_MODE_ON ON}</li>
@@ -1312,7 +1315,8 @@
      *   <li>{@link #CONTROL_AE_MODE_ON_ALWAYS_FLASH ON_ALWAYS_FLASH}</li>
      *   <li>{@link #CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE ON_AUTO_FLASH_REDEYE}</li>
      *   <li>{@link #CONTROL_AE_MODE_ON_EXTERNAL_FLASH ON_EXTERNAL_FLASH}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_MODES android.control.aeAvailableModes}</p>
      * <p>This key is available on all devices.</p>
@@ -1478,12 +1482,13 @@
      * example.</p>
      * <p>If both the precapture and the auto-focus trigger are activated on the same request, then
      * the camera device will complete them in the optimal order for that device.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_AE_PRECAPTURE_TRIGGER_IDLE IDLE}</li>
      *   <li>{@link #CONTROL_AE_PRECAPTURE_TRIGGER_START START}</li>
      *   <li>{@link #CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL CANCEL}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * <p><b>Limited capability</b> -
      * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
@@ -1514,7 +1519,7 @@
      * <p>If the lens is controlled by the camera device auto-focus algorithm,
      * the camera device will report the current AF status in {@link CaptureResult#CONTROL_AF_STATE android.control.afState}
      * in result metadata.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_AF_MODE_OFF OFF}</li>
      *   <li>{@link #CONTROL_AF_MODE_AUTO AUTO}</li>
@@ -1522,7 +1527,8 @@
      *   <li>{@link #CONTROL_AF_MODE_CONTINUOUS_VIDEO CONTINUOUS_VIDEO}</li>
      *   <li>{@link #CONTROL_AF_MODE_CONTINUOUS_PICTURE CONTINUOUS_PICTURE}</li>
      *   <li>{@link #CONTROL_AF_MODE_EDOF EDOF}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#CONTROL_AF_AVAILABLE_MODES android.control.afAvailableModes}</p>
      * <p>This key is available on all devices.</p>
@@ -1637,12 +1643,13 @@
      * focus sweep), the camera device may delay acting on a later trigger until the previous
      * trigger has been fully handled. This may lead to longer intervals between the trigger and
      * changes to {@link CaptureResult#CONTROL_AF_STATE android.control.afState}, for example.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_AF_TRIGGER_IDLE IDLE}</li>
      *   <li>{@link #CONTROL_AF_TRIGGER_START START}</li>
      *   <li>{@link #CONTROL_AF_TRIGGER_CANCEL CANCEL}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p>This key is available on all devices.</p>
      *
      * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
@@ -1710,7 +1717,7 @@
      * {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform},
      * {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
      * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} are ignored.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_AWB_MODE_OFF OFF}</li>
      *   <li>{@link #CONTROL_AWB_MODE_AUTO AUTO}</li>
@@ -1721,7 +1728,8 @@
      *   <li>{@link #CONTROL_AWB_MODE_CLOUDY_DAYLIGHT CLOUDY_DAYLIGHT}</li>
      *   <li>{@link #CONTROL_AWB_MODE_TWILIGHT TWILIGHT}</li>
      *   <li>{@link #CONTROL_AWB_MODE_SHADE SHADE}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#CONTROL_AWB_AVAILABLE_MODES android.control.awbAvailableModes}</p>
      * <p>This key is available on all devices.</p>
@@ -1835,7 +1843,7 @@
      * MANUAL_SENSOR.
      *   * MOTION_TRACKING will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains
      * MOTION_TRACKING.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_CAPTURE_INTENT_CUSTOM CUSTOM}</li>
      *   <li>{@link #CONTROL_CAPTURE_INTENT_PREVIEW PREVIEW}</li>
@@ -1845,7 +1853,8 @@
      *   <li>{@link #CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG ZERO_SHUTTER_LAG}</li>
      *   <li>{@link #CONTROL_CAPTURE_INTENT_MANUAL MANUAL}</li>
      *   <li>{@link #CONTROL_CAPTURE_INTENT_MOTION_TRACKING MOTION_TRACKING}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p>This key is available on all devices.</p>
      *
      * @see CaptureRequest#CONTROL_MODE
@@ -1872,7 +1881,7 @@
      * implementor of the camera device, and should not be
      * depended on to be consistent (or present) across all
      * devices.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_EFFECT_MODE_OFF OFF}</li>
      *   <li>{@link #CONTROL_EFFECT_MODE_MONO MONO}</li>
@@ -1883,7 +1892,8 @@
      *   <li>{@link #CONTROL_EFFECT_MODE_WHITEBOARD WHITEBOARD}</li>
      *   <li>{@link #CONTROL_EFFECT_MODE_BLACKBOARD BLACKBOARD}</li>
      *   <li>{@link #CONTROL_EFFECT_MODE_AQUA AQUA}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#CONTROL_AVAILABLE_EFFECTS android.control.availableEffects}</p>
      * <p>This key is available on all devices.</p>
@@ -1922,14 +1932,15 @@
      * update, as if this frame is never captured. This mode can be used in the scenario
      * where the application doesn't want a 3A manual control capture to affect
      * the subsequent auto 3A capture results.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_MODE_OFF OFF}</li>
      *   <li>{@link #CONTROL_MODE_AUTO AUTO}</li>
      *   <li>{@link #CONTROL_MODE_USE_SCENE_MODE USE_SCENE_MODE}</li>
      *   <li>{@link #CONTROL_MODE_OFF_KEEP_STATE OFF_KEEP_STATE}</li>
      *   <li>{@link #CONTROL_MODE_USE_EXTENDED_SCENE_MODE USE_EXTENDED_SCENE_MODE}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#CONTROL_AVAILABLE_MODES android.control.availableModes}</p>
      * <p>This key is available on all devices.</p>
@@ -1959,7 +1970,7 @@
      * to the implementor of the camera device. Their behavior will not be
      * consistent across all devices, and any given device may only implement
      * a subset of these modes.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_SCENE_MODE_DISABLED DISABLED}</li>
      *   <li>{@link #CONTROL_SCENE_MODE_FACE_PRIORITY FACE_PRIORITY}</li>
@@ -1980,7 +1991,8 @@
      *   <li>{@link #CONTROL_SCENE_MODE_BARCODE BARCODE}</li>
      *   <li>{@link #CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO HIGH_SPEED_VIDEO}</li>
      *   <li>{@link #CONTROL_SCENE_MODE_HDR HDR}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES android.control.availableSceneModes}</p>
      * <p>This key is available on all devices.</p>
@@ -2041,11 +2053,12 @@
      * ({@link CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE android.lens.opticalStabilizationMode}), turning both modes on may
      * produce undesirable interaction, so it is recommended not to enable
      * both at the same time.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_VIDEO_STABILIZATION_MODE_OFF OFF}</li>
      *   <li>{@link #CONTROL_VIDEO_STABILIZATION_MODE_ON ON}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p>This key is available on all devices.</p>
      *
      * @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
@@ -2155,12 +2168,13 @@
      * with different field of view. As a result, when bokeh mode is enabled, the camera device
      * may override {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} or {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}, and the field of
      * view may be smaller than when bokeh mode is off.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_EXTENDED_SCENE_MODE_DISABLED DISABLED}</li>
      *   <li>{@link #CONTROL_EXTENDED_SCENE_MODE_BOKEH_STILL_CAPTURE BOKEH_STILL_CAPTURE}</li>
      *   <li>{@link #CONTROL_EXTENDED_SCENE_MODE_BOKEH_CONTINUOUS BOKEH_CONTINUOUS}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      *
      * @see CaptureRequest#CONTROL_ZOOM_RATIO
@@ -2243,7 +2257,10 @@
      * explicitly set {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}, its value defaults to 1.0.</p>
      * <p>One limitation of controlling zoom using zoomRatio is that the {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}
      * must only be used for letterboxing or pillarboxing of the sensor active array, and no
-     * FREEFORM cropping can be used with {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} other than 1.0.</p>
+     * FREEFORM cropping can be used with {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} other than 1.0. If
+     * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} is not 1.0, and {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} is set to be
+     * windowboxing, the camera framework will override the {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to be
+     * the active array.</p>
      * <p><b>Range of valid values:</b><br>
      * {@link CameraCharacteristics#CONTROL_ZOOM_RATIO_RANGE android.control.zoomRatioRange}</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
@@ -2284,13 +2301,14 @@
      * device will apply FAST/HIGH_QUALITY YUV-domain edge enhancement, respectively.
      * The camera device may adjust its internal edge enhancement parameters for best
      * image quality based on the {@link CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR android.reprocess.effectiveExposureFactor}, if it is set.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #EDGE_MODE_OFF OFF}</li>
      *   <li>{@link #EDGE_MODE_FAST FAST}</li>
      *   <li>{@link #EDGE_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
      *   <li>{@link #EDGE_MODE_ZERO_SHUTTER_LAG ZERO_SHUTTER_LAG}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#EDGE_AVAILABLE_EDGE_MODES android.edge.availableEdgeModes}</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
@@ -2326,12 +2344,13 @@
      * <p>When set to TORCH, the flash will be on continuously. This mode can be used
      * for use cases such as preview, auto-focus assist, still capture, or video recording.</p>
      * <p>The flash status will be reported by {@link CaptureResult#FLASH_STATE android.flash.state} in the capture result metadata.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #FLASH_MODE_OFF OFF}</li>
      *   <li>{@link #FLASH_MODE_SINGLE SINGLE}</li>
      *   <li>{@link #FLASH_MODE_TORCH TORCH}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p>This key is available on all devices.</p>
      *
      * @see CaptureRequest#CONTROL_AE_MODE
@@ -2352,12 +2371,13 @@
      * <p>Hotpixel correction interpolates out, or otherwise removes, pixels
      * that do not accurately measure the incoming light (i.e. pixels that
      * are stuck at an arbitrary value or are oversensitive).</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #HOT_PIXEL_MODE_OFF OFF}</li>
      *   <li>{@link #HOT_PIXEL_MODE_FAST FAST}</li>
      *   <li>{@link #HOT_PIXEL_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES android.hotPixel.availableHotPixelModes}</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
@@ -2685,11 +2705,12 @@
      * <p>Not all devices will support OIS; see
      * {@link CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION android.lens.info.availableOpticalStabilization} for
      * available controls.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #LENS_OPTICAL_STABILIZATION_MODE_OFF OFF}</li>
      *   <li>{@link #LENS_OPTICAL_STABILIZATION_MODE_ON ON}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION android.lens.info.availableOpticalStabilization}</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
@@ -2735,14 +2756,15 @@
      * will apply FAST/HIGH_QUALITY YUV domain noise reduction, respectively. The camera device
      * may adjust the noise reduction parameters for best image quality based on the
      * {@link CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR android.reprocess.effectiveExposureFactor} if it is set.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #NOISE_REDUCTION_MODE_OFF OFF}</li>
      *   <li>{@link #NOISE_REDUCTION_MODE_FAST FAST}</li>
      *   <li>{@link #NOISE_REDUCTION_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
      *   <li>{@link #NOISE_REDUCTION_MODE_MINIMAL MINIMAL}</li>
      *   <li>{@link #NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG ZERO_SHUTTER_LAG}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES android.noiseReduction.availableNoiseReductionModes}</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
@@ -2956,14 +2978,15 @@
      * <li>640x480 stream: top-left: <code>(781, 375)</code> on active array, size: <code>(640, 480)</code>, downscaled 1.17x from sensor pixels</li>
      * <li>1280x720 stream: top-left: <code>(711, 375)</code> on active array, size: <code>(1280, 720)</code>, upscaled 1.71x from sensor pixels</li>
      * </ul>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #SCALER_ROTATE_AND_CROP_NONE NONE}</li>
      *   <li>{@link #SCALER_ROTATE_AND_CROP_90 90}</li>
      *   <li>{@link #SCALER_ROTATE_AND_CROP_180 180}</li>
      *   <li>{@link #SCALER_ROTATE_AND_CROP_270 270}</li>
      *   <li>{@link #SCALER_ROTATE_AND_CROP_AUTO AUTO}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES android.scaler.availableRotateAndCropModes}</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
@@ -3163,7 +3186,7 @@
      * occur (and that the test pattern remain unmodified, since the flash
      * would not actually affect it).</p>
      * <p>Defaults to OFF.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #SENSOR_TEST_PATTERN_MODE_OFF OFF}</li>
      *   <li>{@link #SENSOR_TEST_PATTERN_MODE_SOLID_COLOR SOLID_COLOR}</li>
@@ -3171,7 +3194,8 @@
      *   <li>{@link #SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY COLOR_BARS_FADE_TO_GRAY}</li>
      *   <li>{@link #SENSOR_TEST_PATTERN_MODE_PN9 PN9}</li>
      *   <li>{@link #SENSOR_TEST_PATTERN_MODE_CUSTOM1 CUSTOM1}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#SENSOR_AVAILABLE_TEST_PATTERN_MODES android.sensor.availableTestPatternModes}</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
@@ -3215,12 +3239,13 @@
      * AWB are in AUTO modes({@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} <code>!=</code> OFF and {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} <code>!=</code>
      * OFF), to get best results, it is recommended that the applications wait for the AE and AWB
      * to be converged before using the returned shading map data.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #SHADING_MODE_OFF OFF}</li>
      *   <li>{@link #SHADING_MODE_FAST FAST}</li>
      *   <li>{@link #SHADING_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#SHADING_AVAILABLE_MODES android.shading.availableModes}</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
@@ -3249,12 +3274,13 @@
      * <p>Whether face detection is enabled, and whether it
      * should output just the basic fields or the full set of
      * fields.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #STATISTICS_FACE_DETECT_MODE_OFF OFF}</li>
      *   <li>{@link #STATISTICS_FACE_DETECT_MODE_SIMPLE SIMPLE}</li>
      *   <li>{@link #STATISTICS_FACE_DETECT_MODE_FULL FULL}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES android.statistics.info.availableFaceDetectModes}</p>
      * <p>This key is available on all devices.</p>
@@ -3292,11 +3318,12 @@
      * android.statistics.lensShadingMap will be provided in
      * the output result metadata.</p>
      * <p>ON is always supported on devices with the RAW capability.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #STATISTICS_LENS_SHADING_MAP_MODE_OFF OFF}</li>
      *   <li>{@link #STATISTICS_LENS_SHADING_MAP_MODE_ON ON}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES android.statistics.info.availableLensShadingMapModes}</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
@@ -3323,11 +3350,12 @@
      * at 30fps may have 6-7 OIS samples per capture result. This information can be combined
      * with the rolling shutter skew to account for lens motion during image exposure in
      * post-processing algorithms.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #STATISTICS_OIS_DATA_MODE_OFF OFF}</li>
      *   <li>{@link #STATISTICS_OIS_DATA_MODE_ON ON}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_OIS_DATA_MODES android.statistics.info.availableOisDataModes}</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
@@ -3520,14 +3548,15 @@
      * <p>If a request is sent with CONTRAST_CURVE with the camera device's
      * provided curve in FAST or HIGH_QUALITY, the image's tonemap will be
      * roughly the same.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #TONEMAP_MODE_CONTRAST_CURVE CONTRAST_CURVE}</li>
      *   <li>{@link #TONEMAP_MODE_FAST FAST}</li>
      *   <li>{@link #TONEMAP_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
      *   <li>{@link #TONEMAP_MODE_GAMMA_VALUE GAMMA_VALUE}</li>
      *   <li>{@link #TONEMAP_MODE_PRESET_CURVE PRESET_CURVE}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#TONEMAP_AVAILABLE_TONE_MAP_MODES android.tonemap.availableToneMapModes}</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
@@ -3582,11 +3611,12 @@
      * <p><img alt="Rec. 709 tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png" /></p>
      * <p>Note that above figures show a 16 control points approximation of preset
      * curves. Camera devices may apply a different approximation to the curve.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #TONEMAP_PRESET_CURVE_SRGB SRGB}</li>
      *   <li>{@link #TONEMAP_PRESET_CURVE_REC709 REC709}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      *
      * @see CaptureRequest#TONEMAP_MODE
@@ -3751,12 +3781,13 @@
      * <li>{@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}</li>
      * <li>{@link CaptureResult#STATISTICS_FACES android.statistics.faces}</li>
      * </ul>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #DISTORTION_CORRECTION_MODE_OFF OFF}</li>
      *   <li>{@link #DISTORTION_CORRECTION_MODE_FAST FAST}</li>
      *   <li>{@link #DISTORTION_CORRECTION_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#DISTORTION_CORRECTION_AVAILABLE_MODES android.distortionCorrection.availableModes}</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index cd69788..66d8b50 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -449,12 +449,13 @@
      * </code></pre>
      * <p>Both the input and output value ranges must match. Overflow/underflow
      * values are clipped to fit within the range.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #COLOR_CORRECTION_MODE_TRANSFORM_MATRIX TRANSFORM_MATRIX}</li>
      *   <li>{@link #COLOR_CORRECTION_MODE_FAST FAST}</li>
      *   <li>{@link #COLOR_CORRECTION_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
      * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
@@ -542,12 +543,13 @@
      * capture rate. FAST means the camera device will not slow down capture rate when
      * applying aberration correction.</p>
      * <p>LEGACY devices will always be in FAST mode.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #COLOR_CORRECTION_ABERRATION_MODE_OFF OFF}</li>
      *   <li>{@link #COLOR_CORRECTION_ABERRATION_MODE_FAST FAST}</li>
      *   <li>{@link #COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES android.colorCorrection.availableAberrationModes}</p>
      * <p>This key is available on all devices.</p>
@@ -594,13 +596,14 @@
      * ensure it selects exposure times that do not cause banding
      * issues. The {@link CaptureResult#STATISTICS_SCENE_FLICKER android.statistics.sceneFlicker} key can assist
      * the application in this.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_AE_ANTIBANDING_MODE_OFF OFF}</li>
      *   <li>{@link #CONTROL_AE_ANTIBANDING_MODE_50HZ 50HZ}</li>
      *   <li>{@link #CONTROL_AE_ANTIBANDING_MODE_60HZ 60HZ}</li>
      *   <li>{@link #CONTROL_AE_ANTIBANDING_MODE_AUTO AUTO}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br></p>
      * <p>{@link CameraCharacteristics#CONTROL_AE_AVAILABLE_ANTIBANDING_MODES android.control.aeAvailableAntibandingModes}</p>
      * <p>This key is available on all devices.</p>
@@ -725,7 +728,7 @@
      * camera device auto-exposure routine for the overridden
      * fields for a given capture will be available in its
      * CaptureResult.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_AE_MODE_OFF OFF}</li>
      *   <li>{@link #CONTROL_AE_MODE_ON ON}</li>
@@ -733,7 +736,8 @@
      *   <li>{@link #CONTROL_AE_MODE_ON_ALWAYS_FLASH ON_ALWAYS_FLASH}</li>
      *   <li>{@link #CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE ON_AUTO_FLASH_REDEYE}</li>
      *   <li>{@link #CONTROL_AE_MODE_ON_EXTERNAL_FLASH ON_EXTERNAL_FLASH}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_MODES android.control.aeAvailableModes}</p>
      * <p>This key is available on all devices.</p>
@@ -899,12 +903,13 @@
      * example.</p>
      * <p>If both the precapture and the auto-focus trigger are activated on the same request, then
      * the camera device will complete them in the optimal order for that device.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_AE_PRECAPTURE_TRIGGER_IDLE IDLE}</li>
      *   <li>{@link #CONTROL_AE_PRECAPTURE_TRIGGER_START START}</li>
      *   <li>{@link #CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL CANCEL}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * <p><b>Limited capability</b> -
      * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
@@ -1139,7 +1144,7 @@
      * </tr>
      * </tbody>
      * </table>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_AE_STATE_INACTIVE INACTIVE}</li>
      *   <li>{@link #CONTROL_AE_STATE_SEARCHING SEARCHING}</li>
@@ -1147,7 +1152,8 @@
      *   <li>{@link #CONTROL_AE_STATE_LOCKED LOCKED}</li>
      *   <li>{@link #CONTROL_AE_STATE_FLASH_REQUIRED FLASH_REQUIRED}</li>
      *   <li>{@link #CONTROL_AE_STATE_PRECAPTURE PRECAPTURE}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * <p><b>Limited capability</b> -
      * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
@@ -1184,7 +1190,7 @@
      * <p>If the lens is controlled by the camera device auto-focus algorithm,
      * the camera device will report the current AF status in {@link CaptureResult#CONTROL_AF_STATE android.control.afState}
      * in result metadata.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_AF_MODE_OFF OFF}</li>
      *   <li>{@link #CONTROL_AF_MODE_AUTO AUTO}</li>
@@ -1192,7 +1198,8 @@
      *   <li>{@link #CONTROL_AF_MODE_CONTINUOUS_VIDEO CONTINUOUS_VIDEO}</li>
      *   <li>{@link #CONTROL_AF_MODE_CONTINUOUS_PICTURE CONTINUOUS_PICTURE}</li>
      *   <li>{@link #CONTROL_AF_MODE_EDOF EDOF}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#CONTROL_AF_AVAILABLE_MODES android.control.afAvailableModes}</p>
      * <p>This key is available on all devices.</p>
@@ -1307,12 +1314,13 @@
      * focus sweep), the camera device may delay acting on a later trigger until the previous
      * trigger has been fully handled. This may lead to longer intervals between the trigger and
      * changes to {@link CaptureResult#CONTROL_AF_STATE android.control.afState}, for example.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_AF_TRIGGER_IDLE IDLE}</li>
      *   <li>{@link #CONTROL_AF_TRIGGER_START START}</li>
      *   <li>{@link #CONTROL_AF_TRIGGER_CANCEL CANCEL}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p>This key is available on all devices.</p>
      *
      * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
@@ -1708,7 +1716,7 @@
      * </tr>
      * </tbody>
      * </table>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_AF_STATE_INACTIVE INACTIVE}</li>
      *   <li>{@link #CONTROL_AF_STATE_PASSIVE_SCAN PASSIVE_SCAN}</li>
@@ -1717,7 +1725,8 @@
      *   <li>{@link #CONTROL_AF_STATE_FOCUSED_LOCKED FOCUSED_LOCKED}</li>
      *   <li>{@link #CONTROL_AF_STATE_NOT_FOCUSED_LOCKED NOT_FOCUSED_LOCKED}</li>
      *   <li>{@link #CONTROL_AF_STATE_PASSIVE_UNFOCUSED PASSIVE_UNFOCUSED}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p>This key is available on all devices.</p>
      *
      * @see CaptureRequest#CONTROL_AF_MODE
@@ -1790,7 +1799,7 @@
      * {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform},
      * {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
      * {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} are ignored.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_AWB_MODE_OFF OFF}</li>
      *   <li>{@link #CONTROL_AWB_MODE_AUTO AUTO}</li>
@@ -1801,7 +1810,8 @@
      *   <li>{@link #CONTROL_AWB_MODE_CLOUDY_DAYLIGHT CLOUDY_DAYLIGHT}</li>
      *   <li>{@link #CONTROL_AWB_MODE_TWILIGHT TWILIGHT}</li>
      *   <li>{@link #CONTROL_AWB_MODE_SHADE SHADE}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#CONTROL_AWB_AVAILABLE_MODES android.control.awbAvailableModes}</p>
      * <p>This key is available on all devices.</p>
@@ -1915,7 +1925,7 @@
      * MANUAL_SENSOR.
      *   * MOTION_TRACKING will be supported if {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains
      * MOTION_TRACKING.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_CAPTURE_INTENT_CUSTOM CUSTOM}</li>
      *   <li>{@link #CONTROL_CAPTURE_INTENT_PREVIEW PREVIEW}</li>
@@ -1925,7 +1935,8 @@
      *   <li>{@link #CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG ZERO_SHUTTER_LAG}</li>
      *   <li>{@link #CONTROL_CAPTURE_INTENT_MANUAL MANUAL}</li>
      *   <li>{@link #CONTROL_CAPTURE_INTENT_MOTION_TRACKING MOTION_TRACKING}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p>This key is available on all devices.</p>
      *
      * @see CaptureRequest#CONTROL_MODE
@@ -2061,13 +2072,14 @@
      * </tr>
      * </tbody>
      * </table>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_AWB_STATE_INACTIVE INACTIVE}</li>
      *   <li>{@link #CONTROL_AWB_STATE_SEARCHING SEARCHING}</li>
      *   <li>{@link #CONTROL_AWB_STATE_CONVERGED CONVERGED}</li>
      *   <li>{@link #CONTROL_AWB_STATE_LOCKED LOCKED}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * <p><b>Limited capability</b> -
      * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
@@ -2096,7 +2108,7 @@
      * implementor of the camera device, and should not be
      * depended on to be consistent (or present) across all
      * devices.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_EFFECT_MODE_OFF OFF}</li>
      *   <li>{@link #CONTROL_EFFECT_MODE_MONO MONO}</li>
@@ -2107,7 +2119,8 @@
      *   <li>{@link #CONTROL_EFFECT_MODE_WHITEBOARD WHITEBOARD}</li>
      *   <li>{@link #CONTROL_EFFECT_MODE_BLACKBOARD BLACKBOARD}</li>
      *   <li>{@link #CONTROL_EFFECT_MODE_AQUA AQUA}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#CONTROL_AVAILABLE_EFFECTS android.control.availableEffects}</p>
      * <p>This key is available on all devices.</p>
@@ -2146,14 +2159,15 @@
      * update, as if this frame is never captured. This mode can be used in the scenario
      * where the application doesn't want a 3A manual control capture to affect
      * the subsequent auto 3A capture results.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_MODE_OFF OFF}</li>
      *   <li>{@link #CONTROL_MODE_AUTO AUTO}</li>
      *   <li>{@link #CONTROL_MODE_USE_SCENE_MODE USE_SCENE_MODE}</li>
      *   <li>{@link #CONTROL_MODE_OFF_KEEP_STATE OFF_KEEP_STATE}</li>
      *   <li>{@link #CONTROL_MODE_USE_EXTENDED_SCENE_MODE USE_EXTENDED_SCENE_MODE}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#CONTROL_AVAILABLE_MODES android.control.availableModes}</p>
      * <p>This key is available on all devices.</p>
@@ -2183,7 +2197,7 @@
      * to the implementor of the camera device. Their behavior will not be
      * consistent across all devices, and any given device may only implement
      * a subset of these modes.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_SCENE_MODE_DISABLED DISABLED}</li>
      *   <li>{@link #CONTROL_SCENE_MODE_FACE_PRIORITY FACE_PRIORITY}</li>
@@ -2204,7 +2218,8 @@
      *   <li>{@link #CONTROL_SCENE_MODE_BARCODE BARCODE}</li>
      *   <li>{@link #CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO HIGH_SPEED_VIDEO}</li>
      *   <li>{@link #CONTROL_SCENE_MODE_HDR HDR}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES android.control.availableSceneModes}</p>
      * <p>This key is available on all devices.</p>
@@ -2265,11 +2280,12 @@
      * ({@link CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE android.lens.opticalStabilizationMode}), turning both modes on may
      * produce undesirable interaction, so it is recommended not to enable
      * both at the same time.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_VIDEO_STABILIZATION_MODE_OFF OFF}</li>
      *   <li>{@link #CONTROL_VIDEO_STABILIZATION_MODE_ON ON}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p>This key is available on all devices.</p>
      *
      * @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
@@ -2362,11 +2378,12 @@
      * result. Otherwise the value will be NOT_DETECTED. The threshold for detection is similar
      * to what would trigger a new passive focus scan to begin in CONTINUOUS autofocus modes.</p>
      * <p>This key will be available if the camera device advertises this key via {@link android.hardware.camera2.CameraCharacteristics#getAvailableCaptureResultKeys }.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_AF_SCENE_CHANGE_NOT_DETECTED NOT_DETECTED}</li>
      *   <li>{@link #CONTROL_AF_SCENE_CHANGE_DETECTED DETECTED}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * @see #CONTROL_AF_SCENE_CHANGE_NOT_DETECTED
      * @see #CONTROL_AF_SCENE_CHANGE_DETECTED
@@ -2402,12 +2419,13 @@
      * with different field of view. As a result, when bokeh mode is enabled, the camera device
      * may override {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} or {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}, and the field of
      * view may be smaller than when bokeh mode is off.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #CONTROL_EXTENDED_SCENE_MODE_DISABLED DISABLED}</li>
      *   <li>{@link #CONTROL_EXTENDED_SCENE_MODE_BOKEH_STILL_CAPTURE BOKEH_STILL_CAPTURE}</li>
      *   <li>{@link #CONTROL_EXTENDED_SCENE_MODE_BOKEH_CONTINUOUS BOKEH_CONTINUOUS}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      *
      * @see CaptureRequest#CONTROL_ZOOM_RATIO
@@ -2490,7 +2508,10 @@
      * explicitly set {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}, its value defaults to 1.0.</p>
      * <p>One limitation of controlling zoom using zoomRatio is that the {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}
      * must only be used for letterboxing or pillarboxing of the sensor active array, and no
-     * FREEFORM cropping can be used with {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} other than 1.0.</p>
+     * FREEFORM cropping can be used with {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} other than 1.0. If
+     * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} is not 1.0, and {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} is set to be
+     * windowboxing, the camera framework will override the {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to be
+     * the active array.</p>
      * <p><b>Range of valid values:</b><br>
      * {@link CameraCharacteristics#CONTROL_ZOOM_RATIO_RANGE android.control.zoomRatioRange}</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
@@ -2531,13 +2552,14 @@
      * device will apply FAST/HIGH_QUALITY YUV-domain edge enhancement, respectively.
      * The camera device may adjust its internal edge enhancement parameters for best
      * image quality based on the {@link CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR android.reprocess.effectiveExposureFactor}, if it is set.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #EDGE_MODE_OFF OFF}</li>
      *   <li>{@link #EDGE_MODE_FAST FAST}</li>
      *   <li>{@link #EDGE_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
      *   <li>{@link #EDGE_MODE_ZERO_SHUTTER_LAG ZERO_SHUTTER_LAG}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#EDGE_AVAILABLE_EDGE_MODES android.edge.availableEdgeModes}</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
@@ -2573,12 +2595,13 @@
      * <p>When set to TORCH, the flash will be on continuously. This mode can be used
      * for use cases such as preview, auto-focus assist, still capture, or video recording.</p>
      * <p>The flash status will be reported by {@link CaptureResult#FLASH_STATE android.flash.state} in the capture result metadata.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #FLASH_MODE_OFF OFF}</li>
      *   <li>{@link #FLASH_MODE_SINGLE SINGLE}</li>
      *   <li>{@link #FLASH_MODE_TORCH TORCH}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p>This key is available on all devices.</p>
      *
      * @see CaptureRequest#CONTROL_AE_MODE
@@ -2610,14 +2633,15 @@
      * </ul>
      * <p>In all other conditions the state will not be available on
      * LEGACY devices (i.e. it will be <code>null</code>).</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #FLASH_STATE_UNAVAILABLE UNAVAILABLE}</li>
      *   <li>{@link #FLASH_STATE_CHARGING CHARGING}</li>
      *   <li>{@link #FLASH_STATE_READY READY}</li>
      *   <li>{@link #FLASH_STATE_FIRED FIRED}</li>
      *   <li>{@link #FLASH_STATE_PARTIAL PARTIAL}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * <p><b>Limited capability</b> -
      * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
@@ -2643,12 +2667,13 @@
      * <p>Hotpixel correction interpolates out, or otherwise removes, pixels
      * that do not accurately measure the incoming light (i.e. pixels that
      * are stuck at an arbitrary value or are oversensitive).</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #HOT_PIXEL_MODE_OFF OFF}</li>
      *   <li>{@link #HOT_PIXEL_MODE_FAST FAST}</li>
      *   <li>{@link #HOT_PIXEL_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES android.hotPixel.availableHotPixelModes}</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
@@ -2985,11 +3010,12 @@
      * <p>Not all devices will support OIS; see
      * {@link CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION android.lens.info.availableOpticalStabilization} for
      * available controls.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #LENS_OPTICAL_STABILIZATION_MODE_OFF OFF}</li>
      *   <li>{@link #LENS_OPTICAL_STABILIZATION_MODE_ON ON}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION android.lens.info.availableOpticalStabilization}</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
@@ -3029,11 +3055,12 @@
      * <p>Then this state will always be STATIONARY.</p>
      * <p>When the state is MOVING, it indicates that at least one of the lens parameters
      * is changing.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #LENS_STATE_STATIONARY STATIONARY}</li>
      *   <li>{@link #LENS_STATE_MOVING MOVING}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * <p><b>Limited capability</b> -
      * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
@@ -3335,14 +3362,15 @@
      * will apply FAST/HIGH_QUALITY YUV domain noise reduction, respectively. The camera device
      * may adjust the noise reduction parameters for best image quality based on the
      * {@link CaptureRequest#REPROCESS_EFFECTIVE_EXPOSURE_FACTOR android.reprocess.effectiveExposureFactor} if it is set.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #NOISE_REDUCTION_MODE_OFF OFF}</li>
      *   <li>{@link #NOISE_REDUCTION_MODE_FAST FAST}</li>
      *   <li>{@link #NOISE_REDUCTION_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
      *   <li>{@link #NOISE_REDUCTION_MODE_MINIMAL MINIMAL}</li>
      *   <li>{@link #NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG ZERO_SHUTTER_LAG}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES android.noiseReduction.availableNoiseReductionModes}</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
@@ -3619,14 +3647,15 @@
      * <li>640x480 stream: top-left: <code>(781, 375)</code> on active array, size: <code>(640, 480)</code>, downscaled 1.17x from sensor pixels</li>
      * <li>1280x720 stream: top-left: <code>(711, 375)</code> on active array, size: <code>(1280, 720)</code>, upscaled 1.71x from sensor pixels</li>
      * </ul>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #SCALER_ROTATE_AND_CROP_NONE NONE}</li>
      *   <li>{@link #SCALER_ROTATE_AND_CROP_90 90}</li>
      *   <li>{@link #SCALER_ROTATE_AND_CROP_180 180}</li>
      *   <li>{@link #SCALER_ROTATE_AND_CROP_270 270}</li>
      *   <li>{@link #SCALER_ROTATE_AND_CROP_AUTO AUTO}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#SCALER_AVAILABLE_ROTATE_AND_CROP_MODES android.scaler.availableRotateAndCropModes}</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
@@ -3948,7 +3977,7 @@
      * occur (and that the test pattern remain unmodified, since the flash
      * would not actually affect it).</p>
      * <p>Defaults to OFF.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #SENSOR_TEST_PATTERN_MODE_OFF OFF}</li>
      *   <li>{@link #SENSOR_TEST_PATTERN_MODE_SOLID_COLOR SOLID_COLOR}</li>
@@ -3956,7 +3985,8 @@
      *   <li>{@link #SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY COLOR_BARS_FADE_TO_GRAY}</li>
      *   <li>{@link #SENSOR_TEST_PATTERN_MODE_PN9 PN9}</li>
      *   <li>{@link #SENSOR_TEST_PATTERN_MODE_CUSTOM1 CUSTOM1}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#SENSOR_AVAILABLE_TEST_PATTERN_MODES android.sensor.availableTestPatternModes}</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
@@ -4102,12 +4132,13 @@
      * AWB are in AUTO modes({@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} <code>!=</code> OFF and {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} <code>!=</code>
      * OFF), to get best results, it is recommended that the applications wait for the AE and AWB
      * to be converged before using the returned shading map data.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #SHADING_MODE_OFF OFF}</li>
      *   <li>{@link #SHADING_MODE_FAST FAST}</li>
      *   <li>{@link #SHADING_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#SHADING_AVAILABLE_MODES android.shading.availableModes}</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
@@ -4136,12 +4167,13 @@
      * <p>Whether face detection is enabled, and whether it
      * should output just the basic fields or the full set of
      * fields.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #STATISTICS_FACE_DETECT_MODE_OFF OFF}</li>
      *   <li>{@link #STATISTICS_FACE_DETECT_MODE_SIMPLE SIMPLE}</li>
      *   <li>{@link #STATISTICS_FACE_DETECT_MODE_FULL FULL}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES android.statistics.info.availableFaceDetectModes}</p>
      * <p>This key is available on all devices.</p>
@@ -4506,12 +4538,13 @@
      * into this metadata field. See
      * {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE android.control.aeAntibandingMode} for more details.</p>
      * <p>Reports NONE if there doesn't appear to be flickering illumination.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #STATISTICS_SCENE_FLICKER_NONE NONE}</li>
      *   <li>{@link #STATISTICS_SCENE_FLICKER_50HZ 50HZ}</li>
      *   <li>{@link #STATISTICS_SCENE_FLICKER_60HZ 60HZ}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * <p><b>Full capability</b> -
      * Present on all camera devices that report being {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_FULL HARDWARE_LEVEL_FULL} devices in the
@@ -4575,11 +4608,12 @@
      * android.statistics.lensShadingMap will be provided in
      * the output result metadata.</p>
      * <p>ON is always supported on devices with the RAW capability.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #STATISTICS_LENS_SHADING_MAP_MODE_OFF OFF}</li>
      *   <li>{@link #STATISTICS_LENS_SHADING_MAP_MODE_ON ON}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES android.statistics.info.availableLensShadingMapModes}</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
@@ -4606,11 +4640,12 @@
      * at 30fps may have 6-7 OIS samples per capture result. This information can be combined
      * with the rolling shutter skew to account for lens motion during image exposure in
      * post-processing algorithms.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #STATISTICS_OIS_DATA_MODE_OFF OFF}</li>
      *   <li>{@link #STATISTICS_OIS_DATA_MODE_ON ON}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_OIS_DATA_MODES android.statistics.info.availableOisDataModes}</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
@@ -4878,14 +4913,15 @@
      * <p>If a request is sent with CONTRAST_CURVE with the camera device's
      * provided curve in FAST or HIGH_QUALITY, the image's tonemap will be
      * roughly the same.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #TONEMAP_MODE_CONTRAST_CURVE CONTRAST_CURVE}</li>
      *   <li>{@link #TONEMAP_MODE_FAST FAST}</li>
      *   <li>{@link #TONEMAP_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
      *   <li>{@link #TONEMAP_MODE_GAMMA_VALUE GAMMA_VALUE}</li>
      *   <li>{@link #TONEMAP_MODE_PRESET_CURVE PRESET_CURVE}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#TONEMAP_AVAILABLE_TONE_MAP_MODES android.tonemap.availableToneMapModes}</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
@@ -4940,11 +4976,12 @@
      * <p><img alt="Rec. 709 tonemapping curve" src="/reference/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png" /></p>
      * <p>Note that above figures show a 16 control points approximation of preset
      * curves. Camera devices may apply a different approximation to the curve.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #TONEMAP_PRESET_CURVE_SRGB SRGB}</li>
      *   <li>{@link #TONEMAP_PRESET_CURVE_REC709 REC709}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      *
      * @see CaptureRequest#TONEMAP_MODE
@@ -5045,11 +5082,12 @@
      * <p>In other words, results for this current request and up to
      * {@link CameraCharacteristics#REQUEST_PIPELINE_MAX_DEPTH android.request.pipelineMaxDepth} prior requests may have their
      * android.sync.frameNumber change to CONVERGING.</p>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #SYNC_FRAME_NUMBER_CONVERGING CONVERGING}</li>
      *   <li>{@link #SYNC_FRAME_NUMBER_UNKNOWN UNKNOWN}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * Either a non-negative value corresponding to a
      * <code>frame_number</code>, or one of the two enums (CONVERGING / UNKNOWN).</p>
@@ -5171,12 +5209,13 @@
      * <li>{@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}</li>
      * <li>{@link CaptureResult#STATISTICS_FACES android.statistics.faces}</li>
      * </ul>
-     * <p><b>Possible values:</b>
+     * <p><b>Possible values:</b></p>
      * <ul>
      *   <li>{@link #DISTORTION_CORRECTION_MODE_OFF OFF}</li>
      *   <li>{@link #DISTORTION_CORRECTION_MODE_FAST FAST}</li>
      *   <li>{@link #DISTORTION_CORRECTION_MODE_HIGH_QUALITY HIGH_QUALITY}</li>
-     * </ul></p>
+     * </ul>
+     *
      * <p><b>Available values for this device:</b><br>
      * {@link CameraCharacteristics#DISTORTION_CORRECTION_AVAILABLE_MODES android.distortionCorrection.availableModes}</p>
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
diff --git a/core/java/android/hardware/display/BrightnessConfiguration.java b/core/java/android/hardware/display/BrightnessConfiguration.java
index d9c1063..366734e 100644
--- a/core/java/android/hardware/display/BrightnessConfiguration.java
+++ b/core/java/android/hardware/display/BrightnessConfiguration.java
@@ -24,13 +24,13 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Pair;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 
-import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -343,15 +343,15 @@
      *
      * @hide
      */
-    public void saveToXml(@NonNull XmlSerializer serializer) throws IOException {
+    public void saveToXml(@NonNull TypedXmlSerializer serializer) throws IOException {
         serializer.startTag(null, TAG_BRIGHTNESS_CURVE);
         if (mDescription != null) {
             serializer.attribute(null, ATTR_DESCRIPTION, mDescription);
         }
         for (int i = 0; i < mLux.length; i++) {
             serializer.startTag(null, TAG_BRIGHTNESS_POINT);
-            serializer.attribute(null, ATTR_LUX, Float.toString(mLux[i]));
-            serializer.attribute(null, ATTR_NITS, Float.toString(mNits[i]));
+            serializer.attributeFloat(null, ATTR_LUX, mLux[i]);
+            serializer.attributeFloat(null, ATTR_NITS, mNits[i]);
             serializer.endTag(null, TAG_BRIGHTNESS_POINT);
         }
         serializer.endTag(null, TAG_BRIGHTNESS_CURVE);
@@ -370,7 +370,7 @@
             final int category = entry.getKey();
             final BrightnessCorrection correction = entry.getValue();
             serializer.startTag(null, TAG_BRIGHTNESS_CORRECTION);
-            serializer.attribute(null, ATTR_CATEGORY, Integer.toString(category));
+            serializer.attributeInt(null, ATTR_CATEGORY, category);
             correction.saveToXml(serializer);
             serializer.endTag(null, TAG_BRIGHTNESS_CORRECTION);
         }
@@ -378,19 +378,18 @@
 
         serializer.startTag(null, TAG_BRIGHTNESS_PARAMS);
         if (mShouldCollectColorSamples) {
-            serializer.attribute(null, ATTR_COLLECT_COLOR, Boolean.toString(true));
+            serializer.attributeBoolean(null, ATTR_COLLECT_COLOR, true);
         }
         if (mShortTermModelTimeout >= 0) {
-            serializer.attribute(null, ATTR_MODEL_TIMEOUT,
-                    Long.toString(mShortTermModelTimeout));
+            serializer.attributeLong(null, ATTR_MODEL_TIMEOUT, mShortTermModelTimeout);
         }
         if (!Float.isNaN(mShortTermModelLowerLuxMultiplier)) {
-            serializer.attribute(null, ATTR_MODEL_LOWER_BOUND,
-                    Float.toString(mShortTermModelLowerLuxMultiplier));
+            serializer.attributeFloat(null, ATTR_MODEL_LOWER_BOUND,
+                    mShortTermModelLowerLuxMultiplier);
         }
         if (!Float.isNaN(mShortTermModelUpperLuxMultiplier)) {
-            serializer.attribute(null, ATTR_MODEL_UPPER_BOUND,
-                    Float.toString(mShortTermModelUpperLuxMultiplier));
+            serializer.attributeFloat(null, ATTR_MODEL_UPPER_BOUND,
+                    mShortTermModelUpperLuxMultiplier);
         }
         serializer.endTag(null, TAG_BRIGHTNESS_PARAMS);
     }
@@ -408,7 +407,7 @@
      *
      * @hide
      */
-    public static BrightnessConfiguration loadFromXml(@NonNull XmlPullParser parser)
+    public static BrightnessConfiguration loadFromXml(@NonNull TypedXmlPullParser parser)
             throws IOException, XmlPullParserException {
         String description = null;
         List<Float> luxList = new ArrayList<>();
@@ -440,22 +439,17 @@
                         continue;
                     }
                     final String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
-                    final String categoryText = parser.getAttributeValue(null, ATTR_CATEGORY);
+                    final int category = parser.getAttributeInt(null, ATTR_CATEGORY, -1);
                     BrightnessCorrection correction = BrightnessCorrection.loadFromXml(parser);
                     if (packageName != null) {
                         correctionsByPackageName.put(packageName, correction);
-                    } else if (categoryText != null) {
-                        try {
-                            final int category = Integer.parseInt(categoryText);
-                            correctionsByCategory.put(category, correction);
-                        } catch (NullPointerException | NumberFormatException e) {
-                            continue;
-                        }
+                    } else if (category != -1) {
+                        correctionsByCategory.put(category, correction);
                     }
                 }
             } else if (TAG_BRIGHTNESS_PARAMS.equals(parser.getName())) {
                 shouldCollectColorSamples =
-                        Boolean.parseBoolean(parser.getAttributeValue(null, ATTR_COLLECT_COLOR));
+                        parser.getAttributeBoolean(null, ATTR_COLLECT_COLOR, false);
                 Long timeout = loadLongFromXml(parser, ATTR_MODEL_TIMEOUT);
                 if (timeout != null) {
                     shortTermModelTimeout = timeout;
@@ -491,23 +485,16 @@
         return builder.build();
     }
 
-    private static float loadFloatFromXml(XmlPullParser parser, String attribute) {
-        final String string = parser.getAttributeValue(null, attribute);
-        try {
-            return Float.parseFloat(string);
-        } catch (NullPointerException | NumberFormatException e) {
-            return Float.NaN;
-        }
+    private static float loadFloatFromXml(TypedXmlPullParser parser, String attribute) {
+        return parser.getAttributeFloat(null, attribute, Float.NaN);
     }
 
-    private static Long loadLongFromXml(XmlPullParser parser, String attribute) {
-        final String string = parser.getAttributeValue(null, attribute);
+    private static Long loadLongFromXml(TypedXmlPullParser parser, String attribute) {
         try {
-            return Long.parseLong(string);
-        } catch (NullPointerException | NumberFormatException e) {
-            // Ignoring
+            return parser.getAttributeLong(null, attribute);
+        } catch (Exception e) {
+            return null;
         }
-        return null;
     }
 
     /**
diff --git a/core/java/android/hardware/display/BrightnessCorrection.java b/core/java/android/hardware/display/BrightnessCorrection.java
index bbfc45e..2919ec3 100644
--- a/core/java/android/hardware/display/BrightnessCorrection.java
+++ b/core/java/android/hardware/display/BrightnessCorrection.java
@@ -23,12 +23,12 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.MathUtils;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 
 import com.android.internal.util.XmlUtils;
 
-import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
 
@@ -153,7 +153,7 @@
      *
      * @hide
      */
-    public void saveToXml(XmlSerializer serializer) throws IOException {
+    public void saveToXml(TypedXmlSerializer serializer) throws IOException {
         mImplementation.saveToXml(serializer);
     }
 
@@ -170,7 +170,7 @@
      *
      * @hide
      */
-    public static BrightnessCorrection loadFromXml(XmlPullParser parser) throws IOException,
+    public static BrightnessCorrection loadFromXml(TypedXmlPullParser parser) throws IOException,
             XmlPullParserException {
         final int depth = parser.getDepth();
         while (XmlUtils.nextElementWithin(parser, depth)) {
@@ -181,20 +181,15 @@
         return null;
     }
 
-    private static float loadFloatFromXml(XmlPullParser parser, String attribute) {
-        final String string = parser.getAttributeValue(null, attribute);
-        try {
-            return Float.parseFloat(string);
-        } catch (NullPointerException | NumberFormatException e) {
-            return Float.NaN;
-        }
+    private static float loadFloatFromXml(TypedXmlPullParser parser, String attribute) {
+        return parser.getAttributeFloat(null, attribute, Float.NaN);
     }
 
     private interface BrightnessCorrectionImplementation {
         float apply(float brightness);
         String toString();
         void writeToParcel(Parcel dest);
-        void saveToXml(XmlSerializer serializer) throws IOException;
+        void saveToXml(TypedXmlSerializer serializer) throws IOException;
         // Package-private static methods:
         // static BrightnessCorrection readFromParcel(Parcel in);
         // static BrightnessCorrection loadFromXml(XmlPullParser parser) throws IOException,
@@ -263,10 +258,10 @@
         }
 
         @Override
-        public void saveToXml(XmlSerializer serializer) throws IOException {
+        public void saveToXml(TypedXmlSerializer serializer) throws IOException {
             serializer.startTag(null, TAG_SCALE_AND_TRANSLATE_LOG);
-            serializer.attribute(null, ATTR_SCALE, Float.toString(mScale));
-            serializer.attribute(null, ATTR_TRANSLATE, Float.toString(mTranslate));
+            serializer.attributeFloat(null, ATTR_SCALE, mScale);
+            serializer.attributeFloat(null, ATTR_TRANSLATE, mTranslate);
             serializer.endTag(null, TAG_SCALE_AND_TRANSLATE_LOG);
         }
 
@@ -276,7 +271,7 @@
             return BrightnessCorrection.createScaleAndTranslateLog(scale, translate);
         }
 
-        static BrightnessCorrection loadFromXml(XmlPullParser parser) throws IOException,
+        static BrightnessCorrection loadFromXml(TypedXmlPullParser parser) throws IOException,
                 XmlPullParserException {
             final float scale = loadFloatFromXml(parser, ATTR_SCALE);
             final float translate = loadFloatFromXml(parser, ATTR_TRANSLATE);
diff --git a/core/java/android/hardware/display/OWNERS b/core/java/android/hardware/display/OWNERS
index 9ca3910..5bcd9bb8 100644
--- a/core/java/android/hardware/display/OWNERS
+++ b/core/java/android/hardware/display/OWNERS
@@ -1,2 +1,6 @@
+# Bug component: 345010
+
+include /services/core/java/com/android/server/display/OWNERS
+
 michaelwr@google.com
 santoscordon@google.com
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index c5c51e4..468157a 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -33,8 +33,8 @@
     // Creates a test session with the specified sensorId
     ITestSession createTestSession(int sensorId, String opPackageName);
 
-    // Requests a proto dump of the service to the specified fd
-    byte[] dumpSensorServiceStateProto();
+    // Requests a proto dump of the specified sensor
+    byte[] dumpSensorServiceStateProto(int sensorId);
 
     // Retrieve static sensor properties for all face sensors
     List<FaceSensorPropertiesInternal> getSensorPropertiesInternal(String opPackageName);
diff --git a/core/java/android/hardware/face/OWNERS b/core/java/android/hardware/face/OWNERS
new file mode 100644
index 0000000..33527f8
--- /dev/null
+++ b/core/java/android/hardware/face/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 879035
+
+jaggies@google.com
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index a4ce29b..64abbea 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -34,8 +34,8 @@
     // Creates a test session with the specified sensorId
     ITestSession createTestSession(int sensorId, String opPackageName);
 
-    // Requests a proto dump of the service to the specified fd
-    byte[] dumpSensorServiceStateProto();
+    // Requests a proto dump of the specified sensor
+    byte[] dumpSensorServiceStateProto(int sensorId);
 
     // Retrieve static sensor properties for all fingerprint sensors
     List<FingerprintSensorPropertiesInternal> getSensorPropertiesInternal(String opPackageName);
diff --git a/core/java/android/hardware/fingerprint/OWNERS b/core/java/android/hardware/fingerprint/OWNERS
new file mode 100644
index 0000000..dcead40
--- /dev/null
+++ b/core/java/android/hardware/fingerprint/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 114777
+
+jaggies@google.com
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index eef4089..ae10f40 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -367,35 +367,35 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface HdmiCecVersion {}
 
-    // -- Which devices the playback device can send a <Standby> message to upon going to sleep.
+    // -- Scope of CEC power control messages sent by a playback device.
     /**
-     * Send <Standby> to TV only.
+     * Send CEC power control messages to TV only.
      *
      * @hide
      */
-    public static final String SEND_STANDBY_ON_SLEEP_TO_TV = "to_tv";
+    public static final String POWER_CONTROL_MODE_TV = "to_tv";
     /**
-     * Broadcast <Standby> to all devices in the network.
+     * Broadcast CEC power control messages to all devices in the network.
      *
      * @hide
      */
-    public static final String SEND_STANDBY_ON_SLEEP_BROADCAST = "broadcast";
+    public static final String POWER_CONTROL_MODE_BROADCAST = "broadcast";
     /**
-     * Don't send any <Standby> message.
+     * Don't send any CEC power control messages.
      *
      * @hide
      */
-    public static final String SEND_STANDBY_ON_SLEEP_NONE = "none";
+    public static final String POWER_CONTROL_MODE_NONE = "none";
     /**
      * @hide
      */
     @StringDef({
-            SEND_STANDBY_ON_SLEEP_TO_TV,
-            SEND_STANDBY_ON_SLEEP_BROADCAST,
-            SEND_STANDBY_ON_SLEEP_NONE
+            POWER_CONTROL_MODE_TV,
+            POWER_CONTROL_MODE_BROADCAST,
+            POWER_CONTROL_MODE_NONE
     })
     @Retention(RetentionPolicy.SOURCE)
-    public @interface StandbyBehavior {}
+    public @interface PowerControlMode {}
 
     // -- Which power state action should be taken when Active Source is lost.
     /**
@@ -457,11 +457,11 @@
      */
     public static final String CEC_SETTING_NAME_HDMI_CEC_VERSION = "hdmi_cec_version";
     /**
-     * Name of a setting deciding on the Standby message behaviour on sleep.
+     * Name of a setting deciding on the power control mode.
      *
      * @hide
      */
-    public static final String CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP = "send_standby_on_sleep";
+    public static final String CEC_SETTING_NAME_POWER_CONTROL_MODE = "send_standby_on_sleep";
     /**
      * Name of a setting deciding on power state action when losing Active Source.
      *
@@ -482,7 +482,7 @@
     @StringDef({
         CEC_SETTING_NAME_HDMI_CEC_ENABLED,
         CEC_SETTING_NAME_HDMI_CEC_VERSION,
-        CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
+        CEC_SETTING_NAME_POWER_CONTROL_MODE,
         CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
         CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
     })
@@ -1506,7 +1506,7 @@
     }
 
     /**
-     * Set the 'send_standby_on_sleep' option.
+     * Set the 'power_control_mode' option.
      *
      * @param value the desired value
      * @throws IllegalArgumentException when the new value is not allowed.
@@ -1515,20 +1515,20 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
-    public void setSendStandbyOnSleep(@NonNull @StandbyBehavior String value) {
+    public void setPowerControlMode(@NonNull @PowerControlMode String value) {
         if (mService == null) {
             Log.e(TAG, "HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
-            mService.setCecSettingStringValue(CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP, value);
+            mService.setCecSettingStringValue(CEC_SETTING_NAME_POWER_CONTROL_MODE, value);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Get the value of 'send_standby_on_sleep' option.
+     * Get the value of 'power_control_mode' option.
      *
      * @return the current value.
      * @throws RuntimeException when the HdmiControlService is not available.
@@ -1536,15 +1536,15 @@
      * @hide
      */
     @NonNull
-    @StandbyBehavior
+    @PowerControlMode
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
-    public String getSendStandbyOnSleep() {
+    public String getPowerControlMode() {
         if (mService == null) {
             Log.e(TAG, "HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
-            return mService.getCecSettingStringValue(CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP);
+            return mService.getCecSettingStringValue(CEC_SETTING_NAME_POWER_CONTROL_MODE);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/hardware/hdmi/OWNERS b/core/java/android/hardware/hdmi/OWNERS
new file mode 100644
index 0000000..e9557f8
--- /dev/null
+++ b/core/java/android/hardware/hdmi/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 345010
+
+include /services/core/java/com/android/server/display/OWNERS
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index dc6f579..57c0398 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -22,6 +22,7 @@
 import android.hardware.input.IInputDevicesChangedListener;
 import android.hardware.input.ITabletModeChangedListener;
 import android.hardware.input.TouchCalibration;
+import android.os.CombinedVibrationEffect;
 import android.os.IBinder;
 import android.os.VibrationEffect;
 import android.view.InputDevice;
@@ -85,7 +86,10 @@
 
     // Input device vibrator control.
     void vibrate(int deviceId, in VibrationEffect effect, IBinder token);
+    void vibrateCombined(int deviceId, in CombinedVibrationEffect effect, IBinder token);
     void cancelVibrate(int deviceId, IBinder token);
+    int[] getVibratorIds(int deviceId);
+    boolean isVibrating(int deviceId);
 
     void setPointerIconType(int typeId);
     void setCustomPointerIcon(in PointerIcon icon);
diff --git a/core/java/android/hardware/input/InputDeviceVibrator.java b/core/java/android/hardware/input/InputDeviceVibrator.java
new file mode 100644
index 0000000..c60d6ce
--- /dev/null
+++ b/core/java/android/hardware/input/InputDeviceVibrator.java
@@ -0,0 +1,94 @@
+/*
+ * 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.hardware.input;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.os.Binder;
+import android.os.VibrationAttributes;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Vibrator implementation that communicates with the input device vibrators.
+ */
+final class InputDeviceVibrator extends Vibrator {
+    // mDeviceId represents InputDevice ID the vibrator belongs to
+    private final int mDeviceId;
+    private final int mVibratorId;
+    private final Binder mToken;
+    private final InputManager mInputManager;
+
+    InputDeviceVibrator(InputManager inputManager, int deviceId, int vibratorId) {
+        mInputManager = inputManager;
+        mDeviceId = deviceId;
+        mVibratorId = vibratorId;
+        mToken = new Binder();
+    }
+
+    @Override
+    public boolean hasVibrator() {
+        return true;
+    }
+
+    @Override
+    public boolean isVibrating() {
+        return mInputManager.isVibrating(mDeviceId);
+    }
+
+    /* TODO: b/161634264 Support Vibrator listener API in input devices */
+    @Override
+    public void addVibratorStateListener(@NonNull OnVibratorStateChangedListener listener) {
+        throw new UnsupportedOperationException(
+            "addVibratorStateListener not supported in InputDeviceVibrator");
+    }
+
+    @Override
+    public void addVibratorStateListener(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OnVibratorStateChangedListener listener) {
+        throw new UnsupportedOperationException(
+            "addVibratorStateListener not supported in InputDeviceVibrator");
+    }
+
+    @Override
+    public void removeVibratorStateListener(@NonNull OnVibratorStateChangedListener listener) {
+        throw new UnsupportedOperationException(
+            "removeVibratorStateListener not supported in InputDeviceVibrator");
+    }
+
+    @Override
+    public boolean hasAmplitudeControl() {
+        return true;
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void vibrate(int uid, String opPkg, @NonNull VibrationEffect effect,
+            String reason, @NonNull VibrationAttributes attributes) {
+        mInputManager.vibrate(mDeviceId, effect, mToken);
+    }
+
+    @Override
+    public void cancel() {
+        mInputManager.cancelVibrate(mDeviceId, mToken);
+    }
+}
diff --git a/core/java/android/hardware/input/InputDeviceVibratorManager.java b/core/java/android/hardware/input/InputDeviceVibratorManager.java
new file mode 100644
index 0000000..a381b02
--- /dev/null
+++ b/core/java/android/hardware/input/InputDeviceVibratorManager.java
@@ -0,0 +1,125 @@
+/*
+ * 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.hardware.input;
+
+import android.os.Binder;
+import android.os.CombinedVibrationEffect;
+import android.os.NullVibrator;
+import android.os.Vibrator;
+import android.os.VibratorManager;
+import android.util.SparseArray;
+import android.view.InputDevice;
+
+import com.android.internal.annotations.GuardedBy;
+
+/**
+ * Vibrator manager implementation that communicates with the input device vibrators.
+ *
+ * @hide
+ */
+public class InputDeviceVibratorManager extends VibratorManager
+        implements InputManager.InputDeviceListener {
+    private static final String TAG = "InputDeviceVibratorManager";
+    private static final boolean DEBUG = false;
+
+    private final Binder mToken;
+    private final InputManager mInputManager;
+
+    // The input device Id.
+    private final int mDeviceId;
+    // Vibrator map from Vibrator Id to Vibrator
+    @GuardedBy("mVibrators")
+    private final SparseArray<Vibrator> mVibrators = new SparseArray<>();
+
+    public InputDeviceVibratorManager(InputManager inputManager, int deviceId) {
+        mInputManager = inputManager;
+        mDeviceId = deviceId;
+        mToken = new Binder();
+
+        initializeVibrators();
+    }
+
+    private void initializeVibrators() {
+        synchronized (mVibrators) {
+            mVibrators.clear();
+            InputDevice inputDevice = InputDevice.getDevice(mDeviceId);
+            final int[] vibratorIds =
+                    mInputManager.getVibratorIds(mDeviceId);
+            for (int i = 0; i < vibratorIds.length; i++) {
+                mVibrators.put(vibratorIds[i],
+                        new InputDeviceVibrator(mInputManager, mDeviceId, vibratorIds[i]));
+            }
+        }
+    }
+
+    @Override
+    public void onInputDeviceAdded(int deviceId) {
+    }
+
+    @Override
+    public void onInputDeviceRemoved(int deviceId) {
+        synchronized (mVibrators) {
+            if (deviceId == mDeviceId) {
+                mVibrators.clear();
+            }
+        }
+    }
+
+    @Override
+    public void onInputDeviceChanged(int deviceId) {
+        if (deviceId == mDeviceId) {
+            initializeVibrators();
+        }
+    }
+
+    @Override
+    public int[] getVibratorIds() {
+        synchronized (mVibrators) {
+            int[] vibratorIds = new int[mVibrators.size()];
+            for (int idx = 0; idx < mVibrators.size(); idx++) {
+                vibratorIds[idx++] = mVibrators.keyAt(idx);
+            }
+            return vibratorIds;
+        }
+    }
+
+    @Override
+    public Vibrator getVibrator(int vibratorId) {
+        synchronized (mVibrators) {
+            if (mVibrators.contains(vibratorId)) {
+                return mVibrators.get(vibratorId);
+            }
+        }
+        return NullVibrator.getInstance();
+    }
+
+    @Override
+    public Vibrator getDefaultVibrator() {
+        // Returns vibrator ID 0
+        synchronized (mVibrators) {
+            if (mVibrators.size() > 0) {
+                return mVibrators.valueAt(0);
+            }
+        }
+        return NullVibrator.getInstance();
+    }
+
+    @Override
+    public void vibrate(CombinedVibrationEffect effect) {
+        mInputManager.vibrate(mDeviceId, effect, mToken);
+    }
+}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 81ea2f5..f1d60f6 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -17,7 +17,6 @@
 package android.hardware.input;
 
 import android.Manifest;
-import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -29,9 +28,9 @@
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
-import android.os.Binder;
 import android.os.BlockUntrustedTouchesMode;
 import android.os.Build;
+import android.os.CombinedVibrationEffect;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.InputEventInjectionSync;
@@ -41,9 +40,9 @@
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
 import android.os.SystemClock;
-import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
+import android.os.VibratorManager;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.util.Log;
@@ -64,7 +63,6 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.Executor;
 
 /**
  * Provides information about input devices and available key layouts.
@@ -1287,8 +1285,75 @@
      * @return The vibrator, never null.
      * @hide
      */
-    public Vibrator getInputDeviceVibrator(int deviceId) {
-        return new InputDeviceVibrator(deviceId);
+    public Vibrator getInputDeviceVibrator(int deviceId, int vibratorId) {
+        return new InputDeviceVibrator(this, deviceId, vibratorId);
+    }
+
+    /**
+     * Gets a vibrator manager service associated with an input device, always create a new
+     * instance.
+     * @return The vibrator manager, never null.
+     * @hide
+     */
+    @NonNull
+    public VibratorManager getInputDeviceVibratorManager(int deviceId) {
+        return new InputDeviceVibratorManager(InputManager.this, deviceId);
+    }
+
+    /*
+     * Get the list of device vibrators
+     * @return The list of vibrators IDs
+     */
+    int[] getVibratorIds(int deviceId) {
+        try {
+            return mIm.getVibratorIds(deviceId);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /*
+     * Perform vibration effect
+     */
+    void vibrate(int deviceId, VibrationEffect effect, IBinder token) {
+        try {
+            mIm.vibrate(deviceId, effect, token);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /*
+     * Perform combined vibration effect
+     */
+    void vibrate(int deviceId, CombinedVibrationEffect effect, IBinder token) {
+        try {
+            mIm.vibrateCombined(deviceId, effect, token);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /*
+     * Cancel an ongoing vibration
+     */
+    void cancelVibrate(int deviceId, IBinder token) {
+        try {
+            mIm.cancelVibrate(deviceId, token);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /*
+     * Check if input device is vibrating
+     */
+    boolean isVibrating(int deviceId)  {
+        try {
+            return mIm.isVibrating(deviceId);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -1401,72 +1466,4 @@
             }
         }
     }
-
-    private final class InputDeviceVibrator extends Vibrator {
-        private final int mDeviceId;
-        private final Binder mToken;
-
-        public InputDeviceVibrator(int deviceId) {
-            mDeviceId = deviceId;
-            mToken = new Binder();
-        }
-
-        @Override
-        public boolean hasVibrator() {
-            return true;
-        }
-
-        @Override
-        public boolean isVibrating() {
-            throw new UnsupportedOperationException(
-                "isVibrating not supported in InputDeviceVibrator");
-        }
-
-        @Override
-        public void addVibratorStateListener(@NonNull OnVibratorStateChangedListener listener) {
-            throw new UnsupportedOperationException(
-                "addVibratorStateListener not supported in InputDeviceVibrator");
-        }
-
-        @Override
-        public void addVibratorStateListener(
-                @NonNull @CallbackExecutor Executor executor,
-                @NonNull OnVibratorStateChangedListener listener) {
-            throw new UnsupportedOperationException(
-                "addVibratorStateListener not supported in InputDeviceVibrator");
-        }
-
-        @Override
-        public void removeVibratorStateListener(@NonNull OnVibratorStateChangedListener listener) {
-            throw new UnsupportedOperationException(
-                "removeVibratorStateListener not supported in InputDeviceVibrator");
-        }
-
-        @Override
-        public boolean hasAmplitudeControl() {
-            return true;
-        }
-
-        /**
-         * @hide
-         */
-        @Override
-        public void vibrate(int uid, String opPkg, @NonNull VibrationEffect effect,
-                String reason, @NonNull VibrationAttributes attributes) {
-            try {
-                mIm.vibrate(mDeviceId, effect, mToken);
-            } catch (RemoteException ex) {
-                throw ex.rethrowFromSystemServer();
-            }
-        }
-
-        @Override
-        public void cancel() {
-            try {
-                mIm.cancelVibrate(mDeviceId, mToken);
-            } catch (RemoteException ex) {
-                throw ex.rethrowFromSystemServer();
-            }
-        }
-    }
 }
diff --git a/core/java/android/hardware/input/OWNERS b/core/java/android/hardware/input/OWNERS
index 0313a40..25e02e1 100644
--- a/core/java/android/hardware/input/OWNERS
+++ b/core/java/android/hardware/input/OWNERS
@@ -1,2 +1,6 @@
+# Bug component: 136048
+
+include /services/core/java/com/android/server/input/OWNERS
+
 michaelwr@google.com
 svv@google.com
diff --git a/core/java/android/hardware/iris/OWNERS b/core/java/android/hardware/iris/OWNERS
new file mode 100644
index 0000000..33527f8
--- /dev/null
+++ b/core/java/android/hardware/iris/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 879035
+
+jaggies@google.com
diff --git a/core/java/android/hardware/lights/OWNERS b/core/java/android/hardware/lights/OWNERS
new file mode 100644
index 0000000..cb46a80
--- /dev/null
+++ b/core/java/android/hardware/lights/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/lights/OWNERS
diff --git a/core/java/android/hardware/location/OWNERS b/core/java/android/hardware/location/OWNERS
new file mode 100644
index 0000000..383321b
--- /dev/null
+++ b/core/java/android/hardware/location/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 880425
+
+mstogaitis@google.com
+wyattriley@google.com
+etn@google.com
+weiwa@google.com
diff --git a/core/java/android/hardware/soundtrigger/OWNERS b/core/java/android/hardware/soundtrigger/OWNERS
new file mode 100644
index 0000000..816bc6b
--- /dev/null
+++ b/core/java/android/hardware/soundtrigger/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/media/soundtrigger/OWNERS
diff --git a/core/java/android/hardware/usb/OWNERS b/core/java/android/hardware/usb/OWNERS
index 8ee72b5..8f2b39d 100644
--- a/core/java/android/hardware/usb/OWNERS
+++ b/core/java/android/hardware/usb/OWNERS
@@ -1,6 +1,4 @@
-badhri@google.com
-elaurent@google.com
+# Bug component: 175220
+
 moltmann@google.com
-albertccwang@google.com
-jameswei@google.com
-howardyen@google.com
\ No newline at end of file
+badhri@google.com
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index aac57fe..c28bab7 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -609,7 +609,7 @@
     public @interface UsbFunctionMode {}
 
     /** @hide */
-    @IntDef(flag = true, prefix = { "GADGET_HAL_" }, value = {
+    @IntDef(prefix = { "GADGET_HAL_" }, value = {
             GADGET_HAL_NOT_SUPPORTED,
             GADGET_HAL_V1_0,
             GADGET_HAL_V1_1,
diff --git a/core/java/android/hardware/usb/UsbPortStatus.java b/core/java/android/hardware/usb/UsbPortStatus.java
index 43c418e..bb7aff6 100644
--- a/core/java/android/hardware/usb/UsbPortStatus.java
+++ b/core/java/android/hardware/usb/UsbPortStatus.java
@@ -202,7 +202,7 @@
     public static final int CONTAMINANT_PROTECTION_DISABLED =
             android.hardware.usb.V1_2.Constants.ContaminantProtectionStatus.DISABLED;
 
-    @IntDef(prefix = { "CONTAMINANT_DETECION_" }, flag = true, value = {
+    @IntDef(prefix = { "CONTAMINANT_DETECTION_" }, value = {
             CONTAMINANT_DETECTION_NOT_SUPPORTED,
             CONTAMINANT_DETECTION_DISABLED,
             CONTAMINANT_DETECTION_NOT_DETECTED,
@@ -221,7 +221,7 @@
     @Retention(RetentionPolicy.SOURCE)
     @interface ContaminantProtectionStatus{}
 
-    @IntDef(prefix = { "MODE_" }, flag = true, value = {
+    @IntDef(prefix = { "MODE_" }, value = {
             MODE_NONE,
             MODE_DFP,
             MODE_UFP,
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 5576857..6831eca 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -630,6 +630,9 @@
         @MainThread
         @Override
         public void updateInputMethodDisplay(int displayId) {
+            if (getDisplayId() == displayId) {
+                return;
+            }
             // Update display for adding IME window to the right display.
             // TODO(b/111364446) Need to address context lifecycle issue if need to re-create
             // for update resources & configuration correctly when show soft input
@@ -804,12 +807,12 @@
                     null /* icProto */);
             final boolean wasVisible = isInputViewShown();
             if (dispatchOnShowInputRequested(flags, false)) {
-
                 showWindow(true);
                 applyVisibilityInInsetsConsumerIfNecessary(true /* setVisible */);
+            } else {
+                // If user uses hard keyboard, IME button should always be shown.
+                setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
             }
-            // If user uses hard keyboard, IME button should always be shown.
-            setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
             final boolean isVisible = isInputViewShown();
             final boolean visibilityChanged = isVisible != wasVisible;
             if (resultReceiver != null) {
@@ -1273,6 +1276,9 @@
         super.onCreate();
         mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
         mSettingsObserver = SettingsObserver.createAndRegister(this);
+        // cache preference so we don't have to read ContentProvider when IME is requested to be
+        // shown the first time (cold start).
+        mSettingsObserver.shouldShowImeWithHardKeyboard();
 
         mIsAutomotive = isAutomotive();
         mAutomotiveHideNavBarForKeyboard = getApplicationContext().getResources().getBoolean(
@@ -1341,13 +1347,7 @@
         mRootView = mInflater.inflate(
                 com.android.internal.R.layout.input_method, null);
         mWindow.setContentView(mRootView);
-        mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(mInsetsComputer);
         mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer);
-        if (Settings.Global.getInt(getContentResolver(),
-                Settings.Global.FANCY_IME_ANIMATIONS, 0) != 0) {
-            mWindow.getWindow().setWindowAnimations(
-                    com.android.internal.R.style.Animation_InputMethodFancy);
-        }
         mFullscreenArea = mRootView.findViewById(com.android.internal.R.id.fullscreenArea);
         mExtractViewHidden = false;
         mExtractFrame = mRootView.findViewById(android.R.id.extractArea);
@@ -1413,6 +1413,7 @@
         int showFlags = mShowInputFlags;
         boolean showingInput = mShowInputRequested;
         CompletionInfo[] completions = mCurCompletions;
+        mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(mInsetsComputer);
         initViews();
         mInputViewStarted = false;
         mCandidatesViewStarted = false;
diff --git a/core/java/android/inputmethodservice/OWNERS b/core/java/android/inputmethodservice/OWNERS
index 4447197..e6a04da 100644
--- a/core/java/android/inputmethodservice/OWNERS
+++ b/core/java/android/inputmethodservice/OWNERS
@@ -1,3 +1,4 @@
+# Bug component: 34867
 set noparent
 
-include ../../../../services/core/java/com/android/server/inputmethod/OWNERS
+include /services/core/java/com/android/server/inputmethod/OWNERS
diff --git a/core/java/android/metrics/OWNERS b/core/java/android/metrics/OWNERS
new file mode 100644
index 0000000..ba867e0
--- /dev/null
+++ b/core/java/android/metrics/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 26805
+
+cwren@android.com
+cwren@google.com
diff --git a/core/java/android/net/ConnectivityMetricsEvent.java b/core/java/android/net/ConnectivityMetricsEvent.java
index 522add1..8b06ebe 100644
--- a/core/java/android/net/ConnectivityMetricsEvent.java
+++ b/core/java/android/net/ConnectivityMetricsEvent.java
@@ -19,7 +19,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import com.android.internal.util.BitUtils;
+import java.util.BitSet;
 
 /**
  * Represents a core networking event defined in package android.net.metrics.
@@ -86,9 +86,7 @@
         if (ifname != null) {
             buffer.append(", ").append(ifname);
         }
-        for (int t : BitUtils.unpackBits(transports)) {
-            buffer.append(", ").append(NetworkCapabilities.transportNameOf(t));
-        }
+        buffer.append(", transports=").append(BitSet.valueOf(new long[] { transports }));
         buffer.append("): ").append(data.toString());
         return buffer.toString();
     }
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
index 9876fc6..183f500 100644
--- a/core/java/android/net/Ikev2VpnProfile.java
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -16,12 +16,9 @@
 
 package android.net;
 
-import static android.net.PlatformVpnProfile.TYPE_IKEV2_IPSEC_PSK;
-import static android.net.PlatformVpnProfile.TYPE_IKEV2_IPSEC_RSA;
-import static android.net.PlatformVpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
-
 import static com.android.internal.annotations.VisibleForTesting.Visibility;
 import static com.android.internal.util.Preconditions.checkStringNotEmpty;
+import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -158,9 +155,8 @@
         // IPv6 MTU is greater; since profiles may be started by the system on IPv4 and IPv6
         // networks, the VPN must provide a link fulfilling the stricter of the two conditions
         // (at least that of the IPv6 MTU).
-        if (mMaxMtu < LinkProperties.MIN_MTU_V6) {
-            throw new IllegalArgumentException(
-                    "Max MTU must be at least" + LinkProperties.MIN_MTU_V6);
+        if (mMaxMtu < IPV6_MIN_MTU) {
+            throw new IllegalArgumentException("Max MTU must be at least" + IPV6_MIN_MTU);
         }
 
         switch (mType) {
@@ -811,9 +807,8 @@
             // IPv6 MTU is greater; since profiles may be started by the system on IPv4 and IPv6
             // networks, the VPN must provide a link fulfilling the stricter of the two conditions
             // (at least that of the IPv6 MTU).
-            if (mtu < LinkProperties.MIN_MTU_V6) {
-                throw new IllegalArgumentException(
-                        "Max MTU must be at least " + LinkProperties.MIN_MTU_V6);
+            if (mtu < IPV6_MIN_MTU) {
+                throw new IllegalArgumentException("Max MTU must be at least " + IPV6_MIN_MTU);
             }
             mMaxMtu = mtu;
             return this;
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index fa1497d..b48c1fd 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -17,8 +17,6 @@
 
 import static android.net.IpSecManager.INVALID_RESOURCE_ID;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
-
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -28,7 +26,6 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Binder;
-import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -182,7 +179,6 @@
         try {
             IIpSecService svc = getIpSecService();
             svc.deleteTransform(mResourceId);
-            stopNattKeepalive();
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         } catch (Exception e) {
@@ -213,36 +209,6 @@
     private int mResourceId;
     private final Context mContext;
     private final CloseGuard mCloseGuard = CloseGuard.get();
-    private ConnectivityManager.PacketKeepalive mKeepalive;
-    private Handler mCallbackHandler;
-    private final ConnectivityManager.PacketKeepaliveCallback mKeepaliveCallback =
-            new ConnectivityManager.PacketKeepaliveCallback() {
-
-                @Override
-                public void onStarted() {
-                    synchronized (this) {
-                        mCallbackHandler.post(() -> mUserKeepaliveCallback.onStarted());
-                    }
-                }
-
-                @Override
-                public void onStopped() {
-                    synchronized (this) {
-                        mKeepalive = null;
-                        mCallbackHandler.post(() -> mUserKeepaliveCallback.onStopped());
-                    }
-                }
-
-                @Override
-                public void onError(int error) {
-                    synchronized (this) {
-                        mKeepalive = null;
-                        mCallbackHandler.post(() -> mUserKeepaliveCallback.onError(error));
-                    }
-                }
-            };
-
-    private NattKeepaliveCallback mUserKeepaliveCallback;
 
     /** @hide */
     @VisibleForTesting
@@ -274,76 +240,6 @@
         public void onError(int error) {}
     }
 
-    /**
-     * Start a NAT-T keepalive session for the current transform.
-     *
-     * For a transform that is using UDP encapsulated IPv4, NAT-T offloading provides
-     * a power efficient mechanism of sending NAT-T packets at a specified interval.
-     *
-     * @param userCallback a {@link #NattKeepaliveCallback} to receive asynchronous status
-     *      information about the requested NAT-T keepalive session.
-     * @param intervalSeconds the interval between NAT-T keepalives being sent. The
-     *      the allowed range is between 20 and 3600 seconds.
-     * @param handler a handler on which to post callbacks when received.
-     *
-     * @hide
-     */
-    @RequiresPermission(anyOf = {
-            android.Manifest.permission.MANAGE_IPSEC_TUNNELS,
-            android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD
-    })
-    public void startNattKeepalive(@NonNull NattKeepaliveCallback userCallback,
-            int intervalSeconds, @NonNull Handler handler) throws IOException {
-        checkNotNull(userCallback);
-        if (intervalSeconds < 20 || intervalSeconds > 3600) {
-            throw new IllegalArgumentException("Invalid NAT-T keepalive interval");
-        }
-        checkNotNull(handler);
-        if (mResourceId == INVALID_RESOURCE_ID) {
-            throw new IllegalStateException(
-                    "Packet keepalive cannot be started for an inactive transform");
-        }
-
-        synchronized (mKeepaliveCallback) {
-            if (mKeepaliveCallback != null) {
-                throw new IllegalStateException("Keepalive already active");
-            }
-
-            mUserKeepaliveCallback = userCallback;
-            ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
-                    Context.CONNECTIVITY_SERVICE);
-            mKeepalive = cm.startNattKeepalive(
-                    mConfig.getNetwork(), intervalSeconds, mKeepaliveCallback,
-                    NetworkUtils.numericToInetAddress(mConfig.getSourceAddress()),
-                    4500, // FIXME urgently, we need to get the port number from the Encap socket
-                    NetworkUtils.numericToInetAddress(mConfig.getDestinationAddress()));
-            mCallbackHandler = handler;
-        }
-    }
-
-    /**
-     * Stop an ongoing NAT-T keepalive session.
-     *
-     * Calling this API will request that an ongoing NAT-T keepalive session be terminated.
-     * If this API is not called when a Transform is closed, the underlying NAT-T session will
-     * be terminated automatically.
-     *
-     * @hide
-     */
-    @RequiresPermission(anyOf = {
-            android.Manifest.permission.MANAGE_IPSEC_TUNNELS,
-            android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD
-    })
-    public void stopNattKeepalive() {
-        synchronized (mKeepaliveCallback) {
-            if (mKeepalive == null) {
-                Log.e(TAG, "No active keepalive to stop");
-                return;
-            }
-            mKeepalive.stop();
-        }
-    }
-
     /** This class is used to build {@link IpSecTransform} objects. */
     public static class Builder {
         private Context mContext;
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 81e6e78..e41ed72 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -82,8 +82,7 @@
 
     private static final int MIN_MTU    = 68;
 
-    /** @hide */
-    public static final int MIN_MTU_V6 = 1280;
+    private static final int MIN_MTU_V6 = 1280;
 
     private static final int MAX_MTU    = 10000;
 
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index 9c10388..e65c27c 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -17,8 +17,6 @@
 package android.net;
 
 import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.ConnectivityManager.getNetworkTypeName;
-import static android.net.ConnectivityManager.isNetworkTypeMobile;
 
 import android.annotation.Nullable;
 import android.content.Context;
@@ -27,7 +25,6 @@
 import android.os.Build;
 import android.service.NetworkIdentityProto;
 import android.telephony.Annotation.NetworkType;
-import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
 import java.util.Objects;
@@ -85,7 +82,7 @@
     @Override
     public String toString() {
         final StringBuilder builder = new StringBuilder("{");
-        builder.append("type=").append(getNetworkTypeName(mType));
+        builder.append("type=").append(mType);
         builder.append(", subType=");
         if (mSubType == SUBTYPE_COMBINED) {
             builder.append("COMBINED");
@@ -195,18 +192,9 @@
         boolean metered = !state.networkCapabilities.hasCapability(
                 NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
 
-        if (isNetworkTypeMobile(type)) {
-            if (state.subscriberId == null) {
-                if (state.networkInfo.getState() != NetworkInfo.State.DISCONNECTED &&
-                        state.networkInfo.getState() != NetworkInfo.State.UNKNOWN) {
-                    Slog.w(TAG, "Active mobile network without subscriber! ni = "
-                            + state.networkInfo);
-                }
-            }
+        subscriberId = state.subscriberId;
 
-            subscriberId = state.subscriberId;
-
-        } else if (type == TYPE_WIFI) {
+        if (type == TYPE_WIFI) {
             if (state.networkId != null) {
                 networkId = state.networkId;
             } else {
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index a643d09..f05f033 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -144,6 +144,8 @@
     public static final String FIREWALL_CHAIN_NAME_STANDBY = "standby";
     /** @hide */
     public static final String FIREWALL_CHAIN_NAME_POWERSAVE = "powersave";
+    /** @hide */
+    public static final String FIREWALL_CHAIN_NAME_RESTRICTED = "restricted";
 
     private static final boolean ALLOW_PLATFORM_APP_POLICY = true;
 
diff --git a/core/java/android/net/NetworkProvider.java b/core/java/android/net/NetworkProvider.java
index a17a498..14cb51c 100644
--- a/core/java/android/net/NetworkProvider.java
+++ b/core/java/android/net/NetworkProvider.java
@@ -63,7 +63,7 @@
 
     private final Messenger mMessenger;
     private final String mName;
-    private final ConnectivityManager mCm;
+    private final Context mContext;
 
     private int mProviderId = ID_NONE;
 
@@ -78,8 +78,6 @@
      */
     @SystemApi
     public NetworkProvider(@NonNull Context context, @NonNull Looper looper, @NonNull String name) {
-        mCm = ConnectivityManager.from(context);
-
         Handler handler = new Handler(looper) {
             @Override
             public void handleMessage(Message m) {
@@ -95,6 +93,7 @@
                 }
             }
         };
+        mContext = context;
         mMessenger = new Messenger(handler);
         mName = name;
     }
@@ -158,6 +157,6 @@
     @SystemApi
     @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
     public void declareNetworkRequestUnfulfillable(@NonNull NetworkRequest request) {
-        mCm.declareNetworkRequestUnfulfillable(request);
+        ConnectivityManager.from(mContext).declareNetworkRequestUnfulfillable(request);
     }
 }
diff --git a/core/java/android/net/OWNERS b/core/java/android/net/OWNERS
index 5e2a718..2f8f685 100644
--- a/core/java/android/net/OWNERS
+++ b/core/java/android/net/OWNERS
@@ -2,7 +2,7 @@
 
 codewiz@google.com
 jchalard@google.com
-jsharkey@android.com
+jsharkey@google.com
 junyulai@google.com
 lorenzo@google.com
 reminv@google.com
diff --git a/core/java/android/net/metrics/ConnectStats.java b/core/java/android/net/metrics/ConnectStats.java
index b320b75..c67259d 100644
--- a/core/java/android/net/metrics/ConnectStats.java
+++ b/core/java/android/net/metrics/ConnectStats.java
@@ -16,14 +16,14 @@
 
 package android.net.metrics;
 
-import android.net.NetworkCapabilities;
 import android.system.OsConstants;
 import android.util.IntArray;
 import android.util.SparseIntArray;
 
-import com.android.internal.util.BitUtils;
 import com.android.internal.util.TokenBucket;
 
+import java.util.BitSet;
+
 /**
  * A class that aggregates connect() statistics.
  * {@hide}
@@ -120,10 +120,9 @@
     @Override
     public String toString() {
         StringBuilder builder =
-                new StringBuilder("ConnectStats(").append("netId=").append(netId).append(", ");
-        for (int t : BitUtils.unpackBits(transports)) {
-            builder.append(NetworkCapabilities.transportNameOf(t)).append(", ");
-        }
+                new StringBuilder("ConnectStats(").append("netId=").append(netId)
+                        .append(", transports=").append(BitSet.valueOf(new long[] { transports }))
+                        .append(", ");
         builder.append(String.format("%d events, ", eventCount));
         builder.append(String.format("%d success, ", connectCount));
         builder.append(String.format("%d blocking, ", connectBlockingCount));
diff --git a/core/java/android/net/metrics/DefaultNetworkEvent.java b/core/java/android/net/metrics/DefaultNetworkEvent.java
index 6f383b4..8988983 100644
--- a/core/java/android/net/metrics/DefaultNetworkEvent.java
+++ b/core/java/android/net/metrics/DefaultNetworkEvent.java
@@ -16,12 +16,7 @@
 
 package android.net.metrics;
 
-import static android.net.ConnectivityManager.NETID_UNSET;
-
-import android.net.NetworkCapabilities;
-
-import com.android.internal.util.BitUtils;
-
+import java.util.BitSet;
 import java.util.StringJoiner;
 
 /**
@@ -32,8 +27,8 @@
 
     // The creation time in milliseconds of this DefaultNetworkEvent.
     public final long creationTimeMs;
-    // The network ID of the network or NETID_UNSET if none.
-    public int netId = NETID_UNSET;
+    // The network ID of the network or 0 if none.
+    public int netId = 0;
     // The list of transport types, as defined in NetworkCapabilities.java.
     public int transports;
     // The list of transport types of the last previous default network.
@@ -63,9 +58,7 @@
     public String toString() {
         StringJoiner j = new StringJoiner(", ", "DefaultNetworkEvent(", ")");
         j.add("netId=" + netId);
-        for (int t : BitUtils.unpackBits(transports)) {
-            j.add(NetworkCapabilities.transportNameOf(t));
-        }
+        j.add("transports=" + BitSet.valueOf(new long[] { transports }));
         j.add("ip=" + ipSupport());
         if (initialScore > 0) {
             j.add("initial_score=" + initialScore);
diff --git a/core/java/android/net/metrics/DnsEvent.java b/core/java/android/net/metrics/DnsEvent.java
index 5aa705b..bf351ce 100644
--- a/core/java/android/net/metrics/DnsEvent.java
+++ b/core/java/android/net/metrics/DnsEvent.java
@@ -16,11 +16,8 @@
 
 package android.net.metrics;
 
-import android.net.NetworkCapabilities;
-
-import com.android.internal.util.BitUtils;
-
 import java.util.Arrays;
+import java.util.BitSet;
 
 /**
  * A batch of DNS events recorded by NetdEventListenerService for a specific network.
@@ -86,10 +83,10 @@
     @Override
     public String toString() {
         StringBuilder builder =
-                new StringBuilder("DnsEvent(").append("netId=").append(netId).append(", ");
-        for (int t : BitUtils.unpackBits(transports)) {
-            builder.append(NetworkCapabilities.transportNameOf(t)).append(", ");
-        }
+                new StringBuilder("DnsEvent(").append("netId=").append(netId)
+                        .append(", transports=")
+                        .append(BitSet.valueOf(new long[] { transports }))
+                        .append(", ");
         builder.append(String.format("%d events, ", eventCount));
         builder.append(String.format("%d success)", successCount));
         return builder.toString();
diff --git a/core/java/android/net/metrics/NetworkMetrics.java b/core/java/android/net/metrics/NetworkMetrics.java
index 66d92c4..8f2f612 100644
--- a/core/java/android/net/metrics/NetworkMetrics.java
+++ b/core/java/android/net/metrics/NetworkMetrics.java
@@ -16,11 +16,9 @@
 
 package android.net.metrics;
 
-import android.net.NetworkCapabilities;
-
-import com.android.internal.util.BitUtils;
 import com.android.internal.util.TokenBucket;
 
+import java.util.BitSet;
 import java.util.StringJoiner;
 
 /**
@@ -144,9 +142,7 @@
         public String toString() {
             StringJoiner j = new StringJoiner(", ", "{", "}");
             j.add("netId=" + netId);
-            for (int t : BitUtils.unpackBits(transports)) {
-                j.add(NetworkCapabilities.transportNameOf(t));
-            }
+            j.add("transports=" + BitSet.valueOf(new long[] { transports }));
             j.add(String.format("dns avg=%dms max=%dms err=%.1f%% tot=%d",
                     (int) dnsLatencies.average(), (int) dnsLatencies.max,
                     100 * dnsErrorRate.average(), dnsErrorRate.count));
diff --git a/core/java/android/nfc/OWNERS b/core/java/android/nfc/OWNERS
new file mode 100644
index 0000000..6aaf039
--- /dev/null
+++ b/core/java/android/nfc/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 48448
+
+zachoverflow@google.com
+alisher@google.com
diff --git a/core/java/android/nfc/cardemulation/OWNERS b/core/java/android/nfc/cardemulation/OWNERS
new file mode 100644
index 0000000..6aaf039
--- /dev/null
+++ b/core/java/android/nfc/cardemulation/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 48448
+
+zachoverflow@google.com
+alisher@google.com
diff --git a/core/java/android/nfc/dta/OWNERS b/core/java/android/nfc/dta/OWNERS
new file mode 100644
index 0000000..6aaf039
--- /dev/null
+++ b/core/java/android/nfc/dta/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 48448
+
+zachoverflow@google.com
+alisher@google.com
diff --git a/core/java/android/nfc/tech/OWNERS b/core/java/android/nfc/tech/OWNERS
new file mode 100644
index 0000000..6aaf039
--- /dev/null
+++ b/core/java/android/nfc/tech/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 48448
+
+zachoverflow@google.com
+alisher@google.com
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java
new file mode 100644
index 0000000..d00c3c3
--- /dev/null
+++ b/core/java/android/os/BatteryConsumer.java
@@ -0,0 +1,89 @@
+/*
+ * 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.os;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Interface for objects containing battery attribution data.
+ *
+ * @hide
+ */
+public abstract class BatteryConsumer {
+
+    /**
+     * Power usage component, describing the particular part of the system
+     * responsible for power drain.
+     *
+     * @hide
+     */
+    @IntDef(prefix = {"POWER_COMPONENT_"}, value = {
+            POWER_COMPONENT_CPU,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public static @interface PowerComponent {
+    }
+
+    public static final int POWER_COMPONENT_CPU = 0;
+
+    public static final int POWER_COMPONENT_COUNT = 1;
+
+    public static final int FIRST_CUSTOM_POWER_COMPONENT_ID = 1000;
+    public static final int LAST_CUSTOM_POWER_COMPONENT_ID = 9999;
+
+    private final PowerComponents mPowerComponents;
+
+    protected BatteryConsumer(@NonNull PowerComponents powerComponents) {
+        mPowerComponents = powerComponents;
+    }
+
+    /**
+     * Total power consumed by this consumer, in mAh.
+     */
+    public double getConsumedPower() {
+        return mPowerComponents.getTotalPowerConsumed();
+    }
+
+    /**
+     * Returns the amount of drain attributed to the specified drain type, e.g. CPU, WiFi etc.
+     *
+     * @param componentId The ID of the power component, e.g.
+     *                    {@link BatteryConsumer#POWER_COMPONENT_CPU}.
+     * @return Amount of consumed power in mAh.
+     */
+    public double getConsumedPower(@PowerComponent int componentId) {
+        return mPowerComponents.getConsumedPower(componentId);
+    }
+
+    /**
+     * Returns the amount of drain attributed to the specified custom drain type.
+     *
+     * @param componentId The ID of the custom power component.
+     * @return Amount of consumed power in mAh.
+     */
+    public double getConsumedPowerForCustomComponent(int componentId) {
+        return mPowerComponents.getConsumedPowerForCustomComponent(componentId);
+    }
+
+    protected void writeToParcel(Parcel dest, int flags) {
+        mPowerComponents.writeToParcel(dest, flags);
+    }
+}
diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java
index a9585c6..d9e01cd 100644
--- a/core/java/android/os/BatteryStatsManager.java
+++ b/core/java/android/os/BatteryStatsManager.java
@@ -161,6 +161,22 @@
     }
 
     /**
+     * Returns BatteryUsageStats, which contains power attribution data on a per-subsystem
+     * and per-UID basis.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.BATTERY_STATS)
+    @NonNull
+    public BatteryUsageStats getBatteryUsageStats() {
+        try {
+            return mBatteryStats.getBatteryUsageStats();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Indicates that the wifi connection RSSI has changed.
      *
      * @param newRssi The new RSSI value.
diff --git a/core/java/android/os/BatteryUsageStats.aidl b/core/java/android/os/BatteryUsageStats.aidl
new file mode 100644
index 0000000..0400f19
--- /dev/null
+++ b/core/java/android/os/BatteryUsageStats.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.os;
+
+parcelable BatteryUsageStats;
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
new file mode 100644
index 0000000..3f036cd
--- /dev/null
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -0,0 +1,138 @@
+/*
+ * 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.os;
+
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Contains a snapshot of battery attribution data, on a per-subsystem and per-UID basis.
+ *
+ * @hide
+ */
+public final class BatteryUsageStats implements Parcelable {
+    private final double mConsumedPower;
+    private final int mDischargePercentage;
+    private final ArrayList<UidBatteryConsumer> mUidBatteryConsumers;
+
+    private BatteryUsageStats(@NonNull Builder builder) {
+        mConsumedPower = builder.mConsumedPower;
+        mDischargePercentage = builder.mDischargePercentage;
+        mUidBatteryConsumers = builder.mUidBatteryConsumers;
+    }
+
+    /**
+     * Portion of battery charge drained since BatteryStats reset (e.g. due to being fully
+     * charged), as percentage of the full charge in the range [0:100]
+     */
+    public int getDischargePercentage() {
+        return mDischargePercentage;
+    }
+
+    /**
+     * Total amount of battery charge drained since BatteryStats reset (e.g. due to being fully
+     * charged), in mAh
+     */
+    public double getConsumedPower() {
+        return mConsumedPower;
+    }
+
+    @NonNull
+    public List<UidBatteryConsumer> getUidBatteryConsumers() {
+        return mUidBatteryConsumers;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    private BatteryUsageStats(@NonNull Parcel source) {
+        mUidBatteryConsumers = new ArrayList<>();
+        source.readParcelableList(mUidBatteryConsumers, getClass().getClassLoader());
+        mConsumedPower = source.readDouble();
+        mDischargePercentage = source.readInt();
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeParcelableList(mUidBatteryConsumers, flags);
+        dest.writeDouble(mConsumedPower);
+        dest.writeInt(mDischargePercentage);
+    }
+
+    @NonNull
+    public static final Creator<BatteryUsageStats> CREATOR = new Creator<BatteryUsageStats>() {
+        public BatteryUsageStats createFromParcel(@NonNull Parcel source) {
+            return new BatteryUsageStats(source);
+        }
+
+        public BatteryUsageStats[] newArray(int size) {
+            return new BatteryUsageStats[size];
+        }
+    };
+
+    /**
+     * Builder for BatteryUsageStats.
+     */
+    public static final class Builder {
+        private double mConsumedPower;
+        private int mDischargePercentage;
+        private final ArrayList<UidBatteryConsumer> mUidBatteryConsumers = new ArrayList<>();
+
+        /**
+         * Constructs a read-only object using the Builder values.
+         */
+        @NonNull
+        public BatteryUsageStats build() {
+            return new BatteryUsageStats(this);
+        }
+
+        /**
+         * Sets the battery discharge amount since BatteryStats reset as percentage of the full
+         * charge.
+         */
+        @SuppressLint("PercentageInt") // See b/174188159
+        @NonNull
+        public Builder setDischargePercentage(int dischargePercentage) {
+            mDischargePercentage = dischargePercentage;
+            return this;
+        }
+
+        /**
+         * Sets the battery discharge amount since BatteryStats reset, in mAh.
+         */
+        @NonNull
+        public Builder setConsumedPower(double consumedPower) {
+            mConsumedPower = consumedPower;
+            return this;
+        }
+
+        /**
+         * Adds a UidBatteryConsumer, which represents battery attribution data for an
+         * individual UID.
+         */
+        @NonNull
+        public Builder addUidBatteryConsumer(@NonNull UidBatteryConsumer uidBatteryConsumer) {
+            mUidBatteryConsumers.add(uidBatteryConsumer);
+            return this;
+        }
+    }
+}
diff --git a/core/java/android/os/CombinedVibrationEffect.java b/core/java/android/os/CombinedVibrationEffect.java
index c9ebc1b..7ec7fff 100644
--- a/core/java/android/os/CombinedVibrationEffect.java
+++ b/core/java/android/os/CombinedVibrationEffect.java
@@ -30,8 +30,6 @@
  * Vibrator Vibrators}.
  *
  * These effects may be any number of things, from single shot vibrations to complex waveforms.
- *
- * @hide
  * @see VibrationEffect
  */
 @SuppressWarnings({"ParcelNotFinal", "ParcelCreator"}) // Parcel only extended here.
@@ -94,7 +92,6 @@
     /**
      * A combination of haptic effects that should be played in multiple vibrators in sync.
      *
-     * @hide
      * @see CombinedVibrationEffect#startSynced()
      */
     public static final class SyncedCombination {
@@ -144,7 +141,6 @@
     /**
      * A combination of haptic effects that should be played in multiple vibrators in sequence.
      *
-     * @hide
      * @see CombinedVibrationEffect#startSequential()
      */
     public static final class SequentialCombination {
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index a4af0db..e2e1bbe 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -1946,7 +1946,13 @@
      */
     public static final int MEMINFO_KRECLAIMABLE = 15;
     /** @hide */
-    public static final int MEMINFO_COUNT = 16;
+    public static final int MEMINFO_ACTIVE = 16;
+    /** @hide */
+    public static final int MEMINFO_INACTIVE = 17;
+    /** @hide */
+    public static final int MEMINFO_UNEVICTABLE = 18;
+    /** @hide */
+    public static final int MEMINFO_COUNT = 19;
 
     /**
      * Retrieves /proc/meminfo.  outSizes is filled with fields
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 5db4107..379d6e6 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -1436,7 +1436,8 @@
     public static FileDescriptor convertToModernFd(FileDescriptor fd) {
         try {
             Context context = AppGlobals.getInitialApplication();
-            if (!SystemProperties.getBoolean("persist.sys.fuse.transcode", false)
+            // TODO(b/169327180): Consider device config.
+            if (!SystemProperties.getBoolean("persist.sys.fuse.transcode_enabled", false)
                     || !SystemProperties.getBoolean("persist.sys.fuse.transcode_optimize", true)
                     || UserHandle.getAppId(Process.myUid()) == getMediaProviderAppId(context)) {
                 // If transcode is enabled we optimize by default, unless explicitly disabled.
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 91eb2a5..d392d71 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -16,7 +16,7 @@
 per-file PowerManager.java = michaelwr@google.com, santoscordon@google.com
 per-file PowerManagerInternal.java = michaelwr@google.com, santoscordon@google.com
 
-# Zygote
-per-file ZygoteProcess.java = calin@google.com, chriswailes@google.com, maco@google.com, narayan@google.com, ngeoffray@google.com
 
 per-file GraphicsEnvironment.java = chrisforbes@google.com, cnorthrop@google.com, lpy@google.com, timvp@google.com, zzyiwei@google.com
+
+per-file *Zygote* = file:/ZYGOTE_OWNERS
diff --git a/core/java/android/os/ParcelableHolder.java b/core/java/android/os/ParcelableHolder.java
index fb9fa10..1be367c 100644
--- a/core/java/android/os/ParcelableHolder.java
+++ b/core/java/android/os/ParcelableHolder.java
@@ -120,31 +120,37 @@
 
     /**
      * Write a parcelable into ParcelableHolder, the previous parcelable will be removed.
-     * @return {@code false} if the parcelable's stability is more unstable ParcelableHolder.
+     * @throws BadParcelableException if the parcelable's stability is more unstable
+     *         ParcelableHolder.
      */
-    public boolean setParcelable(@Nullable Parcelable p) {
-        // a ParcelableHolder can only hold things at its stability or higher
+    public void setParcelable(@Nullable Parcelable p) {
+        // A ParcelableHolder can only hold things at its stability or higher.
         if (p != null && this.getStability() > p.getStability()) {
-            return false;
+            throw new BadParcelableException(
+                "A ParcelableHolder can only hold things at its stability or higher. "
+                + "The ParcelableHolder's stability is " + this.getStability()
+                + ", but the parcelable's stability is " + p.getStability());
         }
         mParcelable = p;
         if (mParcel != null) {
             mParcel.recycle();
             mParcel = null;
         }
-        return true;
     }
 
     /**
      * @return the parcelable that was written by {@link #setParcelable} or {@link #readFromParcel},
-     *         or {@code null} if the parcelable has not been written, or T is different from
-     *         the type written by (@link #setParcelable}.
+     *         or {@code null} if the parcelable has not been written.
+     * @throws BadParcelableException if T is different from the type written by
+     *         (@link #setParcelable}.
      */
     @Nullable
     public <T extends Parcelable> T getParcelable(@NonNull Class<T> clazz) {
         if (mParcel == null) {
-            if (!clazz.isInstance(mParcelable)) {
-                return null;
+            if (mParcelable != null && !clazz.isInstance(mParcelable)) {
+                throw new BadParcelableException(
+                    "The ParcelableHolder has " + mParcelable.getClass().getName()
+                    + ", but the requested type is " + clazz.getName());
             }
             return (T) mParcelable;
         }
@@ -152,8 +158,10 @@
         mParcel.setDataPosition(0);
 
         T parcelable = mParcel.readParcelable(clazz.getClassLoader());
-        if (!clazz.isInstance(parcelable)) {
-            return null;
+        if (parcelable != null && !clazz.isInstance(parcelable)) {
+            throw new BadParcelableException(
+                    "The ParcelableHolder has " + parcelable.getClass().getName()
+                    + ", but the requested type is " + clazz.getName());
         }
         mParcelable = parcelable;
 
diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java
new file mode 100644
index 0000000..42ba1ff
--- /dev/null
+++ b/core/java/android/os/PowerComponents.java
@@ -0,0 +1,170 @@
+/*
+ * 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.os;
+
+
+import android.annotation.NonNull;
+
+/**
+ * Contains details of battery attribution data broken down to individual power drain types
+ * such as CPU, RAM, GPU etc.
+ *
+ * @hide
+ */
+class PowerComponents {
+
+    private final double mTotalPowerConsumed;
+    private final double[] mPowerComponents;
+
+    PowerComponents(@NonNull Builder builder) {
+        mTotalPowerConsumed = builder.mTotalPowerConsumed;
+        mPowerComponents = builder.mPowerComponents;
+    }
+
+    PowerComponents(@NonNull Parcel source) {
+        mTotalPowerConsumed = source.readDouble();
+        mPowerComponents = source.createDoubleArray();
+    }
+
+    /** Writes contents to Parcel */
+    void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeDouble(mTotalPowerConsumed);
+        dest.writeDoubleArray(mPowerComponents);
+    }
+
+    /**
+     * Total power consumed by this consumer, in mAh.
+     */
+    public double getTotalPowerConsumed() {
+        return mTotalPowerConsumed;
+    }
+
+    /**
+     * Returns the amount of drain attributed to the specified drain type, e.g. CPU, WiFi etc.
+     *
+     * @param componentId The ID of the power component, e.g.
+     *                    {@link BatteryConsumer#POWER_COMPONENT_CPU}.
+     * @return Amount of consumed power in mAh.
+     */
+    public double getConsumedPower(@UidBatteryConsumer.PowerComponent int componentId) {
+        if (componentId >= BatteryConsumer.POWER_COMPONENT_COUNT) {
+            throw new IllegalArgumentException(
+                    "Unsupported power component ID: " + componentId);
+        }
+        try {
+            return mPowerComponents[componentId];
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw new IllegalArgumentException("Unsupported power component ID: " + componentId);
+        }
+    }
+
+    /**
+     * Returns the amount of drain attributed to the specified custom drain type.
+     *
+     * @param componentId The ID of the custom power component.
+     * @return Amount of consumed power in mAh.
+     */
+    public double getConsumedPowerForCustomComponent(int componentId) {
+        if (componentId < BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID) {
+            throw new IllegalArgumentException(
+                    "Unsupported custom power component ID: " + componentId);
+        }
+        try {
+            return mPowerComponents[
+                    BatteryConsumer.POWER_COMPONENT_COUNT + componentId
+                            - BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID];
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw new IllegalArgumentException(
+                    "Unsupported custom power component ID: " + componentId);
+        }
+    }
+
+    /**
+     * Builder for PowerComponents.
+     */
+    static final class Builder {
+        private double mTotalPowerConsumed;
+        private final double[] mPowerComponents;
+
+        Builder(int customPowerComponentCount) {
+            mPowerComponents = new double[BatteryConsumer.POWER_COMPONENT_COUNT
+                    + customPowerComponentCount];
+        }
+
+        /**
+         * Sets the sum amount of power consumed since BatteryStats reset.
+         */
+        @NonNull
+        public Builder setTotalPowerConsumed(double totalPowerConsumed) {
+            mTotalPowerConsumed = totalPowerConsumed;
+            return this;
+        }
+
+        /**
+         * Sets the amount of drain attributed to the specified drain type, e.g. CPU, WiFi etc.
+         *
+         * @param componentId    The ID of the power component, e.g.
+         *                       {@link BatteryConsumer#POWER_COMPONENT_CPU}.
+         * @param componentPower Amount of consumed power in mAh.
+         */
+        @NonNull
+        public Builder setConsumedPower(@UidBatteryConsumer.PowerComponent int componentId,
+                double componentPower) {
+            if (componentId >= BatteryConsumer.POWER_COMPONENT_COUNT) {
+                throw new IllegalArgumentException(
+                        "Unsupported power component ID: " + componentId);
+            }
+            try {
+                mPowerComponents[componentId] = componentPower;
+            } catch (ArrayIndexOutOfBoundsException e) {
+                throw new IllegalArgumentException(
+                        "Unsupported power component ID: " + componentId);
+            }
+            return this;
+        }
+
+        /**
+         * Sets the amount of drain attributed to the specified custom drain type.
+         *
+         * @param componentId    The ID of the custom power component.
+         * @param componentPower Amount of consumed power in mAh.
+         */
+        @NonNull
+        public Builder setConsumedPowerForCustomComponent(int componentId, double componentPower) {
+            if (componentId < BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID) {
+                throw new IllegalArgumentException(
+                        "Unsupported custom power component ID: " + componentId);
+            }
+            try {
+                mPowerComponents[BatteryConsumer.POWER_COMPONENT_COUNT + componentId
+                        - BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID] = componentPower;
+            } catch (ArrayIndexOutOfBoundsException e) {
+                throw new IllegalArgumentException(
+                        "Unsupported custom power component ID: " + componentId);
+            }
+            return this;
+        }
+
+        /**
+         * Creates a read-only object out of the Builder values.
+         */
+        @NonNull
+        public PowerComponents build() {
+            return new PowerComponents(this);
+        }
+    }
+}
diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java
new file mode 100644
index 0000000..7dcbf7d
--- /dev/null
+++ b/core/java/android/os/UidBatteryConsumer.java
@@ -0,0 +1,145 @@
+/*
+ * 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.os;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+/**
+ * Contains power consumption data attributed to a specific UID.
+ *
+ * @hide
+ */
+public final class UidBatteryConsumer extends BatteryConsumer implements Parcelable {
+
+    private final int mUid;
+    @Nullable
+    private final String mPackageWithHighestDrain;
+
+    public int getUid() {
+        return mUid;
+    }
+
+    @Nullable
+    public String getPackageWithHighestDrain() {
+        return mPackageWithHighestDrain;
+    }
+
+    private UidBatteryConsumer(@NonNull Builder builder) {
+        super(builder.mPowerComponentsBuilder.build());
+        mUid = builder.mUid;
+        mPackageWithHighestDrain = builder.mPackageWithHighestDrain;
+    }
+
+    private UidBatteryConsumer(@NonNull Parcel source) {
+        super(new PowerComponents(source));
+        mUid = source.readInt();
+        mPackageWithHighestDrain = source.readString();
+    }
+
+    /**
+     * Writes the contents into a Parcel.
+     */
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeInt(mUid);
+        dest.writeString(mPackageWithHighestDrain);
+    }
+
+    @NonNull
+    public static final Creator<UidBatteryConsumer> CREATOR = new Creator<UidBatteryConsumer>() {
+        public UidBatteryConsumer createFromParcel(@NonNull Parcel source) {
+            return new UidBatteryConsumer(source);
+        }
+
+        public UidBatteryConsumer[] newArray(int size) {
+            return new UidBatteryConsumer[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Builder for UidBatteryConsumer.
+     */
+    public static final class Builder {
+        private final PowerComponents.Builder mPowerComponentsBuilder;
+        private final int mUid;
+        private String mPackageWithHighestDrain;
+
+        public Builder(int customPowerComponentCount, int uid) {
+            mPowerComponentsBuilder = new PowerComponents.Builder(customPowerComponentCount);
+            mUid = uid;
+        }
+
+        /**
+         * Creates a read-only object out of the Builder values.
+         */
+        @NonNull
+        public UidBatteryConsumer build() {
+            return new UidBatteryConsumer(this);
+        }
+
+        /**
+         * Sets the amount of drain attributed to the specified drain type, e.g. CPU, WiFi etc.
+         *
+         * @param componentId    The ID of the power component, e.g.
+         * {@link BatteryConsumer#POWER_COMPONENT_CPU}.
+         * @param componentPower Amount of consumed power in mAh.
+         */
+        @NonNull
+        public Builder setConsumedPower(@PowerComponent int componentId, double componentPower) {
+            mPowerComponentsBuilder.setConsumedPower(componentId, componentPower);
+            return this;
+        }
+
+        /**
+         * Sets the amount of drain attributed to the specified custom drain type.
+         *
+         * @param componentId    The ID of the custom power component.
+         * @param componentPower Amount of consumed power in mAh.
+         */
+        @NonNull
+        public Builder setConsumedPowerForCustomComponent(int componentId, double componentPower) {
+            mPowerComponentsBuilder.setConsumedPowerForCustomComponent(componentId, componentPower);
+            return this;
+        }
+
+        /**
+         * Sets the amount of power consumed since BatteryStats reset, mAh.
+         */
+        @NonNull
+        public Builder setConsumedPower(double consumedPower) {
+            mPowerComponentsBuilder.setTotalPowerConsumed(consumedPower);
+            return this;
+        }
+
+        /**
+         * Sets the name of the package owned by this UID that consumed the highest amount
+         * of power since BatteryStats reset.
+         */
+        @NonNull
+        public Builder setPackageWithHighestDrain(@Nullable String packageName) {
+            mPackageWithHighestDrain = packageName;
+            return this;
+        }
+    }
+}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index aba1f28..e7d19c5 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -136,6 +136,12 @@
     public static final String USER_TYPE_PROFILE_MANAGED = "android.os.usertype.profile.MANAGED";
 
     /**
+     * User type representing a generic profile for testing purposes. Only on debuggable builds.
+     * @hide
+     */
+    public static final String USER_TYPE_PROFILE_TEST = "android.os.usertype.profile.TEST";
+
+    /**
      * User type representing a {@link UserHandle#USER_SYSTEM system} user that is <b>not</b> a
      * human user.
      * This type of user cannot be created; it can only pre-exist on first boot.
diff --git a/core/java/android/os/VibratorManager.java b/core/java/android/os/VibratorManager.java
new file mode 100644
index 0000000..1d5a587
--- /dev/null
+++ b/core/java/android/os/VibratorManager.java
@@ -0,0 +1,61 @@
+/*
+ * 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.os;
+
+import android.annotation.NonNull;
+
+/**
+ * VibratorManager provides access to multiple vibrators, as well as the ability to run them in
+ * a synchronized fashion.
+ */
+public abstract class VibratorManager {
+    /** @hide */
+    protected static final String TAG = "VibratorManager";
+
+    /**
+     * {@hide}
+     */
+    public VibratorManager() {
+    }
+
+    /**
+     * This method lists all available actuator ids, returning a possible empty list.
+     * If the device has only a single actuator, this should return a single entry with a
+     * default id.
+     */
+    @NonNull
+    public abstract int[] getVibratorIds();
+
+    /**
+    * Returns a Vibrator service for given id.
+    * This allows users to perform a vibration effect on a single actuator.
+    */
+    @NonNull
+    public abstract Vibrator getVibrator(int vibratorId);
+
+    /**
+    * Returns the system default Vibrator service.
+    */
+    @NonNull
+    public abstract Vibrator getDefaultVibrator();
+
+    /**
+     * Vibrates all actuators by passing each VibrationEffect within CombinedVibrationEffect
+     * to the respective actuator, in sync.
+     */
+    public abstract void vibrate(@NonNull CombinedVibrationEffect effect);
+}
diff --git a/core/java/android/os/connectivity/OWNERS b/core/java/android/os/connectivity/OWNERS
new file mode 100644
index 0000000..a0f0238
--- /dev/null
+++ b/core/java/android/os/connectivity/OWNERS
@@ -0,0 +1 @@
+dplotnikov@google.com
diff --git a/core/java/android/os/health/OWNERS b/core/java/android/os/health/OWNERS
new file mode 100644
index 0000000..6045344
--- /dev/null
+++ b/core/java/android/os/health/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 26805
+
+dplotnikov@google.com
+mwachens@google.com
diff --git a/core/java/android/os/image/OWNERS b/core/java/android/os/image/OWNERS
new file mode 100644
index 0000000..389b55b
--- /dev/null
+++ b/core/java/android/os/image/OWNERS
@@ -0,0 +1 @@
+andrewhsieh@google.com
diff --git a/core/java/android/os/storage/OWNERS b/core/java/android/os/storage/OWNERS
new file mode 100644
index 0000000..8af7de5
--- /dev/null
+++ b/core/java/android/os/storage/OWNERS
@@ -0,0 +1,7 @@
+# Bug component: 95221
+
+narayan@google.com
+nandana@google.com
+corinac@google.com
+zezeozue@google.com
+maco@google.com
diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl
index 1001668..a94077d 100644
--- a/core/java/android/permission/IPermissionManager.aidl
+++ b/core/java/android/permission/IPermissionManager.aidl
@@ -73,10 +73,6 @@
 
     void resetRuntimePermissions();
 
-    boolean setDefaultBrowser(String packageName, int userId);
-
-    String getDefaultBrowser(int userId);
-
     void grantDefaultPermissionsToEnabledCarrierApps(in String[] packageNames, int userId);
 
     void grantDefaultPermissionsToEnabledImsServices(in String[] packageNames, int userId);
@@ -91,10 +87,6 @@
 
     void revokeDefaultPermissionsFromLuiApps(in String[] packageNames, int userId);
 
-    void setPermissionEnforced(String permName, boolean enforced);
-
-    boolean isPermissionEnforced(String permName);
-
     boolean shouldShowRequestPermissionRationale(String permName,
             String packageName, int userId);
 
diff --git a/core/java/android/permission/OWNERS b/core/java/android/permission/OWNERS
new file mode 100644
index 0000000..d09f351
--- /dev/null
+++ b/core/java/android/permission/OWNERS
@@ -0,0 +1,8 @@
+# Bug component: 137825
+
+moltmann@google.com
+evanseverson@google.com
+ntmyren@google.com
+zhanghai@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
diff --git a/core/java/android/permission/PermissionManagerInternal.java b/core/java/android/permission/PermissionManagerInternal.java
index 3134ec0..a4676c4 100644
--- a/core/java/android/permission/PermissionManagerInternal.java
+++ b/core/java/android/permission/PermissionManagerInternal.java
@@ -19,11 +19,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
-import android.os.UserHandle;
-
-import com.android.internal.util.function.TriFunction;
-
-import java.util.function.BiFunction;
 
 /**
  * Internal interfaces to be used by other components within the system server.
@@ -32,96 +27,39 @@
  *
  * @hide
  */
-public abstract class PermissionManagerInternal {
-
+public interface PermissionManagerInternal {
     /**
-     * Listener for package permission state (permissions or flags) changes.
-     */
-    public interface OnRuntimePermissionStateChangedListener {
-
-        /**
-         * Called when the runtime permission state (permissions or flags) changed.
-         *
-         * @param packageName The package for which the change happened.
-         * @param userId the user id for which the change happened.
-         */
-        @Nullable
-        void onRuntimePermissionStateChanged(@NonNull String packageName,
-                @UserIdInt int userId);
-    }
-
-    /** Interface to override permission checks via composition */
-    public interface CheckPermissionDelegate {
-        /**
-         * Checks whether the given package has been granted the specified permission.
-         *
-         * @return If the package has the permission, PERMISSION_GRANTED is
-         * returned.  If it does not have the permission, PERMISSION_DENIED
-         * is returned.
-         *
-         * @see android.content.pm.PackageManager#checkPermission(String, String)
-         */
-        int checkPermission(String permName, String pkgName, int userId,
-                TriFunction<String, String, Integer, Integer> superImpl);
-
-        /**
-        /**
-         * Checks whether the given uid has been granted the specified permission.
-         *
-         * @return If the package has the permission, PERMISSION_GRANTED is
-         * returned.  If it does not have the permission, PERMISSION_DENIED
-         * is returned.
-         *
-         */
-        int checkUidPermission(String permName, int uid,
-                BiFunction<String, Integer, Integer> superImpl);
-    }
-
-    /**
-     * Get the state of the runtime permissions as xml file.
+     * Get the state of the runtime permissions as a blob.
      *
-     * @param user The user the data should be extracted for
+     * @param userId The user ID the data should be extracted for
      *
-     * @return The state as a xml file
+     * @return the state as a blob
      */
-    public abstract @Nullable byte[] backupRuntimePermissions(@NonNull UserHandle user);
+    //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+    @Nullable
+    byte[] backupRuntimePermissions(@UserIdInt int userId);
 
     /**
      * Restore a permission state previously backed up via {@link #backupRuntimePermissions}.
+     * <p>
+     * If not all state can be restored, the un-restorable state will be delayed and can be
+     * retried via {@link #restoreDelayedRuntimePermissions}.
      *
-     * <p>If not all state can be restored, the un-restoreable state will be delayed and can be
-     * re-tried via {@link #restoreDelayedRuntimePermissions}.
-     *
-     * @param backup The state as an xml file
-     * @param user The user the data should be restored for
+     * @param backup the state as a blob
+     * @param userId the user ID the data should be restored for
      */
-    public abstract void restoreRuntimePermissions(@NonNull byte[] backup,
-            @NonNull UserHandle user);
+    //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+    void restoreRuntimePermissions(@NonNull byte[] backup, @UserIdInt int userId);
 
     /**
      * Try to apply permission backup of a package that was previously not applied.
      *
-     * @param packageName The package that is newly installed
-     * @param user The user the package is installed for
+     * @param packageName the package that is newly installed
+     * @param userId the user ID the package is installed for
      *
      * @see #restoreRuntimePermissions
      */
-    public abstract void restoreDelayedRuntimePermissions(@NonNull String packageName,
-            @NonNull UserHandle user);
-
-    /**
-     * Adds a listener for runtime permission state (permissions or flags) changes.
-     *
-     * @param listener The listener.
-     */
-    public abstract void addOnRuntimePermissionStateChangedListener(
-            @NonNull OnRuntimePermissionStateChangedListener listener);
-
-    /**
-     * Removes a listener for runtime permission state (permissions or flags) changes.
-     *
-     * @param listener The listener.
-     */
-    public abstract void removeOnRuntimePermissionStateChangedListener(
-            @NonNull OnRuntimePermissionStateChangedListener listener);
+    //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+    void restoreDelayedRuntimePermissions(@NonNull String packageName,
+            @UserIdInt int userId);
 }
diff --git a/core/java/android/permissionpresenterservice/OWNERS b/core/java/android/permissionpresenterservice/OWNERS
new file mode 100644
index 0000000..d09f351
--- /dev/null
+++ b/core/java/android/permissionpresenterservice/OWNERS
@@ -0,0 +1,8 @@
+# Bug component: 137825
+
+moltmann@google.com
+evanseverson@google.com
+ntmyren@google.com
+zhanghai@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
diff --git a/core/java/android/print/OWNERS b/core/java/android/print/OWNERS
new file mode 100644
index 0000000..72f0983
--- /dev/null
+++ b/core/java/android/print/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 47273
+
+moltmann@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
diff --git a/core/java/android/print/pdf/OWNERS b/core/java/android/print/pdf/OWNERS
new file mode 100644
index 0000000..72f0983
--- /dev/null
+++ b/core/java/android/print/pdf/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 47273
+
+moltmann@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
diff --git a/core/java/android/printservice/OWNERS b/core/java/android/printservice/OWNERS
new file mode 100644
index 0000000..72f0983
--- /dev/null
+++ b/core/java/android/printservice/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 47273
+
+moltmann@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
diff --git a/core/java/android/printservice/recommendation/OWNERS b/core/java/android/printservice/recommendation/OWNERS
new file mode 100644
index 0000000..72f0983
--- /dev/null
+++ b/core/java/android/printservice/recommendation/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 47273
+
+moltmann@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 03e8a07..da06e82 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -19,6 +19,7 @@
 import android.accounts.Account;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
@@ -47,6 +48,9 @@
 import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Build;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.os.RemoteException;
 import android.telecom.PhoneAccountHandle;
 import android.text.TextUtils;
@@ -54,11 +58,15 @@
 import android.util.Pair;
 import android.view.View;
 
+import com.google.android.collect.Sets;
+
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
+import java.util.Set;
 
 /**
  * <p>
@@ -8188,6 +8196,321 @@
         public static final String RAW_CONTACT_ID2 = "raw_contact_id2";
     }
 
+
+    /**
+     * Class containing utility methods around determine what accounts in the ContactsProvider are
+     * related to the SIM cards in the device.
+     * <p>
+     * Apps interested in managing contacts from SIM cards can query the ContactsProvider using
+     * {@link #getSimAccounts(ContentResolver)} to get all accounts that relate to SIM cards. They
+     * can also register a receiver for the {@link #ACTION_SIM_ACCOUNTS_CHANGED} broadcast to be
+     * notified when these accounts change.
+     */
+    public static final class SimContacts {
+        /**
+         * This utility class cannot be instantiated
+         */
+        private SimContacts() {
+        }
+
+        /**
+         * The method to invoke in order to add a new SIM account for a newly inserted SIM card.
+         *
+         * @hide
+         */
+        public static final String ADD_SIM_ACCOUNT_METHOD = "addSimAccount";
+
+        /**
+         * The method to invoke in order to remove a SIM account once the corresponding SIM card is
+         * ejected.
+         *
+         * @hide
+         */
+        public static final String REMOVE_SIM_ACCOUNT_METHOD = "removeSimAccount";
+
+        /**
+         * The method to invoke in order to query all SIM accounts.
+         *
+         * @hide
+         */
+        public static final String QUERY_SIM_ACCOUNTS_METHOD = "querySimAccounts";
+
+        /**
+         * Key to add in the outgoing Bundle for the SIM slot.
+         *
+         * @hide
+         */
+        public static final String KEY_SIM_SLOT_INDEX = "key_sim_slot_index";
+
+        /**
+         * Key to add in the outgoing Bundle for the SIM account's EF type.
+         * See {@link SimAccount#mEfType} for more information.
+         *
+         * @hide
+         */
+        public static final String KEY_SIM_EF_TYPE = "key_sim_ef_type";
+
+        /**
+         * Key to add in the outgoing Bundle for the account name.
+         *
+         * @hide
+         */
+        public static final String KEY_ACCOUNT_NAME = "key_sim_account_name";
+
+        /**
+         * Key to add in the outgoing Bundle for the account type.
+         *
+         * @hide
+         */
+        public static final String KEY_ACCOUNT_TYPE = "key_sim_account_type";
+
+        /**
+         * Key in the incoming Bundle for the all the SIM accounts.
+         *
+         * @hide
+         */
+        public static final String KEY_SIM_ACCOUNTS = "key_sim_accounts";
+
+        /**
+         * Broadcast Action: SIM accounts have changed, call
+         * {@link #getSimAccounts(ContentResolver)} to get the latest.
+         */
+        @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+        public static final String ACTION_SIM_ACCOUNTS_CHANGED =
+                "android.provider.action.SIM_ACCOUNTS_CHANGED";
+
+        /**
+         * Adds a new SIM account that maps to the corresponding SIM slot.
+         *
+         * @param accountName     accountName value for the account
+         * @param accountType     accountType value for the account
+         * @param contentResolver to perform the operation on.
+         * @param simSlotIndex    the SIM slot index of this new account.
+         * @param efType          the EF type of this new account.
+         * @hide
+         */
+        @SystemApi
+        @RequiresPermission("android.contacts.permission.MANAGE_SIM_ACCOUNTS")
+        public static void addSimAccount(@NonNull ContentResolver contentResolver,
+                @NonNull String accountName,
+                @NonNull String accountType,
+                int simSlotIndex,
+                int efType) {
+            if (simSlotIndex < 0) {
+                throw new IllegalArgumentException("Sim slot is negative");
+            }
+            if (!SimAccount.getValidEfTypes().contains(efType)) {
+                throw new IllegalArgumentException("Invalid EF type");
+            }
+            if (TextUtils.isEmpty(accountName) || TextUtils.isEmpty(accountType)) {
+                throw new IllegalArgumentException("Account name or type is empty");
+            }
+
+            Bundle extras = new Bundle();
+            extras.putInt(KEY_SIM_SLOT_INDEX, simSlotIndex);
+            extras.putInt(KEY_SIM_EF_TYPE, efType);
+            extras.putString(KEY_ACCOUNT_NAME, accountName);
+            extras.putString(KEY_ACCOUNT_TYPE, accountType);
+
+            contentResolver.call(ContactsContract.AUTHORITY_URI,
+                    ContactsContract.SimContacts.ADD_SIM_ACCOUNT_METHOD,
+                    null, extras);
+        }
+
+        /**
+         * Removes all SIM accounts that map to the corresponding SIM slot.
+         *
+         * @param contentResolver to perform the operation on.
+         * @param simSlotIndex    the SIM slot index of the accounts to remove.
+         * @hide
+         */
+        @SystemApi
+        @RequiresPermission("android.contacts.permission.MANAGE_SIM_ACCOUNTS")
+        public static void removeSimAccounts(@NonNull ContentResolver contentResolver,
+                int simSlotIndex) {
+            if (simSlotIndex < 0) {
+                throw new IllegalArgumentException("Sim slot is negative");
+            }
+
+            Bundle extras = new Bundle();
+            extras.putInt(KEY_SIM_SLOT_INDEX, simSlotIndex);
+
+            contentResolver.call(ContactsContract.AUTHORITY_URI,
+                    ContactsContract.SimContacts.REMOVE_SIM_ACCOUNT_METHOD,
+                    null, extras);
+        }
+
+        /**
+         * Returns all known SIM accounts. May be empty but never null.
+         *
+         * @param contentResolver content resolver to query.
+         */
+        public static @NonNull List<SimAccount> getSimAccounts(
+                @NonNull ContentResolver contentResolver) {
+            Bundle response = contentResolver.call(ContactsContract.AUTHORITY_URI,
+                    ContactsContract.SimContacts.QUERY_SIM_ACCOUNTS_METHOD,
+                    null, null);
+            List<SimAccount> result = response.getParcelableArrayList(KEY_SIM_ACCOUNTS);
+
+            if (result == null) {
+                result = new ArrayList<>();
+            }
+
+            return result;
+        }
+    }
+
+    /**
+     * A parcelable class encapsulating account data for contacts that originate from a SIM card.
+     */
+    public static final class SimAccount implements Parcelable {
+        /** An invalid EF type identifier. */
+        public static final int UNKNOWN_EF_TYPE = 0;
+        /** EF type identifier for the ADN partition. */
+        public static final int ADN_EF_TYPE = 1;
+        /** EF type identifier for the SDN partition. */
+        public static final int SDN_EF_TYPE = 2;
+        /** EF type identifier for the FDN partition. */
+        public static final int FDN_EF_TYPE = 3;
+
+        /**
+         * The account_name of this SIM account. See {@link RawContacts#ACCOUNT_NAME}.
+         */
+        private final String mAccountName;
+
+        /**
+         * The account_type of this SIM account. See {@link RawContacts#ACCOUNT_TYPE}.
+         */
+        private final String mAccountType;
+
+        /**
+         * The slot index of the SIM card this account maps to. See {@link
+         * android.telephony.SubscriptionInfo#getSimSlotIndex()}.
+         */
+        private final int mSimSlotIndex;
+
+        /**
+         * The EF type of the contacts stored in this account. One of
+         * {@link #ADN_EF_TYPE}, {@link #SDN_EF_TYPE} or {@link #FDN_EF_TYPE}.
+         *
+         * EF type is the Elementary File type of the partition these contacts come from within the
+         * SIM card.
+         *
+         * ADN is the "abbreviated dialing numbers" or the user managed SIM contacts.
+         *
+         * SDN is the "service dialing numbers" which are usually preloaded onto the SIM by the
+         * carrier.
+         *
+         * FDN is the "fixed dialing numbers" which are contacts which can only be dialed from that
+         * SIM, used in cases such as parental control.
+         */
+        private final int mEfType;
+
+        /**
+         * @return A set containing all known EF type values
+         * @hide
+         */
+        public static @NonNull Set<Integer> getValidEfTypes() {
+            return Sets.newArraySet(ADN_EF_TYPE, SDN_EF_TYPE, FDN_EF_TYPE);
+        }
+
+        /**
+         * @hide
+         */
+        public SimAccount(@NonNull String accountName, @NonNull String accountType,
+                int simSlotIndex,
+                int efType) {
+            this.mAccountName = accountName;
+            this.mAccountType = accountType;
+            this.mSimSlotIndex = simSlotIndex;
+            this.mEfType = efType;
+        }
+
+        /**
+         * @return The account_name of this SIM account. See {@link RawContacts#ACCOUNT_NAME}.
+         */
+        public @NonNull String getAccountName() {
+            return mAccountName;
+        }
+
+        /**
+         * @return The account_type of this SIM account. See {@link RawContacts#ACCOUNT_TYPE}.
+         */
+        public @NonNull String getAccountType() {
+            return mAccountType;
+        }
+
+        /**
+         * @return The slot index of the SIM card this account maps to. See
+         * {@link android.telephony.SubscriptionInfo#getSimSlotIndex()}.
+         */
+        public int getSimSlotIndex() {
+            return mSimSlotIndex;
+        }
+
+        /**
+         * @return The EF type of the contacts stored in this account.
+         */
+        public int getEfType() {
+            return mEfType;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mAccountName, mAccountType, mSimSlotIndex, mEfType);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == null) return false;
+            if (obj == this) return true;
+
+            SimAccount toCompare;
+            try {
+                toCompare = (SimAccount) obj;
+            } catch (ClassCastException ex) {
+                return false;
+            }
+
+            return mSimSlotIndex == toCompare.mSimSlotIndex
+                    && mEfType == toCompare.mEfType
+                    && Objects.equals(mAccountName, toCompare.mAccountName)
+                    && Objects.equals(mAccountType, toCompare.mAccountType);
+        }
+
+        @Override
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            dest.writeString(mAccountName);
+            dest.writeString(mAccountType);
+            dest.writeInt(mSimSlotIndex);
+            dest.writeInt(mEfType);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        public static final @NonNull Parcelable.Creator<SimAccount> CREATOR =
+                new Parcelable.Creator<SimAccount>() {
+                    @Override
+                    public SimAccount createFromParcel(Parcel source) {
+                        String accountName = source.readString();
+                        String accountType = source.readString();
+                        int simSlot = source.readInt();
+                        int efType = source.readInt();
+                        SimAccount simAccount = new SimAccount(accountName, accountType, simSlot,
+                                efType);
+                        return simAccount;
+                    }
+
+                    @Override
+                    public SimAccount[] newArray(int size) {
+                        return new SimAccount[size];
+                    }
+                };
+    }
+
     /**
      * @see Settings
      */
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 44cc0f5..f58fa15 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -126,6 +126,14 @@
     public static final String NAMESPACE_AUTOFILL = "autofill";
 
     /**
+     * Namespace for battery saver feature.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_BATTERY_SAVER = "battery_saver";
+
+    /**
      * Namespace for blobstore feature that allows apps to share data blobs.
      *
      * @hide
diff --git a/core/java/android/provider/OWNERS b/core/java/android/provider/OWNERS
index 97e0156..792ff20 100644
--- a/core/java/android/provider/OWNERS
+++ b/core/java/android/provider/OWNERS
@@ -2,4 +2,8 @@
 per-file DeviceConfig.java = hackbod@google.com
 per-file DeviceConfig.java = schfan@google.com
 
-
+per-file CallLog.java = file:/telephony/OWNERS
+per-file DocumentsContract.java = file:/core/java/android/os/storage/OWNERS
+per-file DocumentsProvider.java = file:/core/java/android/os/storage/OWNERS
+per-file MediaStore.java = file:/core/java/android/os/storage/OWNERS
+per-file Telephony.java = file:/telephony/OWNERS
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b86b9ff8..fb0aea0 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9962,13 +9962,13 @@
          * upon going to sleep. It additionally controls whether a playback device attempts to turn
          * on the connected Audio system when waking up. Supported values are:
          * <ul>
-         * <li>{@link HdmiControlManager#SEND_STANDBY_ON_SLEEP_TO_TV} Upon going to sleep, device
+         * <li>{@link HdmiControlManager#POWER_CONTROL_MODE_TV} Upon going to sleep, device
          * sends {@code <Standby>} to TV only. Upon waking up, device does not turn on the Audio
          * system via {@code <System Audio Mode Request>}.</li>
-         * <li>{@link HdmiControlManager#SEND_STANDBY_ON_SLEEP_BROADCAST} Upon going to sleep,
+         * <li>{@link HdmiControlManager#POWER_CONTROL_MODE_BROADCAST} Upon going to sleep,
          * device sends {@code <Standby>} to all devices in the network. Upon waking up, device
          * attempts to turn on the Audio system via {@code <System Audio Mode Request>}.</li>
-         * <li>{@link HdmiControlManager#SEND_STANDBY_ON_SLEEP_NONE} Upon going to sleep, device
+         * <li>{@link HdmiControlManager#POWER_CONTROL_MODE_NONE} Upon going to sleep, device
          * does not send any {@code <Standby>} message. Upon waking up, device does not turn on the
          * Audio system via {@code <System Audio Mode Request>}.</li>
          * </ul>
@@ -11717,24 +11717,6 @@
                 "battery_saver_device_specific_constants";
 
         /**
-         * Settings for adaptive Battery Saver mode. Uses the same flags as
-         * {@link #BATTERY_SAVER_CONSTANTS}.
-         *
-         * @hide
-         */
-        public static final String BATTERY_SAVER_ADAPTIVE_CONSTANTS =
-                "battery_saver_adaptive_constants";
-
-        /**
-         * Device specific settings for adaptive Battery Saver mode. Uses the same flags as
-         * {@link #BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS}.
-         *
-         * @hide
-         */
-        public static final String BATTERY_SAVER_ADAPTIVE_DEVICE_SPECIFIC_CONSTANTS =
-                "battery_saver_adaptive_device_specific_constants";
-
-        /**
          * Battery tip specific settings
          * This is encoded as a key=value list, separated by commas. Ex:
          *
@@ -14502,10 +14484,11 @@
         public static final String SHOW_PEOPLE_SPACE = "show_people_space";
 
         /**
-         * Which types of conversations to show in People Space.
+         * Which types of conversation(s) to show in People Space.
          * Values are:
-         * 0: All conversations (default)
+         * 0: Single user-selected conversation (default)
          * 1: Priority conversations only
+         * 2: All conversations
          * @hide
          */
         public static final String PEOPLE_SPACE_CONVERSATION_TYPE =
diff --git a/core/java/android/se/OWNERS b/core/java/android/se/OWNERS
new file mode 100644
index 0000000..f1539dc
--- /dev/null
+++ b/core/java/android/se/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 456592
+
+cbrubaker@google.com
+vishwath@google.com
diff --git a/core/java/android/se/omapi/OWNERS b/core/java/android/se/omapi/OWNERS
new file mode 100644
index 0000000..f1539dc
--- /dev/null
+++ b/core/java/android/se/omapi/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 456592
+
+cbrubaker@google.com
+vishwath@google.com
diff --git a/core/java/android/security/OWNERS b/core/java/android/security/OWNERS
index 7120376..3f8d75e 100644
--- a/core/java/android/security/OWNERS
+++ b/core/java/android/security/OWNERS
@@ -1,3 +1,8 @@
+# Bug component: 36824
+
+cbrubaker@google.com
+vishwath@google.com
+
 per-file NetworkSecurityPolicy.java = cbrubaker@google.com
 per-file NetworkSecurityPolicy.java = klyubin@google.com
 per-file FrameworkNetworkSecurityPolicy.java = cbrubaker@google.com
diff --git a/core/java/android/security/keymaster/OWNERS b/core/java/android/security/keymaster/OWNERS
new file mode 100644
index 0000000..65129a4
--- /dev/null
+++ b/core/java/android/security/keymaster/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 189335
+
+swillden@google.com
+jdanis@google.com
+jbires@google.com
diff --git a/core/java/android/security/keystore/OWNERS b/core/java/android/security/keystore/OWNERS
index bb487fb..65129a4 100644
--- a/core/java/android/security/keystore/OWNERS
+++ b/core/java/android/security/keystore/OWNERS
@@ -1,4 +1,5 @@
-aseemk@google.com
-bozhu@google.com
-dementyev@google.com
-robertberry@google.com
+# Bug component: 189335
+
+swillden@google.com
+jdanis@google.com
+jbires@google.com
diff --git a/core/java/android/security/keystore/recovery/OWNERS b/core/java/android/security/keystore/recovery/OWNERS
new file mode 100644
index 0000000..65129a4
--- /dev/null
+++ b/core/java/android/security/keystore/recovery/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 189335
+
+swillden@google.com
+jdanis@google.com
+jbires@google.com
diff --git a/core/java/android/security/net/OWNERS b/core/java/android/security/net/OWNERS
new file mode 100644
index 0000000..d828164
--- /dev/null
+++ b/core/java/android/security/net/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 36824
+
+cbrubaker@google.com
+brambonne@google.com
diff --git a/core/java/android/security/net/config/OWNERS b/core/java/android/security/net/config/OWNERS
index 5350373..85ce3c6 100644
--- a/core/java/android/security/net/config/OWNERS
+++ b/core/java/android/security/net/config/OWNERS
@@ -1,3 +1,5 @@
+# Bug component: 36824
 set noparent
+
 cbrubaker@google.com
-klyubin@google.com
+brambonne@google.com
diff --git a/core/java/android/service/appprediction/OWNERS b/core/java/android/service/appprediction/OWNERS
new file mode 100644
index 0000000..fe012da
--- /dev/null
+++ b/core/java/android/service/appprediction/OWNERS
@@ -0,0 +1,2 @@
+adamcohen@google.com
+sunnygoyal@google.com
diff --git a/core/java/android/service/attention/OWNERS b/core/java/android/service/attention/OWNERS
new file mode 100644
index 0000000..dd579b6
--- /dev/null
+++ b/core/java/android/service/attention/OWNERS
@@ -0,0 +1 @@
+asalo@google.com
diff --git a/core/java/android/service/autofill/OWNERS b/core/java/android/service/autofill/OWNERS
new file mode 100644
index 0000000..a088632
--- /dev/null
+++ b/core/java/android/service/autofill/OWNERS
@@ -0,0 +1,9 @@
+# Bug component: 351486
+
+joannechung@google.com
+adamhe@google.com
+tymtsai@google.com
+lpeter@google.com
+augale@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
diff --git a/core/java/android/service/autofill/augmented/OWNERS b/core/java/android/service/autofill/augmented/OWNERS
new file mode 100644
index 0000000..a088632
--- /dev/null
+++ b/core/java/android/service/autofill/augmented/OWNERS
@@ -0,0 +1,9 @@
+# Bug component: 351486
+
+joannechung@google.com
+adamhe@google.com
+tymtsai@google.com
+lpeter@google.com
+augale@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
diff --git a/core/java/android/service/carrier/CarrierMessagingService.java b/core/java/android/service/carrier/CarrierMessagingService.java
index 88a78c3..61213e6 100644
--- a/core/java/android/service/carrier/CarrierMessagingService.java
+++ b/core/java/android/service/carrier/CarrierMessagingService.java
@@ -16,6 +16,7 @@
 
 package android.service.carrier;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
@@ -25,6 +26,8 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.List;
 
 /**
@@ -74,6 +77,15 @@
      */
     public static final int RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_PROTECTED_STORAGE_UNAVAILABLE = 0x2;
 
+    /** @hide */
+    @IntDef(flag = true, prefix = { "RECEIVE_OPTIONS_" }, value = {
+            RECEIVE_OPTIONS_DEFAULT,
+            RECEIVE_OPTIONS_DROP,
+            RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_PROTECTED_STORAGE_UNAVAILABLE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface FilterCompleteResult{}
+
     /**
      * Indicates that an SMS or MMS message was successfully sent.
      */
@@ -89,6 +101,15 @@
      */
     public static final int SEND_STATUS_ERROR = 2;
 
+    /** @hide */
+    @IntDef(prefix = { "SEND_STATUS_" }, value = {
+            SEND_STATUS_OK,
+            SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
+            SEND_STATUS_ERROR
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SendResult {}
+
     /**
      * Successfully downloaded an MMS message.
      */
@@ -104,10 +125,26 @@
      */
     public static final int DOWNLOAD_STATUS_ERROR = 2;
 
+    /** @hide */
+    @IntDef(prefix = { "DOWNLOAD_STATUS_" }, value = {
+            DOWNLOAD_STATUS_OK,
+            DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK,
+            DOWNLOAD_STATUS_ERROR
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DownloadResult {}
+
     /**
      * Flag to request SMS delivery status report.
      */
-    public static final int SEND_FLAG_REQUEST_DELIVERY_STATUS = 1;
+    public static final int SEND_FLAG_REQUEST_DELIVERY_STATUS = 0x1;
+
+    /** @hide */
+    @IntDef(flag = true, prefix = { "SEND_FLAG_" }, value = {
+            SEND_FLAG_REQUEST_DELIVERY_STATUS
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SendRequest {}
 
     private final ICarrierMessagingWrapper mWrapper = new ICarrierMessagingWrapper();
 
diff --git a/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java b/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java
index 4ffffc6..197c5a6 100644
--- a/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java
+++ b/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java
@@ -16,19 +16,25 @@
 
 package android.service.carrier;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.telephony.SmsMessage;
 
 import com.android.internal.util.Preconditions;
 
 import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
 
 /**
  * Provides basic structure for platform to connect to the carrier messaging service.
@@ -46,6 +52,7 @@
  * CarrierMessagingService.
  * @hide
  */
+@SystemApi
 public final class CarrierMessagingServiceWrapper {
     // Populated by bindToCarrierMessagingService. bindToCarrierMessagingService must complete
     // prior to calling disposeConnection so that mCarrierMessagingServiceConnection is initialized.
@@ -53,6 +60,7 @@
 
     private volatile ICarrierMessagingService mICarrierMessagingService;
     private Runnable mOnServiceReadyCallback;
+    private Executor mServiceReadyCallbackExecutor;
 
     /**
      * Binds to the carrier messaging service under package {@code carrierPackageName}. This method
@@ -60,18 +68,27 @@
      *
      * @param context the context
      * @param carrierPackageName the carrier package name
+     * @param executor the executor to run the callback.
+     * @param onServiceReadyCallback the callback when service becomes ready.
      * @return true upon successfully binding to a carrier messaging service, false otherwise
      * @hide
      */
+    @SystemApi
     public boolean bindToCarrierMessagingService(@NonNull Context context,
             @NonNull String carrierPackageName,
+            @NonNull @CallbackExecutor Executor executor,
             @NonNull Runnable onServiceReadyCallback) {
         Preconditions.checkState(mCarrierMessagingServiceConnection == null);
+        Objects.requireNonNull(context);
+        Objects.requireNonNull(carrierPackageName);
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(onServiceReadyCallback);
 
         Intent intent = new Intent(CarrierMessagingService.SERVICE_INTERFACE);
         intent.setPackage(carrierPackageName);
         mCarrierMessagingServiceConnection = new CarrierMessagingServiceConnection();
         mOnServiceReadyCallback = onServiceReadyCallback;
+        mServiceReadyCallbackExecutor = executor;
         return context.bindService(intent, mCarrierMessagingServiceConnection,
                 Context.BIND_AUTO_CREATE);
     }
@@ -82,11 +99,13 @@
      * @param context the context
      * @hide
      */
+    @SystemApi
     public void disposeConnection(@NonNull Context context) {
         Preconditions.checkNotNull(mCarrierMessagingServiceConnection);
         context.unbindService(mCarrierMessagingServiceConnection);
         mCarrierMessagingServiceConnection = null;
         mOnServiceReadyCallback = null;
+        mServiceReadyCallbackExecutor = null;
     }
 
     /**
@@ -96,26 +115,38 @@
      */
     private void onServiceReady(ICarrierMessagingService carrierMessagingService) {
         mICarrierMessagingService = carrierMessagingService;
-        if (mOnServiceReadyCallback != null) mOnServiceReadyCallback.run();
+        if (mOnServiceReadyCallback != null && mServiceReadyCallbackExecutor != null) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                mServiceReadyCallbackExecutor.execute(mOnServiceReadyCallback);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
     }
 
     /**
-     * Request filtering an incoming SMS message.
+     * Request the CarrierMessagingService to process an incoming SMS text or data message.
      * The service will call callback.onFilterComplete with the filtering result.
      *
      * @param pdu the PDUs of the message
-     * @param format the format of the PDUs, typically "3gpp" or "3gpp2"
+     * @param format the format of the PDUs, typically "3gpp" or "3gpp2".
+     *               See {@link SmsMessage#FORMAT_3GPP} and {@link SmsMessage#FORMAT_3GPP2} for
+     *               more details.
      * @param destPort the destination port of a data SMS. It will be -1 for text SMS
      * @param subId SMS subscription ID of the SIM
+     * @param executor the executor to run the callback.
      * @param callback the callback to notify upon completion
      * @hide
      */
-    public void filterSms(@NonNull MessagePdu pdu, @NonNull String format, int destPort,
-            int subId, @NonNull final CarrierMessagingCallback callback) {
+    @SystemApi
+    public void receiveSms(@NonNull MessagePdu pdu, @NonNull @SmsMessage.Format String format,
+            int destPort, int subId, @NonNull @CallbackExecutor final Executor executor,
+            @NonNull final CarrierMessagingCallback callback) {
         if (mICarrierMessagingService != null) {
             try {
                 mICarrierMessagingService.filterSms(pdu, format, destPort, subId,
-                        new CarrierMessagingCallbackInternal(callback));
+                        new CarrierMessagingCallbackInternal(callback, executor));
             } catch (RemoteException e) {
                 throw new RuntimeException(e);
             }
@@ -130,19 +161,23 @@
      * @param text the text to send
      * @param subId SMS subscription ID of the SIM
      * @param destAddress phone number of the recipient of the message
-     * @param sendSmsFlag flag for sending SMS
+     * @param sendSmsFlag Flag for sending SMS. Acceptable values are 0 and
+     *        {@link CarrierMessagingService#SEND_FLAG_REQUEST_DELIVERY_STATUS}.
+     * @param executor the executor to run the callback.
      * @param callback the callback to notify upon completion
      * @hide
      */
+    @SystemApi
     public void sendTextSms(@NonNull String text, int subId, @NonNull String destAddress,
-            int sendSmsFlag, @NonNull final CarrierMessagingCallback callback) {
-        if (mICarrierMessagingService != null) {
-            try {
-                mICarrierMessagingService.sendTextSms(text, subId, destAddress, sendSmsFlag,
-                        new CarrierMessagingCallbackInternal(callback));
-            } catch (RemoteException e) {
-                throw new RuntimeException(e);
-            }
+            @CarrierMessagingService.SendRequest int sendSmsFlag,
+            @NonNull @CallbackExecutor final Executor executor,
+            @NonNull final CarrierMessagingCallback callback) {
+        Objects.requireNonNull(mICarrierMessagingService);
+        try {
+            mICarrierMessagingService.sendTextSms(text, subId, destAddress, sendSmsFlag,
+                    new CarrierMessagingCallbackInternal(callback, executor));
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
         }
     }
 
@@ -155,20 +190,24 @@
      * @param subId SMS subscription ID of the SIM
      * @param destAddress phone number of the recipient of the message
      * @param destPort port number of the recipient of the message
-     * @param sendSmsFlag flag for sending SMS
+     * @param sendSmsFlag Flag for sending SMS. Acceptable values are 0 and
+     *        {@link CarrierMessagingService#SEND_FLAG_REQUEST_DELIVERY_STATUS}.
+     * @param executor the executor to run the callback.
      * @param callback the callback to notify upon completion
      * @hide
      */
+    @SystemApi
     public void sendDataSms(@NonNull byte[] data, int subId, @NonNull String destAddress,
-            int destPort, int sendSmsFlag,
+            int destPort, @CarrierMessagingService.SendRequest int sendSmsFlag,
+            @NonNull @CallbackExecutor final Executor executor,
             @NonNull final CarrierMessagingCallback callback) {
-        if (mICarrierMessagingService != null) {
-            try {
-                mICarrierMessagingService.sendDataSms(data, subId, destAddress, destPort,
-                        sendSmsFlag, new CarrierMessagingCallbackInternal(callback));
-            } catch (RemoteException e) {
-                throw new RuntimeException(e);
-            }
+        Objects.requireNonNull(mICarrierMessagingService);
+        try {
+            mICarrierMessagingService.sendDataSms(data, subId, destAddress, destPort,
+                    sendSmsFlag, new CarrierMessagingCallbackInternal(
+                            callback, executor));
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
         }
     }
 
@@ -180,20 +219,24 @@
      * @param parts the parts of the multi-part text SMS to send
      * @param subId SMS subscription ID of the SIM
      * @param destAddress phone number of the recipient of the message
-     * @param sendSmsFlag flag for sending SMS
+     * @param sendSmsFlag Flag for sending SMS. Acceptable values are 0 and
+     *        {@link CarrierMessagingService#SEND_FLAG_REQUEST_DELIVERY_STATUS}.
+     * @param executor the executor to run the callback.
      * @param callback the callback to notify upon completion
      * @hide
      */
+    @SystemApi
     public void sendMultipartTextSms(@NonNull List<String> parts, int subId,
-            @NonNull String destAddress, int sendSmsFlag,
+            @NonNull String destAddress,
+            @CarrierMessagingService.SendRequest int sendSmsFlag,
+            @NonNull @CallbackExecutor final Executor executor,
             @NonNull final CarrierMessagingCallback callback) {
-        if (mICarrierMessagingService != null) {
-            try {
-                mICarrierMessagingService.sendMultipartTextSms(parts, subId, destAddress,
-                        sendSmsFlag, new CarrierMessagingCallbackInternal(callback));
-            } catch (RemoteException e) {
-                throw new RuntimeException(e);
-            }
+        Objects.requireNonNull(mICarrierMessagingService);
+        try {
+            mICarrierMessagingService.sendMultipartTextSms(parts, subId, destAddress,
+                    sendSmsFlag, new CarrierMessagingCallbackInternal(callback, executor));
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
         }
     }
 
@@ -206,18 +249,20 @@
      * @param subId SMS subscription ID of the SIM
      * @param location the optional URI to send this MMS PDU. If this is {code null},
      *        the PDU should be sent to the default MMSC URL.
+     * @param executor the executor to run the callback.
      * @param callback the callback to notify upon completion
      * @hide
      */
+    @SystemApi
     public void sendMms(@NonNull Uri pduUri, int subId, @NonNull Uri location,
+            @NonNull @CallbackExecutor final Executor executor,
             @NonNull final CarrierMessagingCallback callback) {
-        if (mICarrierMessagingService != null) {
-            try {
-                mICarrierMessagingService.sendMms(pduUri, subId, location,
-                        new CarrierMessagingCallbackInternal(callback));
-            } catch (RemoteException e) {
-                throw new RuntimeException(e);
-            }
+        Objects.requireNonNull(mICarrierMessagingService);
+        try {
+            mICarrierMessagingService.sendMms(pduUri, subId, location,
+                    new CarrierMessagingCallbackInternal(callback, executor));
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
         }
     }
 
@@ -229,18 +274,20 @@
      * @param pduUri the content provider URI of the PDU to be downloaded.
      * @param subId SMS subscription ID of the SIM
      * @param location the URI of the message to be downloaded.
+     * @param executor the executor to run the callback.
      * @param callback the callback to notify upon completion
      * @hide
      */
+    @SystemApi
     public void downloadMms(@NonNull Uri pduUri, int subId, @NonNull Uri location,
+            @NonNull @CallbackExecutor final Executor executor,
             @NonNull final CarrierMessagingCallback callback) {
-        if (mICarrierMessagingService != null) {
-            try {
-                mICarrierMessagingService.downloadMms(pduUri, subId, location,
-                        new CarrierMessagingCallbackInternal(callback));
-            } catch (RemoteException e) {
-                throw new RuntimeException(e);
-            }
+        Objects.requireNonNull(mICarrierMessagingService);
+        try {
+            mICarrierMessagingService.downloadMms(pduUri, subId, location,
+                    new CarrierMessagingCallbackInternal(callback, executor));
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
         }
     }
 
@@ -263,19 +310,19 @@
      * {@link CarrierMessagingServiceWrapper}.
      * @hide
      */
+    @SystemApi
     public interface CarrierMessagingCallback {
-
         /**
-         * Response callback for {@link CarrierMessagingServiceWrapper#filterSms}.
+         * Response callback for {@link CarrierMessagingServiceWrapper#receiveSms}.
          * @param result a bitmask integer to indicate how the incoming text SMS should be handled
          *               by the platform. Bits set can be
          *               {@link CarrierMessagingService#RECEIVE_OPTIONS_DROP} and
          *               {@link CarrierMessagingService#
          *               RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_PROTECTED_STORAGE_UNAVAILABLE}.
-         *               {@see CarrierMessagingService#onReceiveTextSms}.
-         * @hide
+         *               {@link CarrierMessagingService#onReceiveTextSms}.
          */
-        default void onFilterComplete(int result) {
+        default void onReceiveSmsComplete(
+                @CarrierMessagingService.FilterCompleteResult int result) {
 
         }
 
@@ -287,10 +334,9 @@
          *               and {@link CarrierMessagingService#SEND_STATUS_ERROR}.
          * @param messageRef message reference of the just-sent message. This field is applicable
          *                   only if result is {@link CarrierMessagingService#SEND_STATUS_OK}.
-         * @hide
          */
-        default void onSendSmsComplete(int result, int messageRef) {
-
+        default void onSendSmsComplete(@CarrierMessagingService.SendResult
+                int result, int messageRef) {
         }
 
         /**
@@ -301,9 +347,9 @@
          * @param messageRefs an array of message references, one for each part of the
          *                    multipart SMS. This field is applicable only if result is
          *                    {@link CarrierMessagingService#SEND_STATUS_OK}.
-         * @hide
          */
-        default void onSendMultipartSmsComplete(int result, @Nullable int[] messageRefs) {
+        default void onSendMultipartSmsComplete(@CarrierMessagingService.SendResult
+                int result, @Nullable int[] messageRefs) {
 
         }
 
@@ -315,56 +361,62 @@
          * @param sendConfPdu a possibly {code null} SendConf PDU, which confirms that the message
          *                    was sent. sendConfPdu is ignored if the {@code result} is not
          *                    {@link CarrierMessagingService#SEND_STATUS_OK}.
-         * @hide
          */
-        default void onSendMmsComplete(int result, @Nullable byte[] sendConfPdu) {
+        default void onSendMmsComplete(@CarrierMessagingService.SendResult
+                int result, @Nullable byte[] sendConfPdu) {
 
         }
 
         /**
          * Response callback for {@link CarrierMessagingServiceWrapper#downloadMms}.
-         * @param result download status, one of {@link CarrierMessagingService#SEND_STATUS_OK},
-         *               {@link CarrierMessagingService#SEND_STATUS_RETRY_ON_CARRIER_NETWORK},
-         *               and {@link CarrierMessagingService#SEND_STATUS_ERROR}.
-         * @hide
+         * @param result download status, one of {@link CarrierMessagingService#DOWNLOAD_STATUS_OK},
+         *               {@link CarrierMessagingService#DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK},
+         *               and {@link CarrierMessagingService#DOWNLOAD_STATUS_ERROR}.
          */
-        default void onDownloadMmsComplete(int result) {
+        default void onDownloadMmsComplete(@CarrierMessagingService.DownloadResult
+                int result) {
 
         }
     }
 
     private final class CarrierMessagingCallbackInternal
             extends ICarrierMessagingCallback.Stub {
-        CarrierMessagingCallback mCarrierMessagingCallback;
+        final CarrierMessagingCallback mCarrierMessagingCallback;
+        final Executor mExecutor;
 
-        CarrierMessagingCallbackInternal(CarrierMessagingCallback callback) {
+        CarrierMessagingCallbackInternal(CarrierMessagingCallback callback,
+                final Executor executor) {
             mCarrierMessagingCallback = callback;
+            mExecutor = executor;
         }
 
         @Override
         public void onFilterComplete(int result) throws RemoteException {
-            mCarrierMessagingCallback.onFilterComplete(result);
+            mExecutor.execute(() -> mCarrierMessagingCallback.onReceiveSmsComplete(result));
         }
 
         @Override
         public void onSendSmsComplete(int result, int messageRef) throws RemoteException {
-            mCarrierMessagingCallback.onSendSmsComplete(result, messageRef);
+            mExecutor.execute(() -> mCarrierMessagingCallback.onSendSmsComplete(
+                    result, messageRef));
         }
 
         @Override
         public void onSendMultipartSmsComplete(int result, int[] messageRefs)
                 throws RemoteException {
-            mCarrierMessagingCallback.onSendMultipartSmsComplete(result, messageRefs);
+            mExecutor.execute(() -> mCarrierMessagingCallback.onSendMultipartSmsComplete(
+                    result, messageRefs));
         }
 
         @Override
         public void onSendMmsComplete(int result, byte[] sendConfPdu) throws RemoteException {
-            mCarrierMessagingCallback.onSendMmsComplete(result, sendConfPdu);
+            mExecutor.execute(() -> mCarrierMessagingCallback.onSendMmsComplete(
+                    result, sendConfPdu));
         }
 
         @Override
         public void onDownloadMmsComplete(int result) throws RemoteException {
-            mCarrierMessagingCallback.onDownloadMmsComplete(result);
+            mExecutor.execute(() -> mCarrierMessagingCallback.onDownloadMmsComplete(result));
         }
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/android/service/carrier/OWNERS b/core/java/android/service/carrier/OWNERS
new file mode 100644
index 0000000..d768ef4
--- /dev/null
+++ b/core/java/android/service/carrier/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 20868
+
+rgreenwalt@google.com
+tgunn@google.com
+fionaxu@google.com
diff --git a/core/java/android/service/chooser/OWNERS b/core/java/android/service/chooser/OWNERS
new file mode 100644
index 0000000..a5acba5
--- /dev/null
+++ b/core/java/android/service/chooser/OWNERS
@@ -0,0 +1,4 @@
+asc@google.com
+mpietal@google.com
+dsandler@android.com
+dsandler@google.com
diff --git a/core/java/android/service/contentcapture/OWNERS b/core/java/android/service/contentcapture/OWNERS
new file mode 100644
index 0000000..6337327
--- /dev/null
+++ b/core/java/android/service/contentcapture/OWNERS
@@ -0,0 +1,9 @@
+# Bug component: 544200
+
+joannechung@google.com
+adamhe@google.com
+tymtsai@google.com
+lpeter@google.com
+augale@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
diff --git a/core/java/android/service/contentsuggestions/OWNERS b/core/java/android/service/contentsuggestions/OWNERS
new file mode 100644
index 0000000..46b5ea0
--- /dev/null
+++ b/core/java/android/service/contentsuggestions/OWNERS
@@ -0,0 +1,7 @@
+joannechung@google.com
+adamhe@google.com
+tymtsai@google.com
+lpeter@google.com
+augale@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
diff --git a/core/java/android/service/dreams/OWNERS b/core/java/android/service/dreams/OWNERS
index 708ab4c..f831805 100644
--- a/core/java/android/service/dreams/OWNERS
+++ b/core/java/android/service/dreams/OWNERS
@@ -1,4 +1,3 @@
-dsandler@android.com
-michaelwr@google.com
-roosa@google.com
-galinap@google.com
+# Bug component: 78010
+
+dsandler@google.com
diff --git a/core/java/android/service/gatekeeper/OWNERS b/core/java/android/service/gatekeeper/OWNERS
new file mode 100644
index 0000000..2ca52cd
--- /dev/null
+++ b/core/java/android/service/gatekeeper/OWNERS
@@ -0,0 +1,3 @@
+swillden@google.com
+jdanis@google.com
+jbires@google.com
diff --git a/core/java/android/service/media/OWNERS b/core/java/android/service/media/OWNERS
new file mode 100644
index 0000000..916fc36
--- /dev/null
+++ b/core/java/android/service/media/OWNERS
@@ -0,0 +1,8 @@
+# Bug component: 137631
+
+hdmoon@google.com
+insun@google.com
+jaewan@google.com
+jinpark@google.com
+klhyun@google.com
+gyumin@google.com
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index aa9e289..440eeb1 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1517,8 +1517,10 @@
      */
     public static class Ranking {
 
-        /** Value signifying that the user has not expressed a per-app visibility override value.
-         * @hide */
+        /**
+         * Value signifying that the user and device policy manager have not expressed a lockscreen
+         * visibility override for a notification.
+         */
         public static final int VISIBILITY_NO_OVERRIDE = NotificationManager.VISIBILITY_NO_OVERRIDE;
 
         /**
@@ -1695,14 +1697,13 @@
         }
 
         /**
-         * Returns the user specified visibility for the package that posted
-         * this notification, or
+         * Returns the user or device policy manager specified visibility (see
+         * {@link Notification#VISIBILITY_PRIVATE}, {@link Notification#VISIBILITY_PUBLIC},
+         * {@link Notification#VISIBILITY_SECRET}) for this notification, or
          * {@link NotificationListenerService.Ranking#VISIBILITY_NO_OVERRIDE} if
          * no such preference has been expressed.
-         * @hide
          */
-        @UnsupportedAppUsage
-        public int getVisibilityOverride() {
+        public int getLockscreenVisibilityOverride() {
             return mVisibilityOverride;
         }
 
diff --git a/core/java/android/service/notification/OWNERS b/core/java/android/service/notification/OWNERS
index 2e94be5..debb493 100644
--- a/core/java/android/service/notification/OWNERS
+++ b/core/java/android/service/notification/OWNERS
@@ -1,4 +1,6 @@
+# Bug component: 34005
+
 juliacr@google.com
-beverlyt@google.com
+pixel@google.com
 dsandler@android.com
-pixel@google.com
\ No newline at end of file
+dsandler@google.com
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 787a81b..12d9055 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -45,13 +45,14 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.R;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -515,7 +516,7 @@
         }
     }
 
-    public static ZenModeConfig readXml(XmlPullParser parser)
+    public static ZenModeConfig readXml(TypedXmlPullParser parser)
             throws XmlPullParserException, IOException {
         int type = parser.getEventType();
         if (type != XmlPullParser.START_TAG) return null;
@@ -611,28 +612,28 @@
      * @param version uses XML_VERSION if version is null
      * @throws IOException
      */
-    public void writeXml(XmlSerializer out, Integer version) throws IOException {
+    public void writeXml(TypedXmlSerializer out, Integer version) throws IOException {
         out.startTag(null, ZEN_TAG);
         out.attribute(null, ZEN_ATT_VERSION, version == null
                 ? Integer.toString(XML_VERSION) : Integer.toString(version));
-        out.attribute(null, ZEN_ATT_USER, Integer.toString(user));
+        out.attributeInt(null, ZEN_ATT_USER, user);
         out.startTag(null, ALLOW_TAG);
-        out.attribute(null, ALLOW_ATT_CALLS, Boolean.toString(allowCalls));
-        out.attribute(null, ALLOW_ATT_REPEAT_CALLERS, Boolean.toString(allowRepeatCallers));
-        out.attribute(null, ALLOW_ATT_MESSAGES, Boolean.toString(allowMessages));
-        out.attribute(null, ALLOW_ATT_REMINDERS, Boolean.toString(allowReminders));
-        out.attribute(null, ALLOW_ATT_EVENTS, Boolean.toString(allowEvents));
-        out.attribute(null, ALLOW_ATT_CALLS_FROM, Integer.toString(allowCallsFrom));
-        out.attribute(null, ALLOW_ATT_MESSAGES_FROM, Integer.toString(allowMessagesFrom));
-        out.attribute(null, ALLOW_ATT_ALARMS, Boolean.toString(allowAlarms));
-        out.attribute(null, ALLOW_ATT_MEDIA, Boolean.toString(allowMedia));
-        out.attribute(null, ALLOW_ATT_SYSTEM, Boolean.toString(allowSystem));
-        out.attribute(null, ALLOW_ATT_CONV, Boolean.toString(allowConversations));
-        out.attribute(null, ALLOW_ATT_CONV_FROM, Integer.toString(allowConversationsFrom));
+        out.attributeBoolean(null, ALLOW_ATT_CALLS, allowCalls);
+        out.attributeBoolean(null, ALLOW_ATT_REPEAT_CALLERS, allowRepeatCallers);
+        out.attributeBoolean(null, ALLOW_ATT_MESSAGES, allowMessages);
+        out.attributeBoolean(null, ALLOW_ATT_REMINDERS, allowReminders);
+        out.attributeBoolean(null, ALLOW_ATT_EVENTS, allowEvents);
+        out.attributeInt(null, ALLOW_ATT_CALLS_FROM, allowCallsFrom);
+        out.attributeInt(null, ALLOW_ATT_MESSAGES_FROM, allowMessagesFrom);
+        out.attributeBoolean(null, ALLOW_ATT_ALARMS, allowAlarms);
+        out.attributeBoolean(null, ALLOW_ATT_MEDIA, allowMedia);
+        out.attributeBoolean(null, ALLOW_ATT_SYSTEM, allowSystem);
+        out.attributeBoolean(null, ALLOW_ATT_CONV, allowConversations);
+        out.attributeInt(null, ALLOW_ATT_CONV_FROM, allowConversationsFrom);
         out.endTag(null, ALLOW_TAG);
 
         out.startTag(null, DISALLOW_TAG);
-        out.attribute(null, DISALLOW_ATT_VISUAL_EFFECTS, Integer.toString(suppressedVisualEffects));
+        out.attributeInt(null, DISALLOW_ATT_VISUAL_EFFECTS, suppressedVisualEffects);
         out.endTag(null, DISALLOW_TAG);
 
         if (manualRule != null) {
@@ -651,14 +652,13 @@
         }
 
         out.startTag(null, STATE_TAG);
-        out.attribute(null, STATE_ATT_CHANNELS_BYPASSING_DND,
-                Boolean.toString(areChannelsBypassingDnd));
+        out.attributeBoolean(null, STATE_ATT_CHANNELS_BYPASSING_DND, areChannelsBypassingDnd);
         out.endTag(null, STATE_TAG);
 
         out.endTag(null, ZEN_TAG);
     }
 
-    public static ZenRule readRuleXml(XmlPullParser parser) {
+    public static ZenRule readRuleXml(TypedXmlPullParser parser) {
         final ZenRule rt = new ZenRule();
         rt.enabled = safeBoolean(parser, RULE_ATT_ENABLED, true);
         rt.name = parser.getAttributeValue(null, RULE_ATT_NAME);
@@ -691,12 +691,12 @@
         return rt;
     }
 
-    public static void writeRuleXml(ZenRule rule, XmlSerializer out) throws IOException {
-        out.attribute(null, RULE_ATT_ENABLED, Boolean.toString(rule.enabled));
+    public static void writeRuleXml(ZenRule rule, TypedXmlSerializer out) throws IOException {
+        out.attributeBoolean(null, RULE_ATT_ENABLED, rule.enabled);
         if (rule.name != null) {
             out.attribute(null, RULE_ATT_NAME, rule.name);
         }
-        out.attribute(null, RULE_ATT_ZEN, Integer.toString(rule.zenMode));
+        out.attributeInt(null, RULE_ATT_ZEN, rule.zenMode);
         if (rule.component != null) {
             out.attribute(null, RULE_ATT_COMPONENT, rule.component.flattenToString());
         }
@@ -707,7 +707,7 @@
         if (rule.conditionId != null) {
             out.attribute(null, RULE_ATT_CONDITION_ID, rule.conditionId.toString());
         }
-        out.attribute(null, RULE_ATT_CREATION_TIME, Long.toString(rule.creationTime));
+        out.attributeLong(null, RULE_ATT_CREATION_TIME, rule.creationTime);
         if (rule.enabler != null) {
             out.attribute(null, RULE_ATT_ENABLER, rule.enabler);
         }
@@ -717,10 +717,10 @@
         if (rule.zenPolicy != null) {
             writeZenPolicyXml(rule.zenPolicy, out);
         }
-        out.attribute(null, RULE_ATT_MODIFIED, Boolean.toString(rule.modified));
+        out.attributeBoolean(null, RULE_ATT_MODIFIED, rule.modified);
     }
 
-    public static Condition readConditionXml(XmlPullParser parser) {
+    public static Condition readConditionXml(TypedXmlPullParser parser) {
         final Uri id = safeUri(parser, CONDITION_ATT_ID);
         if (id == null) return null;
         final String summary = parser.getAttributeValue(null, CONDITION_ATT_SUMMARY);
@@ -737,21 +737,21 @@
         }
     }
 
-    public static void writeConditionXml(Condition c, XmlSerializer out) throws IOException {
+    public static void writeConditionXml(Condition c, TypedXmlSerializer out) throws IOException {
         out.attribute(null, CONDITION_ATT_ID, c.id.toString());
         out.attribute(null, CONDITION_ATT_SUMMARY, c.summary);
         out.attribute(null, CONDITION_ATT_LINE1, c.line1);
         out.attribute(null, CONDITION_ATT_LINE2, c.line2);
-        out.attribute(null, CONDITION_ATT_ICON, Integer.toString(c.icon));
-        out.attribute(null, CONDITION_ATT_STATE, Integer.toString(c.state));
-        out.attribute(null, CONDITION_ATT_FLAGS, Integer.toString(c.flags));
+        out.attributeInt(null, CONDITION_ATT_ICON, c.icon);
+        out.attributeInt(null, CONDITION_ATT_STATE, c.state);
+        out.attributeInt(null, CONDITION_ATT_FLAGS, c.flags);
     }
 
     /**
      * Read the zen policy from xml
      * Returns null if no zen policy exists
      */
-    public static ZenPolicy readZenPolicyXml(XmlPullParser parser) {
+    public static ZenPolicy readZenPolicyXml(TypedXmlPullParser parser) {
         boolean policySet = false;
 
         ZenPolicy.Builder builder = new ZenPolicy.Builder();
@@ -845,7 +845,7 @@
     /**
      * Writes zen policy to xml
      */
-    public static void writeZenPolicyXml(ZenPolicy policy, XmlSerializer out)
+    public static void writeZenPolicyXml(ZenPolicy policy, TypedXmlSerializer out)
             throws IOException {
         writeZenPolicyState(ALLOW_ATT_CALLS_FROM, policy.getPriorityCallSenders(), out);
         writeZenPolicyState(ALLOW_ATT_MESSAGES_FROM, policy.getPriorityMessageSenders(), out);
@@ -868,16 +868,16 @@
                 out);
     }
 
-    private static void writeZenPolicyState(String attr, int val, XmlSerializer out)
+    private static void writeZenPolicyState(String attr, int val, TypedXmlSerializer out)
             throws IOException {
         if (Objects.equals(attr, ALLOW_ATT_CALLS_FROM)
                 || Objects.equals(attr, ALLOW_ATT_MESSAGES_FROM)) {
             if (val != ZenPolicy.PEOPLE_TYPE_UNSET) {
-                out.attribute(null, attr, Integer.toString(val));
+                out.attributeInt(null, attr, val);
             }
         } else {
             if (val != ZenPolicy.STATE_UNSET) {
-                out.attribute(null, attr, Integer.toString(val));
+                out.attributeInt(null, attr, val);
             }
         }
     }
@@ -894,15 +894,16 @@
         return source >= SOURCE_ANYONE && source <= MAX_SOURCE;
     }
 
-    private static Boolean unsafeBoolean(XmlPullParser parser, String att) {
-        final String val = parser.getAttributeValue(null, att);
-        if (TextUtils.isEmpty(val)) return null;
-        return Boolean.parseBoolean(val);
+    private static Boolean unsafeBoolean(TypedXmlPullParser parser, String att) {
+        try {
+            return parser.getAttributeBoolean(null, att);
+        } catch (Exception e) {
+            return null;
+        }
     }
 
-    private static boolean safeBoolean(XmlPullParser parser, String att, boolean defValue) {
-        final String val = parser.getAttributeValue(null, att);
-        return safeBoolean(val, defValue);
+    private static boolean safeBoolean(TypedXmlPullParser parser, String att, boolean defValue) {
+        return parser.getAttributeBoolean(null, att, defValue);
     }
 
     private static boolean safeBoolean(String val, boolean defValue) {
@@ -910,24 +911,23 @@
         return Boolean.parseBoolean(val);
     }
 
-    private static int safeInt(XmlPullParser parser, String att, int defValue) {
-        final String val = parser.getAttributeValue(null, att);
-        return tryParseInt(val, defValue);
+    private static int safeInt(TypedXmlPullParser parser, String att, int defValue) {
+        return parser.getAttributeInt(null, att, defValue);
     }
 
-    private static ComponentName safeComponentName(XmlPullParser parser, String att) {
+    private static ComponentName safeComponentName(TypedXmlPullParser parser, String att) {
         final String val = parser.getAttributeValue(null, att);
         if (TextUtils.isEmpty(val)) return null;
         return ComponentName.unflattenFromString(val);
     }
 
-    private static Uri safeUri(XmlPullParser parser, String att) {
+    private static Uri safeUri(TypedXmlPullParser parser, String att) {
         final String val = parser.getAttributeValue(null, att);
         if (TextUtils.isEmpty(val)) return null;
         return Uri.parse(val);
     }
 
-    private static long safeLong(XmlPullParser parser, String att, long defValue) {
+    private static long safeLong(TypedXmlPullParser parser, String att, long defValue) {
         final String val = parser.getAttributeValue(null, att);
         return tryParseLong(val, defValue);
     }
diff --git a/core/java/android/service/quicksettings/OWNERS b/core/java/android/service/quicksettings/OWNERS
new file mode 100644
index 0000000..12eb7c7
--- /dev/null
+++ b/core/java/android/service/quicksettings/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 78010
+
+kozynski@google.com
+pixel@google.com
+dsandler@android.com
+dsandler@google.com
diff --git a/core/java/android/service/resolver/OWNERS b/core/java/android/service/resolver/OWNERS
new file mode 100644
index 0000000..10150c37
--- /dev/null
+++ b/core/java/android/service/resolver/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 78010
+
+asc@google.com
+mpietal@google.com
+dsandler@android.com
+dsandler@google.com
diff --git a/core/java/android/service/restrictions/OWNERS b/core/java/android/service/restrictions/OWNERS
new file mode 100644
index 0000000..eaba2e9
--- /dev/null
+++ b/core/java/android/service/restrictions/OWNERS
@@ -0,0 +1 @@
+yamasani@google.com
diff --git a/core/java/android/service/textclassifier/OWNERS b/core/java/android/service/textclassifier/OWNERS
new file mode 100644
index 0000000..a535f52
--- /dev/null
+++ b/core/java/android/service/textclassifier/OWNERS
@@ -0,0 +1,9 @@
+# Bug component: 709498
+
+joannechung@google.com
+adamhe@google.com
+tymtsai@google.com
+lpeter@google.com
+augale@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
diff --git a/core/java/android/service/textservice/OWNERS b/core/java/android/service/textservice/OWNERS
new file mode 100644
index 0000000..a637754
--- /dev/null
+++ b/core/java/android/service/textservice/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 34867
+
+ogunwale@google.com
+roosa@google.com
+yukawa@google.com
diff --git a/core/java/android/service/trust/OWNERS b/core/java/android/service/trust/OWNERS
new file mode 100644
index 0000000..affe471
--- /dev/null
+++ b/core/java/android/service/trust/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 36824
+
+cbrubaker@google.com
+vishwath@google.com
diff --git a/core/java/android/service/voice/OWNERS b/core/java/android/service/voice/OWNERS
new file mode 100644
index 0000000..46b5ea0
--- /dev/null
+++ b/core/java/android/service/voice/OWNERS
@@ -0,0 +1,7 @@
+joannechung@google.com
+adamhe@google.com
+tymtsai@google.com
+lpeter@google.com
+augale@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
diff --git a/core/java/android/service/wallpaper/OWNERS b/core/java/android/service/wallpaper/OWNERS
new file mode 100644
index 0000000..756eef8
--- /dev/null
+++ b/core/java/android/service/wallpaper/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 78010
+
+dupin@google.com
+dsandler@android.com
+dsandler@google.com
diff --git a/core/java/android/service/watchdog/OWNERS b/core/java/android/service/watchdog/OWNERS
new file mode 100644
index 0000000..1c045e1
--- /dev/null
+++ b/core/java/android/service/watchdog/OWNERS
@@ -0,0 +1,3 @@
+narayan@google.com
+nandana@google.com
+olilan@google.com
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index 479a0c1..ac6208b 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -17,7 +17,10 @@
 package android.telephony;
 
 import android.Manifest;
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.compat.annotation.ChangeId;
@@ -28,17 +31,27 @@
 import android.os.HandlerExecutor;
 import android.os.Looper;
 import android.telephony.Annotation.CallState;
+import android.telephony.Annotation.DataActivityType;
+import android.telephony.Annotation.DisconnectCauses;
+import android.telephony.Annotation.NetworkType;
+import android.telephony.Annotation.PreciseDisconnectCauses;
 import android.telephony.Annotation.RadioPowerState;
 import android.telephony.Annotation.SimActivationState;
 import android.telephony.Annotation.SrvccState;
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.ims.ImsReasonInfo;
+import android.telephony.NetworkRegistrationInfo.Domain;
+import android.telephony.TelephonyManager.DataEnabledReason;
+import android.telephony.TelephonyManager.DataState;
+import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.IPhoneStateListener;
 
 import dalvik.system.VMRuntime;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
 import java.util.List;
 import java.util.Map;
@@ -113,7 +126,9 @@
      *
      *  @see #onServiceStateChanged
      *  @see ServiceState
+     *  @deprecated Use {@link ServiceStateChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_SERVICE_STATE                            = 0x00000001;
 
     /**
@@ -121,8 +136,7 @@
      * {@more}
      *
      * @see #onSignalStrengthChanged
-     *
-     * @deprecated by {@link #LISTEN_SIGNAL_STRENGTHS}
+     * @deprecated Use {@link SignalStrengthsChangedListener} instead.
      */
     @Deprecated
     public static final int LISTEN_SIGNAL_STRENGTH                          = 0x00000002;
@@ -138,7 +152,9 @@
      * voicemail icon.
      *
      * @see #onMessageWaitingIndicatorChanged
+     * @deprecated Use {@link MessageWaitingIndicatorChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_MESSAGE_WAITING_INDICATOR                = 0x00000004;
 
     /**
@@ -149,7 +165,9 @@
      * {@link TelephonyManager#hasCarrierPrivileges}).
      *
      * @see #onCallForwardingIndicatorChanged
+     * @deprecated Use {@link CallForwardingIndicatorChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_CALL_FORWARDING_INDICATOR                = 0x00000008;
 
     /**
@@ -165,7 +183,9 @@
      * instead.
      *
      * @see #onCellLocationChanged
+     * @deprecated Use {@link CellLocationChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_CELL_LOCATION                            = 0x00000010;
 
     /**
@@ -173,14 +193,18 @@
      * {@more}
      *
      * @see #onCallStateChanged
+     * @deprecated Use {@link CallStateChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_CALL_STATE                               = 0x00000020;
 
     /**
      * Listen for changes to the data connection state (cellular).
      *
      * @see #onDataConnectionStateChanged
+     * @deprecated Use {@link DataConnectionStateChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_DATA_CONNECTION_STATE                    = 0x00000040;
 
     /**
@@ -191,7 +215,9 @@
      * data-traffic icon.
      *
      * @see #onDataActivity
+     * @deprecated Use {@link DataActivityListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_DATA_ACTIVITY                            = 0x00000080;
 
     /**
@@ -201,7 +227,9 @@
      * icon.
      *
      * @see #onSignalStrengthsChanged
+     * @deprecated Use {@link SignalStrengthsChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_SIGNAL_STRENGTHS                         = 0x00000100;
 
     /**
@@ -211,7 +239,9 @@
      * @see #onSignalStrengthsChanged
      *
      * @hide
+     * @deprecated Use {@link AlwaysReportedSignalStrengthChangedListener} instead.
      */
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
     public static final int LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH          = 0x00000200;
 
@@ -222,7 +252,9 @@
      * permission.
      *
      * @see #onCellInfoChanged
+     * @deprecated Use {@link CellInfoChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_CELL_INFO = 0x00000400;
 
     /**
@@ -234,8 +266,10 @@
      * (see {@link TelephonyManager#hasCarrierPrivileges}).
      *
      * @hide
+     * @deprecated Use {@link PreciseCallStateChangedListener} instead.
      */
-    @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
+    @Deprecated
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
     @SystemApi
     public static final int LISTEN_PRECISE_CALL_STATE                       = 0x00000800;
 
@@ -247,8 +281,10 @@
      * (see {@link TelephonyManager#hasCarrierPrivileges}).
      *
      * @see #onPreciseDataConnectionStateChanged
+     * @deprecated Use {@link PreciseDataConnectionStateChangedListener} instead.
      */
-    @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
+    @Deprecated
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
     public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE            = 0x00001000;
 
     /**
@@ -258,7 +294,7 @@
      * READ_PRECISE_PHONE_STATE}
      * @see #onDataConnectionRealTimeInfoChanged(DataConnectionRealTimeInfo)
      *
-     * @deprecated Use {@link TelephonyManager#getModemActivityInfo()}
+     * @deprecated Use {@link TelephonyManager#requestModemActivityInfo} instead.
      * @hide
      */
     @Deprecated
@@ -271,7 +307,9 @@
      *
      * @see #onServiceStateChanged(ServiceState)
      * @hide
+     * @deprecated Use {@link SrvccStateChangedListener} instead.
      */
+    @Deprecated
     @SystemApi
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public static final int LISTEN_SRVCC_STATE_CHANGED                     = 0x00004000;
@@ -289,10 +327,11 @@
     /**
      * Listen for carrier network changes indicated by a carrier app.
      *
-     * @see #onCarrierNetworkRequest
-     * @see TelephonyManager#notifyCarrierNetworkChange(boolean)
+     * @see android.service.carrier.CarrierService#notifyCarrierNetworkChange(boolean)
      * @hide
+     * @deprecated Use {@link CarrierNetworkChangeListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_CARRIER_NETWORK_CHANGE                   = 0x00010000;
 
     /**
@@ -311,7 +350,9 @@
      *
      * @see #onVoiceActivationStateChanged
      * @hide
+     * @deprecated Use {@link VoiceActivationStateChangedListener} instead.
      */
+    @Deprecated
     @SystemApi
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public static final int LISTEN_VOICE_ACTIVATION_STATE                   = 0x00020000;
@@ -323,20 +364,24 @@
      * @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED
      * @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED
      * @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN
-     * {@more}
+     *
      * Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates data service has been
      * fully activated
      *
      * @see #onDataActivationStateChanged
      * @hide
+     * @deprecated Use {@link DataActivationStateChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_DATA_ACTIVATION_STATE                   = 0x00040000;
 
     /**
      *  Listen for changes to the user mobile data state
      *
      *  @see #onUserMobileDataStateChanged
+     *  @deprecated Use {@link UserMobileDataStateChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_USER_MOBILE_DATA_STATE                  = 0x00080000;
 
     /**
@@ -347,7 +392,9 @@
      *  {@link TelephonyManager#hasCarrierPrivileges}).
      *
      *  @see #onDisplayInfoChanged
+     * @deprecated Use {@link DisplayInfoChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_DISPLAY_INFO_CHANGED = 0x00100000;
 
     /**
@@ -355,7 +402,9 @@
      *
      *  @see #onPhoneCapabilityChanged
      *  @hide
+     *  @deprecated Use {@link PhoneCapabilityChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_PHONE_CAPABILITY_CHANGE                 = 0x00200000;
 
     /**
@@ -365,17 +414,19 @@
      *  subscription user selected as default data subscription in DSDS mode.
      *
      *  @see #onActiveDataSubscriptionIdChanged
+     *  @deprecated Use {@link ActiveDataSubscriptionIdChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE = 0x00400000;
 
     /**
      *  Listen for changes to the radio power state.
      *
-     * <p>Requires permission {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}
-     *
      *  @see #onRadioPowerStateChanged
      *  @hide
+     *  @deprecated Use {@link RadioPowerStateChangedListener} instead.
      */
+    @Deprecated
     @SystemApi
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public static final int LISTEN_RADIO_POWER_STATE_CHANGED               = 0x00800000;
@@ -385,7 +436,10 @@
      *
      * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
      * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     * @deprecated Use {@link EmergencyNumberListChangedListener} instead.
      */
+    @Deprecated
     public static final int LISTEN_EMERGENCY_NUMBER_LIST                   = 0x01000000;
 
     /**
@@ -396,8 +450,10 @@
      * or the calling app has carrier privileges
      * (see {@link TelephonyManager#hasCarrierPrivileges}).
      *
+     * @deprecated Use {@link CallDisconnectCauseChangedListener} instead.
      */
-    @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
+    @Deprecated
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
     public static final int LISTEN_CALL_DISCONNECT_CAUSES                  = 0x02000000;
 
     /**
@@ -409,9 +465,11 @@
      *
      * @see #onCallAttributesChanged
      * @hide
+     * @deprecated Use {@link CallAttributesChangedListener} instead.
      */
+    @Deprecated
     @SystemApi
-    @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
     public static final int LISTEN_CALL_ATTRIBUTES_CHANGED                 = 0x04000000;
 
     /**
@@ -423,18 +481,20 @@
      * (see {@link TelephonyManager#hasCarrierPrivileges}).
      *
      * @see #onImsCallDisconnectCauseChanged(ImsReasonInfo)
+     * @deprecated Use {@link ImsCallDisconnectCauseChangedListener} instead.
      */
-    @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
+    @Deprecated
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
     public static final int LISTEN_IMS_CALL_DISCONNECT_CAUSES              = 0x08000000;
 
     /**
      * Listen for the emergency number placed from an outgoing call.
      *
-     * <p>Requires permission {@link android.Manifest.permission#READ_ACTIVE_EMERGENCY_SESSION}
-     *
      * @see #onOutgoingEmergencyCall
      * @hide
+     * @deprecated Use {@link OutgoingEmergencyCallListener} instead.
      */
+    @Deprecated
     @SystemApi
     @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
     public static final int LISTEN_OUTGOING_EMERGENCY_CALL                  = 0x10000000;
@@ -442,11 +502,11 @@
     /**
      * Listen for the emergency number placed from an outgoing SMS.
      *
-     * <p>Requires permission {@link android.Manifest.permission#READ_ACTIVE_EMERGENCY_SESSION}
-     *
      * @see #onOutgoingEmergencySms
      * @hide
+     * @deprecated Use {@link OutgoingEmergencySmsListener} instead.
      */
+    @Deprecated
     @SystemApi
     @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
     public static final int LISTEN_OUTGOING_EMERGENCY_SMS                   = 0x20000000;
@@ -465,7 +525,9 @@
      * of whether the calling app has carrier privileges.
      *
      * @see #onRegistrationFailed
+     * @deprecated Use {@link RegistrationFailedListener} instead.
      */
+    @Deprecated
     @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
     public static final int LISTEN_REGISTRATION_FAILURE = 0x40000000;
 
@@ -479,19 +541,525 @@
      * of whether the calling app has carrier privileges.
      *
      * @see #onBarringInfoChanged
+     * @deprecated Use {@link BarringInfoChangedListener} instead.
      */
+    @Deprecated
     @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
     public static final int LISTEN_BARRING_INFO = 0x80000000;
 
     /**
-     *  Listen for changes to the physical channel configuration.
+     *  Event for changes to the network service state (cellular).
      *
-     * @see #onPhysicalChannelConfigurationChanged
+     *  @see ServiceStateChangedListener#onServiceStateChanged
+     *  @see ServiceState
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EVENT_SERVICE_STATE_CHANGED = 1;
+
+    /**
+     * Event for changes to the network signal strength (cellular).
+     *
+     * @see SignalStrengthsChangedListener#onSignalStrengthsChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EVENT_SIGNAL_STRENGTH_CHANGED = 2;
+
+    /**
+     * Event for changes to the message-waiting indicator.
+     *
+     * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE} or that
+     * the calling app has carrier privileges (see
+     * {@link TelephonyManager#hasCarrierPrivileges}).
+     * <p>
+     * Example: The status bar uses this to determine when to display the
+     * voicemail icon.
+     *
+     * @see MessageWaitingIndicatorChangedListener#onMessageWaitingIndicatorChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    public static final int EVENT_MESSAGE_WAITING_INDICATOR_CHANGED = 3;
+
+    /**
+     * Event for changes to the call-forwarding indicator.
+     *
+     * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE} or that
+     * the calling app has carrier privileges (see
+     * {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     * @see CallForwardingIndicatorChangedListener#onCallForwardingIndicatorChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    public static final int EVENT_CALL_FORWARDING_INDICATOR_CHANGED = 4;
+
+    /**
+     * Event for changes to the device's cell location. Note that
+     * this will result in frequent callbacks to the listener.
+     *
+     * If you need regular location updates but want more control over
+     * the update interval or location precision, you can set up a listener
+     * through the {@link android.location.LocationManager location manager}
+     * instead.
+     *
+     * @see CellLocationChangedListener#onCellLocationChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
+    public static final int EVENT_CELL_LOCATION_CHANGED = 5;
+
+    /**
+     * Event for changes to the device call state.
+     *
+     * @see CallStateChangedListener#onCallStateChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_CALL_LOG)
+    public static final int EVENT_CALL_STATE_CHANGED = 6;
+
+    /**
+     * Event for changes to the data connection state (cellular).
+     *
+     * @see DataConnectionStateChangedListener#onDataConnectionStateChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EVENT_DATA_CONNECTION_STATE_CHANGED = 7;
+
+    /**
+     * Event for changes to the direction of data traffic on the data
+     * connection (cellular).
+     *
+     * Example: The status bar uses this to display the appropriate
+     * data-traffic icon.
+     *
+     * @see DataActivityListener#onDataActivity
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EVENT_DATA_ACTIVITY_CHANGED = 8;
+
+    /**
+     * Event for changes to the network signal strengths (cellular).
+     * <p>
+     * Example: The status bar uses this to control the signal-strength
+     * icon.
+     *
+     * @see SignalStrengthsChangedListener#onSignalStrengthsChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EVENT_SIGNAL_STRENGTHS_CHANGED = 9;
+
+    /**
+     * Event for changes of the network signal strengths (cellular) always reported from modem,
+     * even in some situations such as the screen of the device is off.
+     *
+     * @see AlwaysReportedSignalStrengthChangedListener#onSignalStrengthsChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
+    public static final int EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED = 10;
+
+    /**
+     * Event for changes to observed cell info.
+     *
+     * @see CellInfoChangedListener#onCellInfoChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
+    public static final int EVENT_CELL_INFO_CHANGED = 11;
+
+    /**
+     * Event for {@link android.telephony.Annotation.PreciseCallStates} of ringing,
+     * background and foreground calls.
+     *
+     * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+     * or the calling app has carrier privileges
+     * (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     * @see PreciseCallStateChangedListener#onPreciseCallStateChanged
+     *
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
-    public static final long LISTEN_PHYSICAL_CHANNEL_CONFIGURATION = 0x100000000L;
+    public static final int EVENT_PRECISE_CALL_STATE_CHANGED = 12;
+
+    /**
+     * Event for {@link PreciseDataConnectionState} on the data connection (cellular).
+     *
+     * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+     * or the calling app has carrier privileges
+     * (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     * @see PreciseDataConnectionStateChangedListener#onPreciseDataConnectionStateChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+    public static final int EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED = 13;
+
+    /**
+     * Event for real time info for all data connections (cellular)).
+     *
+     * @see #onDataConnectionRealTimeInfoChanged(DataConnectionRealTimeInfo)
+     *
+     * @deprecated Use {@link TelephonyManager#requestModemActivityInfo}
+     * @hide
+     */
+    @Deprecated
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+    public static final int EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED = 14;
+
+    /**
+     * Event for OEM hook raw event
+     *
+     * @see #onOemHookRawEvent
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public static final int EVENT_OEM_HOOK_RAW = 15;
+
+    /**
+     * Event for changes to the SRVCC state of the active call.
+     *
+     * @see SrvccStateChangedListener#onSrvccStateChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public static final int EVENT_SRVCC_STATE_CHANGED = 16;
+
+    /**
+     * Event for carrier network changes indicated by a carrier app.
+     *
+     * @see android.service.carrier.CarrierService#notifyCarrierNetworkChange(boolean)
+     * @see CarrierNetworkChangeListener#onCarrierNetworkChange
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int EVENT_CARRIER_NETWORK_CHANGED = 17;
+
+    /**
+     * Event for changes to the sim voice activation state
+     *
+     * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING
+     * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED
+     * @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED
+     * @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED
+     * @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN
+     *
+     * Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates voice service has been
+     * fully activated
+     *
+     * @see VoiceActivationStateChangedListener#onVoiceActivationStateChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public static final int EVENT_VOICE_ACTIVATION_STATE_CHANGED = 18;
+
+    /**
+     * Event for changes to the sim data activation state
+     * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING
+     * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED
+     * @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED
+     * @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED
+     * @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN
+     *
+     * Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates data service has been
+     * fully activated
+     *
+     * @see DataActivationStateChangedListener#onDataActivationStateChanged
+     * @hide
+     */
+    @SystemApi
+    public static final int EVENT_DATA_ACTIVATION_STATE_CHANGED = 19;
+
+    /**
+     *  Event for changes to the user mobile data state
+     *
+     *  @see UserMobileDataStateChangedListener#onUserMobileDataStateChanged
+     *
+     *  @hide
+     */
+    @SystemApi
+    public static final int EVENT_USER_MOBILE_DATA_STATE_CHANGED = 20;
+
+    /**
+     *  Event for display info changed event.
+     *
+     *  @see DisplayInfoChangedListener#onDisplayInfoChanged
+     *
+     *  @hide
+     */
+    @SystemApi
+    public static final int EVENT_DISPLAY_INFO_CHANGED = 21;
+
+    /**
+     *  Event for changes to the phone capability.
+     *
+     *  @see PhoneCapabilityChangedListener#onPhoneCapabilityChanged
+     *
+     *  @hide
+     */
+    @SystemApi
+    public static final int EVENT_PHONE_CAPABILITY_CHANGED = 22;
+
+    /**
+     *  Event for changes to active data subscription ID. Active data subscription is
+     *  the current subscription used to setup Cellular Internet data. For example,
+     *  it could be the current active opportunistic subscription in use, or the
+     *  subscription user selected as default data subscription in DSDS mode.
+     *
+     *  <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
+     *  app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     *  @see ActiveDataSubscriptionIdChangedListener#onActiveDataSubscriptionIdChanged
+     *
+     *  @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    public static final int EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED = 23;
+
+    /**
+     *  Event for changes to the radio power state.
+     *
+     *  @see RadioPowerStateChangedListener#onRadioPowerStateChanged
+     *
+     *  @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public static final int EVENT_RADIO_POWER_STATE_CHANGED = 24;
+
+    /**
+     * Event for changes to emergency number list based on all active subscriptions.
+     *
+     * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
+     * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     *  @see EmergencyNumberListChangedListener#onEmergencyNumberListChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    public static final int EVENT_EMERGENCY_NUMBER_LIST_CHANGED = 25;
+
+    /**
+     * Event for call disconnect causes which contains {@link DisconnectCause} and
+     * {@link PreciseDisconnectCause}.
+     *
+     * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+     * or the calling app has carrier privileges
+     * (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     *  @see CallDisconnectCauseChangedListener#onCallDisconnectCauseChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+    public static final int EVENT_CALL_DISCONNECT_CAUSE_CHANGED = 26;
+
+    /**
+     * Event for changes to the call attributes of a currently active call.
+     *
+     * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+     * or the calling app has carrier privileges
+     * (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     * @see CallAttributesChangedListener#onCallAttributesChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+    public static final int EVENT_CALL_ATTRIBUTES_CHANGED = 27;
+
+    /**
+     * Event for IMS call disconnect causes which contains
+     * {@link android.telephony.ims.ImsReasonInfo}
+     *
+     * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+     * or the calling app has carrier privileges
+     * (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     * @see ImsCallDisconnectCauseChangedListener#onImsCallDisconnectCauseChanged(ImsReasonInfo)
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+    public static final int EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED = 28;
+
+    /**
+     * Event for the emergency number placed from an outgoing call.
+     *
+     * @see OutgoingEmergencyCallListener#onOutgoingEmergencyCall
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
+    public static final int EVENT_OUTGOING_EMERGENCY_CALL = 29;
+
+    /**
+     * Event for the emergency number placed from an outgoing SMS.
+     *
+     * @see OutgoingEmergencySmsListener#onOutgoingEmergencySms
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
+    public static final int EVENT_OUTGOING_EMERGENCY_SMS = 30;
+
+    /**
+     * Event for registration failures.
+     *
+     * Event for indications that a registration procedure has failed in either the CS or PS
+     * domain. This indication does not necessarily indicate a change of service state, which should
+     * be tracked via {@link #EVENT_SERVICE_STATE_CHANGED}.
+     *
+     * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} or
+     * the calling app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     * <p>Also requires the {@link Manifest.permission#ACCESS_FINE_LOCATION} permission, regardless
+     * of whether the calling app has carrier privileges.
+     *
+     * @see RegistrationFailedListener#onRegistrationFailed
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(allOf = {
+            Manifest.permission.READ_PRECISE_PHONE_STATE,
+            Manifest.permission.ACCESS_FINE_LOCATION
+    })
+    public static final int EVENT_REGISTRATION_FAILURE = 31;
+
+    /**
+     * Event for Barring Information for the current registered / camped cell.
+     *
+     * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} or
+     * the calling app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     * <p>Also requires the {@link Manifest.permission#ACCESS_FINE_LOCATION} permission, regardless
+     * of whether the calling app has carrier privileges.
+     *
+     * @see BarringInfoChangedListener#onBarringInfoChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(allOf = {
+            Manifest.permission.READ_PRECISE_PHONE_STATE,
+            Manifest.permission.ACCESS_FINE_LOCATION
+    })
+    public static final int EVENT_BARRING_INFO_CHANGED = 32;
+
+    /**
+     * Event for changes to the physical channel configuration.
+     *
+     * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+     * or the calling app has carrier privileges
+     * (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     * @see PhysicalChannelConfigChangedListener#onPhysicalChannelConfigChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+    public static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 33;
+
+
+    /**
+     * Event for changes to the data enabled.
+     *
+     * Event for indications that the enabled status of current data has changed.
+     *
+     * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+     * or the calling app has carrier privileges
+     * (see {@link TelephonyManager#hasCarrierPrivileges}).
+     *
+     * @see DataEnabledChangedListener#onDataEnabledChanged
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+    public static final int EVENT_DATA_ENABLED_CHANGED = 34;
+
+    /** @hide */
+    @IntDef(prefix = { "EVENT_" }, value = {
+            EVENT_SERVICE_STATE_CHANGED,
+            EVENT_SIGNAL_STRENGTH_CHANGED,
+            EVENT_MESSAGE_WAITING_INDICATOR_CHANGED,
+            EVENT_CALL_FORWARDING_INDICATOR_CHANGED,
+            EVENT_CELL_LOCATION_CHANGED,
+            EVENT_CALL_STATE_CHANGED,
+            EVENT_DATA_CONNECTION_STATE_CHANGED,
+            EVENT_DATA_ACTIVITY_CHANGED,
+            EVENT_SIGNAL_STRENGTHS_CHANGED,
+            EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED,
+            EVENT_CELL_INFO_CHANGED,
+            EVENT_PRECISE_CALL_STATE_CHANGED,
+            EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED,
+            EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED,
+            EVENT_OEM_HOOK_RAW,
+            EVENT_SRVCC_STATE_CHANGED,
+            EVENT_CARRIER_NETWORK_CHANGED,
+            EVENT_VOICE_ACTIVATION_STATE_CHANGED,
+            EVENT_DATA_ACTIVATION_STATE_CHANGED,
+            EVENT_USER_MOBILE_DATA_STATE_CHANGED,
+            EVENT_DISPLAY_INFO_CHANGED,
+            EVENT_PHONE_CAPABILITY_CHANGED,
+            EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED,
+            EVENT_RADIO_POWER_STATE_CHANGED,
+            EVENT_EMERGENCY_NUMBER_LIST_CHANGED,
+            EVENT_CALL_DISCONNECT_CAUSE_CHANGED,
+            EVENT_CALL_ATTRIBUTES_CHANGED,
+            EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED,
+            EVENT_OUTGOING_EMERGENCY_CALL,
+            EVENT_OUTGOING_EMERGENCY_SMS,
+            EVENT_REGISTRATION_FAILURE,
+            EVENT_BARRING_INFO_CHANGED,
+            EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED,
+            EVENT_DATA_ENABLED_CHANGED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface TelephonyEvent {}
 
     /*
      * Subscription used to listen to the phone state changes
@@ -504,9 +1072,13 @@
     /**
      * @hide
      */
+    //TODO: The maxTargetSdk should be S if the build time tool updates it.
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-    @UnsupportedAppUsage
-    public final IPhoneStateListener callback;
+    @UnsupportedAppUsage(
+            maxTargetSdk = Build.VERSION_CODES.R,
+            publicAlternatives = "Use {@code TelephonyManager#registerPhoneStateListener(" +
+                    "Executor, PhoneStateListener)} instead")
+    public IPhoneStateListener callback;
 
     /**
      * Create a PhoneStateListener for the Phone with the default subscription.
@@ -563,17 +1135,742 @@
      * The Executor must not be null.
      *
      * @param executor a non-null Executor that will execute callbacks for the PhoneStateListener.
+     * @deprecated Use
+     * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)} instead.
      */
+    @Deprecated
     public PhoneStateListener(@NonNull Executor executor) {
         this(null, executor);
     }
 
-    private PhoneStateListener(Integer subId, Executor e) {
-        if (e == null) {
+    private @NonNull Executor mExecutor;
+
+    /**
+     * @hide
+     */
+    public void setExecutor(@NonNull @CallbackExecutor Executor executor) {
+        if (executor == null) {
             throw new IllegalArgumentException("PhoneStateListener Executor must be non-null");
         }
+        mExecutor = executor;
+    }
+
+    private PhoneStateListener(Integer subId, Executor executor) {
+        setExecutor(executor);
         mSubId = subId;
-        callback = new IPhoneStateListenerStub(this, e);
+        callback = new IPhoneStateListenerStub(this, mExecutor);
+    }
+
+    /**
+     * Interface for service state listener.
+     */
+    public interface ServiceStateChangedListener {
+        /**
+         * Callback invoked when device service state changes on the registered subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * The instance of {@link ServiceState} passed as an argument here will have various
+         * levels of location information stripped from it depending on the location permissions
+         * that your app holds.
+         * Only apps holding the {@link Manifest.permission#ACCESS_FINE_LOCATION} permission will
+         * receive all the information in {@link ServiceState}.
+         *
+         * @see ServiceState#STATE_EMERGENCY_ONLY
+         * @see ServiceState#STATE_IN_SERVICE
+         * @see ServiceState#STATE_OUT_OF_SERVICE
+         * @see ServiceState#STATE_POWER_OFF
+         */
+        @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+        public void onServiceStateChanged(@NonNull ServiceState serviceState);
+    }
+
+    /**
+     * Interface for message waiting indicator listener.
+     */
+    public interface MessageWaitingIndicatorChangedListener {
+        /**
+         * Callback invoked when the message-waiting indicator changes on the registered
+         * subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         */
+        @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+        public void onMessageWaitingIndicatorChanged(boolean mwi);
+    }
+
+    /**
+     * Interface for call-forwarding indicator listener.
+     */
+    public interface CallForwardingIndicatorChangedListener {
+        /**
+         * Callback invoked when the call-forwarding indicator changes on the registered
+         * subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         */
+        @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+        public void onCallForwardingIndicatorChanged(boolean cfi);
+    }
+
+    /**
+     * Interface for device cell location listener.
+     */
+    public interface CellLocationChangedListener {
+        /**
+         * Callback invoked when device cell location changes on the registered subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         */
+        @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
+        public void onCellLocationChanged(@NonNull CellLocation location);
+    }
+
+    /**
+     * Interface for call state listener.
+     */
+    public interface CallStateChangedListener {
+        /**
+         * Callback invoked when device call state changes.
+         * <p>
+         * Reports the state of Telephony (mobile) calls on the device for the registered s
+         * ubscription.
+         * <p>
+         * Note: the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         * <p>
+         * Note: The state returned here may differ from that returned by
+         * {@link TelephonyManager#getCallState()}. Receivers of this callback should be aware that
+         * calling {@link TelephonyManager#getCallState()} from within this callback may return a
+         * different state than the callback reports.
+         *
+         * @param state call state
+         * @param phoneNumber call phone number. If application does not have
+         * {@link android.Manifest.permission#READ_CALL_LOG} permission or carrier
+         * privileges (see {@link TelephonyManager#hasCarrierPrivileges}), an empty string will be
+         * passed as an argument.
+         */
+        @RequiresPermission(android.Manifest.permission.READ_CALL_LOG)
+        public void onCallStateChanged(@CallState int state, @Nullable String phoneNumber);
+    }
+
+    /**
+     * Interface for data connection state listener.
+     */
+    public interface DataConnectionStateChangedListener {
+        /**
+         * Callback invoked when connection state changes on the registered subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * @see TelephonyManager#DATA_DISCONNECTED
+         * @see TelephonyManager#DATA_CONNECTING
+         * @see TelephonyManager#DATA_CONNECTED
+         * @see TelephonyManager#DATA_SUSPENDED
+         *
+         * @param state is the current state of data connection.
+         * @param networkType is the current network type of data connection.
+         */
+        @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+        public void onDataConnectionStateChanged(@DataState int state,
+                                                 @NetworkType int networkType);
+    }
+
+    /**
+     * Interface for data activity state listener.
+     */
+    public interface DataActivityListener {
+        /**
+         * Callback invoked when data activity state changes on the registered subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * @see TelephonyManager#DATA_ACTIVITY_NONE
+         * @see TelephonyManager#DATA_ACTIVITY_IN
+         * @see TelephonyManager#DATA_ACTIVITY_OUT
+         * @see TelephonyManager#DATA_ACTIVITY_INOUT
+         * @see TelephonyManager#DATA_ACTIVITY_DORMANT
+         */
+        @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+        public void onDataActivity(@DataActivityType int direction);
+    }
+
+    /**
+     * Interface for network signal strengths listener.
+     */
+    public interface SignalStrengthsChangedListener {
+        /**
+         * Callback invoked when network signal strengths changes on the registered subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         */
+        @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+        public void onSignalStrengthsChanged(@NonNull SignalStrength signalStrength);
+    }
+
+    /**
+     * Interface for network signal strengths listener which always reported from modem.
+     */
+    public interface AlwaysReportedSignalStrengthChangedListener {
+        /**
+         * Callback always invoked from modem when network signal strengths changes on the
+         * registered subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         */
+        @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
+        public void onSignalStrengthsChanged(@NonNull SignalStrength signalStrength);
+    }
+
+    /**
+     * Interface for cell info listener.
+     */
+    public interface CellInfoChangedListener {
+        /**
+         * Callback invoked when a observed cell info has changed or new cells have been added
+         * or removed on the registered subscription.
+         * Note, the registration subscription ID s from {@link TelephonyManager} object
+         * which registersPhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * @param cellInfo is the list of currently visible cells.
+         */
+        @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
+        public void onCellInfoChanged(@NonNull List<CellInfo> cellInfo);
+    }
+
+    /**
+     * Interface for precise device call state listener.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface PreciseCallStateChangedListener {
+        /**
+         * Callback invoked when precise device call state changes on the registered subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * @param callState {@link PreciseCallState}
+         */
+        @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+        public void onPreciseCallStateChanged(@NonNull PreciseCallState callState);
+    }
+
+    /**
+     * Interface for call disconnect cause listener.
+     */
+    public interface CallDisconnectCauseChangedListener {
+        /**
+         * Callback invoked when call disconnect cause changes on the registered subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * @param disconnectCause {@link DisconnectCause}.
+         * @param preciseDisconnectCause {@link PreciseDisconnectCause}.
+         */
+        @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+        public void onCallDisconnectCauseChanged(@DisconnectCauses int disconnectCause,
+                @PreciseDisconnectCauses int preciseDisconnectCause);
+    }
+
+    /**
+     * Interface for IMS call disconnect cause listener.
+     */
+    public interface ImsCallDisconnectCauseChangedListener {
+        /**
+         * Callback invoked when IMS call disconnect cause changes on the registered subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * @param imsReasonInfo {@link ImsReasonInfo} contains details on why IMS call failed.
+         *
+         */
+        @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+        public void onImsCallDisconnectCauseChanged(@NonNull ImsReasonInfo imsReasonInfo);
+    }
+
+    /**
+     * Interface for precise data connection state listener.
+     */
+    public interface PreciseDataConnectionStateChangedListener {
+        /**
+         * Callback providing update about the default/internet data connection on the registered
+         * subscription.
+         *
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+         * or the calling app has carrier privileges
+         * (see {@link TelephonyManager#hasCarrierPrivileges}).
+         *
+         * @param dataConnectionState {@link PreciseDataConnectionState}
+         */
+        @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+        public void onPreciseDataConnectionStateChanged(
+                @NonNull PreciseDataConnectionState dataConnectionState);
+    }
+
+    /**
+     * Interface for Single Radio Voice Call Continuity listener.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface SrvccStateChangedListener {
+        /**
+         * Callback invoked when there has been a change in the Single Radio Voice Call Continuity
+         * (SRVCC) state for the currently active call on the registered subscription.
+         *
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         */
+        @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+        public void onSrvccStateChanged(@SrvccState int srvccState);
+    }
+
+    /**
+     * Interface for SIM voice activation state listener.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface VoiceActivationStateChangedListener {
+        /**
+         * Callback invoked when the SIM voice activation state has changed on the registered
+         * subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * @param state is the current SIM voice activation state
+         */
+        @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+        public void onVoiceActivationStateChanged(@SimActivationState int state);
+
+    }
+
+    /**
+     * Interface for SIM data activation state listener.
+     */
+    public interface DataActivationStateChangedListener {
+        /**
+         * Callback invoked when the SIM data activation state has changed on the registered
+         * subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * @param state is the current SIM data activation state
+         */
+        @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+        public void onDataActivationStateChanged(@SimActivationState int state);
+    }
+
+    /**
+     * Interface for user mobile data state listener.
+     */
+    public interface UserMobileDataStateChangedListener {
+        /**
+         * Callback invoked when the user mobile data state has changed on the registered
+         * subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * @param enabled indicates whether the current user mobile data state is enabled or
+         *                disabled.
+         */
+        @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+        public void onUserMobileDataStateChanged(boolean enabled);
+    }
+
+    /**
+     * Interface for display info listener.
+     */
+    public interface DisplayInfoChangedListener {
+        /**
+         * Callback invoked when the display info has changed on the registered subscription.
+         * <p> The {@link TelephonyDisplayInfo} contains status information shown to the user
+         * based on carrier policy.
+         *
+         * @param telephonyDisplayInfo The display information.
+         */
+        @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+        public void onDisplayInfoChanged(@NonNull TelephonyDisplayInfo telephonyDisplayInfo);
+    }
+
+    /**
+     * Interface for the current emergency number list listener.
+     */
+    public interface EmergencyNumberListChangedListener {
+        /**
+         * Callback invoked when the current emergency number list has changed on the registered
+         * subscription.
+         *
+         * Note, the registered subscription is associated with {@link TelephonyManager} object
+         * on which
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}
+         * was called.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * given subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * @param emergencyNumberList Map associating all active subscriptions on the device with
+         *                            the list of emergency numbers originating from that
+         *                            subscription.
+         *                            If there are no active subscriptions, the map will contain a
+         *                            single entry with
+         *                            {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} as
+         *                            the key and a list of emergency numbers as the value. If no
+         *                            emergency number information is available, the value will be
+         *                            empty.
+         */
+        @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+        public void onEmergencyNumberListChanged(
+                @NonNull Map<Integer, List<EmergencyNumber>> emergencyNumberList);
+    }
+
+    /**
+     * Interface for outgoing emergency call listener.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface OutgoingEmergencyCallListener {
+        /**
+         * Callback invoked when an outgoing call is placed to an emergency number.
+         *
+         * This method will be called when an emergency call is placed on any subscription
+         * (including the no-SIM case), regardless of which subscription this listener was
+         * registered on.
+         *
+         * The default implementation of this method calls
+         * {@link #onOutgoingEmergencyCall(EmergencyNumber)} for backwards compatibility purposes.
+         * Do not call {@code super(...)} from within your implementation unless you want
+         * {@link #onOutgoingEmergencyCall(EmergencyNumber)} to be called as well.
+         *
+         * @param placedEmergencyNumber The {@link EmergencyNumber} the emergency call was
+         *                              placed to.
+         * @param subscriptionId The subscription ID used to place the emergency call. If the
+         *                       emergency call was placed without a valid subscription
+         *                       (e.g. when there are no SIM cards in the device), this will be
+         *                       equal to {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
+         */
+        @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
+        public void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber,
+                                     int subscriptionId);
+    }
+
+    /**
+     * Interface for outgoing emergency sms listener.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface OutgoingEmergencySmsListener {
+        /**
+         * Smsback invoked when an outgoing sms is sent to an emergency number.
+         *
+         * This method will be called when an emergency sms is sent on any subscription,
+         * regardless of which subscription this listener was registered on.
+         *
+         * The default implementation of this method calls
+         * {@link #onOutgoingEmergencySms(EmergencyNumber)} for backwards compatibility purposes. Do
+         * not call {@code super(...)} from within your implementation unless you want
+         * {@link #onOutgoingEmergencySms(EmergencyNumber)} to be called as well.
+         *
+         * @param sentEmergencyNumber The {@link EmergencyNumber} the emergency sms was sent to.
+         * @param subscriptionId The subscription ID used to send the emergency sms.
+         */
+        @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
+        public void onOutgoingEmergencySms(@NonNull EmergencyNumber sentEmergencyNumber,
+                                    int subscriptionId);
+    }
+
+    /**
+     * Interface for phone capability listener.
+     *
+     */
+    public interface PhoneCapabilityChangedListener {
+        /**
+         * Callback invoked when phone capability changes.
+         * Note, this callback triggers regardless of registered subscription.
+         *
+         * @param capability the new phone capability
+         */
+        @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+        public void onPhoneCapabilityChanged(@NonNull PhoneCapability capability);
+    }
+
+    /**
+     * Interface for active data subscription ID listener.
+     */
+    public interface ActiveDataSubscriptionIdChangedListener {
+        /**
+         * Callback invoked when active data subscription ID changes.
+         * Note, this callback triggers regardless of registered subscription.
+         *
+         * @param subId current subscription used to setup Cellular Internet data.
+         *              For example, it could be the current active opportunistic subscription
+         *              in use, or the subscription user selected as default data subscription in
+         *              DSDS mode.
+         */
+        @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+        public void onActiveDataSubscriptionIdChanged(int subId);
+    }
+
+    /**
+     * Interface for modem radio power state listener.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface RadioPowerStateChangedListener {
+        /**
+         * Callback invoked when modem radio power state changes on the registered subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * @param state the modem radio power state
+         */
+        @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+        public void onRadioPowerStateChanged(@RadioPowerState int state);
+    }
+
+    /**
+     * Interface for carrier network listener.
+     */
+    public interface CarrierNetworkChangeListener {
+        /**
+         * Callback invoked when telephony has received notice from a carrier
+         * app that a network action that could result in connectivity loss
+         * has been requested by an app using
+         * {@link android.service.carrier.CarrierService#notifyCarrierNetworkChange(boolean)}
+         *
+         * This is optional and is only used to allow the system to provide alternative UI while
+         * telephony is performing an action that may result in intentional, temporary network
+         * lack of connectivity.
+         *
+         * Note, this callback is pinned to the registered subscription and will be invoked when
+         * the notifying carrier app has carrier privilege rule on the registered
+         * subscription. {@link android.telephony.TelephonyManager#hasCarrierPrivileges}
+         *
+         * @param active If the carrier network change is or shortly will be active,
+         *               {@code true} indicate that showing alternative UI, {@code false} otherwise.
+         */
+        public void onCarrierNetworkChange(boolean active);
+    }
+
+    /**
+     * Interface for registration failures listener.
+     */
+    public interface RegistrationFailedListener {
+        /**
+         * Report that Registration or a Location/Routing/Tracking Area update has failed.
+         *
+         * <p>Indicate whenever a registration procedure, including a location, routing, or tracking
+         * area update fails. This includes procedures that do not necessarily result in a change of
+         * the modem's registration status. If the modem's registration status changes, that is
+         * reflected in the onNetworkStateChanged() and subsequent
+         * get{Voice/Data}RegistrationState().
+         *
+         * <p>Because registration failures are ephemeral, this callback is not sticky.
+         * Registrants will not receive the most recent past value when registering.
+         *
+         * @param cellIdentity the CellIdentity, which must include the globally unique identifier
+         *        for the cell (for example, all components of the CGI or ECGI).
+         * @param chosenPlmn a 5 or 6 digit alphanumeric PLMN (MCC|MNC) among those broadcast by the
+         *         cell that was chosen for the failed registration attempt.
+         * @param domain DOMAIN_CS, DOMAIN_PS or both in case of a combined procedure.
+         * @param causeCode the primary failure cause code of the procedure.
+         *        For GSM/UMTS (MM), values are in TS 24.008 Sec 10.5.95
+         *        For GSM/UMTS (GMM), values are in TS 24.008 Sec 10.5.147
+         *        For LTE (EMM), cause codes are TS 24.301 Sec 9.9.3.9
+         *        For NR (5GMM), cause codes are TS 24.501 Sec 9.11.3.2
+         *        Integer.MAX_VALUE if this value is unused.
+         * @param additionalCauseCode the cause code of any secondary/combined procedure
+         *                            if appropriate. For UMTS, if a combined attach succeeds for
+         *                            PS only, then the GMM cause code shall be included as an
+         *                            additionalCauseCode. For LTE (ESM), cause codes are in
+         *                            TS 24.301 9.9.4.4. Integer.MAX_VALUE if this value is unused.
+         */
+        @RequiresPermission(allOf = {
+                Manifest.permission.READ_PRECISE_PHONE_STATE,
+                Manifest.permission.ACCESS_FINE_LOCATION
+        })
+        public void onRegistrationFailed(@NonNull CellIdentity cellIdentity,
+                                         @NonNull String chosenPlmn, @Domain int domain,
+                                         int causeCode, int additionalCauseCode);
+    }
+
+    /**
+     * Interface for call attributes listener.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface CallAttributesChangedListener {
+        /**
+         * Callback invoked when the call attributes changes on the registered subscription.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers PhoneStateListener by
+         * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         *
+         * @param callAttributes the call attributes
+         */
+        @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+        void onCallAttributesChanged(@NonNull CallAttributes callAttributes);
+    }
+
+    /**
+     * Interface for barring information listener.
+     */
+    public interface BarringInfoChangedListener {
+        /**
+         * Report updated barring information for the current camped/registered cell.
+         *
+         * <p>Barring info is provided for all services applicable to the current camped/registered
+         * cell, for the registered PLMN and current access class/access category.
+         *
+         * @param barringInfo for all services on the current cell.
+         * @see android.telephony.BarringInfo
+         */
+        @RequiresPermission(allOf = {
+                Manifest.permission.READ_PRECISE_PHONE_STATE,
+                Manifest.permission.ACCESS_FINE_LOCATION
+        })
+        public void onBarringInfoChanged(@NonNull BarringInfo barringInfo);
+    }
+
+    /**
+     * Interface for current physical channel configuration listener.
+     * @hide
+     */
+    @SystemApi
+    public interface PhysicalChannelConfigChangedListener {
+        /**
+         * Callback invoked when the current physical channel configuration has changed
+         *
+         * @param configs List of the current {@link PhysicalChannelConfig}s
+         */
+        @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+        public void onPhysicalChannelConfigChanged(@NonNull List<PhysicalChannelConfig> configs);
+    }
+
+    /**
+     * Interface for data enabled listener.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface DataEnabledChangedListener {
+        /**
+         * Callback invoked when the data enabled changes.
+         *
+         * @param enabled {@code true} if data is enabled, otherwise disabled.
+         * @param reason Reason for data enabled/disabled.
+         *               See {@link TelephonyManager.DataEnabledReason}.
+         */
+        @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+        public void onDataEnabledChanged(boolean enabled,
+                                  @DataEnabledReason int reason);
     }
 
     /**
@@ -707,6 +2004,7 @@
      * same as above, but with the network type.  Both called.
      */
     public void onDataConnectionStateChanged(int state, int networkType) {
+        // default implementation empty
     }
 
     /**
@@ -754,6 +2052,7 @@
      * @param cellInfo is the list of currently visible cells.
      */
     public void onCellInfoChanged(List<CellInfo> cellInfo) {
+        // default implementation empty
     }
 
     /**
@@ -767,7 +2066,7 @@
      * @param callState {@link PreciseCallState}
      * @hide
      */
-    @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
     @SystemApi
     public void onPreciseCallStateChanged(@NonNull PreciseCallState callState) {
         // default implementation empty
@@ -786,9 +2085,9 @@
      * @param preciseDisconnectCause {@link PreciseDisconnectCause}.
      *
      */
-    @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
-    public void onCallDisconnectCauseChanged(@Annotation.DisconnectCauses int disconnectCause,
-            int preciseDisconnectCause) {
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+    public void onCallDisconnectCauseChanged(@DisconnectCauses int disconnectCause,
+            @PreciseDisconnectCauses int preciseDisconnectCause) {
         // default implementation empty
     }
 
@@ -804,7 +2103,7 @@
      * @param imsReasonInfo {@link ImsReasonInfo} contains details on why IMS call failed.
      *
      */
-    @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
+    @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
     public void onImsCallDisconnectCauseChanged(@NonNull ImsReasonInfo imsReasonInfo) {
         // default implementation empty
     }
@@ -826,7 +2125,7 @@
      *
      * @param dataConnectionState {@link PreciseDataConnectionState}
      */
-    @RequiresPermission((android.Manifest.permission.MODIFY_PHONE_STATE))
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public void onPreciseDataConnectionStateChanged(
             @NonNull PreciseDataConnectionState dataConnectionState) {
         // default implementation empty
@@ -864,6 +2163,7 @@
      */
     @SystemApi
     public void onSrvccStateChanged(@SrvccState int srvccState) {
+        // default implementation empty
 
     }
 
@@ -882,6 +2182,7 @@
      */
     @SystemApi
     public void onVoiceActivationStateChanged(@SimActivationState int state) {
+        // default implementation empty
     }
 
     /**
@@ -898,6 +2199,7 @@
      * @hide
      */
     public void onDataActivationStateChanged(@SimActivationState int state) {
+        // default implementation empty
     }
 
     /**
@@ -925,7 +2227,7 @@
      *
      * @param telephonyDisplayInfo The display information.
      */
-    @RequiresPermission((android.Manifest.permission.READ_PHONE_STATE))
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public void onDisplayInfoChanged(@NonNull TelephonyDisplayInfo telephonyDisplayInfo) {
         // default implementation empty
     }
@@ -1036,7 +2338,8 @@
     /**
      * Callback invoked when OEM hook raw event is received on the registered subscription.
      * Note, the registration subId comes from {@link TelephonyManager} object which registers
-     * PhoneStateListener by {@link TelephonyManager#listen(PhoneStateListener, int)}.
+     * PhoneStateListener by
+     * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)}.
      * If this TelephonyManager object was created with
      * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
      * subId. Otherwise, this callback applies to
@@ -1058,7 +2361,7 @@
      * @param capability the new phone capability
      * @hide
      */
-    public void onPhoneCapabilityChanged(PhoneCapability capability) {
+    public void onPhoneCapabilityChanged(@NonNull PhoneCapability capability) {
         // default implementation empty
     }
 
@@ -1102,7 +2405,8 @@
      * subId. Otherwise, this callback applies to
      * {@link SubscriptionManager#getDefaultSubscriptionId()}.
      *
-     * @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE}
+     * Requires permission {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}
+     *
      * @param state the modem radio power state
      * @hide
      */
@@ -1178,18 +2482,6 @@
     }
 
     /**
-     * Callback invoked when the current physical channel configuration has changed
-     *
-     * @param configs List of the current {@link PhysicalChannelConfig}s
-     * @hide
-     */
-    @SystemApi
-    public void onPhysicalChannelConfigurationChanged(
-            @NonNull List<PhysicalChannelConfig> configs) {
-        // default implementation empty
-    }
-
-    /**
      * The callback methods need to be called on the handler thread where
      * this object was created.  If the binder did that for us it'd be nice.
      *
@@ -1471,18 +2763,16 @@
             Binder.withCleanCallingIdentity(
                     () -> mExecutor.execute(
                             () -> psl.onImsCallDisconnectCauseChanged(disconnectCause)));
-
         }
 
         public void onRegistrationFailed(@NonNull CellIdentity cellIdentity,
-                @NonNull String chosenPlmn, int domain,
-                int causeCode, int additionalCauseCode) {
+                @NonNull String chosenPlmn, int domain, int causeCode, int additionalCauseCode) {
             PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
             if (psl == null) return;
 
             Binder.withCleanCallingIdentity(
                     () -> mExecutor.execute(() -> psl.onRegistrationFailed(
-                            cellIdentity, chosenPlmn, domain, causeCode, additionalCauseCode)));
+                                cellIdentity, chosenPlmn, domain, causeCode, additionalCauseCode)));
             // default implementation empty
         }
 
@@ -1494,17 +2784,30 @@
                     () -> mExecutor.execute(() -> psl.onBarringInfoChanged(barringInfo)));
         }
 
-        public void onPhysicalChannelConfigurationChanged(List<PhysicalChannelConfig> configs) {
+        public void onPhysicalChannelConfigChanged(List<PhysicalChannelConfig> configs) {
             PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
-            if (psl == null) return;
+            PhysicalChannelConfigChangedListener listener =
+                    (PhysicalChannelConfigChangedListener) mPhoneStateListenerWeakRef.get();
+            if (listener == null) return;
 
             Binder.withCleanCallingIdentity(
-                    () -> mExecutor.execute(
-                            () -> psl.onPhysicalChannelConfigurationChanged(configs)));
+                    () -> mExecutor.execute(() -> listener.onPhysicalChannelConfigChanged(
+                            configs)));
+        }
+
+        public void onDataEnabledChanged(boolean enabled, @DataEnabledReason int reason) {
+            if ((mPhoneStateListenerWeakRef.get() instanceof DataEnabledChangedListener)) {
+                DataEnabledChangedListener listener =
+                        (DataEnabledChangedListener) mPhoneStateListenerWeakRef.get();
+                if (listener == null) return;
+
+                Binder.withCleanCallingIdentity(
+                        () -> mExecutor.execute(() -> listener.onDataEnabledChanged(
+                                enabled, reason)));
+            }
         }
     }
 
-
     private void log(String s) {
         Rlog.d(LOG_TAG, s);
     }
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 24ed29a..cc3284a 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -15,6 +15,7 @@
  */
 package android.telephony;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -24,6 +25,9 @@
 import android.content.Context;
 import android.os.Binder;
 import android.os.Build;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.telephony.Annotation.CallState;
@@ -37,6 +41,7 @@
 import android.telephony.Annotation.SrvccState;
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.ims.ImsReasonInfo;
+import android.util.ArraySet;
 import android.util.Log;
 
 import com.android.internal.telephony.IOnSubscriptionsChangedListener;
@@ -45,6 +50,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.Executor;
 
 /**
@@ -206,7 +212,7 @@
     }
 
     /**
-     * To check the SDK version for {@link #listenForSubscriber}.
+     * To check the SDK version for {@link #listenWithEventList}.
      */
     @ChangeId
     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.P)
@@ -218,23 +224,23 @@
      * @param pkg Package name
      * @param featureId Feature ID
      * @param listener Listener providing callback
-     * @param events Events
+     * @param events List events
      * @param notifyNow Whether to notify instantly
      */
-    public void listenForSubscriber(int subId, @NonNull String pkg, @NonNull String featureId,
-            @NonNull PhoneStateListener listener, long events, boolean notifyNow) {
+    public void listenWithEventList(int subId, @NonNull String pkg, @NonNull String featureId,
+            @NonNull PhoneStateListener listener, @NonNull int[] events, boolean notifyNow) {
         try {
             // subId from PhoneStateListener is deprecated Q on forward, use the subId from
             // TelephonyManager instance. Keep using subId from PhoneStateListener for pre-Q.
             if (Compatibility.isChangeEnabled(LISTEN_CODE_CHANGE)) {
                 // Since mSubId in PhoneStateListener is deprecated from Q on forward, this is
                 // the only place to set mSubId and its for "informational" only.
-                listener.mSubId = (events == PhoneStateListener.LISTEN_NONE)
+                listener.mSubId = (events.length == 0)
                         ? SubscriptionManager.INVALID_SUBSCRIPTION_ID : subId;
             } else if (listener.mSubId != null) {
                 subId = listener.mSubId;
             }
-            sRegistry.listenForSubscriber(
+            sRegistry.listenWithEventList(
                     subId, pkg, featureId, listener.callback, events, notifyNow);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -771,13 +777,345 @@
      * @param subId the subId
      * @param configs a list of {@link PhysicalChannelConfig}, the configs of physical channel.
      */
-    public void notifyPhysicalChannelConfigurationForSubscriber(
+    public void notifyPhysicalChannelConfigForSubscriber(
             int subId, List<PhysicalChannelConfig> configs) {
         try {
-            sRegistry.notifyPhysicalChannelConfigurationForSubscriber(subId, configs);
+            sRegistry.notifyPhysicalChannelConfigForSubscriber(subId, configs);
         } catch (RemoteException ex) {
             // system server crash
         }
     }
 
+    public @NonNull Set<Integer> getEventsFromListener(@NonNull PhoneStateListener listener) {
+
+        Set<Integer> eventList = new ArraySet<>();
+
+        if (listener instanceof PhoneStateListener.ServiceStateChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_SERVICE_STATE_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.MessageWaitingIndicatorChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.CallForwardingIndicatorChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.CellLocationChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_CELL_LOCATION_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.CallStateChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_CALL_STATE_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.DataConnectionStateChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.DataActivityListener) {
+            eventList.add(PhoneStateListener.EVENT_DATA_ACTIVITY_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.SignalStrengthsChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.AlwaysReportedSignalStrengthChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.CellInfoChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_CELL_INFO_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.PreciseCallStateChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.CallDisconnectCauseChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_CALL_DISCONNECT_CAUSE_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.ImsCallDisconnectCauseChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.PreciseDataConnectionStateChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.SrvccStateChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_SRVCC_STATE_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.VoiceActivationStateChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.DataActivationStateChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_DATA_ACTIVATION_STATE_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.UserMobileDataStateChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.DisplayInfoChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.EmergencyNumberListChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.OutgoingEmergencyCallListener) {
+            eventList.add(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_CALL);
+        }
+
+        if (listener instanceof PhoneStateListener.OutgoingEmergencySmsListener) {
+            eventList.add(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_SMS);
+        }
+
+        if (listener instanceof PhoneStateListener.PhoneCapabilityChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_PHONE_CAPABILITY_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.ActiveDataSubscriptionIdChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.RadioPowerStateChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.CarrierNetworkChangeListener) {
+            eventList.add(PhoneStateListener.EVENT_CARRIER_NETWORK_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.RegistrationFailedListener) {
+            eventList.add(PhoneStateListener.EVENT_REGISTRATION_FAILURE);
+        }
+
+        if (listener instanceof PhoneStateListener.CallAttributesChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.BarringInfoChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_BARRING_INFO_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.PhysicalChannelConfigChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED);
+        }
+
+        if (listener instanceof PhoneStateListener.DataEnabledChangedListener) {
+            eventList.add(PhoneStateListener.EVENT_DATA_ENABLED_CHANGED);
+        }
+
+        return eventList;
+    }
+
+    private @NonNull Set<Integer> getEventsFromBitmask(int eventMask) {
+
+        Set<Integer> eventList = new ArraySet<>();
+
+        if ((eventMask & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
+            eventList.add(PhoneStateListener.EVENT_SERVICE_STATE_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
+            eventList.add(PhoneStateListener.EVENT_SIGNAL_STRENGTH_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
+            eventList.add(PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
+            eventList.add(PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
+            eventList.add(PhoneStateListener.EVENT_CELL_LOCATION_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
+            eventList.add(PhoneStateListener.EVENT_CALL_STATE_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
+            eventList.add(PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
+            eventList.add(PhoneStateListener.EVENT_DATA_ACTIVITY_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
+            eventList.add(PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) != 0) {
+            eventList.add(PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_CELL_INFO) != 0) {
+            eventList.add(PhoneStateListener.EVENT_CELL_INFO_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
+            eventList.add(PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
+            eventList.add(PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO) != 0) {
+            eventList.add(PhoneStateListener.EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT) != 0) {
+            eventList.add(PhoneStateListener.EVENT_OEM_HOOK_RAW);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED) != 0) {
+            eventList.add(PhoneStateListener.EVENT_SRVCC_STATE_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE) != 0) {
+            eventList.add(PhoneStateListener.EVENT_CARRIER_NETWORK_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE) != 0) {
+            eventList.add(PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE) != 0) {
+            eventList.add(PhoneStateListener.EVENT_DATA_ACTIVATION_STATE_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) != 0) {
+            eventList.add(PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED) != 0) {
+            eventList.add(PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_PHONE_CAPABILITY_CHANGE) != 0) {
+            eventList.add(PhoneStateListener.EVENT_PHONE_CAPABILITY_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE) != 0) {
+            eventList.add(PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED) != 0) {
+            eventList.add(PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST) != 0) {
+            eventList.add(PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES) != 0) {
+            eventList.add(PhoneStateListener.EVENT_CALL_DISCONNECT_CAUSE_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED) != 0) {
+            eventList.add(PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES) != 0) {
+            eventList.add(PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL) != 0) {
+            eventList.add(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_CALL);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_SMS) != 0) {
+            eventList.add(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_SMS);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_REGISTRATION_FAILURE) != 0) {
+            eventList.add(PhoneStateListener.EVENT_REGISTRATION_FAILURE);
+        }
+
+        if ((eventMask & PhoneStateListener.LISTEN_BARRING_INFO) != 0) {
+            eventList.add(PhoneStateListener.EVENT_BARRING_INFO_CHANGED);
+        }
+        return eventList;
+
+    }
+
+    /**
+     * Registers a listener object to receive notification of changes
+     * in specified telephony states.
+     * <p>
+     * To register a listener, pass a {@link PhoneStateListener} which implements
+     * interfaces of events. For example,
+     * FakeServiceStateChangedListener extends {@link PhoneStateListener} implements
+     * {@link PhoneStateListener.ServiceStateChangedListener}.
+     *
+     * At registration, and when a specified telephony state changes, the telephony manager invokes
+     * the appropriate callback method on the listener object and passes the current (updated)
+     * values.
+     * <p>
+     *
+     * If this TelephonyManager object has been created with
+     * {@link TelephonyManager#createForSubscriptionId}, applies to the given subId.
+     * Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}.
+     * To listen events for multiple subIds, pass a separate listener object to
+     * each TelephonyManager object created with {@link TelephonyManager#createForSubscriptionId}.
+     *
+     * Note: if you call this method while in the middle of a binder transaction, you <b>must</b>
+     * call {@link android.os.Binder#clearCallingIdentity()} before calling this method. A
+     * {@link SecurityException} will be thrown otherwise.
+     *
+     * This API should be used sparingly -- large numbers of listeners will cause system
+     * instability. If a process has registered too many listeners without unregistering them, it
+     * may encounter an {@link IllegalStateException} when trying to register more listeners.
+     *
+     * @param listener The {@link PhoneStateListener} object to register.
+     */
+    public void registerPhoneStateListener(@NonNull @CallbackExecutor Executor executor, int subId,
+            String pkgName, String attributionTag, @NonNull PhoneStateListener listener,
+            boolean notifyNow) {
+        listener.setExecutor(executor);
+        registerPhoneStateListener(subId, pkgName, attributionTag, listener,
+                getEventsFromListener(listener), notifyNow);
+    }
+
+    public void registerPhoneStateListenerWithEvents(int subId, String pkgName,
+            String attributionTag, @NonNull PhoneStateListener listener, int events,
+            boolean notifyNow) {
+        registerPhoneStateListener(
+                subId, pkgName, attributionTag, listener, getEventsFromBitmask(events), notifyNow);
+    }
+
+    private void registerPhoneStateListener(int subId,
+            String pkgName, String attributionTag, @NonNull PhoneStateListener listener,
+            @NonNull Set<Integer> events, boolean notifyNow) {
+        if (listener == null) {
+            throw new IllegalStateException("telephony service is null.");
+        }
+
+        listenWithEventList(subId, pkgName, attributionTag, listener,
+                events.stream().mapToInt(i -> i).toArray(), notifyNow);
+    }
+
+    /**
+     * Unregister an existing {@link PhoneStateListener}.
+     *
+     * @param listener The {@link PhoneStateListener} object to unregister.
+     */
+    public void unregisterPhoneStateListener(int subId, String pkgName, String attributionTag,
+                                             @NonNull PhoneStateListener listener,
+                                             boolean notifyNow) {
+        listenWithEventList(subId, pkgName, attributionTag, listener, new int[0], notifyNow);
+    }
 }
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index 84c209b..00ff687 100755
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -698,7 +698,7 @@
     }
 
     private static String zeroPad(int inValue, int inMinDigits) {
-        return TextUtils.formatSimple("%0" + inMinDigits + "d", inValue);
+        return String.format(Locale.getDefault(), "%0" + inMinDigits + "d", inValue);
     }
 
     /**
diff --git a/core/java/android/timezone/OWNERS b/core/java/android/timezone/OWNERS
new file mode 100644
index 0000000..09447a9
--- /dev/null
+++ b/core/java/android/timezone/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/app/timezone/OWNERS
diff --git a/core/java/android/transition/OWNERS b/core/java/android/transition/OWNERS
new file mode 100644
index 0000000..eb5a581
--- /dev/null
+++ b/core/java/android/transition/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 25700
+
+romainguy@google.com
+mount@google.com
+alanv@google.com
+adamp@google.com
diff --git a/core/java/android/util/Xml.java b/core/java/android/util/Xml.java
index cc6ed2e..c8193b3 100644
--- a/core/java/android/util/Xml.java
+++ b/core/java/android/util/Xml.java
@@ -18,6 +18,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.system.ErrnoException;
+import android.system.Os;
 
 import com.android.internal.util.BinaryXmlPullParser;
 import com.android.internal.util.BinaryXmlSerializer;
@@ -35,7 +37,7 @@
 import org.xmlpull.v1.XmlSerializer;
 
 import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -43,6 +45,7 @@
 import java.io.StringReader;
 import java.io.UnsupportedEncodingException;
 import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
 
 /**
  * XML utility methods.
@@ -59,6 +62,12 @@
     public static String FEATURE_RELAXED = "http://xmlpull.org/v1/doc/features.html#relaxed";
 
     /**
+     * Feature flag: when set, {@link #resolveSerializer(OutputStream)} will
+     * emit binary XML by default.
+     */
+    private static final boolean ENABLE_BINARY_DEFAULT = false;
+
+    /**
      * Parses the given xml string and fires events on the given SAX handler.
      */
     public static void parse(String xml, ContentHandler contentHandler)
@@ -119,6 +128,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("AndroidFrameworkEfficientXml")
     public static @NonNull TypedXmlPullParser newFastPullParser() {
         return XmlUtils.makeTyped(newPullParser());
     }
@@ -151,8 +161,28 @@
      */
     public static @NonNull TypedXmlPullParser resolvePullParser(@NonNull InputStream in)
             throws IOException {
-        // TODO: add support for binary format
-        final TypedXmlPullParser xml = newFastPullParser();
+        final byte[] magic = new byte[4];
+        if (in instanceof FileInputStream) {
+            try {
+                Os.pread(((FileInputStream) in).getFD(), magic, 0, magic.length, 0);
+            } catch (ErrnoException e) {
+                throw e.rethrowAsIOException();
+            }
+        } else {
+            if (!in.markSupported()) {
+                in = new BufferedInputStream(in);
+            }
+            in.mark(4);
+            in.read(magic);
+            in.reset();
+        }
+
+        final TypedXmlPullParser xml;
+        if (Arrays.equals(magic, BinaryXmlSerializer.PROTOCOL_MAGIC_VERSION_0)) {
+            xml = newBinaryPullParser();
+        } else {
+            xml = newFastPullParser();
+        }
         try {
             xml.setInput(in, StandardCharsets.UTF_8.name());
         } catch (XmlPullParserException e) {
@@ -177,6 +207,7 @@
      *
      * @hide
      */
+    @SuppressWarnings("AndroidFrameworkEfficientXml")
     public static @NonNull TypedXmlSerializer newFastSerializer() {
         return XmlUtils.makeTyped(new FastXmlSerializer());
     }
@@ -209,8 +240,12 @@
      */
     public static @NonNull TypedXmlSerializer resolveSerializer(@NonNull OutputStream out)
             throws IOException {
-        // TODO: add support for binary format
-        final TypedXmlSerializer xml = newFastSerializer();
+        final TypedXmlSerializer xml;
+        if (ENABLE_BINARY_DEFAULT) {
+            xml = newBinarySerializer();
+        } else {
+            xml = newFastSerializer();
+        }
         xml.setOutput(out, StandardCharsets.UTF_8.name());
         return xml;
     }
diff --git a/core/java/android/util/proto/OWNERS b/core/java/android/util/proto/OWNERS
new file mode 100644
index 0000000..1eb6abf
--- /dev/null
+++ b/core/java/android/util/proto/OWNERS
@@ -0,0 +1,2 @@
+dplotnikov@google.com
+mwachens@google.com
diff --git a/core/java/android/uwb/AdapterStateListener.java b/core/java/android/uwb/AdapterStateListener.java
new file mode 100644
index 0000000..8875af3
--- /dev/null
+++ b/core/java/android/uwb/AdapterStateListener.java
@@ -0,0 +1,149 @@
+/*
+ * 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.uwb;
+
+import android.annotation.NonNull;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.uwb.UwbManager.AdapterStateCallback;
+import android.uwb.UwbManager.AdapterStateCallback.StateChangedReason;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+/**
+ * @hide
+ */
+public class AdapterStateListener extends IUwbAdapterStateCallbacks.Stub {
+    private static final String TAG = "Uwb.StateListener";
+
+    private final IUwbAdapter mAdapter;
+    private boolean mIsRegistered = false;
+
+    private final Map<AdapterStateCallback, Executor> mCallbackMap = new HashMap<>();
+
+    @StateChangedReason
+    private int mAdapterStateChangeReason = AdapterStateCallback.STATE_CHANGED_REASON_ERROR_UNKNOWN;
+    private boolean mAdapterEnabledState = false;
+
+    public AdapterStateListener(@NonNull IUwbAdapter adapter) {
+        mAdapter = adapter;
+    }
+
+    /**
+     * Register an {@link AdapterStateCallback} with this {@link AdapterStateListener}
+     *
+     * @param executor an {@link Executor} to execute given callback
+     * @param callback user implementation of the {@link AdapterStateCallback}
+     */
+    public void register(@NonNull Executor executor, @NonNull AdapterStateCallback callback) {
+        synchronized (this) {
+            if (mCallbackMap.containsKey(callback)) {
+                return;
+            }
+
+            mCallbackMap.put(callback, executor);
+
+            if (!mIsRegistered) {
+                try {
+                    mAdapter.registerAdapterStateCallbacks(this);
+                    mIsRegistered = true;
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Failed to register adapter state callback");
+                    executor.execute(() -> callback.onStateChanged(false,
+                            AdapterStateCallback.STATE_CHANGED_REASON_ERROR_UNKNOWN));
+                }
+            } else {
+                sendCurrentState(callback);
+            }
+        }
+    }
+
+    /**
+     * Unregister the specified {@link AdapterStateCallback}
+     *
+     * @param callback user implementation of the {@link AdapterStateCallback}
+     */
+    public void unregister(@NonNull AdapterStateCallback callback) {
+        synchronized (this) {
+            if (!mCallbackMap.containsKey(callback)) {
+                return;
+            }
+
+            mCallbackMap.remove(callback);
+
+            if (mCallbackMap.isEmpty() && mIsRegistered) {
+                try {
+                    mAdapter.unregisterAdapterStateCallbacks(this);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Failed to unregister AdapterStateCallback with service");
+                }
+                mIsRegistered = false;
+            }
+        }
+    }
+
+    private void sendCurrentState(@NonNull AdapterStateCallback callback) {
+        synchronized (this) {
+            Executor executor = mCallbackMap.get(callback);
+
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                executor.execute(() -> callback.onStateChanged(
+                        mAdapterEnabledState, mAdapterStateChangeReason));
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+
+    @Override
+    public void onAdapterStateChanged(boolean isEnabled, int reason) {
+        synchronized (this) {
+            @StateChangedReason int localReason =
+                    convertToStateChangedReason(reason);
+            mAdapterEnabledState = isEnabled;
+            mAdapterStateChangeReason = localReason;
+            for (AdapterStateCallback cb : mCallbackMap.keySet()) {
+                sendCurrentState(cb);
+            }
+        }
+    }
+
+    private static @StateChangedReason int convertToStateChangedReason(
+            @StateChangeReason int reason) {
+        switch (reason) {
+            case StateChangeReason.ALL_SESSIONS_CLOSED:
+                return AdapterStateCallback.STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED;
+
+            case StateChangeReason.SESSION_STARTED:
+                return AdapterStateCallback.STATE_CHANGED_REASON_SESSION_STARTED;
+
+            case StateChangeReason.SYSTEM_POLICY:
+                return AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_POLICY;
+
+            case StateChangeReason.SYSTEM_BOOT:
+                return AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_BOOT;
+
+            case StateChangeReason.UNKNOWN:
+            default:
+                return AdapterStateCallback.STATE_CHANGED_REASON_ERROR_UNKNOWN;
+        }
+    }
+}
diff --git a/core/java/android/uwb/IUwbAdapter.aidl b/core/java/android/uwb/IUwbAdapter.aidl
index d29ed34..2c8b2e4 100644
--- a/core/java/android/uwb/IUwbAdapter.aidl
+++ b/core/java/android/uwb/IUwbAdapter.aidl
@@ -98,11 +98,18 @@
   int getMaxSimultaneousSessions();
 
   /**
-   * Get the maximum number of remote devices per session
+   * Get the maximum number of remote devices per session when local device is initiator
    *
    * @return the maximum number of remote devices supported in a single session
    */
-  int getMaxRemoteDevicesPerSession();
+  int getMaxRemoteDevicesPerInitiatorSession();
+
+  /**
+   * Get the maximum number of remote devices per session when local device is responder
+   *
+   * @return the maximum number of remote devices supported in a single session
+   */
+  int getMaxRemoteDevicesPerResponderSession();
 
   /**
    * Provides the capabilities and features of the device
diff --git a/core/java/android/uwb/StateChangeReason.aidl b/core/java/android/uwb/StateChangeReason.aidl
index 46a6e2e..28eaf9f 100644
--- a/core/java/android/uwb/StateChangeReason.aidl
+++ b/core/java/android/uwb/StateChangeReason.aidl
@@ -41,5 +41,10 @@
    * The adapter state changed because of a device system change.
    */
   SYSTEM_POLICY,
+
+  /**
+   * Used to signal the first adapter state message after boot
+   */
+   SYSTEM_BOOT,
 }
 
diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java
index 6488490..ed5cf36 100644
--- a/core/java/android/uwb/UwbManager.java
+++ b/core/java/android/uwb/UwbManager.java
@@ -16,6 +16,7 @@
 
 package android.uwb;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.SuppressLint;
@@ -23,10 +24,13 @@
 import android.content.Context;
 import android.os.IBinder;
 import android.os.PersistableBundle;
+import android.os.RemoteException;
 import android.os.ServiceManager;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.Executor;
@@ -45,6 +49,8 @@
     private IUwbAdapter mUwbAdapter;
     private static final String SERVICE_NAME = "uwb";
 
+    private AdapterStateListener mAdapterStateListener;
+
     /**
      * Interface for receiving UWB adapter state changes
      */
@@ -109,6 +115,7 @@
      */
     private UwbManager(IUwbAdapter adapter) {
         mUwbAdapter = adapter;
+        mAdapterStateListener = new AdapterStateListener(adapter);
     }
 
     /**
@@ -140,8 +147,9 @@
      * @param executor an {@link Executor} to execute given callback
      * @param callback user implementation of the {@link AdapterStateCallback}
      */
-    public void registerAdapterStateCallback(Executor executor, AdapterStateCallback callback) {
-        throw new UnsupportedOperationException();
+    public void registerAdapterStateCallback(@NonNull @CallbackExecutor Executor executor,
+            @NonNull AdapterStateCallback callback) {
+        mAdapterStateListener.register(executor, callback);
     }
 
     /**
@@ -153,8 +161,8 @@
      *
      * @param callback user implementation of the {@link AdapterStateCallback}
      */
-    public void unregisterAdapterStateCallback(AdapterStateCallback callback) {
-        throw new UnsupportedOperationException();
+    public void unregisterAdapterStateCallback(@NonNull AdapterStateCallback callback) {
+        mAdapterStateListener.unregister(callback);
     }
 
     /**
@@ -167,7 +175,11 @@
      */
     @NonNull
     public PersistableBundle getSpecificationInfo() {
-        throw new UnsupportedOperationException();
+        try {
+            return mUwbAdapter.getSpecificationInfo();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -176,7 +188,11 @@
      * @return true if ranging is supported
      */
     public boolean isRangingSupported() {
-        throw new UnsupportedOperationException();
+        try {
+            return mUwbAdapter.isRangingSupported();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     @Retention(RetentionPolicy.SOURCE)
@@ -225,7 +241,24 @@
      */
     @AngleOfArrivalSupportType
     public int getAngleOfArrivalSupport() {
-        throw new UnsupportedOperationException();
+        try {
+            switch (mUwbAdapter.getAngleOfArrivalSupport()) {
+                case AngleOfArrivalSupport.TWO_DIMENSIONAL:
+                    return ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D;
+
+                case AngleOfArrivalSupport.THREE_DIMENSIONAL_HEMISPHERICAL:
+                    return ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL;
+
+                case AngleOfArrivalSupport.THREE_DIMENSIONAL_SPHERICAL:
+                    return ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL;
+
+                case AngleOfArrivalSupport.NONE:
+                default:
+                    return ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE;
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -239,7 +272,15 @@
      */
     @NonNull
     public List<Integer> getSupportedChannelNumbers() {
-        throw new UnsupportedOperationException();
+        List<Integer> channels = new ArrayList<>();
+        try {
+            for (int channel : mUwbAdapter.getSupportedChannels()) {
+                channels.add(channel);
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+        return channels;
     }
 
     /**
@@ -250,7 +291,15 @@
      */
     @NonNull
     public Set<Integer> getSupportedPreambleCodeIndices() {
-        throw new UnsupportedOperationException();
+        Set<Integer> preambles = new HashSet<>();
+        try {
+            for (int preamble : mUwbAdapter.getSupportedPreambleCodes()) {
+                preambles.add(preamble);
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+        return preambles;
     }
 
     /**
@@ -262,7 +311,11 @@
      */
     @SuppressLint("MethodNameUnits")
     public long elapsedRealtimeResolutionNanos() {
-        throw new UnsupportedOperationException();
+        try {
+            return mUwbAdapter.getTimestampResolutionNanos();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -271,7 +324,11 @@
      * @return the maximum allowed number of simultaneously open {@link RangingSession} instances.
      */
     public int getMaxSimultaneousSessions() {
-        throw new UnsupportedOperationException();
+        try {
+            return mUwbAdapter.getMaxSimultaneousSessions();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -281,7 +338,11 @@
      * @return the maximum number of remote devices per {@link RangingSession}
      */
     public int getMaxRemoteDevicesPerInitiatorSession() {
-        throw new UnsupportedOperationException();
+        try {
+            return mUwbAdapter.getMaxRemoteDevicesPerInitiatorSession();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -291,7 +352,11 @@
      * @return the maximum number of remote devices per {@link RangingSession}
      */
     public int getMaxRemoteDevicesPerResponderSession() {
-        throw new UnsupportedOperationException();
+        try {
+            return mUwbAdapter.getMaxRemoteDevicesPerResponderSession();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
diff --git a/core/java/android/view/ContentInfo.java b/core/java/android/view/ContentInfo.java
index b58937b..fcf699f 100644
--- a/core/java/android/view/ContentInfo.java
+++ b/core/java/android/view/ContentInfo.java
@@ -20,16 +20,16 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ClipData;
+import android.content.ClipDescription;
 import android.net.Uri;
 import android.os.Bundle;
-import android.util.ArrayMap;
+import android.util.Pair;
 
 import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
-import java.util.Map;
 import java.util.Objects;
 import java.util.function.Predicate;
 
@@ -208,50 +208,51 @@
     }
 
     /**
-     * Partitions the content based on the given predicate.
+     * Partitions this content based on the given predicate.
      *
-     * <p>Similar to a
-     * {@link java.util.stream.Collectors#partitioningBy(Predicate) partitioning collector},
-     * this function classifies the content and organizes it into a map, grouping the items that
-     * matched vs didn't match the predicate.
+     * <p>This function classifies the content and organizes it into a pair, grouping the items
+     * that matched vs didn't match the predicate.
      *
      * <p>Except for the {@link ClipData} items, the returned objects will contain all the same
-     * metadata as the original.
+     * metadata as this {@link ContentInfo}.
      *
      * @param itemPredicate The predicate to test each {@link ClipData.Item} to determine which
-     * partition to place it into.
-     * @return A map containing the partitioned content. The map will contain a single entry if
-     * all items were classified into the same partition (all matched or all didn't match the
-     * predicate) or two entries (if there's at least one item that matched the predicate and at
-     * least one item that didn't match the predicate).
+     *                      partition to place it into.
+     * @return A pair containing the partitioned content. The pair's first object will have the
+     * content that matched the predicate, or null if none of the items matched. The pair's
+     * second object will have the content that didn't match the predicate, or null if all of
+     * the items matched.
      */
     @NonNull
-    public Map<Boolean, ContentInfo> partition(@NonNull Predicate<ClipData.Item> itemPredicate) {
+    public Pair<ContentInfo, ContentInfo> partition(
+            @NonNull Predicate<ClipData.Item> itemPredicate) {
         if (mClip.getItemCount() == 1) {
-            Map<Boolean, ContentInfo> result = new ArrayMap<>(1);
-            result.put(itemPredicate.test(mClip.getItemAt(0)), this);
-            return result;
+            boolean matched = itemPredicate.test(mClip.getItemAt(0));
+            return Pair.create(matched ? this : null, matched ? null : this);
         }
-        ArrayList<ClipData.Item> accepted = new ArrayList<>();
-        ArrayList<ClipData.Item> remaining = new ArrayList<>();
+        ArrayList<ClipData.Item> acceptedItems = new ArrayList<>();
+        ArrayList<ClipData.Item> remainingItems = new ArrayList<>();
         for (int i = 0; i < mClip.getItemCount(); i++) {
             ClipData.Item item = mClip.getItemAt(i);
             if (itemPredicate.test(item)) {
-                accepted.add(item);
+                acceptedItems.add(item);
             } else {
-                remaining.add(item);
+                remainingItems.add(item);
             }
         }
-        Map<Boolean, ContentInfo> result = new ArrayMap<>(2);
-        if (!accepted.isEmpty()) {
-            ClipData acceptedClip = new ClipData(mClip.getDescription(), accepted);
-            result.put(true, new Builder(this).setClip(acceptedClip).build());
+        if (acceptedItems.isEmpty()) {
+            return Pair.create(null, this);
         }
-        if (!remaining.isEmpty()) {
-            ClipData remainingClip = new ClipData(mClip.getDescription(), remaining);
-            result.put(false, new Builder(this).setClip(remainingClip).build());
+        if (remainingItems.isEmpty()) {
+            return Pair.create(this, null);
         }
-        return result;
+        ContentInfo accepted = new Builder(this)
+                .setClip(new ClipData(new ClipDescription(mClip.getDescription()), acceptedItems))
+                .build();
+        ContentInfo remaining = new Builder(this)
+                .setClip(new ClipData(new ClipDescription(mClip.getDescription()), remainingItems))
+                .build();
+        return Pair.create(accepted, remaining);
     }
 
     /**
diff --git a/core/java/android/view/IPinnedStackController.aidl b/core/java/android/view/IPinnedStackController.aidl
deleted file mode 100644
index 1cf83a3..0000000
--- a/core/java/android/view/IPinnedStackController.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view;
-
-import android.graphics.Rect;
-
-/**
- * An interface to the PinnedStackController to update it of state changes, and to query
- * information based on the current state.
- *
- * @hide
- */
-interface IPinnedStackController {
-    /**
-     * @return what WM considers to be the current device rotation.
-     */
-    int getDisplayRotation();
-}
diff --git a/core/java/android/view/IPinnedStackListener.aidl b/core/java/android/view/IPinnedStackListener.aidl
index f49fee3..84dd8af 100644
--- a/core/java/android/view/IPinnedStackListener.aidl
+++ b/core/java/android/view/IPinnedStackListener.aidl
@@ -21,7 +21,6 @@
 import android.content.pm.ParceledListSlice;
 import android.graphics.Rect;
 import android.view.DisplayInfo;
-import android.view.IPinnedStackController;
 
 /**
  * Listener for changes to the pinned stack made by the WindowManager.
@@ -31,12 +30,6 @@
 oneway interface IPinnedStackListener {
 
     /**
-     * Called when the listener is registered and provides an interface to call back to the pinned
-     * stack controller to update the controller of the pinned stack state.
-     */
-    void onListenerRegistered(IPinnedStackController controller);
-
-    /**
      * Called when the window manager has detected a change that would cause the movement bounds
      * to be changed (ie. after configuration change, aspect ratio change, etc).
      */
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index a23b7e1..025a977 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -780,4 +780,25 @@
      *         verified.
      */
     boolean verifyImpressionToken(in ImpressionToken impressionToken);
+
+    /**
+     * Registers a listener for a {@link android.app.WindowContext} to handle configuration changes
+     * from the server side.
+     *
+     * @param clientToken the window context's token
+     * @param type Window type of the window context
+     * @param displayId The display associated with the window context
+     * @param options A bundle used to pass window-related options and choose the right DisplayArea
+     *
+     * @return {@code true} if the listener was registered successfully.
+     */
+    boolean registerWindowContextListener(IBinder clientToken, int type, int displayId,
+            in Bundle options);
+
+    /**
+     * Unregisters a listener which registered with {@link #registerWindowContextListener()}.
+     *
+     * @param clientToken the window context's token
+     */
+    void unregisterWindowContextListener(IBinder clientToken);
 }
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 8da833a..df96dc3 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -28,7 +29,9 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.Vibrator;
+import android.os.VibratorManager;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.lang.annotation.Retention;
@@ -72,6 +75,9 @@
 
     private Vibrator mVibrator; // guarded by mMotionRanges during initialization
 
+    @GuardedBy("mMotionRanges")
+    private VibratorManager mVibratorManager;
+
     /**
      * A mask for input source classes.
      *
@@ -415,6 +421,8 @@
 
     private static final int MAX_RANGES = 1000;
 
+    private static final int VIBRATOR_ID_ALL = -1;
+
     public static final @android.annotation.NonNull Parcelable.Creator<InputDevice> CREATOR =
             new Parcelable.Creator<InputDevice>() {
         public InputDevice createFromParcel(Parcel in) {
@@ -785,7 +793,8 @@
         synchronized (mMotionRanges) {
             if (mVibrator == null) {
                 if (mHasVibrator) {
-                    mVibrator = InputManager.getInstance().getInputDeviceVibrator(mId);
+                    mVibrator = InputManager.getInstance().getInputDeviceVibrator(mId,
+                            VIBRATOR_ID_ALL);
                 } else {
                     mVibrator = NullVibrator.getInstance();
                 }
@@ -795,6 +804,24 @@
     }
 
     /**
+     * Gets the vibrator manager associated with the device.
+     * Even if the device does not have a vibrator manager, the result is never null.
+     * Use {@link VibratorManager#getVibratorIds} to determine whether any vibrator is
+     * present.
+     *
+     * @return The vibrator manager associated with the device, never null.
+     */
+    @NonNull
+    public VibratorManager getVibratorManager() {
+        synchronized (mMotionRanges) {
+            if (mVibratorManager == null) {
+                mVibratorManager = InputManager.getInstance().getInputDeviceVibratorManager(mId);
+            }
+        }
+        return mVibratorManager;
+    }
+
+    /**
      * Returns true if input device is enabled.
      * @return Whether the input device is enabled.
      */
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index c4f32c4..80437be 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -1057,6 +1057,11 @@
             boolean canRun = false;
             if (show) {
                 // Show request
+                if (fromIme) {
+                    ImeTracing.getInstance().triggerClientDump(
+                            "ImeInsetsSourceConsumer#requestShow", mHost.getInputMethodManager(),
+                            null /* icProto */);
+                }
                 switch(consumer.requestShow(fromIme)) {
                     case ShowResult.SHOW_IMMEDIATELY:
                         canRun = true;
@@ -1096,8 +1101,18 @@
                         + fromIme);
                 // We don't have a control at the moment. However, we still want to update requested
                 // visibility state such that in case we get control, we can apply show animation.
+                if (fromIme) {
+                    ImeTracing.getInstance().triggerClientDump(
+                            "InsetsSourceConsumer#show", mHost.getInputMethodManager(),
+                            null /* icProto */);
+                }
                 consumer.show(fromIme);
             } else if (animationType == ANIMATION_TYPE_HIDE) {
+                if (fromIme) {
+                    ImeTracing.getInstance().triggerClientDump(
+                            "InsetsSourceConsumer#hide", mHost.getInputMethodManager(),
+                            null /* icProto */);
+                }
                 consumer.hide();
             }
         }
@@ -1217,8 +1232,8 @@
 
     private void applyLocalVisibilityOverride() {
         for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
-            final InsetsSourceConsumer controller = mSourceConsumers.valueAt(i);
-            controller.applyLocalVisibilityOverride();
+            final InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
+            consumer.applyLocalVisibilityOverride();
         }
     }
 
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index 537fd42..fd1c3b8 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -25,6 +25,7 @@
 import static android.view.InsetsSourceConsumerProto.PENDING_FRAME;
 import static android.view.InsetsSourceConsumerProto.PENDING_VISIBLE_FRAME;
 import static android.view.InsetsSourceConsumerProto.SOURCE_CONTROL;
+import static android.view.InsetsState.ITYPE_IME;
 import static android.view.InsetsState.getDefaultVisibility;
 import static android.view.InsetsState.toPublicType;
 
@@ -34,6 +35,7 @@
 import android.annotation.Nullable;
 import android.graphics.Rect;
 import android.util.Log;
+import android.util.imetracing.ImeTracing;
 import android.util.proto.ProtoOutputStream;
 import android.view.InsetsState.InternalInsetsType;
 import android.view.SurfaceControl.Transaction;
@@ -108,6 +110,10 @@
      */
     public void setControl(@Nullable InsetsSourceControl control,
             @InsetsType int[] showTypes, @InsetsType int[] hideTypes) {
+        if (mType == ITYPE_IME) {
+            ImeTracing.getInstance().triggerClientDump("InsetsSourceConsumer#setControl",
+                    mController.getHost().getInputMethodManager(), null /* icProto */);
+        }
         if (mSourceControl == control) {
             return;
         }
@@ -237,6 +243,12 @@
         final boolean isVisible = source != null ? source.isVisible() : getDefaultVisibility(mType);
         final boolean hasControl = mSourceControl != null;
 
+        if (mType == ITYPE_IME) {
+            ImeTracing.getInstance().triggerClientDump(
+                    "InsetsSourceConsumer#applyLocalVisibilityOverride",
+                    mController.getHost().getInputMethodManager(), null /* icProto */);
+        }
+
         // We still need to let the legacy app know the visibility change even if we don't have the
         // control. If we don't have the source, we don't change the requested visibility for making
         // the callback behavior compatible.
diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS
index 7b60f2e..4f82b86 100644
--- a/core/java/android/view/OWNERS
+++ b/core/java/android/view/OWNERS
@@ -1,3 +1,14 @@
+# Bug component: 25700
+
+romainguy@google.com
+alanv@google.com
+adamp@google.com
+aurimas@google.com
+nduca@google.com
+sumir@google.com
+ogunwale@google.com
+jjaggi@google.com
+
 # Display
 per-file Display.java = michaelwr@google.com, santoscordon@google.com
 per-file DisplayInfo.java = michaelwr@google.com, santoscordon@google.com
diff --git a/core/java/android/view/OnReceiveContentListener.java b/core/java/android/view/OnReceiveContentListener.java
index b551fa8..419f964 100644
--- a/core/java/android/view/OnReceiveContentListener.java
+++ b/core/java/android/view/OnReceiveContentListener.java
@@ -35,12 +35,12 @@
  *
  *     &#64;Override
  *     public ContentInfo onReceiveContent(View view, ContentInfo payload) {
- *         Map&lt;Boolean, ContentInfo&gt; split =
+ *         Pair&lt;ContentInfo, ContentInfo&gt; split =
  *                 payload.partition(item -&gt; item.getUri() != null);
- *         ContentInfo uriItems = split.get(true);
- *         ContentInfo remainingItems = split.get(false);
- *         if (uriItems != null) {
- *             ClipData clip = uriItems.getClip();
+ *         ContentInfo uriContent = split.first;
+ *         ContentInfo remaining = split.second;
+ *         if (uriContent != null) {
+ *             ClipData clip = uriContent.getClip();
  *             for (int i = 0; i < clip.getItemCount(); i++) {
  *                 Uri uri = clip.getItemAt(i).getUri();
  *                 // ... app-specific logic to handle the URI ...
@@ -48,7 +48,7 @@
  *         }
  *         // Return anything that we didn't handle ourselves. This preserves the default platform
  *         // behavior for text and anything else for which we are not implementing custom handling.
- *         return remainingItems;
+ *         return remaining;
  *     }
  * }
  *
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index a274079..2d633cb 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -19,6 +19,7 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.InputDevice.SOURCE_CLASS_NONE;
+import static android.view.InsetsState.ITYPE_IME;
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
 import static android.view.InsetsState.SIZE;
@@ -118,6 +119,7 @@
 import android.graphics.Region;
 import android.graphics.RenderNode;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManager.DisplayListener;
 import android.hardware.input.InputManager;
@@ -4413,6 +4415,14 @@
                         mView.mContext.getDrawable(value.resourceId);
             }
         }
+        // Sets the focus appearance data into the accessibility focus drawable.
+        if (mAttachInfo.mAccessibilityFocusDrawable instanceof GradientDrawable) {
+            final GradientDrawable drawable =
+                    (GradientDrawable) mAttachInfo.mAccessibilityFocusDrawable;
+            drawable.setStroke(mAccessibilityManager.getAccessibilityFocusStrokeWidth(),
+                    mAccessibilityManager.getAccessibilityFocusColor());
+        }
+
         return mAttachInfo.mAccessibilityFocusDrawable;
     }
 
@@ -7931,6 +7941,10 @@
         if (mTranslator != null) {
             mTranslator.translateInsetsStateInScreenToAppWindow(insetsState);
         }
+        if (insetsState != null && insetsState.getSource(ITYPE_IME).isVisible()) {
+            ImeTracing.getInstance().triggerClientDump("ViewRootImpl#dispatchInsetsChanged",
+                    getInsetsController().getHost().getInputMethodManager(), null /* icProto */);
+        }
         mHandler.obtainMessage(MSG_INSETS_CHANGED, insetsState).sendToTarget();
     }
 
@@ -7947,6 +7961,10 @@
         if (mTranslator != null) {
             mTranslator.translateInsetsStateInScreenToAppWindow(insetsState);
         }
+        if (insetsState != null && insetsState.getSource(ITYPE_IME).isVisible()) {
+            ImeTracing.getInstance().triggerClientDump("ViewRootImpl#dispatchInsetsControlChanged",
+                    getInsetsController().getHost().getInputMethodManager(), null /* icProto */);
+        }
         SomeArgs args = SomeArgs.obtain();
         args.arg1 = insetsState;
         args.arg2 = activeControls;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 9c16378..13d9eb9 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -45,7 +45,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.RemoteException;
 import android.transition.Scene;
 import android.transition.Transition;
 import android.transition.TransitionManager;
@@ -635,7 +634,7 @@
          * Moves the activity between {@link WindowConfiguration#WINDOWING_MODE_FREEFORM} windowing
          * mode and {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN}.
          */
-        void toggleFreeformWindowingMode() throws RemoteException;
+        void toggleFreeformWindowingMode();
 
         /**
          * Puts the activity in picture-in-picture mode if the activity supports.
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index a8534fa..56dcd59 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -19,9 +19,11 @@
 import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_ENABLE_ACCESSIBILITY_VOLUME;
 
 import android.Manifest;
+import android.accessibilityservice.AccessibilityService;
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accessibilityservice.AccessibilityServiceInfo.FeedbackType;
 import android.accessibilityservice.AccessibilityShortcutInfo;
+import android.annotation.ColorInt;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -59,6 +61,7 @@
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent.EventType;
 
+import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.IntPair;
 
@@ -233,6 +236,11 @@
 
     private int mPerformingAction = 0;
 
+    /** The stroke width of the focus rectangle in pixels */
+    private int mFocusStrokeWidth;
+    /** The color of the focus rectangle */
+    private int mFocusColor;
+
     @UnsupportedAppUsage
     private final ArrayMap<AccessibilityStateChangeListener, Handler>
             mAccessibilityStateChangeListeners = new ArrayMap<>();
@@ -410,6 +418,13 @@
         public void setRelevantEventTypes(int eventTypes) {
             mRelevantEventTypes = eventTypes;
         }
+
+        @Override
+        public void setFocusAppearance(int strokeWidth, int color) {
+            synchronized (mLock) {
+                updateFocusAppearanceLocked(strokeWidth, color);
+            }
+        }
     };
 
     /**
@@ -457,6 +472,7 @@
         mHandler = new Handler(context.getMainLooper(), mCallback);
         mUserId = userId;
         synchronized (mLock) {
+            initialFocusAppearanceLocked(context.getResources());
             tryConnectToServiceLocked(service);
         }
     }
@@ -464,18 +480,26 @@
     /**
      * Create an instance.
      *
+     * @param context A {@link Context}.
      * @param handler The handler to use
      * @param service An interface to the backing service.
      * @param userId User id under which to run.
+     * @param serviceConnect {@code true} to connect the service or
+     *                       {@code false} not to connect the service.
      *
      * @hide
      */
-    public AccessibilityManager(Handler handler, IAccessibilityManager service, int userId) {
+    @VisibleForTesting
+    public AccessibilityManager(Context context, Handler handler, IAccessibilityManager service,
+            int userId, boolean serviceConnect) {
         mCallback = new MyCallback();
         mHandler = handler;
         mUserId = userId;
         synchronized (mLock) {
-            tryConnectToServiceLocked(service);
+            initialFocusAppearanceLocked(context.getResources());
+            if (serviceConnect) {
+                tryConnectToServiceLocked(service);
+            }
         }
     }
 
@@ -954,6 +978,32 @@
     }
 
     /**
+     * Gets the strokeWidth of the focus rectangle. This value can be set by
+     * {@link AccessibilityService}.
+     *
+     * @return The strokeWidth of the focus rectangle in pixels.
+     *
+     */
+    public int getAccessibilityFocusStrokeWidth() {
+        synchronized (mLock) {
+            return mFocusStrokeWidth;
+        }
+    }
+
+    /**
+     * Gets the color of the focus rectangle. This value can be set by
+     * {@link AccessibilityService}.
+     *
+     * @return The color of the focus rectangle.
+     *
+     */
+    public @ColorInt int getAccessibilityFocusColor() {
+        synchronized (mLock) {
+            return mFocusColor;
+        }
+    }
+
+    /**
      * Get the preparers that are registered for an accessibility ID
      *
      * @param id The ID of interest
@@ -1551,6 +1601,7 @@
             setStateLocked(IntPair.first(userStateAndRelevantEvents));
             mRelevantEventTypes = IntPair.second(userStateAndRelevantEvents);
             updateUiTimeout(service.getRecommendedTimeoutMillis());
+            updateFocusAppearanceLocked(service.getFocusStrokeWidth(), service.getFocusColor());
             mService = service;
         } catch (RemoteException re) {
             Log.e(LOG_TAG, "AccessibilityManagerService is dead", re);
@@ -1635,6 +1686,40 @@
     }
 
     /**
+     * Updates the stroke width and color of the focus rectangle.
+     *
+     * @param strokeWidth The strokeWidth of the focus rectangle.
+     * @param color The color of the focus rectangle.
+     */
+    private void updateFocusAppearanceLocked(int strokeWidth, int color) {
+        if (mFocusStrokeWidth == strokeWidth && mFocusColor == color) {
+            return;
+        }
+        mFocusStrokeWidth = strokeWidth;
+        mFocusColor = color;
+    }
+
+    /**
+     * Sets the stroke width and color of the focus rectangle to default value.
+     *
+     * @param resource The resources.
+     */
+    private void initialFocusAppearanceLocked(Resources resource) {
+        try {
+            mFocusStrokeWidth = resource.getDimensionPixelSize(
+                    R.dimen.accessibility_focus_highlight_stroke_width);
+            mFocusColor = resource.getColor(R.color.accessibility_focus_highlight_color);
+        } catch (Resources.NotFoundException re) {
+            // Sets the stroke width and color to default value by hardcoded for making
+            // the Talkback can work normally.
+            mFocusStrokeWidth = (int) (4 * resource.getDisplayMetrics().density);
+            mFocusColor = 0xbf39b500;
+            Log.e(LOG_TAG, "Error while initialing the focus appearance data then setting to"
+                    + " default value by hardcoded", re);
+        }
+    }
+
+    /**
      * Determines if the accessibility button within the system navigation area is supported.
      *
      * @return {@code true} if the accessibility button is supported on this device,
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 5d3c720..c71ea53 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -92,4 +92,8 @@
     void associateEmbeddedHierarchy(IBinder host, IBinder embedded);
 
     void disassociateEmbeddedHierarchy(IBinder token);
+
+    int getFocusStrokeWidth();
+
+    int getFocusColor();
 }
diff --git a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
index 94b9ad1..041399c 100644
--- a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
@@ -29,4 +29,6 @@
     void notifyServicesStateChanged(long updatedUiTimeout);
 
     void setRelevantEventTypes(int eventTypes);
+
+    void setFocusAppearance(int strokeWidth, int color);
 }
diff --git a/core/java/android/view/accessibility/OWNERS b/core/java/android/view/accessibility/OWNERS
index c6f42f7..93b5a2e 100644
--- a/core/java/android/view/accessibility/OWNERS
+++ b/core/java/android/view/accessibility/OWNERS
@@ -1,4 +1,11 @@
-svetoslavganov@google.com
+# Bug component: 44214
+
+romainguy@google.com
+alanv@google.com
+adamp@google.com
+aurimas@google.com
+nduca@google.com
+sumir@google.com
+ogunwale@google.com
+jjaggi@google.com
 pweaver@google.com
-rhedjao@google.com
-qasid@google.com
diff --git a/core/java/android/view/animation/OWNERS b/core/java/android/view/animation/OWNERS
new file mode 100644
index 0000000..9b8f4d9
--- /dev/null
+++ b/core/java/android/view/animation/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 25700
+
+romainguy@google.com
+tianliu@google.com
+alanv@google.com
+adamp@google.com
diff --git a/core/java/android/view/autofill/OWNERS b/core/java/android/view/autofill/OWNERS
new file mode 100644
index 0000000..a088632
--- /dev/null
+++ b/core/java/android/view/autofill/OWNERS
@@ -0,0 +1,9 @@
+# Bug component: 351486
+
+joannechung@google.com
+adamhe@google.com
+tymtsai@google.com
+lpeter@google.com
+augale@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
diff --git a/core/java/android/view/contentcapture/OWNERS b/core/java/android/view/contentcapture/OWNERS
new file mode 100644
index 0000000..6337327
--- /dev/null
+++ b/core/java/android/view/contentcapture/OWNERS
@@ -0,0 +1,9 @@
+# Bug component: 544200
+
+joannechung@google.com
+adamhe@google.com
+tymtsai@google.com
+lpeter@google.com
+augale@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 907b5b0..eaf72dc 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -598,6 +598,9 @@
          */
         @Override
         public void finishInput() {
+            ImeTracing.getInstance().triggerClientDump(
+                    "InputMethodManager.DelegateImpl#finishInput", InputMethodManager.this,
+                    null /* icProto */);
             synchronized (mH) {
                 finishInputLocked();
             }
@@ -641,6 +644,10 @@
             int startInputFlags = getStartInputFlags(focusedView, 0);
             startInputFlags |= StartInputFlags.WINDOW_GAINED_FOCUS;
 
+            ImeTracing.getInstance().triggerClientDump(
+                    "InputMethodManager.DelegateImpl#startInputAsyncOnWindowFocusGain",
+                    InputMethodManager.this, null /* icProto */);
+
             final ImeFocusController controller = getFocusController();
             if (controller == null) {
                 return;
@@ -950,6 +957,9 @@
                 case MSG_APPLY_IME_VISIBILITY: {
                     synchronized (mH) {
                         if (mImeInsetsConsumer != null) {
+                            ImeTracing.getInstance().triggerClientDump(
+                                    "ImeInsetsSourceConsumer#applyImeVisibility",
+                                    InputMethodManager.this, null /* icProto */);
                             mImeInsetsConsumer.applyImeVisibility(msg.arg1 != 0);
                         }
                     }
@@ -1860,6 +1870,9 @@
      * {@link #HIDE_NOT_ALWAYS} bit set.
      **/
     public void toggleSoftInputFromWindow(IBinder windowToken, int showFlags, int hideFlags) {
+        ImeTracing.getInstance().triggerClientDump(
+                "InputMethodManager#toggleSoftInputFromWindow", InputMethodManager.this,
+                null /* icProto */);
         synchronized (mH) {
             final View servedView = getServedViewLocked();
             if (servedView == null || servedView.getWindowToken() != windowToken) {
@@ -1887,6 +1900,9 @@
      * {@link #HIDE_NOT_ALWAYS} bit set.
      */
     public void toggleSoftInput(int showFlags, int hideFlags) {
+        ImeTracing.getInstance().triggerClientDump(
+                "InputMethodManager#toggleSoftInput", InputMethodManager.this,
+                null /* icProto */);
         if (mCurMethod != null) {
             try {
                 mCurMethod.toggleSoftInput(showFlags, hideFlags);
diff --git a/core/java/android/view/inputmethod/OWNERS b/core/java/android/view/inputmethod/OWNERS
index 244cc30..e6a04da 100644
--- a/core/java/android/view/inputmethod/OWNERS
+++ b/core/java/android/view/inputmethod/OWNERS
@@ -1,3 +1,4 @@
+# Bug component: 34867
 set noparent
 
-include ../../../../../services/core/java/com/android/server/inputmethod/OWNERS
+include /services/core/java/com/android/server/inputmethod/OWNERS
diff --git a/core/java/android/view/inspector/OWNERS b/core/java/android/view/inspector/OWNERS
index c2827cc..705f4b3 100644
--- a/core/java/android/view/inspector/OWNERS
+++ b/core/java/android/view/inspector/OWNERS
@@ -1,3 +1,6 @@
+romainguy@google.com
 alanv@google.com
+adamp@google.com
 aurimas@google.com
-emberrose@google.com
+nduca@google.com
+sumir@google.com
diff --git a/core/java/android/view/textclassifier/OWNERS b/core/java/android/view/textclassifier/OWNERS
index be4fbaa..ac80d9f 100644
--- a/core/java/android/view/textclassifier/OWNERS
+++ b/core/java/android/view/textclassifier/OWNERS
@@ -1,14 +1,8 @@
 # Bug component: 709498
 
+mns@google.com
 toki@google.com
-tonymak@google.com
-zilka@google.com
-jalt@google.com
-joannechung@google.com
+svetoslavganov@android.com
 svetoslavganov@google.com
-eugeniom@google.com
-samsellem@google.com
-adamhe@google.com
 augale@google.com
-lpeter@google.com
-tymtsai@google.com
\ No newline at end of file
+joannechung@google.com
diff --git a/core/java/android/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java
index d8a632d..5b32649 100644
--- a/core/java/android/view/textclassifier/TextSelection.java
+++ b/core/java/android/view/textclassifier/TextSelection.java
@@ -45,15 +45,19 @@
     private final int mEndIndex;
     private final EntityConfidence mEntityConfidence;
     @Nullable private final String mId;
+    @Nullable
+    private final TextClassification mTextClassification;
     private final Bundle mExtras;
 
     private TextSelection(
             int startIndex, int endIndex, Map<String, Float> entityConfidence, String id,
+            @Nullable TextClassification textClassification,
             Bundle extras) {
         mStartIndex = startIndex;
         mEndIndex = endIndex;
         mEntityConfidence = new EntityConfidence(entityConfidence);
         mId = id;
+        mTextClassification = textClassification;
         mExtras = extras;
     }
 
@@ -111,6 +115,19 @@
     }
 
     /**
+     * Returns the text classification result of the suggested selection span. Enables the text
+     * classification by calling
+     * {@link TextSelection.Request.Builder#setIncludeTextClassification(boolean)}. If the text
+     * classifier does not support it, a {@code null} is returned.
+     *
+     * @see TextSelection.Request.Builder#setIncludeTextClassification(boolean)
+     */
+    @Nullable
+    public TextClassification getTextClassification() {
+        return mTextClassification;
+    }
+
+    /**
      * Returns the extended data.
      *
      * <p><b>NOTE: </b>Do not modify this bundle.
@@ -138,6 +155,8 @@
         private final Map<String, Float> mEntityConfidence = new ArrayMap<>();
         @Nullable private String mId;
         @Nullable
+        private TextClassification mTextClassification;
+        @Nullable
         private Bundle mExtras;
 
         /**
@@ -179,6 +198,21 @@
         }
 
         /**
+         * Sets the text classification result of the suggested selection. If
+         * {@link Request#shouldIncludeTextClassification()} is {@code true}, set this value.
+         * Otherwise this value may be set to null. The intention of this method is to avoid
+         * doing expensive work if the client is not interested in such result.
+         *
+         * @return this builder
+         * @see Request#shouldIncludeTextClassification()
+         */
+        @NonNull
+        public Builder setTextClassification(@Nullable TextClassification textClassification) {
+            mTextClassification = textClassification;
+            return this;
+        }
+
+        /**
          * Sets the extended data.
          *
          * @return this builder
@@ -196,7 +230,7 @@
         public TextSelection build() {
             return new TextSelection(
                     mStartIndex, mEndIndex, mEntityConfidence, mId,
-                    mExtras == null ? Bundle.EMPTY : mExtras);
+                    mTextClassification, mExtras == null ? Bundle.EMPTY : mExtras);
         }
     }
 
@@ -210,6 +244,7 @@
         private final int mEndIndex;
         @Nullable private final LocaleList mDefaultLocales;
         private final boolean mDarkLaunchAllowed;
+        private final boolean mIncludeTextClassification;
         private final Bundle mExtras;
         @Nullable private SystemTextClassifierMetadata mSystemTcMetadata;
 
@@ -219,12 +254,14 @@
                 int endIndex,
                 LocaleList defaultLocales,
                 boolean darkLaunchAllowed,
+                boolean includeTextClassification,
                 Bundle extras) {
             mText = text;
             mStartIndex = startIndex;
             mEndIndex = endIndex;
             mDefaultLocales = defaultLocales;
             mDarkLaunchAllowed = darkLaunchAllowed;
+            mIncludeTextClassification = includeTextClassification;
             mExtras = extras;
         }
 
@@ -303,6 +340,14 @@
         }
 
         /**
+         * Returns true if the client wants the text classifier to classify the text as well and
+         * include a {@link TextClassification} object in the result.
+         */
+        public boolean shouldIncludeTextClassification() {
+            return mIncludeTextClassification;
+        }
+
+        /**
          * Returns the extended data.
          *
          * <p><b>NOTE: </b>Do not modify this bundle.
@@ -320,9 +365,9 @@
             private final CharSequence mText;
             private final int mStartIndex;
             private final int mEndIndex;
-
             @Nullable private LocaleList mDefaultLocales;
             private boolean mDarkLaunchAllowed;
+            private boolean mIncludeTextClassification;
             private Bundle mExtras;
 
             /**
@@ -372,6 +417,21 @@
             }
 
             /**
+             * @param includeTextClassification If true, suggests the TextClassifier to classify the
+             *     text in the suggested selection span and include a TextClassification object in
+             *     the result. The TextClassifier may not support this and in which case,
+             *     {@link TextSelection#getTextClassification()} returns {@code null}.
+             *
+             * @return this builder.
+             * @see TextSelection#getTextClassification()
+             */
+            @NonNull
+            public Builder setIncludeTextClassification(boolean includeTextClassification) {
+                mIncludeTextClassification = includeTextClassification;
+                return this;
+            }
+
+            /**
              * Sets the extended data.
              *
              * @return this builder
@@ -389,6 +449,7 @@
             public Request build() {
                 return new Request(new SpannedString(mText), mStartIndex, mEndIndex,
                         mDefaultLocales, mDarkLaunchAllowed,
+                        mIncludeTextClassification,
                         mExtras == null ? Bundle.EMPTY : mExtras);
             }
         }
@@ -406,6 +467,7 @@
             dest.writeParcelable(mDefaultLocales, flags);
             dest.writeBundle(mExtras);
             dest.writeParcelable(mSystemTcMetadata, flags);
+            dest.writeBoolean(mIncludeTextClassification);
         }
 
         private static Request readFromParcel(Parcel in) {
@@ -415,9 +477,10 @@
             final LocaleList defaultLocales = in.readParcelable(null);
             final Bundle extras = in.readBundle();
             final SystemTextClassifierMetadata systemTcMetadata = in.readParcelable(null);
+            final boolean includeTextClassification = in.readBoolean();
 
             final Request request = new Request(text, startIndex, endIndex, defaultLocales,
-                    /* darkLaunchAllowed= */ false, extras);
+                    /* darkLaunchAllowed= */ false, includeTextClassification, extras);
             request.setSystemTextClassifierMetadata(systemTcMetadata);
             return request;
         }
@@ -448,6 +511,7 @@
         mEntityConfidence.writeToParcel(dest, flags);
         dest.writeString(mId);
         dest.writeBundle(mExtras);
+        dest.writeParcelable(mTextClassification, flags);
     }
 
     public static final @android.annotation.NonNull Parcelable.Creator<TextSelection> CREATOR =
@@ -469,5 +533,6 @@
         mEntityConfidence = EntityConfidence.CREATOR.createFromParcel(in);
         mId = in.readString();
         mExtras = in.readBundle();
+        mTextClassification = in.readParcelable(TextClassification.class.getClassLoader());
     }
 }
diff --git a/core/java/android/view/textclassifier/intent/OWNERS b/core/java/android/view/textclassifier/intent/OWNERS
new file mode 100644
index 0000000..ac80d9f
--- /dev/null
+++ b/core/java/android/view/textclassifier/intent/OWNERS
@@ -0,0 +1,8 @@
+# Bug component: 709498
+
+mns@google.com
+toki@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
+augale@google.com
+joannechung@google.com
diff --git a/core/java/android/view/textclassifier/logging/OWNERS b/core/java/android/view/textclassifier/logging/OWNERS
new file mode 100644
index 0000000..ac80d9f
--- /dev/null
+++ b/core/java/android/view/textclassifier/logging/OWNERS
@@ -0,0 +1,8 @@
+# Bug component: 709498
+
+mns@google.com
+toki@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
+augale@google.com
+joannechung@google.com
diff --git a/core/java/android/view/textservice/OWNERS b/core/java/android/view/textservice/OWNERS
new file mode 100644
index 0000000..a637754
--- /dev/null
+++ b/core/java/android/view/textservice/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 34867
+
+ogunwale@google.com
+roosa@google.com
+yukawa@google.com
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index ea906c6..ce29eea 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -1409,6 +1409,11 @@
         return mFilter;
     }
 
+    @Override
+    public CharSequence getAccessibilityClassName() {
+        return AutoCompleteTextView.class.getName();
+    }
+
     private class DropDownItemClickListener implements AdapterView.OnItemClickListener {
         public void onItemClick(AdapterView parent, View v, int position, long id) {
             performCompletion(v, position, id);
diff --git a/core/java/android/widget/OWNERS b/core/java/android/widget/OWNERS
index 5c79d21..fbb975b 100644
--- a/core/java/android/widget/OWNERS
+++ b/core/java/android/widget/OWNERS
@@ -1 +1,9 @@
+# Bug component: 25700
+
+romainguy@google.com
+alanv@google.com
+adamp@google.com
+aurimas@google.com
+siyamed@google.com
+
 per-file TextView.java, EditText.java, Editor.java = siyamed@google.com, nona@google.com, clarabayarri@google.com
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index e08ccfd..6f18920 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -1124,6 +1124,7 @@
                         mTrimmedText, mRelativeStart, mRelativeEnd)
                         .setDefaultLocales(mDefaultLocales)
                         .setDarkLaunchAllowed(true)
+                        .setIncludeTextClassification(true)
                         .build();
                 selection = mTextClassifier.get().suggestSelection(request);
             } else {
@@ -1181,6 +1182,8 @@
                     // Do not show smart actions for text containing unsupported characters.
                     android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, "");
                     classification = TextClassification.EMPTY;
+                } else if (selection != null && selection.getTextClassification() != null) {
+                    classification = selection.getTextClassification();
                 } else if (mContext.getApplicationInfo().targetSdkVersion
                         >= Build.VERSION_CODES.P) {
                     final TextClassification.Request request =
diff --git a/core/java/android/window/OWNERS b/core/java/android/window/OWNERS
index d10fb31..2c61df9 100644
--- a/core/java/android/window/OWNERS
+++ b/core/java/android/window/OWNERS
@@ -1,3 +1,3 @@
 set noparent
 
-include ../../../../services/core/java/com/android/server/wm/OWNERS
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
index eda168d..c4bdb5a 100644
--- a/core/java/android/window/TaskOrganizer.java
+++ b/core/java/android/window/TaskOrganizer.java
@@ -213,12 +213,12 @@
     private final ITaskOrganizer mInterface = new ITaskOrganizer.Stub() {
         @Override
         public void addStartingWindow(ActivityManager.RunningTaskInfo taskInfo, IBinder appToken) {
-            TaskOrganizer.this.addStartingWindow(taskInfo, appToken);
+            mExecutor.execute(() -> TaskOrganizer.this.addStartingWindow(taskInfo, appToken));
         }
 
         @Override
         public void removeStartingWindow(ActivityManager.RunningTaskInfo taskInfo) {
-            TaskOrganizer.this.removeStartingWindow(taskInfo);
+            mExecutor.execute(() -> TaskOrganizer.this.removeStartingWindow(taskInfo));
         }
 
         @Override
diff --git a/core/java/com/android/ims/OWNERS b/core/java/com/android/ims/OWNERS
new file mode 100644
index 0000000..640baf2
--- /dev/null
+++ b/core/java/com/android/ims/OWNERS
@@ -0,0 +1 @@
+include /telephony/OWNERS
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 6d98a59..0b047a2 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -19,6 +19,7 @@
 import com.android.internal.os.BatteryStatsImpl;
 
 import android.bluetooth.BluetoothActivityEnergyInfo;
+import android.os.BatteryUsageStats;
 import android.os.ParcelFileDescriptor;
 import android.os.WorkSource;
 import android.os.connectivity.CellularBatteryStats;
@@ -49,6 +50,9 @@
     void noteResetFlashlight();
 
     // Remaining methods are only used in Java.
+
+    BatteryUsageStats getBatteryUsageStats();
+
     @UnsupportedAppUsage
     byte[] getStatistics();
 
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 83cbe38..2dbcbb5 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -1220,25 +1220,6 @@
                         if (TextUtils.isEmpty(packageName)) {
                             pm.setDefaultBrowserPackageNameAsUser(ri.activityInfo.packageName, userId);
                         }
-                    } else {
-                        // Update Domain Verification status
-                        ComponentName cn = intent.getComponent();
-                        String packageName = cn.getPackageName();
-                        String dataScheme = (data != null) ? data.getScheme() : null;
-
-                        boolean isHttpOrHttps = (dataScheme != null) &&
-                                (dataScheme.equals(IntentFilter.SCHEME_HTTP) ||
-                                        dataScheme.equals(IntentFilter.SCHEME_HTTPS));
-
-                        boolean isViewAction = (action != null) && action.equals(Intent.ACTION_VIEW);
-                        boolean hasCategoryBrowsable = (categories != null) &&
-                                categories.contains(Intent.CATEGORY_BROWSABLE);
-
-                        if (isHttpOrHttps && isViewAction && hasCategoryBrowsable) {
-                            pm.updateIntentVerificationStatusAsUser(packageName,
-                                    PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS,
-                                    userId);
-                        }
                     }
                 } else {
                     try {
diff --git a/core/java/com/android/internal/config/sysui/OWNERS b/core/java/com/android/internal/config/sysui/OWNERS
new file mode 100644
index 0000000..2e96c97
--- /dev/null
+++ b/core/java/com/android/internal/config/sysui/OWNERS
@@ -0,0 +1 @@
+include /packages/SystemUI/OWNERS
diff --git a/core/java/com/android/internal/net/OWNERS b/core/java/com/android/internal/net/OWNERS
index 050cb5c..fec56c3 100644
--- a/core/java/com/android/internal/net/OWNERS
+++ b/core/java/com/android/internal/net/OWNERS
@@ -3,7 +3,7 @@
 codewiz@google.com
 ek@google.com
 jchalard@google.com
-jsharkey@android.com
+jsharkey@google.com
 lorenzo@google.com
 reminv@google.com
 satk@google.com
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index dcd74fd..fb6eb97 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -90,6 +90,8 @@
 import android.util.SparseIntArray;
 import android.util.SparseLongArray;
 import android.util.TimeUtils;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 import android.view.Display;
 
@@ -112,7 +114,6 @@
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -10830,8 +10831,7 @@
             }
             final ByteArrayOutputStream memStream = new ByteArrayOutputStream();
             try {
-                XmlSerializer out = new FastXmlSerializer();
-                out.setOutput(memStream, StandardCharsets.UTF_8.name());
+                TypedXmlSerializer out = Xml.resolveSerializer(memStream);
                 writeDailyItemsLocked(out);
                 final long initialTimeMs = SystemClock.uptimeMillis() - startTimeMs;
                 BackgroundThread.getHandler().post(new Runnable() {
@@ -10861,15 +10861,15 @@
         }
     }
 
-    private void writeDailyItemsLocked(XmlSerializer out) throws IOException {
+    private void writeDailyItemsLocked(TypedXmlSerializer out) throws IOException {
         StringBuilder sb = new StringBuilder(64);
         out.startDocument(null, true);
         out.startTag(null, "daily-items");
         for (int i=0; i<mDailyItems.size(); i++) {
             final DailyItem dit = mDailyItems.get(i);
             out.startTag(null, "item");
-            out.attribute(null, "start", Long.toString(dit.mStartTime));
-            out.attribute(null, "end", Long.toString(dit.mEndTime));
+            out.attributeLong(null, "start", dit.mStartTime);
+            out.attributeLong(null, "end", dit.mEndTime);
             writeDailyLevelSteps(out, "dis", dit.mDischargeSteps, sb);
             writeDailyLevelSteps(out, "chg", dit.mChargeSteps, sb);
             if (dit.mPackageChanges != null) {
@@ -10878,7 +10878,7 @@
                     if (pc.mUpdate) {
                         out.startTag(null, "upd");
                         out.attribute(null, "pkg", pc.mPackageName);
-                        out.attribute(null, "ver", Long.toString(pc.mVersionCode));
+                        out.attributeLong(null, "ver", pc.mVersionCode);
                         out.endTag(null, "upd");
                     } else {
                         out.startTag(null, "rem");
@@ -10893,11 +10893,11 @@
         out.endDocument();
     }
 
-    private void writeDailyLevelSteps(XmlSerializer out, String tag, LevelStepTracker steps,
+    private void writeDailyLevelSteps(TypedXmlSerializer out, String tag, LevelStepTracker steps,
             StringBuilder tmpBuilder) throws IOException {
         if (steps != null) {
             out.startTag(null, tag);
-            out.attribute(null, "n", Integer.toString(steps.mNumStepDurations));
+            out.attributeInt(null, "n", steps.mNumStepDurations);
             for (int i=0; i<steps.mNumStepDurations; i++) {
                 out.startTag(null, "s");
                 tmpBuilder.setLength(0);
@@ -10919,10 +10919,9 @@
             return;
         }
         try {
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(stream, StandardCharsets.UTF_8.name());
+            TypedXmlPullParser parser = Xml.resolvePullParser(stream);
             readDailyItemsLocked(parser);
-        } catch (XmlPullParserException e) {
+        } catch (IOException e) {
         } finally {
             try {
                 stream.close();
@@ -10931,7 +10930,7 @@
         }
     }
 
-    private void readDailyItemsLocked(XmlPullParser parser) {
+    private void readDailyItemsLocked(TypedXmlPullParser parser) {
         try {
             int type;
             while ((type = parser.next()) != XmlPullParser.START_TAG
@@ -10975,17 +10974,11 @@
         }
     }
 
-    void readDailyItemTagLocked(XmlPullParser parser) throws NumberFormatException,
+    void readDailyItemTagLocked(TypedXmlPullParser parser) throws NumberFormatException,
             XmlPullParserException, IOException {
         DailyItem dit = new DailyItem();
-        String attr = parser.getAttributeValue(null, "start");
-        if (attr != null) {
-            dit.mStartTime = Long.parseLong(attr);
-        }
-        attr = parser.getAttributeValue(null, "end");
-        if (attr != null) {
-            dit.mEndTime = Long.parseLong(attr);
-        }
+        dit.mStartTime = parser.getAttributeLong(null, "start", 0);
+        dit.mEndTime = parser.getAttributeLong(null, "end", 0);
         int outerDepth = parser.getDepth();
         int type;
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -11006,8 +10999,7 @@
                 PackageChange pc = new PackageChange();
                 pc.mUpdate = true;
                 pc.mPackageName = parser.getAttributeValue(null, "pkg");
-                String verStr = parser.getAttributeValue(null, "ver");
-                pc.mVersionCode = verStr != null ? Long.parseLong(verStr) : 0;
+                pc.mVersionCode = parser.getAttributeLong(null, "ver", 0);
                 dit.mPackageChanges.add(pc);
                 XmlUtils.skipCurrentTag(parser);
             } else if (tagName.equals("rem")) {
@@ -11028,16 +11020,15 @@
         mDailyItems.add(dit);
     }
 
-    void readDailyItemTagDetailsLocked(XmlPullParser parser, DailyItem dit, boolean isCharge,
+    void readDailyItemTagDetailsLocked(TypedXmlPullParser parser, DailyItem dit, boolean isCharge,
             String tag)
             throws NumberFormatException, XmlPullParserException, IOException {
-        final String numAttr = parser.getAttributeValue(null, "n");
-        if (numAttr == null) {
+        final int num = parser.getAttributeInt(null, "n", -1);
+        if (num == -1) {
             Slog.w(TAG, "Missing 'n' attribute at " + parser.getPositionDescription());
             XmlUtils.skipCurrentTag(parser);
             return;
         }
-        final int num = Integer.parseInt(numAttr);
         LevelStepTracker steps = new LevelStepTracker(num);
         if (isCharge) {
             dit.mChargeSteps = steps;
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
new file mode 100644
index 0000000..62e9f98
--- /dev/null
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -0,0 +1,76 @@
+/*
+ * 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.internal.os;
+
+import android.content.Context;
+import android.os.BatteryConsumer;
+import android.os.BatteryStats;
+import android.os.BatteryUsageStats;
+import android.os.Bundle;
+import android.os.UidBatteryConsumer;
+import android.os.UserManager;
+
+import java.util.List;
+
+/**
+ * Uses accumulated battery stats data and PowerCalculators to produce power
+ * usage data attributed to subsystems and UIDs.
+ */
+public class BatteryUsageStatsProvider {
+    private final Context mContext;
+    private final BatteryStatsImpl mStats;
+
+    public BatteryUsageStatsProvider(Context context, BatteryStatsImpl stats) {
+        mContext = context;
+        mStats = stats;
+    }
+
+    /**
+     * Returns a snapshot of battery attribution data.
+     */
+    public BatteryUsageStats getBatteryUsageStats() {
+
+        // TODO(b/174186345): instead of BatteryStatsHelper, use PowerCalculators directly.
+        final BatteryStatsHelper batteryStatsHelper = new BatteryStatsHelper(mContext,
+                false /* collectBatteryBroadcast */);
+        batteryStatsHelper.create((Bundle) null);
+        final UserManager userManager = mContext.getSystemService(UserManager.class);
+        batteryStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED,
+                userManager.getUserProfiles());
+
+        // TODO(b/174186358): read extra power component number from configuration
+        final int customPowerComponentCount = 0;
+        final BatteryUsageStats.Builder batteryUsageStatsBuilder = new BatteryUsageStats.Builder()
+                .setDischargePercentage(batteryStatsHelper.getStats().getDischargeAmount(0))
+                .setConsumedPower(batteryStatsHelper.getTotalPower());
+
+        final List<BatterySipper> usageList = batteryStatsHelper.getUsageList();
+        for (int i = 0; i < usageList.size(); i++) {
+            final BatterySipper sipper = usageList.get(i);
+            if (sipper.drainType == BatterySipper.DrainType.APP) {
+                batteryUsageStatsBuilder.addUidBatteryConsumer(
+                        new UidBatteryConsumer.Builder(customPowerComponentCount, sipper.getUid())
+                                .setPackageWithHighestDrain(sipper.packageWithHighestDrain)
+                                .setConsumedPower(sipper.sumPower())
+                                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU,
+                                        sipper.cpuPowerMah)
+                                .build());
+            }
+        }
+        return batteryUsageStatsBuilder.build();
+    }
+}
diff --git a/core/java/com/android/internal/os/KernelWakelockReader.java b/core/java/com/android/internal/os/KernelWakelockReader.java
index f668bba..e595db3 100644
--- a/core/java/com/android/internal/os/KernelWakelockReader.java
+++ b/core/java/com/android/internal/os/KernelWakelockReader.java
@@ -184,6 +184,7 @@
 
         try {
             wlStats = mSuspendControlService.getWakeLockStats();
+            Slog.i(TAG, "Number of wakelock obtained from SystemSuspend: " + wlStats.length);
             updateWakelockStats(wlStats, staleStats);
         } catch (RemoteException e) {
             Slog.wtf(TAG, "Failed to obtain wakelock stats from ISuspendControlService", e);
diff --git a/core/java/com/android/internal/os/OWNERS b/core/java/com/android/internal/os/OWNERS
index afc9432..633d093 100644
--- a/core/java/com/android/internal/os/OWNERS
+++ b/core/java/com/android/internal/os/OWNERS
@@ -1 +1 @@
-per-file ZygoteArguments.java,ZygoteConnection.java,ZygoteInit.java,Zygote.java,ZygoteServer.java = calin@google.com, chriswailes@google.com, maco@google.com, narayan@google.com, ngeoffray@google.com
+per-file *Zygote* = file:/ZYGOTE_OWNERS
diff --git a/core/java/com/android/internal/policy/OWNERS b/core/java/com/android/internal/policy/OWNERS
new file mode 100644
index 0000000..0862c05
--- /dev/null
+++ b/core/java/com/android/internal/policy/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/core/java/com/android/internal/statusbar/OWNERS b/core/java/com/android/internal/statusbar/OWNERS
new file mode 100644
index 0000000..2e96c97
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/OWNERS
@@ -0,0 +1 @@
+include /packages/SystemUI/OWNERS
diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 44dca9b..854fb17 100644
--- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -69,6 +69,6 @@
     void onRegistrationFailed(in CellIdentity cellIdentity,
              String chosenPlmn, int domain, int causeCode, int additionalCauseCode);
     void onBarringInfoChanged(in BarringInfo barringInfo);
-    void onPhysicalChannelConfigurationChanged(in List<PhysicalChannelConfig> configs);
-
+    void onPhysicalChannelConfigChanged(in List<PhysicalChannelConfig> configs);
+    void onDataEnabledChanged(boolean enabled, int reason);
 }
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index a28a663..c2cbc04 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -41,16 +41,9 @@
             IOnSubscriptionsChangedListener callback);
     void removeOnSubscriptionsChangedListener(String pkg,
             IOnSubscriptionsChangedListener callback);
-    /**
-      * @deprecated Use {@link #listenWithFeature(String, String, IPhoneStateListener, int,
-      * boolean) instead
-      */
-    @UnsupportedAppUsage
-    void listen(String pkg, IPhoneStateListener callback, int events, boolean notifyNow);
-    void listenWithFeature(String pkg, String featureId, IPhoneStateListener callback, long events,
-            boolean notifyNow);
-    void listenForSubscriber(in int subId, String pkg, String featureId,
-            IPhoneStateListener callback, long events, boolean notifyNow);
+
+    void listenWithEventList(in int subId, String pkg, String featureId,
+            IPhoneStateListener callback, in int[] events, boolean notifyNow);
     @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
     void notifyCallStateForAllSubs(int state, String incomingNumber);
     void notifyCallState(in int phoneId, in int subId, int state, String incomingNumber);
@@ -99,6 +92,6 @@
     void notifyRegistrationFailed(int slotIndex, int subId, in CellIdentity cellIdentity,
             String chosenPlmn, int domain, int causeCode, int additionalCauseCode);
     void notifyBarringInfoChanged(int slotIndex, int subId, in BarringInfo barringInfo);
-    void notifyPhysicalChannelConfigurationForSubscriber(in int subId,
+    void notifyPhysicalChannelConfigForSubscriber(in int subId,
             in List<PhysicalChannelConfig> configs);
 }
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index e067f5f..5388235 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -208,6 +208,13 @@
     }
 
     /**
+     * Length of the given map or 0 if it's null.
+     */
+    public static int size(@Nullable Map<?, ?> map) {
+        return map == null ? 0 : map.size();
+    }
+
+    /**
      * Checks that value is present as at least one of the elements of the array.
      * @param array the array to check in
      * @param value the value to check for
diff --git a/core/java/com/android/internal/util/BinaryXmlSerializer.java b/core/java/com/android/internal/util/BinaryXmlSerializer.java
index d3fcf71..bc3b1f8 100644
--- a/core/java/com/android/internal/util/BinaryXmlSerializer.java
+++ b/core/java/com/android/internal/util/BinaryXmlSerializer.java
@@ -69,7 +69,7 @@
      * {@code ABX_}, representing "Android Binary XML." The final byte is a
      * version number which may be incremented as the protocol changes.
      */
-    static final byte[] PROTOCOL_MAGIC_VERSION_0 = new byte[] { 0x41, 0x42, 0x58, 0x00 };
+    public static final byte[] PROTOCOL_MAGIC_VERSION_0 = new byte[] { 0x41, 0x42, 0x58, 0x00 };
 
     /**
      * Internal token which represents an attribute associated with the most
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index 8eb0e28..244efc5 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -53,6 +53,7 @@
 public class XmlUtils {
     private static final String STRING_ARRAY_SEPARATOR = ":";
 
+    @SuppressWarnings("AndroidFrameworkEfficientXml")
     private static class ForcedTypedXmlSerializer extends XmlSerializerWrapper
             implements TypedXmlSerializer {
         public ForcedTypedXmlSerializer(XmlSerializer wrapped) {
@@ -133,6 +134,7 @@
         }
     }
 
+    @SuppressWarnings("AndroidFrameworkEfficientXml")
     private static class ForcedTypedXmlPullParser extends XmlPullParserWrapper
             implements TypedXmlPullParser {
         public ForcedTypedXmlPullParser(XmlPullParser wrapped) {
@@ -1715,6 +1717,7 @@
         }
     }
 
+    @SuppressWarnings("AndroidFrameworkEfficientXml")
     public static int readIntAttribute(XmlPullParser in, String name, int defaultValue) {
         if (in instanceof TypedXmlPullParser) {
             return ((TypedXmlPullParser) in).getAttributeInt(null, name, defaultValue);
@@ -1730,6 +1733,7 @@
         }
     }
 
+    @SuppressWarnings("AndroidFrameworkEfficientXml")
     public static int readIntAttribute(XmlPullParser in, String name) throws IOException {
         if (in instanceof TypedXmlPullParser) {
             try {
@@ -1746,6 +1750,7 @@
         }
     }
 
+    @SuppressWarnings("AndroidFrameworkEfficientXml")
     public static void writeIntAttribute(XmlSerializer out, String name, int value)
             throws IOException {
         if (out instanceof TypedXmlSerializer) {
@@ -1755,6 +1760,7 @@
         out.attribute(null, name, Integer.toString(value));
     }
 
+    @SuppressWarnings("AndroidFrameworkEfficientXml")
     public static long readLongAttribute(XmlPullParser in, String name, long defaultValue) {
         if (in instanceof TypedXmlPullParser) {
             return ((TypedXmlPullParser) in).getAttributeLong(null, name, defaultValue);
@@ -1770,6 +1776,7 @@
         }
     }
 
+    @SuppressWarnings("AndroidFrameworkEfficientXml")
     public static long readLongAttribute(XmlPullParser in, String name) throws IOException {
         if (in instanceof TypedXmlPullParser) {
             try {
@@ -1786,6 +1793,7 @@
         }
     }
 
+    @SuppressWarnings("AndroidFrameworkEfficientXml")
     public static void writeLongAttribute(XmlSerializer out, String name, long value)
             throws IOException {
         if (out instanceof TypedXmlSerializer) {
@@ -1795,6 +1803,7 @@
         out.attribute(null, name, Long.toString(value));
     }
 
+    @SuppressWarnings("AndroidFrameworkEfficientXml")
     public static float readFloatAttribute(XmlPullParser in, String name) throws IOException {
         if (in instanceof TypedXmlPullParser) {
             try {
@@ -1811,6 +1820,7 @@
         }
     }
 
+    @SuppressWarnings("AndroidFrameworkEfficientXml")
     public static void writeFloatAttribute(XmlSerializer out, String name, float value)
             throws IOException {
         if (out instanceof TypedXmlSerializer) {
@@ -1820,10 +1830,12 @@
         out.attribute(null, name, Float.toString(value));
     }
 
+    @SuppressWarnings("AndroidFrameworkEfficientXml")
     public static boolean readBooleanAttribute(XmlPullParser in, String name) {
         return readBooleanAttribute(in, name, false);
     }
 
+    @SuppressWarnings("AndroidFrameworkEfficientXml")
     public static boolean readBooleanAttribute(XmlPullParser in, String name,
             boolean defaultValue) {
         if (in instanceof TypedXmlPullParser) {
@@ -1837,6 +1849,7 @@
         }
     }
 
+    @SuppressWarnings("AndroidFrameworkEfficientXml")
     public static void writeBooleanAttribute(XmlSerializer out, String name, boolean value)
             throws IOException {
         if (out instanceof TypedXmlSerializer) {
@@ -1869,6 +1882,7 @@
         }
     }
 
+    @SuppressWarnings("AndroidFrameworkEfficientXml")
     public static byte[] readByteArrayAttribute(XmlPullParser in, String name) {
         if (in instanceof TypedXmlPullParser) {
             try {
@@ -1885,6 +1899,7 @@
         }
     }
 
+    @SuppressWarnings("AndroidFrameworkEfficientXml")
     public static void writeByteArrayAttribute(XmlSerializer out, String name, byte[] value)
             throws IOException {
         if (value != null) {
diff --git a/core/java/com/android/internal/widget/DecorCaptionView.java b/core/java/com/android/internal/widget/DecorCaptionView.java
index 2102145..362fd7b 100644
--- a/core/java/com/android/internal/widget/DecorCaptionView.java
+++ b/core/java/com/android/internal/widget/DecorCaptionView.java
@@ -18,9 +18,7 @@
 
 import android.content.Context;
 import android.graphics.Rect;
-import android.os.RemoteException;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.GestureDetector;
 import android.view.MotionEvent;
 import android.view.View;
@@ -72,7 +70,6 @@
  */
 public class DecorCaptionView extends ViewGroup implements View.OnTouchListener,
         GestureDetector.OnGestureListener {
-    private final static String TAG = "DecorCaptionView";
     private PhoneWindow mOwner = null;
     private boolean mShow = false;
 
@@ -327,11 +324,7 @@
     private void toggleFreeformWindowingMode() {
         Window.WindowControllerCallback callback = mOwner.getWindowControllerCallback();
         if (callback != null) {
-            try {
-                callback.toggleFreeformWindowingMode();
-            } catch (RemoteException ex) {
-                Log.e(TAG, "Cannot change task workspace.");
-            }
+            callback.toggleFreeformWindowingMode();
         }
     }
 
diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java
index ac2361d..b4d8e50 100644
--- a/core/java/com/android/server/BootReceiver.java
+++ b/core/java/com/android/server/BootReceiver.java
@@ -35,24 +35,23 @@
 import android.util.AtomicFile;
 import android.util.EventLog;
 import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.regex.Matcher;
@@ -712,8 +711,7 @@
             HashMap<String, Long> timestamps = new HashMap<String, Long>();
             boolean success = false;
             try (final FileInputStream stream = sFile.openRead()) {
-                XmlPullParser parser = Xml.newPullParser();
-                parser.setInput(stream, StandardCharsets.UTF_8.name());
+                TypedXmlPullParser parser = Xml.resolvePullParser(stream);
 
                 int type;
                 while ((type = parser.next()) != XmlPullParser.START_TAG
@@ -735,8 +733,7 @@
                     String tagName = parser.getName();
                     if (tagName.equals("log")) {
                         final String filename = parser.getAttributeValue(null, "filename");
-                        final long timestamp = Long.valueOf(parser.getAttributeValue(
-                                    null, "timestamp"));
+                        final long timestamp = parser.getAttributeLong(null, "timestamp");
                         timestamps.put(filename, timestamp);
                     } else {
                         Slog.w(TAG, "Unknown tag: " + parser.getName());
@@ -775,8 +772,7 @@
             }
 
             try {
-                XmlSerializer out = new FastXmlSerializer();
-                out.setOutput(stream, StandardCharsets.UTF_8.name());
+                TypedXmlSerializer out = Xml.resolveSerializer(stream);
                 out.startDocument(null, true);
                 out.startTag(null, "log-files");
 
@@ -785,7 +781,7 @@
                     String filename = itor.next();
                     out.startTag(null, "log");
                     out.attribute(null, "filename", filename);
-                    out.attribute(null, "timestamp", timestamps.get(filename).toString());
+                    out.attributeLong(null, "timestamp", timestamps.get(filename));
                     out.endTag(null, "log");
                 }
 
diff --git a/core/java/com/android/server/backup/PermissionBackupHelper.java b/core/java/com/android/server/backup/PermissionBackupHelper.java
index c7c423b..4d1949e 100644
--- a/core/java/com/android/server/backup/PermissionBackupHelper.java
+++ b/core/java/com/android/server/backup/PermissionBackupHelper.java
@@ -17,8 +17,8 @@
 package com.android.server.backup;
 
 import android.annotation.NonNull;
+import android.annotation.UserIdInt;
 import android.app.backup.BlobBackupHelper;
-import android.os.UserHandle;
 import android.permission.PermissionManagerInternal;
 import android.util.Slog;
 
@@ -34,14 +34,14 @@
     // key under which the permission-grant state blob is committed to backup
     private static final String KEY_PERMISSIONS = "permissions";
 
-    private final @NonNull UserHandle mUser;
+    private final @UserIdInt int mUserId;
 
     private final @NonNull PermissionManagerInternal mPermissionManager;
 
     public PermissionBackupHelper(int userId) {
         super(STATE_VERSION, KEY_PERMISSIONS);
 
-        mUser = UserHandle.of(userId);
+        mUserId = userId;
         mPermissionManager = LocalServices.getService(PermissionManagerInternal.class);
     }
 
@@ -53,7 +53,7 @@
         try {
             switch (key) {
                 case KEY_PERMISSIONS:
-                    return mPermissionManager.backupRuntimePermissions(mUser);
+                    return mPermissionManager.backupRuntimePermissions(mUserId);
 
                 default:
                     Slog.w(TAG, "Unexpected backup key " + key);
@@ -72,7 +72,7 @@
         try {
             switch (key) {
                 case KEY_PERMISSIONS:
-                    mPermissionManager.restoreRuntimePermissions(payload, mUser);
+                    mPermissionManager.restoreRuntimePermissions(payload, mUserId);
                     break;
 
                 default:
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index 7d80993..bcd1278 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -16,5 +16,21 @@
 per-file android_view_*MotionEvent.* = michaelwr@google.com, svv@google.com
 per-file android_view_PointerIcon.* = michaelwr@google.com, svv@google.com
 
-# Zygote
-per-file com_android_internal_os_Zygote.*,fd_utils.* = calin@google.com, chriswailes@google.com, maco@google.com, narayan@google.com, ngeoffray@google.com
+per-file *Zygote* = file:/ZYGOTE_OWNERS
+per-file Android.bp = file:platform/build/soong:/OWNERS
+per-file android_animation_* = file:/core/java/android/animation/OWNERS
+per-file android_app_admin_* = file:/core/java/android/app/admin/OWNERS
+per-file android_content_res_* = file:/core/java/android/content/res/OWNERS
+per-file android_graphics_* = file:/graphics/java/android/graphics/OWNERS
+per-file android_hardware_Usb* = file:/services/usb/OWNERS
+per-file android_hardware_display_* = file:/core/java/android/hardware/display/OWNERS
+per-file android_hardware_input_* = file:/core/java/android/hardware/input/OWNERS
+per-file android_hardware_location_* = file:/core/java/android/hardware/location/OWNERS
+per-file android_media_* = file:/media/java/android/media/OWNERS
+per-file android_media_midi_* = file:/media/java/android/media/midi/OWNERS
+per-file android_opengl_* = file:/opengl/java/android/opengl/OWNERS
+per-file android_os_storage_* = file:/core/java/android/os/storage/OWNERS
+per-file android_se_* = file:/core/java/android/se/OWNERS
+per-file android_security_* = file:/core/java/android/security/OWNERS
+per-file android_view_* = file:/core/java/android/view/OWNERS
+per-file com_android_internal_net_* = file:/services/core/java/com/android/server/net/OWNERS
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 5a859aa..bf79a44 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -571,6 +571,9 @@
     MEMINFO_PAGE_TABLES,
     MEMINFO_KERNEL_STACK,
     MEMINFO_KERNEL_RECLAIMABLE,
+    MEMINFO_ACTIVE,
+    MEMINFO_INACTIVE,
+    MEMINFO_UNEVICTABLE,
     MEMINFO_COUNT
 };
 
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index d187220..9113111 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -313,7 +313,41 @@
         // The minimum amount of time between quota check alarms.
         optional int64 min_quota_check_delay_ms = 23;
 
-        // Next tag: 24
+        // The total session limit of the particular standby bucket. Apps in this standby bucket can
+        // only have HPJ sessions totalling HPJ_LIMIT (without factoring in any rewards or free
+        // HPJs).
+        optional int64 hpj_limit_active_ms = 24;
+        // The total session limit of the particular standby bucket. Apps in this standby bucket can
+        // only have HPJ sessions totalling HPJ_LIMIT (without factoring in any rewards or free
+        // HPJs).
+        optional int64 hpj_limit_working_ms = 25;
+        // The total session limit of the particular standby bucket. Apps in this standby bucket can
+        // only have HPJ sessions totalling HPJ_LIMIT (without factoring in any rewards or free
+        // HPJs).
+        optional int64 hpj_limit_frequent_ms = 26;
+        // The total session limit of the particular standby bucket. Apps in this standby bucket can
+        // only have HPJ sessions totalling HPJ_LIMIT (without factoring in any rewards or free
+        // HPJs).
+        optional int64 hpj_limit_rare_ms = 27;
+        // The total session limit of the particular standby bucket. Apps in this standby bucket can
+        // only have HPJ sessions totalling HPJ_LIMIT (without factoring in any rewards or free
+        // HPJs).
+        optional int64 hpj_limit_restricted_ms = 28;
+        // The period of time used to calculate HPJ sessions. Apps can only have HPJ sessions
+        // totalling HPJ_LIMIT_<bucket>_MS within this period of time (without factoring in any
+        // rewards or free HPJs).
+        optional int64 hpj_window_size_ms = 29;
+        // Length of time used to split an app's top time into chunks.
+        optional int64 hpj_top_app_time_chunk_size_ms = 30;
+        // How much HPJ quota to give back to an app based on the number of top app time chunks
+        // it had.
+        optional int64 hpj_reward_top_app_ms = 31;
+        // How much HPJ quota to give back to an app based on each non-top user interaction.
+        optional int64 hpj_reward_interaction_ms = 32;
+        // How much HPJ quota to give back to an app based on each notification seen event.
+        optional int64 hpj_reward_notification_seen_ms = 33;
+
+        // Next tag: 34
     }
     optional QuotaController quota_controller = 24;
 
@@ -560,6 +594,11 @@
             // The amount of time that this job has remaining in its quota. This
             // can be negative if the job is out of quota.
             optional int64 remaining_quota_ms = 6;
+            // True if the app has requested that this be a foreground job.
+            optional bool is_requested_foreground_job = 7;
+            // True if this job is within the foreground quota bounds and is therefore allowed to
+            // run as a foreground job. Valid only if is_foreground_requested_job is true.
+            optional bool is_within_fg_job_quota = 8;
         }
         repeated TrackedJob tracked_jobs = 4;
 
@@ -665,6 +704,19 @@
             repeated JobStatusShortInfoProto running_jobs = 5;
         }
 
+        message TopAppTimer {
+            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+            optional Package pkg = 1;
+            // True if the Timer is actively tracking jobs.
+            optional bool is_active = 2;
+            // The time this timer last became active. Only valid if is_active is true.
+            optional int64 start_time_elapsed = 3;
+            // How many activities are currently in the RESUMED state. Valid only if is_active is
+            // true.
+            optional int32 activity_count = 4;
+        }
+
         message PackageStats {
             option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
@@ -677,6 +729,8 @@
             repeated ExecutionStats execution_stats = 4;
 
             reserved 5; // in_quota_alarm_listener
+
+            optional Timer fg_job_timer = 6;
         }
         repeated PackageStats package_stats = 5;
 
diff --git a/core/res/OWNERS b/core/res/OWNERS
new file mode 100644
index 0000000..263d638
--- /dev/null
+++ b/core/res/OWNERS
@@ -0,0 +1,17 @@
+adamp@google.com
+alanv@google.com
+dsandler@android.com
+dsandler@google.com
+hackbod@android.com
+hackbod@google.com
+jsharkey@android.com
+jsharkey@google.com
+michaelwr@google.com
+nandana@google.com
+narayan@google.com
+ogunwale@google.com
+patb@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
+toddke@google.com
+yamasani@google.com
diff --git a/core/res/res/drawable/view_accessibility_focused.xml b/core/res/res/drawable/view_accessibility_focused.xml
index 025916b..aa3031e 100644
--- a/core/res/res/drawable/view_accessibility_focused.xml
+++ b/core/res/res/drawable/view_accessibility_focused.xml
@@ -17,8 +17,8 @@
 <shape xmlns:android="http://schemas.android.com/apk/res/android" >
 
     <stroke
-        android:width="4dp"
-        android:color="@color/accessibility_focus_highlight" />
+        android:width="@dimen/accessibility_focus_highlight_stroke_width"
+        android:color="@color/accessibility_focus_highlight_color" />
 
     <corners android:radius="2dp" />
 
diff --git a/core/res/res/layout/notification_top_line_views.xml b/core/res/res/layout/notification_top_line_views.xml
index c71e886..60507ed 100644
--- a/core/res/res/layout/notification_top_line_views.xml
+++ b/core/res/res/layout/notification_top_line_views.xml
@@ -88,7 +88,7 @@
 
     <DateTimeView
         android:id="@+id/time"
-        android:textAppearance="@style/TextAppearance.Material.Notification.Time"
+        android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Time"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginStart="@dimen/notification_header_separating_margin"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 03e64a4..f4c3063 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3334,11 +3334,11 @@
 
         <!-- Sets whether this ViewGroup should split MotionEvents
              to separate child views during touch event dispatch.
-             If false (default), touch events will be dispatched to
+             If false (default prior to HONEYCOMB), touch events will be dispatched to
              the child view where the first pointer went down until
              the last pointer goes up.
-             If true, touch events may be dispatched to multiple children.
-             MotionEvents for each pointer will be dispatched to the child
+             If true (default for HONEYCOMB and later), touch events may be dispatched to
+             multiple children. MotionEvents for each pointer will be dispatched to the child
              view where the initial ACTION_DOWN event happened.
              See {@link android.view.ViewGroup#setMotionEventSplittingEnabled(boolean)}
              for more information. -->
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 0079d8c..110e77a 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -159,7 +159,7 @@
     <color name="keyguard_avatar_nick_color">#ffffffff</color>
     <color name="keyguard_avatar_frame_pressed_color">#ff35b5e5</color>
 
-    <color name="accessibility_focus_highlight">#bf39b500</color>
+    <color name="accessibility_focus_highlight_color">#bf39b500</color>
     <color name="autofilled_highlight">#4dffeb3b</color>
 
     <color name="system_notification_accent_color">#ff607D8B</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 84e6f12c..40e11cb 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1613,21 +1613,28 @@
     <!-- Whether the geolocation time zone detection feature is enabled. -->
     <bool name="config_enableGeolocationTimeZoneDetection" translatable="false">true</bool>
 
-    <!-- Whether to enable primary location time zone provider overlay which allows the primary
-         location time zone provider to be replaced by an app at run-time. When disabled, only the
+    <!-- Whether the primary LocationTimeZoneProvider is enabled device.
+         Ignored if config_enableGeolocationTimeZoneDetection is false -->
+    <bool name="config_enablePrimaryLocationTimeZoneProvider" translatable="false">false</bool>
+    <!-- Used when enablePrimaryLocationTimeZoneProvider is true. Controls whether to enable primary
+         location time zone provider overlay which allows the primary location time zone provider to
+         be replaced by an app at run-time. When disabled, only the
          config_primaryLocationTimeZoneProviderPackageName package will be searched for the primary
          location time zone provider, otherwise any system package is eligible. Anyone who wants to
-         disable the overlay mechanism can set it to false. -->
+         disable the runtime overlay mechanism can set it to false. -->
     <bool name="config_enablePrimaryLocationTimeZoneOverlay" translatable="false">false</bool>
     <!-- Package name providing the primary location time zone provider. Used only when
          config_enablePrimaryLocationTimeZoneOverlay is false. -->
     <string name="config_primaryLocationTimeZoneProviderPackageName" translatable="false">@null</string>
 
-    <!-- Whether to enable secondary location time zone provider overlay which allows the secondary
-         location time zone provider to be replaced by an app at run-time. When disabled, only the
-         config_secondaryLocationTimeZoneProviderPackageName package will be searched for the
-         secondary location time zone provider, otherwise any system package is eligible. Anyone who
-         wants to disable the overlay mechanism can set it to false. -->
+    <!-- Whether the secondary LocationTimeZoneProvider is enabled device.
+         Ignored if config_enableGeolocationTimeZoneDetection is false -->
+    <bool name="config_enableSecondaryLocationTimeZoneProvider" translatable="false">true</bool>
+    <!-- Used when enableSecondaryLocationTimeZoneProvider is true. Controls whether to enable
+         secondary location time zone provider overlay which allows the primary location time zone
+         provider to config_secondaryLocationTimeZoneProviderPackageName package will be searched
+         for the secondary location time zone provider, otherwise any system package is eligible.
+         Anyone who wants to disable the runtime overlay mechanism can set it to false. -->
     <bool name="config_enableSecondaryLocationTimeZoneOverlay" translatable="false">false</bool>
     <!-- Package name providing the secondary location time zone provider. Used only when
          config_enableSecondaryLocationTimeZoneOverlay is false.
@@ -4515,7 +4522,7 @@
     <integer name="config_pdp_reject_retry_delay_ms">-1</integer>
 
     <!-- Whether or not to enable the binder heavy hitter watcher by default -->
-    <bool name="config_defaultBinderHeavyHitterWatcherEnabled">true</bool>
+    <bool name="config_defaultBinderHeavyHitterWatcherEnabled">false</bool>
 
     <!-- The default batch size for the binder heavy hitter watcher -->
     <integer name="config_defaultBinderHeavyHitterWatcherBatchSize">2000</integer>
@@ -4526,7 +4533,7 @@
     </item>
 
     <!-- Whether or not to enable the binder heavy hitter auto sampler by default -->
-    <bool name="config_defaultBinderHeavyHitterAutoSamplerEnabled">true</bool>
+    <bool name="config_defaultBinderHeavyHitterAutoSamplerEnabled">false</bool>
 
     <!-- The default batch size for the binder heavy hitter auto sampler -->
     <integer name="config_defaultBinderHeavyHitterAutoSamplerBatchSize">400</integer>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 4bcabff..05db741 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -553,6 +553,9 @@
     <!-- Width of the outline stroke used by the accessibility screen magnification indicator -->
     <dimen name="accessibility_magnification_indicator_width">4dip</dimen>
 
+    <!-- Width of the outline stroke used by the accessibility focus rectangle -->
+    <dimen name="accessibility_focus_highlight_stroke_width">4dp</dimen>
+
     <!-- Margin around the various security views -->
     <dimen name="keyguard_muliuser_selector_margin">8dp</dimen>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index cd00fbf..e50eee6 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2168,8 +2168,10 @@
   <java-symbol type="string" name="config_deviceConfiguratorPackageName" />
   <java-symbol type="array" name="config_autoTimeSourcesPriority" />
   <java-symbol type="bool" name="config_enableGeolocationTimeZoneDetection" />
+  <java-symbol type="bool" name="config_enablePrimaryLocationTimeZoneProvider" />
   <java-symbol type="bool" name="config_enablePrimaryLocationTimeZoneOverlay" />
   <java-symbol type="string" name="config_primaryLocationTimeZoneProviderPackageName" />
+  <java-symbol type="bool" name="config_enableSecondaryLocationTimeZoneProvider" />
   <java-symbol type="bool" name="config_enableSecondaryLocationTimeZoneOverlay" />
   <java-symbol type="string" name="config_secondaryLocationTimeZoneProviderPackageName" />
 
@@ -4115,4 +4117,9 @@
 
   <!-- Component with platform query permissions for AppSearch -->
   <java-symbol type="string" name="config_defaultAppSearchPlatformQuerierComponent" />
+
+  <!-- Color used by the accessibility focus rectangle -->
+  <java-symbol type="color" name="accessibility_focus_highlight_color" />
+  <!-- Width of the outline stroke used by the accessibility focus rectangle -->
+  <java-symbol type="dimen" name="accessibility_focus_highlight_stroke_width" />
 </resources>
diff --git a/core/tests/ConnectivityManagerTest/OWNERS b/core/tests/ConnectivityManagerTest/OWNERS
new file mode 100644
index 0000000..aa87958
--- /dev/null
+++ b/core/tests/ConnectivityManagerTest/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/net/OWNERS
diff --git a/core/tests/PackageInstallerSessions/OWNERS b/core/tests/PackageInstallerSessions/OWNERS
new file mode 100644
index 0000000..d825dfd
--- /dev/null
+++ b/core/tests/PackageInstallerSessions/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/OWNERS
diff --git a/core/tests/benchmarks/src/android/net/OWNERS b/core/tests/benchmarks/src/android/net/OWNERS
new file mode 100644
index 0000000..aa87958
--- /dev/null
+++ b/core/tests/benchmarks/src/android/net/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/net/OWNERS
diff --git a/core/tests/bluetoothtests/OWNERS b/core/tests/bluetoothtests/OWNERS
new file mode 100644
index 0000000..98bb877
--- /dev/null
+++ b/core/tests/bluetoothtests/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/bluetooth/OWNERS
diff --git a/core/tests/coretests/apks/OWNERS b/core/tests/coretests/apks/OWNERS
new file mode 100644
index 0000000..d825dfd
--- /dev/null
+++ b/core/tests/coretests/apks/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/OWNERS
diff --git a/core/tests/coretests/src/android/accessibilityservice/OWNERS b/core/tests/coretests/src/android/accessibilityservice/OWNERS
new file mode 100644
index 0000000..b74281e
--- /dev/null
+++ b/core/tests/coretests/src/android/accessibilityservice/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/accessibility/OWNERS
diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/SetSchemaRequestTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/SetSchemaRequestTest.java
new file mode 100644
index 0000000..e03cea3
--- /dev/null
+++ b/core/tests/coretests/src/android/app/appsearch/external/app/SetSchemaRequestTest.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.appsearch;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.expectThrows;
+
+import org.junit.Test;
+
+public class SetSchemaRequestTest {
+
+    @Test
+    public void testInvalidSchemaReferences() {
+        IllegalArgumentException expected =
+                expectThrows(
+                        IllegalArgumentException.class,
+                        () ->
+                                new SetSchemaRequest.Builder()
+                                        .setSchemaTypeVisibilityForSystemUi(false, "InvalidSchema")
+                                        .build());
+        assertThat(expected).hasMessageThat().contains("referenced, but were not added");
+    }
+
+    @Test
+    public void testSchemaTypeVisibilityForSystemUi_Visible() {
+        AppSearchSchema schema = new AppSearchSchema.Builder("Schema").build();
+
+        // By default, the schema is visible.
+        SetSchemaRequest request = new SetSchemaRequest.Builder().addSchema(schema).build();
+        assertThat(request.getSchemasNotPlatformSurfaceable()).isEmpty();
+
+        request =
+                new SetSchemaRequest.Builder()
+                        .addSchema(schema)
+                        .setSchemaTypeVisibilityForSystemUi(true, "Schema")
+                        .build();
+        assertThat(request.getSchemasNotPlatformSurfaceable()).isEmpty();
+    }
+
+    @Test
+    public void testSchemaTypeVisibilityForSystemUi_NotVisible() {
+        AppSearchSchema schema = new AppSearchSchema.Builder("Schema").build();
+        SetSchemaRequest request =
+                new SetSchemaRequest.Builder()
+                        .addSchema(schema)
+                        .setSchemaTypeVisibilityForSystemUi(false, "Schema")
+                        .build();
+        assertThat(request.getSchemasNotPlatformSurfaceable()).containsExactly("Schema");
+    }
+}
diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/cts/AppSearchSchemaCtsTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/cts/AppSearchSchemaCtsTest.java
index 2eaebd6..7072a81 100644
--- a/core/tests/coretests/src/android/app/appsearch/external/app/cts/AppSearchSchemaCtsTest.java
+++ b/core/tests/coretests/src/android/app/appsearch/external/app/cts/AppSearchSchemaCtsTest.java
@@ -78,4 +78,125 @@
                                                 .build()));
         assertThat(e).hasMessageThat().contains("Property defined more than once: subject");
     }
+
+    @Test
+    public void testEquals_identical() {
+        AppSearchSchema schema1 =
+                new AppSearchSchema.Builder("Email")
+                        .addProperty(
+                                new PropertyConfig.Builder("subject")
+                                        .setDataType(PropertyConfig.DATA_TYPE_STRING)
+                                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+                                        .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
+                                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
+                                        .build())
+                        .build();
+        AppSearchSchema schema2 =
+                new AppSearchSchema.Builder("Email")
+                        .addProperty(
+                                new PropertyConfig.Builder("subject")
+                                        .setDataType(PropertyConfig.DATA_TYPE_STRING)
+                                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+                                        .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
+                                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
+                                        .build())
+                        .build();
+        assertThat(schema1).isEqualTo(schema2);
+        assertThat(schema1.hashCode()).isEqualTo(schema2.hashCode());
+    }
+
+    @Test
+    public void testEquals_differentOrder() {
+        AppSearchSchema schema1 =
+                new AppSearchSchema.Builder("Email")
+                        .addProperty(
+                                new PropertyConfig.Builder("subject")
+                                        .setDataType(PropertyConfig.DATA_TYPE_STRING)
+                                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+                                        .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
+                                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
+                                        .build())
+                        .build();
+        AppSearchSchema schema2 =
+                new AppSearchSchema.Builder("Email")
+                        .addProperty(
+                                new PropertyConfig.Builder("subject")
+                                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
+                                        .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
+                                        .setDataType(PropertyConfig.DATA_TYPE_STRING)
+                                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+                                        .build())
+                        .build();
+        assertThat(schema1).isEqualTo(schema2);
+        assertThat(schema1.hashCode()).isEqualTo(schema2.hashCode());
+    }
+
+    @Test
+    public void testEquals_failure() {
+        AppSearchSchema schema1 =
+                new AppSearchSchema.Builder("Email")
+                        .addProperty(
+                                new PropertyConfig.Builder("subject")
+                                        .setDataType(PropertyConfig.DATA_TYPE_STRING)
+                                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+                                        .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
+                                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
+                                        .build())
+                        .build();
+        AppSearchSchema schema2 =
+                new AppSearchSchema.Builder("Email")
+                        .addProperty(
+                                new PropertyConfig.Builder("subject")
+                                        .setDataType(PropertyConfig.DATA_TYPE_STRING)
+                                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+                                        .setIndexingType(
+                                                PropertyConfig
+                                                        .INDEXING_TYPE_EXACT_TERMS) // Different
+                                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
+                                        .build())
+                        .build();
+        assertThat(schema1).isNotEqualTo(schema2);
+        assertThat(schema1.hashCode()).isNotEqualTo(schema2.hashCode());
+    }
+
+    @Test
+    public void testEquals_failure_differentOrder() {
+        AppSearchSchema schema1 =
+                new AppSearchSchema.Builder("Email")
+                        .addProperty(
+                                new PropertyConfig.Builder("subject")
+                                        .setDataType(PropertyConfig.DATA_TYPE_STRING)
+                                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+                                        .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
+                                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
+                                        .build())
+                        .addProperty(
+                                new PropertyConfig.Builder("body")
+                                        .setDataType(PropertyConfig.DATA_TYPE_STRING)
+                                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+                                        .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
+                                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
+                                        .build())
+                        .build();
+        // Order of 'body' and 'subject' has been switched
+        AppSearchSchema schema2 =
+                new AppSearchSchema.Builder("Email")
+                        .addProperty(
+                                new PropertyConfig.Builder("body")
+                                        .setDataType(PropertyConfig.DATA_TYPE_STRING)
+                                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+                                        .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
+                                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
+                                        .build())
+                        .addProperty(
+                                new PropertyConfig.Builder("subject")
+                                        .setDataType(PropertyConfig.DATA_TYPE_STRING)
+                                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+                                        .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
+                                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
+                                        .build())
+                        .build();
+        assertThat(schema1).isNotEqualTo(schema2);
+        assertThat(schema1.hashCode()).isNotEqualTo(schema2.hashCode());
+    }
 }
diff --git a/core/tests/coretests/src/android/app/appsearch/external/util/BundleUtilTest.java b/core/tests/coretests/src/android/app/appsearch/external/util/BundleUtilTest.java
new file mode 100644
index 0000000..cfcfcc8
--- /dev/null
+++ b/core/tests/coretests/src/android/app/appsearch/external/util/BundleUtilTest.java
@@ -0,0 +1,254 @@
+/*
+ * 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.appsearch.util;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Build;
+import android.os.Bundle;
+import android.os.ParcelUuid;
+import android.os.Parcelable;
+import android.util.Size;
+import android.util.SizeF;
+import android.util.SparseArray;
+
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Test;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.UUID;
+
+public class BundleUtilTest {
+    @Test
+    public void testDeepEquals_self() {
+        Bundle one = new Bundle();
+        one.putString("a", "a");
+        assertThat(BundleUtil.deepEquals(one, one)).isTrue();
+    }
+
+    @Test
+    public void testDeepEquals_simple() {
+        Bundle one = new Bundle();
+        one.putString("a", "a");
+
+        Bundle two = new Bundle();
+        two.putString("a", "a");
+
+        assertThat(one).isNotEqualTo(two);
+        assertThat(BundleUtil.deepEquals(one, two)).isTrue();
+    }
+
+    @Test
+    public void testDeepEquals_keyMismatch() {
+        Bundle one = new Bundle();
+        one.putString("a", "a");
+
+        Bundle two = new Bundle();
+        two.putString("a", "a");
+        two.putString("b", "b");
+        assertThat(BundleUtil.deepEquals(one, two)).isFalse();
+    }
+
+    @Test
+    public void testDeepEquals_thorough_equal() {
+        Bundle[] inputs = new Bundle[2];
+        for (int i = 0; i < 2; i++) {
+            inputs[i] = createThoroughBundle();
+        }
+        assertThat(inputs[0]).isNotEqualTo(inputs[1]);
+        assertThat(BundleUtil.deepEquals(inputs[0], inputs[1])).isTrue();
+    }
+
+    @Test
+    public void testDeepEquals_thorough_notEqual() {
+        Bundle[] inputs = new Bundle[2];
+        for (int i = 0; i < 2; i++) {
+            Bundle b = createThoroughBundle();
+            // Create a difference
+            assertThat(b.containsKey("doubleArray")).isTrue();
+            b.putDoubleArray("doubleArray", new double[] {18., i});
+            inputs[i] = b;
+        }
+        assertThat(inputs[0]).isNotEqualTo(inputs[1]);
+        assertThat(BundleUtil.deepEquals(inputs[0], inputs[1])).isFalse();
+    }
+
+    @Test
+    public void testDeepEquals_nestedNotEquals() {
+        Bundle one = new Bundle();
+        one.putString("a", "a");
+        Bundle two = new Bundle();
+        two.putBundle("b", one);
+        Bundle twoClone = new Bundle();
+        twoClone.putBundle("b", one);
+        Bundle three = new Bundle();
+        three.putBundle("b", two);
+
+        ArrayList<Bundle> listOne = new ArrayList<>(ImmutableList.of(one, two, three));
+        ArrayList<Bundle> listOneClone = new ArrayList<>(ImmutableList.of(one, twoClone, three));
+        ArrayList<Bundle> listTwo = new ArrayList<>(ImmutableList.of(one, three, two));
+        Bundle b1 = new Bundle();
+        b1.putParcelableArrayList("key", listOne);
+        Bundle b1Clone = new Bundle();
+        b1Clone.putParcelableArrayList("key", listOneClone);
+        Bundle b2 = new Bundle();
+        b2.putParcelableArrayList("key", listTwo);
+
+        assertThat(b1).isNotEqualTo(b1Clone);
+        assertThat(BundleUtil.deepEquals(b1, b1Clone)).isTrue();
+        assertThat(BundleUtil.deepEquals(b1, b2)).isFalse();
+        assertThat(BundleUtil.deepEquals(b1Clone, b2)).isFalse();
+    }
+
+    @Test
+    public void testDeepEquals_sparseArray() {
+        Parcelable parcelable1 = new ParcelUuid(UUID.randomUUID());
+        Parcelable parcelable2 = new ParcelUuid(UUID.randomUUID());
+        Parcelable parcelable3 = new ParcelUuid(UUID.randomUUID());
+
+        SparseArray<Parcelable> array1 = new SparseArray<>();
+        array1.put(1, parcelable1);
+        array1.put(10, parcelable2);
+
+        SparseArray<Parcelable> array1Clone = new SparseArray<>();
+        array1Clone.put(1, parcelable1);
+        array1Clone.put(10, parcelable2);
+
+        SparseArray<Parcelable> array2 = new SparseArray<>();
+        array2.put(1, parcelable1);
+        array2.put(10, parcelable3); // Different
+
+        Bundle b1 = new Bundle();
+        b1.putSparseParcelableArray("array1", array1);
+        Bundle b1Clone = new Bundle();
+        b1Clone.putSparseParcelableArray("array1", array1Clone);
+        Bundle b2 = new Bundle();
+        b2.putSparseParcelableArray("array1", array2);
+
+        assertThat(b1).isNotEqualTo(b1Clone);
+        assertThat(BundleUtil.deepEquals(b1, b1Clone)).isTrue();
+        assertThat(BundleUtil.deepEquals(b1, b2)).isFalse();
+        assertThat(BundleUtil.deepEquals(b1Clone, b2)).isFalse();
+    }
+
+    @Test
+    public void testDeepHashCode_same() {
+        Bundle[] inputs = new Bundle[2];
+        for (int i = 0; i < 2; i++) {
+            inputs[i] = createThoroughBundle();
+        }
+        assertThat(BundleUtil.deepHashCode(inputs[0]))
+                .isEqualTo(BundleUtil.deepHashCode(inputs[1]));
+    }
+
+    @Test
+    public void testDeepHashCode_different() {
+        Bundle[] inputs = new Bundle[2];
+        for (int i = 0; i < 2; i++) {
+            Bundle b = createThoroughBundle();
+            // Create a difference
+            assertThat(b.containsKey("doubleArray")).isTrue();
+            b.putDoubleArray("doubleArray", new double[] {18., i});
+            inputs[i] = b;
+        }
+        assertThat(BundleUtil.deepHashCode(inputs[0]))
+                .isNotEqualTo(BundleUtil.deepHashCode(inputs[1]));
+    }
+
+    @Test
+    public void testHashCode_sparseArray() {
+        Parcelable parcelable1 = new ParcelUuid(UUID.randomUUID());
+        Parcelable parcelable2 = new ParcelUuid(UUID.randomUUID());
+        Parcelable parcelable3 = new ParcelUuid(UUID.randomUUID());
+
+        SparseArray<Parcelable> array1 = new SparseArray<>();
+        array1.put(1, parcelable1);
+        array1.put(10, parcelable2);
+
+        SparseArray<Parcelable> array1Clone = new SparseArray<>();
+        array1Clone.put(1, parcelable1);
+        array1Clone.put(10, parcelable2);
+
+        SparseArray<Parcelable> array2 = new SparseArray<>();
+        array2.put(1, parcelable1);
+        array2.put(10, parcelable3); // Different
+
+        Bundle b1 = new Bundle();
+        b1.putSparseParcelableArray("array1", array1);
+        Bundle b1Clone = new Bundle();
+        b1Clone.putSparseParcelableArray("array1", array1Clone);
+        Bundle b2 = new Bundle();
+        b2.putSparseParcelableArray("array1", array2);
+
+        assertThat(b1.hashCode()).isNotEqualTo(b1Clone.hashCode());
+        assertThat(BundleUtil.deepHashCode(b1)).isEqualTo(BundleUtil.deepHashCode(b1Clone));
+        assertThat(BundleUtil.deepHashCode(b1)).isNotEqualTo(BundleUtil.deepHashCode(b2));
+    }
+
+    private static Bundle createThoroughBundle() {
+        Bundle toy1 = new Bundle();
+        toy1.putString("a", "a");
+        Bundle toy2 = new Bundle();
+        toy2.putInt("b", 2);
+
+        Bundle b = new Bundle();
+        // BaseBundle stuff
+        b.putBoolean("boolean", true);
+        b.putByte("byte", (byte) 1);
+        b.putChar("char", 'a');
+        b.putShort("short", (short) 2);
+        b.putInt("int", 3);
+        b.putLong("long", 4L);
+        b.putFloat("float", 5f);
+        b.putDouble("double", 6f);
+        b.putString("string", "b");
+        b.putCharSequence("charSequence", "c");
+        b.putIntegerArrayList("integerArrayList", new ArrayList<>(ImmutableList.of(7, 8)));
+        b.putStringArrayList("stringArrayList", new ArrayList<>(ImmutableList.of("d", "e")));
+        b.putCharSequenceArrayList(
+                "charSequenceArrayList", new ArrayList<>(ImmutableList.of("f", "g")));
+        b.putSerializable("serializable", new BigDecimal(9));
+        b.putBooleanArray("booleanArray", new boolean[] {true, false, true});
+        b.putByteArray("byteArray", new byte[] {(byte) 10, (byte) 11});
+        b.putShortArray("shortArray", new short[] {(short) 12, (short) 13});
+        b.putCharArray("charArray", new char[] {'h', 'i'});
+        b.putLongArray("longArray", new long[] {14L, 15L});
+        b.putFloatArray("floatArray", new float[] {16f, 17f});
+        b.putDoubleArray("doubleArray", new double[] {18., 19.});
+        b.putStringArray("stringArray", new String[] {"j", "k"});
+        b.putCharSequenceArray("charSequenceArrayList", new CharSequence[] {"l", "m"});
+
+        // Bundle stuff
+        b.putParcelable("parcelable", toy1);
+        if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
+            b.putSize("size", new Size(20, 21));
+            b.putSizeF("sizeF", new SizeF(22f, 23f));
+        }
+        b.putParcelableArray("parcelableArray", new Parcelable[] {toy1, toy2});
+        b.putParcelableArrayList(
+                "parcelableArrayList", new ArrayList<>(ImmutableList.of(toy1, toy2)));
+        SparseArray<Parcelable> sparseArray = new SparseArray<>();
+        sparseArray.put(24, toy1);
+        sparseArray.put(1025, toy2);
+        b.putSparseParcelableArray("sparceParcelableArray", sparseArray);
+        b.putBundle("bundle", toy1);
+
+        return b;
+    }
+}
diff --git a/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java b/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
index 365e97d..e04d903 100644
--- a/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
+++ b/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
@@ -24,12 +24,12 @@
 import android.test.AndroidTestCase;
 import android.util.AttributeSet;
 import android.util.SparseArray;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 
 import androidx.test.filters.LargeTest;
 
-import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.ByteArrayInputStream;
 import java.io.File;
@@ -308,12 +308,12 @@
 
     static class TestSerializer implements XmlSerializerAndParser<TestServiceType> {
 
-        public void writeAsXml(TestServiceType item, XmlSerializer out) throws IOException {
+        public void writeAsXml(TestServiceType item, TypedXmlSerializer out) throws IOException {
             out.attribute(null, "type", item.type);
             out.attribute(null, "value", item.value);
         }
 
-        public TestServiceType createFromXml(XmlPullParser parser)
+        public TestServiceType createFromXml(TypedXmlPullParser parser)
                 throws IOException, XmlPullParserException {
             final String type = parser.getAttributeValue(null, "type");
             final String value = parser.getAttributeValue(null, "value");
diff --git a/core/tests/coretests/src/android/database/OWNERS b/core/tests/coretests/src/android/database/OWNERS
new file mode 100644
index 0000000..bb9a2ca
--- /dev/null
+++ b/core/tests/coretests/src/android/database/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/database/OWNERS
diff --git a/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
index 4370462..e750454 100644
--- a/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
+++ b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
@@ -23,18 +23,16 @@
 
 import android.os.Parcel;
 import android.util.Pair;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.internal.util.FastXmlSerializer;
-
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -163,7 +161,7 @@
         BrightnessConfiguration config = builder.build();
 
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        XmlSerializer out = new FastXmlSerializer();
+        TypedXmlSerializer out = Xml.newFastSerializer();
         out.setOutput(baos, StandardCharsets.UTF_8.name());
         out.startDocument(null, true);
         config.saveToXml(out);
@@ -171,7 +169,7 @@
         baos.flush();
 
         ByteArrayInputStream input = new ByteArrayInputStream(baos.toByteArray());
-        XmlPullParser parser = Xml.newPullParser();
+        TypedXmlPullParser parser = Xml.newFastPullParser();
         parser.setInput(input, StandardCharsets.UTF_8.name());
         BrightnessConfiguration loadedConfig = BrightnessConfiguration.loadFromXml(parser);
 
diff --git a/core/tests/coretests/src/android/net/OWNERS b/core/tests/coretests/src/android/net/OWNERS
new file mode 100644
index 0000000..aa87958
--- /dev/null
+++ b/core/tests/coretests/src/android/net/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/net/OWNERS
diff --git a/core/tests/coretests/src/android/util/BinaryXmlTest.java b/core/tests/coretests/src/android/util/BinaryXmlTest.java
index be63a0e..6fa5a23 100644
--- a/core/tests/coretests/src/android/util/BinaryXmlTest.java
+++ b/core/tests/coretests/src/android/util/BinaryXmlTest.java
@@ -20,6 +20,8 @@
 import static android.util.XmlTest.buildPersistableBundle;
 import static android.util.XmlTest.doPersistableBundleRead;
 import static android.util.XmlTest.doPersistableBundleWrite;
+import static android.util.XmlTest.doVerifyRead;
+import static android.util.XmlTest.doVerifyWrite;
 
 import static org.junit.Assert.assertEquals;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -33,6 +35,11 @@
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
 
 @RunWith(AndroidJUnit4.class)
@@ -96,4 +103,58 @@
         final PersistableBundle actual = doPersistableBundleRead(secondIn, os.toByteArray());
         assertEquals(expected.toString(), actual.toString());
     }
+
+    @Test
+    public void testResolve_File() throws Exception {
+        {
+            final File file = File.createTempFile("fast", ".xml");
+            try (OutputStream os = new FileOutputStream(file)) {
+                TypedXmlSerializer xml = Xml.newFastSerializer();
+                xml.setOutput(os, StandardCharsets.UTF_8.name());
+                doVerifyWrite(xml);
+            }
+            try (InputStream is = new FileInputStream(file)) {
+                doVerifyRead(Xml.resolvePullParser(is));
+            }
+        }
+        {
+            final File file = File.createTempFile("binary", ".xml");
+            try (OutputStream os = new FileOutputStream(file)) {
+                TypedXmlSerializer xml = Xml.newBinarySerializer();
+                xml.setOutput(os, StandardCharsets.UTF_8.name());
+                doVerifyWrite(xml);
+            }
+            try (InputStream is = new FileInputStream(file)) {
+                doVerifyRead(Xml.resolvePullParser(is));
+            }
+        }
+    }
+
+    @Test
+    public void testResolve_Memory() throws Exception {
+        {
+            final byte[] data;
+            try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+                TypedXmlSerializer xml = Xml.newFastSerializer();
+                xml.setOutput(os, StandardCharsets.UTF_8.name());
+                doVerifyWrite(xml);
+                data = os.toByteArray();
+            }
+            try (InputStream is = new ByteArrayInputStream(data)) {
+                doVerifyRead(Xml.resolvePullParser(is));
+            }
+        }
+        {
+            final byte[] data;
+            try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+                TypedXmlSerializer xml = Xml.newBinarySerializer();
+                xml.setOutput(os, StandardCharsets.UTF_8.name());
+                doVerifyWrite(xml);
+                data = os.toByteArray();
+            }
+            try (InputStream is = new ByteArrayInputStream(data)) {
+                doVerifyRead(Xml.resolvePullParser(is));
+            }
+        }
+    }
 }
diff --git a/core/tests/coretests/src/android/util/XmlTest.java b/core/tests/coretests/src/android/util/XmlTest.java
index 5ae17c4..a8fc6f9 100644
--- a/core/tests/coretests/src/android/util/XmlTest.java
+++ b/core/tests/coretests/src/android/util/XmlTest.java
@@ -205,7 +205,7 @@
     private static final byte[] TEST_BYTES = new byte[] { 0, 1, 2, 3, 4, 3, 2, 1, 0 };
     private static final byte[] TEST_BYTES_EMPTY = new byte[0];
 
-    private static void doVerifyWrite(TypedXmlSerializer out) throws Exception {
+    static void doVerifyWrite(TypedXmlSerializer out) throws Exception {
         out.startDocument(StandardCharsets.UTF_8.name(), true);
         out.startTag(null, "one");
         {
@@ -244,7 +244,7 @@
         out.endDocument();
     }
 
-    private static void doVerifyRead(TypedXmlPullParser in) throws Exception {
+    static void doVerifyRead(TypedXmlPullParser in) throws Exception {
         assertEquals(START_DOCUMENT, in.getEventType());
         assertNext(in, START_TAG, "one", 1);
         {
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
index 8e24907..75116d8 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
@@ -38,6 +38,7 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.R;
 import com.android.internal.util.IntPair;
 import com.android.server.accessibility.test.MessageCapturingHandler;
 
@@ -73,12 +74,18 @@
     @Mock private IAccessibilityManager mMockService;
     private MessageCapturingHandler mHandler;
     private Instrumentation mInstrumentation;
+    private int mFocusStrokeWidthDefaultValue;
+    private int mFocusColorDefaultValue;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         mHandler = new MessageCapturingHandler(null);
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mFocusStrokeWidthDefaultValue = mInstrumentation.getContext().getResources()
+                .getDimensionPixelSize(R.dimen.accessibility_focus_highlight_stroke_width);
+        mFocusColorDefaultValue = mInstrumentation.getContext().getResources().getColor(
+                R.color.accessibility_focus_highlight_color);
     }
 
     @After
@@ -94,8 +101,12 @@
         when(mMockService.addClient(any(IAccessibilityManagerClient.class), anyInt()))
                 .thenReturn(serviceReturnValue);
 
+        when(mMockService.getFocusStrokeWidth()).thenReturn(mFocusStrokeWidthDefaultValue);
+        when(mMockService.getFocusColor()).thenReturn(mFocusColorDefaultValue);
+
         AccessibilityManager manager =
-                new AccessibilityManager(mHandler, mMockService, UserHandle.USER_CURRENT);
+                new AccessibilityManager(mInstrumentation.getContext(), mHandler, mMockService,
+                        UserHandle.USER_CURRENT, true);
 
         verify(mMockService).addClient(any(IAccessibilityManagerClient.class), anyInt());
         mHandler.setCallback(manager.getCallback());
@@ -205,4 +216,16 @@
 
         verify(mMockService).setWindowMagnificationConnection(connection);
     }
+
+    @Test
+    public void testGetDefaultValueOfFocusAppearanceData() {
+        AccessibilityManager manager =
+                new AccessibilityManager(mInstrumentation.getContext(), mHandler, null,
+                        UserHandle.USER_CURRENT, false);
+
+        assertEquals(mFocusStrokeWidthDefaultValue,
+                manager.getAccessibilityFocusStrokeWidth());
+        assertEquals(mFocusColorDefaultValue,
+                manager.getAccessibilityFocusColor());
+    }
 }
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
index 75a7504..cfdb2b7 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
@@ -161,4 +161,6 @@
     public void setTouchExplorationPassthroughRegion(int displayId, Region region) {}
 
     public void setGestureDetectionPassthroughRegion(int displayId, Region region) {}
+
+    public void setFocusAppearance(int strokeWidth, int color) {}
 }
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
index c17c36e..6baf305 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -68,6 +68,7 @@
 import android.view.accessibility.IAccessibilityManager;
 import android.widget.Toast;
 
+import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.R;
@@ -148,7 +149,8 @@
 
         // Use the extra level of indirection in the object to mock framework objects
         AccessibilityManager accessibilityManager =
-                new AccessibilityManager(mHandler, mAccessibilityManagerService, 0);
+                new AccessibilityManager(InstrumentationRegistry.getContext(), mHandler,
+                        mAccessibilityManagerService, 0, true);
         when(mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext))
                 .thenReturn(accessibilityManager);
         when(mContext.getSystemService(Context.ACCESSIBILITY_SERVICE))
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/OWNERS b/core/tests/coretests/src/com/android/internal/accessibility/OWNERS
new file mode 100644
index 0000000..b74281e
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/accessibility/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/accessibility/OWNERS
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/OWNERS b/core/tests/coretests/src/com/android/internal/inputmethod/OWNERS
new file mode 100644
index 0000000..5deb2ce
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/inputmethod/OWNERS
diff --git a/core/tests/coretests/src/com/android/internal/policy/OWNERS b/core/tests/coretests/src/com/android/internal/policy/OWNERS
new file mode 100644
index 0000000..0862c05
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/policy/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/core/tests/coretests/src/com/android/internal/power/OWNERS b/core/tests/coretests/src/com/android/internal/power/OWNERS
new file mode 100644
index 0000000..d68066b
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/power/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/power/OWNERS
diff --git a/core/tests/coretests/src/com/android/internal/statusbar/OWNERS b/core/tests/coretests/src/com/android/internal/statusbar/OWNERS
new file mode 100644
index 0000000..2e96c97
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/statusbar/OWNERS
@@ -0,0 +1 @@
+include /packages/SystemUI/OWNERS
diff --git a/core/tests/devicestatetests/src/android/hardware/devicestate/OWNERS b/core/tests/devicestatetests/src/android/hardware/devicestate/OWNERS
new file mode 100644
index 0000000..d9b0e2e
--- /dev/null
+++ b/core/tests/devicestatetests/src/android/hardware/devicestate/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/devicestate/OWNERS
diff --git a/core/tests/hdmitests/OWNERS b/core/tests/hdmitests/OWNERS
new file mode 100644
index 0000000..c3c47ed
--- /dev/null
+++ b/core/tests/hdmitests/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/hardware/hdmi/OWNERS
diff --git a/core/tests/hosttests/test-apps/OWNERS b/core/tests/hosttests/test-apps/OWNERS
new file mode 100644
index 0000000..d825dfd
--- /dev/null
+++ b/core/tests/hosttests/test-apps/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/OWNERS
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
index 46695d2..a74f580 100644
--- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -38,13 +38,11 @@
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
 import android.app.Activity;
-import android.app.ActivityTaskManager;
+import android.app.ActivityClient;
 import android.app.ActivityThread;
 import android.app.ActivityThread.ActivityClientRecord;
-import android.app.IActivityTaskManager;
 import android.app.LoadedApk;
 import android.app.servertransaction.PendingTransactionActions;
 import android.content.ComponentName;
@@ -54,7 +52,6 @@
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.os.IBinder;
-import android.os.RemoteException;
 import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
 import android.testing.PollingCheck;
@@ -224,18 +221,19 @@
         private MockitoSession mMockSession;
         private ActivityThread mThread;
 
-        private ClientMockSession() throws RemoteException {
+        private ClientMockSession() {
             mThread = ActivityThread.currentActivityThread();
             mMockSession = mockitoSession()
                     .strictness(Strictness.LENIENT)
-                    .spyStatic(ActivityTaskManager.class)
+                    .spyStatic(ActivityClient.class)
                     .spyStatic(WindowManagerGlobal.class)
                     .startMocking();
             doReturn(Mockito.mock(WindowManagerGlobal.class))
                     .when(WindowManagerGlobal::getInstance);
-            IActivityTaskManager mockAtm = Mockito.mock(IActivityTaskManager.class);
-            doReturn(mockAtm).when(ActivityTaskManager::getService);
-            when(mockAtm.finishActivity(any(), anyInt(), any(), anyInt())).thenReturn(true);
+            final ActivityClient mockAc = Mockito.mock(ActivityClient.class);
+            doReturn(mockAc).when(ActivityClient::getInstance);
+            doReturn(true).when(mockAc).finishActivity(any() /* token */,
+                    anyInt() /* resultCode */, any() /* resultData */, anyInt() /* finishTask */);
         }
 
         private Activity launchActivity(ActivityClientRecord r) {
diff --git a/core/tests/notificationtests/OWNERS b/core/tests/notificationtests/OWNERS
new file mode 100644
index 0000000..396fd12
--- /dev/null
+++ b/core/tests/notificationtests/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/notification/OWNERS
diff --git a/core/tests/overlaytests/OWNERS b/core/tests/overlaytests/OWNERS
new file mode 100644
index 0000000..afb98d4
--- /dev/null
+++ b/core/tests/overlaytests/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/content/om/OWNERS
diff --git a/core/tests/overlaytests/remount/TEST_MAPPING b/core/tests/overlaytests/remount/TEST_MAPPING
index 54dd431..22b28b5 100644
--- a/core/tests/overlaytests/remount/TEST_MAPPING
+++ b/core/tests/overlaytests/remount/TEST_MAPPING
@@ -1,7 +1,7 @@
 {
-  "presubmit": [
+  "presubmit-large": [
     {
       "name" : "OverlayRemountedTest"
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/core/tests/packagemanagertests/OWNERS b/core/tests/packagemanagertests/OWNERS
new file mode 100644
index 0000000..d825dfd
--- /dev/null
+++ b/core/tests/packagemanagertests/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/OWNERS
diff --git a/core/tests/powertests/OWNERS b/core/tests/powertests/OWNERS
new file mode 100644
index 0000000..d68066b
--- /dev/null
+++ b/core/tests/powertests/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/power/OWNERS
diff --git a/core/tests/uwbtests/Android.bp b/core/tests/uwbtests/Android.bp
index c41c346..8ee86f4 100644
--- a/core/tests/uwbtests/Android.bp
+++ b/core/tests/uwbtests/Android.bp
@@ -17,6 +17,7 @@
     static_libs: [
         "androidx.test.ext.junit",
         "androidx.test.rules",
+        "mockito-target-minus-junit4",
     ],
     libs: [
         "android.test.runner",
diff --git a/core/tests/uwbtests/src/android/uwb/AdapterStateListenerTest.java b/core/tests/uwbtests/src/android/uwb/AdapterStateListenerTest.java
new file mode 100644
index 0000000..ce67ef7
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/AdapterStateListenerTest.java
@@ -0,0 +1,311 @@
+/*
+ * 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.uwb;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+import android.os.RemoteException;
+import android.uwb.UwbManager.AdapterStateCallback;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * Test of {@link AdapterStateListener}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AdapterStateListenerTest {
+
+    IUwbAdapter mUwbAdapter = mock(IUwbAdapter.class);
+
+    Answer mRegisterSuccessAnswer = new Answer() {
+        public Object answer(InvocationOnMock invocation) {
+            Object[] args = invocation.getArguments();
+            IUwbAdapterStateCallbacks cb = (IUwbAdapterStateCallbacks) args[0];
+            try {
+                cb.onAdapterStateChanged(false, StateChangeReason.UNKNOWN);
+            } catch (RemoteException e) {
+                // Nothing to do
+            }
+            return new Object();
+        }
+    };
+
+    Throwable mThrowRemoteException = new RemoteException("RemoteException");
+
+    private static Executor getExecutor() {
+        return new Executor() {
+            @Override
+            public void execute(Runnable command) {
+                command.run();
+            }
+        };
+    }
+
+    private static void verifyCallbackStateChangedInvoked(
+            AdapterStateCallback callback, int numTimes) {
+        verify(callback, times(numTimes)).onStateChanged(anyBoolean(), anyInt());
+    }
+
+    @Test
+    public void testRegister_RegisterUnregister() throws RemoteException {
+        doAnswer(mRegisterSuccessAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any());
+
+        AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
+        AdapterStateCallback callback1 = mock(AdapterStateCallback.class);
+        AdapterStateCallback callback2 = mock(AdapterStateCallback.class);
+
+        // Verify that the adapter state listener registered with the UWB Adapter
+        adapterStateListener.register(getExecutor(), callback1);
+        verify(mUwbAdapter, times(1)).registerAdapterStateCallbacks(any());
+        verifyCallbackStateChangedInvoked(callback1, 1);
+        verifyCallbackStateChangedInvoked(callback2, 0);
+
+        // Register a second client and no new call to UWB Adapter
+        adapterStateListener.register(getExecutor(), callback2);
+        verify(mUwbAdapter, times(1)).registerAdapterStateCallbacks(any());
+        verifyCallbackStateChangedInvoked(callback1, 1);
+        verifyCallbackStateChangedInvoked(callback2, 1);
+
+        // Unregister first callback
+        adapterStateListener.unregister(callback1);
+        verify(mUwbAdapter, times(1)).registerAdapterStateCallbacks(any());
+        verify(mUwbAdapter, times(0)).unregisterAdapterStateCallbacks(any());
+        verifyCallbackStateChangedInvoked(callback1, 1);
+        verifyCallbackStateChangedInvoked(callback2, 1);
+
+        // Unregister second callback
+        adapterStateListener.unregister(callback2);
+        verify(mUwbAdapter, times(1)).registerAdapterStateCallbacks(any());
+        verify(mUwbAdapter, times(1)).unregisterAdapterStateCallbacks(any());
+        verifyCallbackStateChangedInvoked(callback1, 1);
+        verifyCallbackStateChangedInvoked(callback2, 1);
+    }
+
+    @Test
+    public void testRegister_FirstRegisterFails() throws RemoteException {
+        AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
+        AdapterStateCallback callback1 = mock(AdapterStateCallback.class);
+        AdapterStateCallback callback2 = mock(AdapterStateCallback.class);
+
+        // Throw a remote exception whenever first registering
+        doThrow(mThrowRemoteException).when(mUwbAdapter).registerAdapterStateCallbacks(any());
+
+        adapterStateListener.register(getExecutor(), callback1);
+        verify(mUwbAdapter, times(1)).registerAdapterStateCallbacks(any());
+
+        // No longer throw an exception, instead succeed
+        doAnswer(mRegisterSuccessAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any());
+
+        // Register a different callback
+        adapterStateListener.register(getExecutor(), callback2);
+        verify(mUwbAdapter, times(2)).registerAdapterStateCallbacks(any());
+
+        // Ensure first callback was invoked again
+        verifyCallbackStateChangedInvoked(callback1, 2);
+        verifyCallbackStateChangedInvoked(callback2, 1);
+    }
+
+    @Test
+    public void testRegister_RegisterSameCallbackTwice() throws RemoteException {
+        AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
+        AdapterStateCallback callback = mock(AdapterStateCallback.class);
+        doAnswer(mRegisterSuccessAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any());
+
+        adapterStateListener.register(getExecutor(), callback);
+        verifyCallbackStateChangedInvoked(callback, 1);
+
+        adapterStateListener.register(getExecutor(), callback);
+        verifyCallbackStateChangedInvoked(callback, 1);
+
+        // Invoke a state change and ensure the callback is only called once
+        adapterStateListener.onAdapterStateChanged(false, StateChangeReason.UNKNOWN);
+        verifyCallbackStateChangedInvoked(callback, 2);
+    }
+
+    @Test
+    public void testCallback_RunViaExecutor_Success() throws RemoteException {
+        // Verify that the callbacks are invoked on the executor when successful
+        doAnswer(mRegisterSuccessAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any());
+        runViaExecutor();
+    }
+
+    @Test
+    public void testCallback_RunViaExecutor_Failure() throws RemoteException {
+        // Verify that the callbacks are invoked on the executor when there is a remote exception
+        doThrow(mThrowRemoteException).when(mUwbAdapter).registerAdapterStateCallbacks(any());
+        runViaExecutor();
+    }
+
+    private void runViaExecutor() {
+        AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
+        AdapterStateCallback callback = mock(AdapterStateCallback.class);
+
+        Executor executor = mock(Executor.class);
+
+        // Do not run commands received and ensure that the callback is not invoked
+        doAnswer(new ExecutorAnswer(false)).when(executor).execute(any());
+        adapterStateListener.register(executor, callback);
+        verify(executor, times(1)).execute(any());
+        verifyCallbackStateChangedInvoked(callback, 0);
+
+        // Manually invoke the callback and ensure callback is not invoked
+        adapterStateListener.onAdapterStateChanged(false, StateChangeReason.UNKNOWN);
+        verify(executor, times(2)).execute(any());
+        verifyCallbackStateChangedInvoked(callback, 0);
+
+        // Run the command that the executor receives
+        doAnswer(new ExecutorAnswer(true)).when(executor).execute(any());
+        adapterStateListener.onAdapterStateChanged(false, StateChangeReason.UNKNOWN);
+        verify(executor, times(3)).execute(any());
+        verifyCallbackStateChangedInvoked(callback, 1);
+    }
+
+    class ExecutorAnswer implements Answer {
+
+        final boolean mShouldRun;
+        ExecutorAnswer(boolean shouldRun) {
+            mShouldRun = shouldRun;
+        }
+
+        @Override
+        public Object answer(InvocationOnMock invocation) throws Throwable {
+            if (mShouldRun) {
+                ((Runnable) invocation.getArgument(0)).run();
+            }
+            return null;
+        }
+    }
+
+    @Test
+    public void testNotify_AllCallbacksNotified() throws RemoteException {
+        doAnswer(mRegisterSuccessAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any());
+
+        AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
+        List<AdapterStateCallback> callbacks = new ArrayList<>();
+        for (int i = 0; i < 10; i++) {
+            AdapterStateCallback callback = mock(AdapterStateCallback.class);
+            adapterStateListener.register(getExecutor(), callback);
+            callbacks.add(callback);
+        }
+
+            // Ensure every callback got the initial state
+        for (AdapterStateCallback callback : callbacks) {
+            verifyCallbackStateChangedInvoked(callback, 1);
+        }
+
+        // Invoke a state change and ensure all callbacks are invoked
+        adapterStateListener.onAdapterStateChanged(true, StateChangeReason.ALL_SESSIONS_CLOSED);
+        for (AdapterStateCallback callback : callbacks) {
+            verifyCallbackStateChangedInvoked(callback, 2);
+        }
+    }
+
+    @Test
+    public void testStateChange_CorrectValue() {
+        AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
+
+        AdapterStateCallback callback = mock(AdapterStateCallback.class);
+
+        adapterStateListener.register(getExecutor(), callback);
+
+        runStateChangeValue(StateChangeReason.ALL_SESSIONS_CLOSED,
+                AdapterStateCallback.STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED);
+
+        runStateChangeValue(StateChangeReason.SESSION_STARTED,
+                AdapterStateCallback.STATE_CHANGED_REASON_SESSION_STARTED);
+
+        runStateChangeValue(StateChangeReason.SYSTEM_BOOT,
+                AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_BOOT);
+
+        runStateChangeValue(StateChangeReason.SYSTEM_POLICY,
+                AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_POLICY);
+
+        runStateChangeValue(StateChangeReason.UNKNOWN,
+                AdapterStateCallback.STATE_CHANGED_REASON_ERROR_UNKNOWN);
+    }
+
+    private void runStateChangeValue(@StateChangeReason int reasonIn,
+            @AdapterStateCallback.StateChangedReason int reasonOut) {
+        AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
+        AdapterStateCallback callback = mock(AdapterStateCallback.class);
+        adapterStateListener.register(getExecutor(), callback);
+
+        adapterStateListener.onAdapterStateChanged(false, reasonIn);
+        verify(callback, times(1)).onStateChanged(false, reasonOut);
+
+        adapterStateListener.onAdapterStateChanged(true, reasonIn);
+        verify(callback, times(1)).onStateChanged(true, reasonOut);
+    }
+
+    @Test
+    public void testStateChange_FirstRegisterGetsCorrectState() throws RemoteException {
+        AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
+        AdapterStateCallback callback = mock(AdapterStateCallback.class);
+
+        Answer registerAnswer = new Answer() {
+            public Object answer(InvocationOnMock invocation) {
+                Object[] args = invocation.getArguments();
+                IUwbAdapterStateCallbacks cb = (IUwbAdapterStateCallbacks) args[0];
+                try {
+                    cb.onAdapterStateChanged(true, StateChangeReason.SESSION_STARTED);
+                } catch (RemoteException e) {
+                    // Nothing to do
+                }
+                return new Object();
+            }
+        };
+
+        doAnswer(registerAnswer).when(mUwbAdapter).registerAdapterStateCallbacks(any());
+
+        adapterStateListener.register(getExecutor(), callback);
+        verify(callback).onStateChanged(true,
+                AdapterStateCallback.STATE_CHANGED_REASON_SESSION_STARTED);
+    }
+
+    @Test
+    public void testStateChange_SecondRegisterGetsCorrectState() {
+        AdapterStateListener adapterStateListener = new AdapterStateListener(mUwbAdapter);
+        AdapterStateCallback callback1 = mock(AdapterStateCallback.class);
+        AdapterStateCallback callback2 = mock(AdapterStateCallback.class);
+
+        adapterStateListener.register(getExecutor(), callback1);
+        adapterStateListener.onAdapterStateChanged(true, StateChangeReason.SYSTEM_BOOT);
+
+        adapterStateListener.register(getExecutor(), callback2);
+        verify(callback2).onStateChanged(true,
+                AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_BOOT);
+    }
+}
diff --git a/data/etc/OWNERS b/data/etc/OWNERS
index 70d4678..5efd0bd 100644
--- a/data/etc/OWNERS
+++ b/data/etc/OWNERS
@@ -1 +1,13 @@
-per-file privapp-permissions-platform.xml = hackbod@android.com, jsharkey@android.com, svetoslavganov@google.com, toddke@google.com, yamasani@google.com, cbrubaker@google.com, jeffv@google.com, moltmann@google.com, lorenzo@google.com
+cbrubaker@google.com
+hackbod@android.com
+hackbod@google.com
+jeffv@google.com
+jsharkey@android.com
+jsharkey@google.com
+lorenzo@google.com
+moltmann@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
+toddke@android.com
+toddke@google.com
+yamasani@google.com
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 1fb63f0..5f129fe 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -243,6 +243,8 @@
         <permission name="android.permission.LOG_COMPAT_CHANGE" />
         <permission name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
         <permission name="android.permission.REGISTER_STATS_PULL_ATOM" />
+        <!-- Permissions required for reading DeviceConfig -->
+        <permission name="android.permission.READ_DEVICE_CONFIG" />
     </privapp-permissions>
 
     <privapp-permissions package="com.android.providers.telephony">
@@ -375,6 +377,7 @@
         <permission name="android.permission.SIGNAL_PERSISTENT_PROCESSES"/>
         <permission name="android.permission.STATUS_BAR"/>
         <permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" />
+        <permission name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND" />
         <permission name="android.permission.START_TASKS_FROM_RECENTS" />
         <permission name="android.permission.STOP_APP_SWITCHES"/>
         <permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
@@ -445,6 +448,8 @@
         <!-- Permissions required for CTS test - android.server.biometrics -->
         <permission name="android.permission.USE_BIOMETRIC" />
         <permission name="android.permission.TEST_BIOMETRIC" />
+        <!-- Permissions required for CTS test - CtsContactsProviderTestCases -->
+        <permission name="android.contacts.permission.MANAGE_SIM_ACCOUNTS" />
     </privapp-permissions>
 
     <privapp-permissions package="com.android.statementservice">
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 6bcab8a..a5667b2 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -85,6 +85,12 @@
       "group": "WM_DEBUG_REMOTE_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
     },
+    "-2014162875": {
+      "message": "Could not register window container listener token=%s, container=%s",
+      "level": "ERROR",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowContextListenerController.java"
+    },
     "-2012562539": {
       "message": "startAnimation(): Notify animation start:",
       "level": "DEBUG",
@@ -799,12 +805,6 @@
       "group": "WM_DEBUG_RECENTS_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RecentsAnimation.java"
     },
-    "-1155279885": {
-      "message": "Frontmost changed immersion: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IMMERSIVE",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
     "-1144293044": {
       "message": "SURFACE SET FREEZE LAYER: %s",
       "level": "INFO",
@@ -817,6 +817,12 @@
       "group": "WM_DEBUG_FOCUS",
       "at": "com\/android\/server\/wm\/DisplayContent.java"
     },
+    "-1136467585": {
+      "message": "The listener does not exist.",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowContextListenerController.java"
+    },
     "-1136139407": {
       "message": "no-history finish of %s",
       "level": "DEBUG",
@@ -1219,6 +1225,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/RootWindowContainer.java"
     },
+    "-655104359": {
+      "message": "Frontmost changed immersion: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_IMMERSIVE",
+      "at": "com\/android\/server\/wm\/ActivityClientController.java"
+    },
     "-653156702": {
       "message": "createAppAnimations()",
       "level": "DEBUG",
@@ -1573,12 +1585,6 @@
       "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/Task.java"
     },
-    "-272719931": {
-      "message": "startLockTaskModeLocked: %s",
-      "level": "WARN",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
     "-262984451": {
       "message": "Relaunch failed %s",
       "level": "INFO",
@@ -1825,6 +1831,18 @@
       "group": "WM_DEBUG_TASKS",
       "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
     },
+    "90764070": {
+      "message": "Could not report token removal to the window token client.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowContextListenerController.java"
+    },
+    "91350919": {
+      "message": "Attempted to set IME flag to a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
     "94402792": {
       "message": "Moving to RESUMED: %s (in existing)",
       "level": "VERBOSE",
@@ -1969,6 +1987,12 @@
       "group": "WM_DEBUG_WINDOW_ORGANIZER",
       "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
     },
+    "236210101": {
+      "message": "registerWindowContextListener: trying to add listener to a non-existing display:%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
     "241961619": {
       "message": "Adding %s to %s",
       "level": "VERBOSE",
@@ -2047,6 +2071,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/DisplayRotation.java"
     },
+    "295861935": {
+      "message": "startLockTaskMode: %s",
+      "level": "WARN",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
     "302969511": {
       "message": "Task info changed taskId=%d",
       "level": "VERBOSE",
@@ -2557,6 +2587,12 @@
       "group": "WM_DEBUG_TASKS",
       "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
     },
+    "883475718": {
+      "message": "Report configuration: %s %s %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityClientController.java"
+    },
     "892244061": {
       "message": "Waiting for drawn %s: removed=%b visible=%b mHasSurface=%b drawState=%d",
       "level": "INFO",
@@ -3097,12 +3133,6 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
-    "1576607724": {
-      "message": "Report configuration: %s %s %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
     "1577579529": {
       "message": "win=%s destroySurfaces: appStopped=%b win.mWindowRemovalAllowed=%b win.mRemoveOnExit=%b",
       "level": "ERROR",
@@ -3403,6 +3433,12 @@
       "group": "WM_DEBUG_TASKS",
       "at": "com\/android\/server\/wm\/RootWindowContainer.java"
     },
+    "1948483534": {
+      "message": "Could not report config changes to the window token client.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowContextListenerController.java"
+    },
     "1964565370": {
       "message": "Starting remote animation",
       "level": "INFO",
diff --git a/data/fonts/OWNERS b/data/fonts/OWNERS
new file mode 100644
index 0000000..a538331
--- /dev/null
+++ b/data/fonts/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/graphics/fonts/OWNERS
diff --git a/drm/java/android/drm/OWNERS b/drm/java/android/drm/OWNERS
new file mode 100644
index 0000000..4387100
--- /dev/null
+++ b/drm/java/android/drm/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 49079
+
+jtinker@google.com
+robertshih@google.com
diff --git a/errorprone/OWNERS b/errorprone/OWNERS
new file mode 100644
index 0000000..bddbdb3
--- /dev/null
+++ b/errorprone/OWNERS
@@ -0,0 +1,2 @@
+jsharkey@android.com
+jsharkey@google.com
diff --git a/errorprone/refaster/EfficientXml.java b/errorprone/refaster/EfficientXml.java
index bd1ddfc..ae797c4 100644
--- a/errorprone/refaster/EfficientXml.java
+++ b/errorprone/refaster/EfficientXml.java
@@ -292,6 +292,30 @@
         }
     }
 
+    class BooleanToStringTrue {
+        @BeforeTemplate
+        void before(TypedXmlSerializer out, String n) throws Exception {
+            out.attribute(null, n, "true");
+        }
+
+        @AfterTemplate
+        void after(TypedXmlSerializer out, String n) throws Exception {
+            out.attributeBoolean(null, n, true);
+        }
+    }
+
+    class BooleanToStringFalse {
+        @BeforeTemplate
+        void before(TypedXmlSerializer out, String n) throws Exception {
+            out.attribute(null, n, "false");
+        }
+
+        @AfterTemplate
+        void after(TypedXmlSerializer out, String n) throws Exception {
+            out.attributeBoolean(null, n, false);
+        }
+    }
+
     class BooleanFromString {
         @BeforeTemplate
         boolean beforeParse(TypedXmlPullParser in, String n) throws Exception {
diff --git a/errorprone/refaster/EfficientXml.java.refaster b/errorprone/refaster/EfficientXml.java.refaster
index f2974ff..750c2db 100644
--- a/errorprone/refaster/EfficientXml.java.refaster
+++ b/errorprone/refaster/EfficientXml.java.refaster
Binary files differ
diff --git a/graphics/OWNERS b/graphics/OWNERS
new file mode 100644
index 0000000..a6d1bc3
--- /dev/null
+++ b/graphics/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/graphics/OWNERS
diff --git a/graphics/java/android/graphics/OWNERS b/graphics/java/android/graphics/OWNERS
new file mode 100644
index 0000000..6196889
--- /dev/null
+++ b/graphics/java/android/graphics/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 24939
+
+romainguy@google.com
+jreck@google.com
+njawad@google.com
+sumir@google.com
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 24987da..d6b4f18 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -82,7 +82,7 @@
     private static String TAG = "Typeface";
 
     /** @hide */
-    public static final boolean ENABLE_LAZY_TYPEFACE_INITIALIZATION = false;
+    public static final boolean ENABLE_LAZY_TYPEFACE_INITIALIZATION = true;
 
     private static final NativeAllocationRegistry sRegistry =
             NativeAllocationRegistry.createMalloced(
diff --git a/graphics/java/android/graphics/drawable/OWNERS b/graphics/java/android/graphics/drawable/OWNERS
new file mode 100644
index 0000000..6196889
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 24939
+
+romainguy@google.com
+jreck@google.com
+njawad@google.com
+sumir@google.com
diff --git a/graphics/java/android/graphics/drawable/shapes/OWNERS b/graphics/java/android/graphics/drawable/shapes/OWNERS
new file mode 100644
index 0000000..6196889
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/shapes/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 24939
+
+romainguy@google.com
+jreck@google.com
+njawad@google.com
+sumir@google.com
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index e7c1582..fea756c 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -124,6 +124,19 @@
         }
 
         /**
+         * Construct a builder with a byte buffer and file path.
+         *
+         * This method is intended to be called only from SystemFonts.
+         * @param path font file path
+         * @param localeList comma concatenated BCP47 compliant language tag.
+         * @hide
+         */
+        public Builder(@NonNull File path, @NonNull String localeList) {
+            this(path);
+            mLocaleList = localeList;
+        }
+
+        /**
          * Constructs a builder with a file path.
          *
          * @param path a file path to the font file
@@ -809,29 +822,13 @@
 
             // If not found, create Font object from native object for Java API users.
             ByteBuffer buffer = NativeFontBufferHelper.refByteBuffer(ptr);
-            long packed = nGetFontInfo(ptr);
-            int weight = (int) (packed & 0x0000_0000_0000_FFFFL);
-            boolean italic = (packed & 0x0000_0000_0001_0000L) != 0;
-            int ttcIndex = (int) ((packed & 0x0000_FFFF_0000_0000L) >> 32);
-            int axisCount = (int) ((packed & 0xFFFF_0000_0000_0000L) >> 48);
-            FontVariationAxis[] axes = new FontVariationAxis[axisCount];
-            char[] charBuffer = new char[4];
-            for (int i = 0; i < axisCount; ++i) {
-                long packedAxis = nGetAxisInfo(ptr, i);
-                float value = Float.intBitsToFloat((int) (packedAxis & 0x0000_0000_FFFF_FFFFL));
-                charBuffer[0] = (char) ((packedAxis & 0xFF00_0000_0000_0000L) >> 56);
-                charBuffer[1] = (char) ((packedAxis & 0x00FF_0000_0000_0000L) >> 48);
-                charBuffer[2] = (char) ((packedAxis & 0x0000_FF00_0000_0000L) >> 40);
-                charBuffer[3] = (char) ((packedAxis & 0x0000_00FF_0000_0000L) >> 32);
-                axes[i] = new FontVariationAxis(new String(charBuffer), value);
-            }
-            String path = nGetFontPath(ptr);
-            File file = (path == null) ? null : new File(path);
-            Font.Builder builder = new Font.Builder(buffer, file, "")
-                    .setWeight(weight)
-                    .setSlant(italic ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT)
-                    .setTtcIndex(ttcIndex)
-                    .setFontVariationSettings(axes);
+            NativeFont.Font font = NativeFont.readNativeFont(ptr);
+
+            Font.Builder builder = new Font.Builder(buffer, font.getFile(), "")
+                    .setWeight(font.getStyle().getWeight())
+                    .setSlant(font.getStyle().getSlant())
+                    .setTtcIndex(font.getIndex())
+                    .setFontVariationSettings(font.getAxes());
 
             Font newFont = null;
             try {
@@ -845,15 +842,6 @@
         }
     }
 
-    @CriticalNative
-    private static native long nGetFontInfo(long ptr);
-
-    @CriticalNative
-    private static native long nGetAxisInfo(long ptr, int i);
-
-    @FastNative
-    private static native String nGetFontPath(long ptr);
-
     @FastNative
     private static native float nGetGlyphBounds(long font, int glyphId, long paint, RectF rect);
 
diff --git a/graphics/java/android/graphics/fonts/NativeFont.java b/graphics/java/android/graphics/fonts/NativeFont.java
new file mode 100644
index 0000000..9e9d76a
--- /dev/null
+++ b/graphics/java/android/graphics/fonts/NativeFont.java
@@ -0,0 +1,205 @@
+/*
+ * 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.graphics.fonts;
+
+import android.graphics.Typeface;
+
+import dalvik.annotation.optimization.CriticalNative;
+import dalvik.annotation.optimization.FastNative;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Read native font objects.
+ *
+ * @hide
+ */
+public class NativeFont {
+
+    /**
+     * Represents native font object.
+     */
+    public static final class Font {
+        private final File mFile;
+        private final int mIndex;
+        private final FontVariationAxis[] mAxes;
+        private final FontStyle mStyle;
+
+        public Font(File file, int index, FontVariationAxis[] axes, FontStyle style) {
+            mFile = file;
+            mIndex = index;
+            mAxes = axes;
+            mStyle = style;
+        }
+
+        public File getFile() {
+            return mFile;
+        }
+
+        public FontVariationAxis[] getAxes() {
+            return mAxes;
+        }
+
+        public FontStyle getStyle() {
+            return mStyle;
+        }
+
+        public int getIndex() {
+            return mIndex;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            Font font = (Font) o;
+            return mIndex == font.mIndex && mFile.equals(font.mFile)
+                    && Arrays.equals(mAxes, font.mAxes) && mStyle.equals(font.mStyle);
+        }
+
+        @Override
+        public int hashCode() {
+            int result = Objects.hash(mFile, mIndex, mStyle);
+            result = 31 * result + Arrays.hashCode(mAxes);
+            return result;
+        }
+    }
+
+    /**
+     * Represents native font family object.
+     */
+    public static final class Family {
+        private final List<Font> mFonts;
+        private final String mLocale;
+
+        public Family(List<Font> fonts, String locale) {
+            mFonts = fonts;
+            mLocale = locale;
+        }
+
+        public List<Font> getFonts() {
+            return mFonts;
+        }
+
+        public String getLocale() {
+            return mLocale;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            Family family = (Family) o;
+            return mFonts.equals(family.mFonts) && mLocale.equals(family.mLocale);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mFonts, mLocale);
+        }
+    }
+
+    /**
+     * Get underlying font families from Typeface
+     *
+     * @param typeface a typeface
+     * @return list of family
+     */
+    public static List<Family> readTypeface(Typeface typeface) {
+        int familyCount = nGetFamilyCount(typeface.native_instance);
+        List<Family> result = new ArrayList<>(familyCount);
+        for (int i = 0; i < familyCount; ++i) {
+            result.add(readNativeFamily(nGetFamily(typeface.native_instance, i)));
+        }
+        return result;
+    }
+
+    /**
+     * Read family object from native pointer
+     *
+     * @param familyPtr a font family pointer
+     * @return a family
+     */
+    public static Family readNativeFamily(long familyPtr) {
+        int fontCount = nGetFontCount(familyPtr);
+        List<Font> result = new ArrayList<>(fontCount);
+        for (int i = 0; i < fontCount; ++i) {
+            result.add(readNativeFont(nGetFont(familyPtr, i)));
+        }
+        String localeList = nGetLocaleList(familyPtr);
+        return new Family(result, localeList);
+    }
+
+    /**
+     * Read font object from native pointer.
+     *
+     * @param ptr a font pointer
+     * @return a font
+     */
+    public static Font readNativeFont(long ptr) {
+        long packed = nGetFontInfo(ptr);
+        int weight = (int) (packed & 0x0000_0000_0000_FFFFL);
+        boolean italic = (packed & 0x0000_0000_0001_0000L) != 0;
+        int ttcIndex = (int) ((packed & 0x0000_FFFF_0000_0000L) >> 32);
+        int axisCount = (int) ((packed & 0xFFFF_0000_0000_0000L) >> 48);
+        FontVariationAxis[] axes = new FontVariationAxis[axisCount];
+        char[] charBuffer = new char[4];
+        for (int i = 0; i < axisCount; ++i) {
+            long packedAxis = nGetAxisInfo(ptr, i);
+            float value = Float.intBitsToFloat((int) (packedAxis & 0x0000_0000_FFFF_FFFFL));
+            charBuffer[0] = (char) ((packedAxis & 0xFF00_0000_0000_0000L) >> 56);
+            charBuffer[1] = (char) ((packedAxis & 0x00FF_0000_0000_0000L) >> 48);
+            charBuffer[2] = (char) ((packedAxis & 0x0000_FF00_0000_0000L) >> 40);
+            charBuffer[3] = (char) ((packedAxis & 0x0000_00FF_0000_0000L) >> 32);
+            axes[i] = new FontVariationAxis(new String(charBuffer), value);
+        }
+        String path = nGetFontPath(ptr);
+        File file = (path == null) ? null : new File(path);
+        FontStyle style = new FontStyle(weight,
+                italic ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT);
+
+        return new Font(file, ttcIndex, axes, style);
+    }
+
+    @CriticalNative
+    private static native int nGetFamilyCount(long ptr);
+
+    @CriticalNative
+    private static native long nGetFamily(long ptr, int index);
+
+    @FastNative
+    private static native String nGetLocaleList(long familyPtr);
+
+    @CriticalNative
+    private static native long nGetFont(long familyPtr, int fontIndex);
+
+    @CriticalNative
+    private static native int nGetFontCount(long familyPtr);
+
+    @CriticalNative
+    private static native long nGetFontInfo(long fontPtr);
+
+    @CriticalNative
+    private static native long nGetAxisInfo(long fontPtr, int i);
+
+    @FastNative
+    private static native String nGetFontPath(long fontPtr);
+}
diff --git a/graphics/java/android/graphics/fonts/OWNERS b/graphics/java/android/graphics/fonts/OWNERS
new file mode 100644
index 0000000..e0a354e
--- /dev/null
+++ b/graphics/java/android/graphics/fonts/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 24939
+
+romainguy@google.com
+nona@google.com
+siyamed@google.com
diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java
index 3635adc..fb6ea99 100644
--- a/graphics/java/android/graphics/fonts/SystemFonts.java
+++ b/graphics/java/android/graphics/fonts/SystemFonts.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.FontListParser;
+import android.graphics.Typeface;
 import android.text.FontConfig;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -68,21 +69,40 @@
                 return sAvailableFonts;
             }
 
-            Set<Font> set = new HashSet<>();
-
-            for (FontFamily[] items : sFamilyMap.values()) {
-                for (FontFamily family : items) {
-                    for (int i = 0; i < family.getSize(); ++i) {
-                        set.add(family.getFont(i));
+            if (Typeface.ENABLE_LAZY_TYPEFACE_INITIALIZATION) {
+                sAvailableFonts = collectAllFonts();
+            } else {
+                Set<Font> set = new HashSet<>();
+                for (FontFamily[] items : sFamilyMap.values()) {
+                    for (FontFamily family : items) {
+                        for (int i = 0; i < family.getSize(); ++i) {
+                            set.add(family.getFont(i));
+                        }
                     }
                 }
-            }
 
-            sAvailableFonts = Collections.unmodifiableSet(set);
+                sAvailableFonts = Collections.unmodifiableSet(set);
+            }
             return sAvailableFonts;
         }
     }
 
+    private static @NonNull Set<Font> collectAllFonts() {
+        final FontCustomizationParser.Result oemCustomization =
+                readFontCustomization("/product/etc/fonts_customization.xml", "/product/fonts/");
+        Map<String, FontFamily[]> map = new ArrayMap<>();
+        buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/", oemCustomization, map);
+        Set<Font> res = new HashSet<>();
+        for (FontFamily[] families : map.values()) {
+            for (FontFamily family : families) {
+                for (int i = 0; i < family.getSize(); ++i) {
+                    res.add(family.getFont(i));
+                }
+            }
+        }
+        return res;
+    }
+
     private static @Nullable ByteBuffer mmap(@NonNull String fullPath) {
         try (FileInputStream file = new FileInputStream(fullPath)) {
             final FileChannel fileChannel = file.getChannel();
diff --git a/graphics/java/android/graphics/pdf/OWNERS b/graphics/java/android/graphics/pdf/OWNERS
new file mode 100644
index 0000000..f04e200
--- /dev/null
+++ b/graphics/java/android/graphics/pdf/OWNERS
@@ -0,0 +1,8 @@
+# Bug component: 24939
+
+romainguy@google.com
+djsollen@google.com
+sumir@google.com
+svetoslavganov@android.com
+svetoslavganov@google.com
+moltmann@google.com
diff --git a/graphics/java/android/graphics/text/OWNERS b/graphics/java/android/graphics/text/OWNERS
new file mode 100644
index 0000000..e0a354e
--- /dev/null
+++ b/graphics/java/android/graphics/text/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 24939
+
+romainguy@google.com
+nona@google.com
+siyamed@google.com
diff --git a/libs/WindowManager/OWNERS b/libs/WindowManager/OWNERS
index 063d459..2c61df9 100644
--- a/libs/WindowManager/OWNERS
+++ b/libs/WindowManager/OWNERS
@@ -1,3 +1,3 @@
 set noparent
 
-include ../../services/core/java/com/android/server/wm/OWNERS
\ No newline at end of file
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 856c9c2..96e0559 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -122,6 +122,7 @@
         "kotlinx-coroutines-android",
         "kotlinx-coroutines-core",
         "iconloader_base",
+        "jsr330",
         "protolog-lib",
         "SettingsLib",
         "WindowManager-Shell-proto",
diff --git a/libs/WindowManager/Shell/res/layout/split_divider.xml b/libs/WindowManager/Shell/res/layout/split_divider.xml
index b86f36a..341fe61 100644
--- a/libs/WindowManager/Shell/res/layout/split_divider.xml
+++ b/libs/WindowManager/Shell/res/layout/split_divider.xml
@@ -14,7 +14,7 @@
   ~ limitations under the License.
   -->
 
-<com.android.wm.shell.apppairs.DividerView
+<com.android.wm.shell.common.split.DividerView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_height="match_parent"
     android:layout_width="match_parent">
@@ -24,4 +24,4 @@
         android:id="@+id/docked_divider_background"
         android:background="@color/docked_divider_background"/>
 
-</com.android.wm.shell.apppairs.DividerView>
+</com.android.wm.shell.common.split.DividerView>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandler.java
index ada7e1a..45948dd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandler.java
@@ -19,6 +19,7 @@
 import android.view.Gravity;
 
 import com.android.wm.shell.apppairs.AppPairs;
+import com.android.wm.shell.common.annotations.ExternalThread;
 import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
 import com.android.wm.shell.letterbox.LetterboxConfigController;
 import com.android.wm.shell.onehanded.OneHanded;
@@ -61,6 +62,7 @@
     }
 
     /** Dumps WM Shell internal state. */
+    @ExternalThread
     public void dump(PrintWriter pw) {
         mShellTaskOrganizer.dump(pw, "");
         pw.println();
@@ -76,6 +78,7 @@
 
 
     /** Returns {@code true} if command was found and executed. */
+    @ExternalThread
     public boolean handleCommand(String[] args, PrintWriter pw) {
         if (args.length < 2) {
             // Argument at position 0 is "WMShell".
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInit.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInit.java
index 118f189..94555de 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInit.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInit.java
@@ -21,6 +21,7 @@
 
 import com.android.wm.shell.apppairs.AppPairs;
 import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.annotations.ExternalThread;
 import com.android.wm.shell.draganddrop.DragAndDropController;
 import com.android.wm.shell.letterbox.LetterboxTaskListener;
 import com.android.wm.shell.splitscreen.SplitScreen;
@@ -56,6 +57,7 @@
         mFullscreenTaskListener = fullscreenTaskListener;
     }
 
+    @ExternalThread
     public void init() {
         // Start listening for display changes
         mDisplayImeController.startMonitorDisplays();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index beb9690..174c16a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -31,12 +31,14 @@
 import android.os.IBinder;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.util.Slog;
 import android.util.SparseArray;
 import android.view.SurfaceControl;
 import android.window.ITaskOrganizerController;
 import android.window.TaskAppearedInfo;
 import android.window.TaskOrganizer;
 
+import androidx.annotation.BinderThread;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
@@ -45,6 +47,7 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.common.annotations.ShellMainThread;
 import com.android.wm.shell.startingsurface.StartingSurfaceDrawer;
 
 import java.io.PrintWriter;
@@ -119,7 +122,7 @@
             ShellExecutor mainExecutor, ShellExecutor animExecutor, Context context) {
         super(taskOrganizerController, mainExecutor);
         mTransitions = new Transitions(this, transactionPool, mainExecutor, animExecutor);
-        if (Transitions.ENABLE_SHELL_TRANSITIONS) registerTransitionPlayer(mTransitions);
+        if (Transitions.ENABLE_SHELL_TRANSITIONS) mTransitions.register(this);
         // TODO(b/131727939) temporarily live here, the starting surface drawer should be controlled
         //  by a controller, that class should be create while porting
         //  ActivityRecord#addStartingWindow to WMShell.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java
index 120039d..10195b6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java
@@ -23,9 +23,9 @@
 
 import android.animation.Animator;
 import android.animation.ValueAnimator;
-import android.annotation.MainThread;
 import android.annotation.NonNull;
 import android.os.IBinder;
+import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.util.ArrayMap;
 import android.util.Slog;
@@ -35,15 +35,18 @@
 import android.window.TransitionInfo;
 import android.window.WindowOrganizer;
 
+import androidx.annotation.BinderThread;
+
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.common.annotations.ShellMainThread;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 
 import java.util.ArrayList;
 
 /** Plays transition animations */
-public class Transitions extends ITransitionPlayer.Stub {
+public class Transitions {
     private static final String TAG = "ShellTransitions";
 
     /** Set to {@code true} to enable shell transitions. */
@@ -54,6 +57,7 @@
     private final TransactionPool mTransactionPool;
     private final ShellExecutor mMainExecutor;
     private final ShellExecutor mAnimExecutor;
+    private final TransitionPlayerImpl mPlayerImpl;
 
     /** Keeps track of currently tracked transitions and all the animations associated with each */
     private final ArrayMap<IBinder, ArrayList<Animator>> mActiveTransitions = new ArrayMap<>();
@@ -64,6 +68,11 @@
         mTransactionPool = pool;
         mMainExecutor = mainExecutor;
         mAnimExecutor = animExecutor;
+        mPlayerImpl = new TransitionPlayerImpl();
+    }
+
+    public void register(ShellTaskOrganizer taskOrganizer) {
+        taskOrganizer.registerTransitionPlayer(mPlayerImpl);
     }
 
     // TODO(shell-transitions): real animations
@@ -115,77 +124,73 @@
                 || type == WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
     }
 
-    @Override
-    public void onTransitionReady(@NonNull IBinder transitionToken, @NonNull TransitionInfo info,
+    private void onTransitionReady(@NonNull IBinder transitionToken, @NonNull TransitionInfo info,
             @NonNull SurfaceControl.Transaction t) {
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "onTransitionReady %s: %s",
                 transitionToken, info);
         // start task
-        mMainExecutor.execute(() -> {
-            if (!mActiveTransitions.containsKey(transitionToken)) {
-                Slog.e(TAG, "Got transitionReady for non-active transition " + transitionToken
-                        + " expecting one of " + mActiveTransitions.keySet());
-            }
-            if (mActiveTransitions.get(transitionToken) != null) {
-                throw new IllegalStateException("Got a duplicate onTransitionReady call for "
-                        + transitionToken);
-            }
-            mActiveTransitions.put(transitionToken, new ArrayList<>());
-            boolean isOpening = isOpeningType(info.getType());
-            if (info.getRootLeash().isValid()) {
-                t.show(info.getRootLeash());
-            }
-            // changes should be ordered top-to-bottom in z
-            for (int i = info.getChanges().size() - 1; i >= 0; --i) {
-                final TransitionInfo.Change change = info.getChanges().get(i);
-                final SurfaceControl leash = change.getLeash();
-                final int mode = info.getChanges().get(i).getMode();
+        if (!mActiveTransitions.containsKey(transitionToken)) {
+            Slog.e(TAG, "Got transitionReady for non-active transition " + transitionToken
+                    + " expecting one of " + mActiveTransitions.keySet());
+        }
+        if (mActiveTransitions.get(transitionToken) != null) {
+            throw new IllegalStateException("Got a duplicate onTransitionReady call for "
+                    + transitionToken);
+        }
+        mActiveTransitions.put(transitionToken, new ArrayList<>());
+        boolean isOpening = isOpeningType(info.getType());
+        if (info.getRootLeash().isValid()) {
+            t.show(info.getRootLeash());
+        }
+        // changes should be ordered top-to-bottom in z
+        for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+            final TransitionInfo.Change change = info.getChanges().get(i);
+            final SurfaceControl leash = change.getLeash();
+            final int mode = info.getChanges().get(i).getMode();
 
-                // Don't animate anything with an animating parent
-                if (change.getParent() != null) {
-                    if (mode == TRANSIT_OPEN || mode == TRANSIT_SHOW) {
-                        t.show(leash);
-                        t.setMatrix(leash, 1, 0, 0, 1);
-                    }
-                    continue;
-                }
-
-                t.reparent(leash, info.getRootLeash());
-                t.setPosition(leash, change.getEndAbsBounds().left - info.getRootOffset().x,
-                        change.getEndAbsBounds().top - info.getRootOffset().y);
-                // Put all the OPEN/SHOW on top
+            // Don't animate anything with an animating parent
+            if (change.getParent() != null) {
                 if (mode == TRANSIT_OPEN || mode == TRANSIT_SHOW) {
                     t.show(leash);
                     t.setMatrix(leash, 1, 0, 0, 1);
-                    if (isOpening) {
-                        // put on top and fade in
-                        t.setLayer(leash, info.getChanges().size() - i);
-                        t.setAlpha(leash, 0.f);
-                        startExampleAnimation(transitionToken, leash, true /* show */);
-                    } else {
-                        // put on bottom and leave it visible without fade
-                        t.setLayer(leash, -i);
-                        t.setAlpha(leash, 1.f);
-                    }
-                } else if (mode == TRANSIT_CLOSE || mode == TRANSIT_HIDE) {
-                    if (isOpening) {
-                        // put on bottom and leave visible without fade
-                        t.setLayer(leash, -i);
-                    } else {
-                        // put on top and fade out
-                        t.setLayer(leash, info.getChanges().size() - i);
-                        startExampleAnimation(transitionToken, leash, false /* show */);
-                    }
-                } else {
-                    t.setLayer(leash, info.getChanges().size() - i);
                 }
+                continue;
             }
-            t.apply();
-            onFinish(transitionToken);
-        });
+
+            t.reparent(leash, info.getRootLeash());
+            t.setPosition(leash, change.getEndAbsBounds().left - info.getRootOffset().x,
+                    change.getEndAbsBounds().top - info.getRootOffset().y);
+            // Put all the OPEN/SHOW on top
+            if (mode == TRANSIT_OPEN || mode == TRANSIT_SHOW) {
+                t.show(leash);
+                t.setMatrix(leash, 1, 0, 0, 1);
+                if (isOpening) {
+                    // put on top and fade in
+                    t.setLayer(leash, info.getChanges().size() - i);
+                    t.setAlpha(leash, 0.f);
+                    startExampleAnimation(transitionToken, leash, true /* show */);
+                } else {
+                    // put on bottom and leave it visible without fade
+                    t.setLayer(leash, -i);
+                    t.setAlpha(leash, 1.f);
+                }
+            } else if (mode == TRANSIT_CLOSE || mode == TRANSIT_HIDE) {
+                if (isOpening) {
+                    // put on bottom and leave visible without fade
+                    t.setLayer(leash, -i);
+                } else {
+                    // put on top and fade out
+                    t.setLayer(leash, info.getChanges().size() - i);
+                    startExampleAnimation(transitionToken, leash, false /* show */);
+                }
+            } else {
+                t.setLayer(leash, info.getChanges().size() - i);
+            }
+        }
+        t.apply();
+        onFinish(transitionToken);
     }
 
-    @MainThread
     private void onFinish(IBinder transition) {
         if (!mActiveTransitions.get(transition).isEmpty()) return;
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
@@ -194,16 +199,32 @@
         mOrganizer.finishTransition(transition, null, null);
     }
 
-    @Override
-    public void requestStartTransition(int type, @NonNull IBinder transitionToken) {
+    private void requestStartTransition(int type, @NonNull IBinder transitionToken) {
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Transition requested: type=%d %s",
                 type, transitionToken);
-        mMainExecutor.execute(() -> {
-            if (mActiveTransitions.containsKey(transitionToken)) {
-                throw new RuntimeException("Transition already started " + transitionToken);
-            }
-            IBinder transition = mOrganizer.startTransition(type, transitionToken, null /* wct */);
-            mActiveTransitions.put(transition, null);
-        });
+
+        if (mActiveTransitions.containsKey(transitionToken)) {
+            throw new RuntimeException("Transition already started " + transitionToken);
+        }
+        IBinder transition = mOrganizer.startTransition(type, transitionToken, null /* wct */);
+        mActiveTransitions.put(transition, null);
+    }
+
+    @BinderThread
+    private class TransitionPlayerImpl extends ITransitionPlayer.Stub {
+        @Override
+        public void onTransitionReady(IBinder iBinder, TransitionInfo transitionInfo,
+                SurfaceControl.Transaction transaction) throws RemoteException {
+            mMainExecutor.execute(() -> {
+                Transitions.this.onTransitionReady(iBinder, transitionInfo, transaction);
+            });
+        }
+
+        @Override
+        public void requestStartTransition(int i, IBinder iBinder) throws RemoteException {
+            mMainExecutor.execute(() -> {
+                Transitions.this.requestStartTransition(i, iBinder);
+            });
+        }
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/WindowManagerShellWrapper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/WindowManagerShellWrapper.java
index acb9a5da..834de3f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/WindowManagerShellWrapper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/WindowManagerShellWrapper.java
@@ -18,11 +18,11 @@
 
 import static android.view.Display.DEFAULT_DISPLAY;
 
-import android.app.WindowConfiguration;
 import android.os.RemoteException;
-import android.view.WindowManagerGlobal;
 
+import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.pip.PinnedStackListenerForwarder;
+import com.android.wm.shell.pip.PinnedStackListenerForwarder.PinnedStackListener;
 
 /**
  * The singleton wrapper to communicate between WindowManagerService and WMShell features
@@ -31,32 +31,30 @@
 public class WindowManagerShellWrapper {
     private static final String TAG = WindowManagerShellWrapper.class.getSimpleName();
 
-    public static final int WINDOWING_MODE_PINNED = WindowConfiguration.WINDOWING_MODE_PINNED;
-
     /**
      * Forwarder to which we can add multiple pinned stack listeners. Each listener will receive
      * updates from the window manager service.
      */
-    private PinnedStackListenerForwarder mPinnedStackListenerForwarder =
-            new PinnedStackListenerForwarder();
+    private final PinnedStackListenerForwarder mPinnedStackListenerForwarder;
+
+    public WindowManagerShellWrapper(ShellExecutor shellMainExecutor) {
+        mPinnedStackListenerForwarder = new PinnedStackListenerForwarder(shellMainExecutor);
+    }
 
     /**
      * Adds a pinned stack listener, which will receive updates from the window manager service
      * along with any other pinned stack listeners that were added via this method.
      */
-    public void addPinnedStackListener(PinnedStackListenerForwarder.PinnedStackListener listener)
-            throws
-            RemoteException {
+    public void addPinnedStackListener(PinnedStackListener listener)
+            throws RemoteException {
         mPinnedStackListenerForwarder.addListener(listener);
-        WindowManagerGlobal.getWindowManagerService().registerPinnedStackListener(
-                DEFAULT_DISPLAY, mPinnedStackListenerForwarder);
+        mPinnedStackListenerForwarder.register(DEFAULT_DISPLAY);
     }
 
     /**
      * Removes a pinned stack listener.
      */
-    public void removePinnedStackListener(
-            PinnedStackListenerForwarder.PinnedStackListener listener) {
+    public void removePinnedStackListener(PinnedStackListener listener) {
         mPinnedStackListenerForwarder.removeListener(listener);
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
index d3032f8..cfbf845 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
@@ -29,11 +29,13 @@
 import android.window.WindowContainerTransaction;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.common.split.SplitLayout;
 
 import java.io.PrintWriter;
 
@@ -42,7 +44,7 @@
  * {@link #mTaskInfo1} and {@link #mTaskInfo2} in the pair.
  * Also includes all UI for managing the pair like the divider.
  */
-class AppPair implements ShellTaskOrganizer.TaskListener {
+class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.LayoutChangeListener {
     private static final String TAG = AppPair.class.getSimpleName();
 
     private ActivityManager.RunningTaskInfo mRootTaskInfo;
@@ -55,7 +57,7 @@
     private final AppPairsController mController;
     private final SyncTransactionQueue mSyncQueue;
     private final DisplayController mDisplayController;
-    private AppPairLayout mAppPairLayout;
+    private SplitLayout mSplitLayout;
 
     AppPair(AppPairsController controller) {
         mController = controller;
@@ -92,11 +94,9 @@
 
         mTaskInfo1 = task1;
         mTaskInfo2 = task2;
-        mAppPairLayout = new AppPairLayout(
+        mSplitLayout = new SplitLayout(
                 mDisplayController.getDisplayContext(mRootTaskInfo.displayId),
-                mDisplayController.getDisplay(mRootTaskInfo.displayId),
-                mRootTaskInfo.configuration,
-                mRootTaskLeash);
+                mRootTaskInfo.configuration, this, mRootTaskLeash);
 
         final WindowContainerToken token1 = task1.token;
         final WindowContainerToken token2 = task2.token;
@@ -107,8 +107,8 @@
                 .reparent(token2, mRootTaskInfo.token, true /* onTop */)
                 .setWindowingMode(token1, WINDOWING_MODE_MULTI_WINDOW)
                 .setWindowingMode(token2, WINDOWING_MODE_MULTI_WINDOW)
-                .setBounds(token1, mAppPairLayout.getBounds1())
-                .setBounds(token2, mAppPairLayout.getBounds2())
+                .setBounds(token1, mSplitLayout.getBounds1())
+                .setBounds(token2, mSplitLayout.getBounds2())
                 // Moving the root task to top after the child tasks were repareted , or the root
                 // task cannot be visible and focused.
                 .reorder(mRootTaskInfo.token, true);
@@ -117,6 +117,10 @@
     }
 
     void unpair() {
+        unpair(null /* toTopToken */);
+    }
+
+    private void unpair(@Nullable WindowContainerToken toTopToken) {
         final WindowContainerToken token1 = mTaskInfo1.token;
         final WindowContainerToken token2 = mTaskInfo2.token;
         final WindowContainerTransaction wct = new WindowContainerTransaction();
@@ -124,16 +128,16 @@
         // Reparent out of this container and reset windowing mode.
         wct.setHidden(mRootTaskInfo.token, true)
                 .reorder(mRootTaskInfo.token, false)
-                .reparent(token1, null, false /* onTop */)
-                .reparent(token2, null, false /* onTop */)
+                .reparent(token1, null, token1 == toTopToken /* onTop */)
+                .reparent(token2, null, token2 == toTopToken /* onTop */)
                 .setWindowingMode(token1, WINDOWING_MODE_UNDEFINED)
                 .setWindowingMode(token2, WINDOWING_MODE_UNDEFINED);
         mController.getTaskOrganizer().applyTransaction(wct);
 
         mTaskInfo1 = null;
         mTaskInfo2 = null;
-        mAppPairLayout.release();
-        mAppPairLayout = null;
+        mSplitLayout.release();
+        mSplitLayout = null;
     }
 
     @Override
@@ -153,17 +157,17 @@
 
         if (mTaskLeash1 == null || mTaskLeash2 == null) return;
 
-        mAppPairLayout.init();
-        final SurfaceControl dividerLeash = mAppPairLayout.getDividerLeash();
-        final Rect dividerBounds = mAppPairLayout.getDividerBounds();
+        mSplitLayout.init();
+        final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
+        final Rect dividerBounds = mSplitLayout.getDividerBounds();
 
         // TODO: Is there more we need to do here?
         mSyncQueue.runInSync(t -> {
-            t.setPosition(mTaskLeash1, mTaskInfo1.positionInParent.x,
-                    mTaskInfo1.positionInParent.y)
+            t.setLayer(dividerLeash, Integer.MAX_VALUE)
+                    .setPosition(mTaskLeash1, mTaskInfo1.positionInParent.x,
+                            mTaskInfo1.positionInParent.y)
                     .setPosition(mTaskLeash2, mTaskInfo2.positionInParent.x,
                             mTaskInfo2.positionInParent.y)
-                    .setLayer(dividerLeash, Integer.MAX_VALUE)
                     .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top)
                     .show(mRootTaskLeash)
                     .show(mTaskLeash1)
@@ -185,14 +189,14 @@
             }
             mRootTaskInfo = taskInfo;
 
-            if (mAppPairLayout != null
-                    && mAppPairLayout.updateConfiguration(mRootTaskInfo.configuration)) {
+            if (mSplitLayout != null
+                    && mSplitLayout.updateConfiguration(mRootTaskInfo.configuration)) {
                 // Update bounds when root bounds or its orientation changed.
                 final WindowContainerTransaction wct = new WindowContainerTransaction();
-                final SurfaceControl dividerLeash = mAppPairLayout.getDividerLeash();
-                final Rect dividerBounds = mAppPairLayout.getDividerBounds();
-                final Rect bounds1 = mAppPairLayout.getBounds1();
-                final Rect bounds2 = mAppPairLayout.getBounds2();
+                final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
+                final Rect dividerBounds = mSplitLayout.getDividerBounds();
+                final Rect bounds1 = mSplitLayout.getBounds1();
+                final Rect bounds2 = mSplitLayout.getBounds2();
 
                 wct.setBounds(mTaskInfo1.token, bounds1)
                         .setBounds(mTaskInfo2.token, bounds2);
@@ -200,7 +204,9 @@
                 mSyncQueue.runInSync(t -> t
                         .setPosition(mTaskLeash1, bounds1.left, bounds1.top)
                         .setPosition(mTaskLeash2, bounds2.left, bounds2.top)
-                        .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top));
+                        .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top)
+                        // Resets layer to divider bar to make sure it is always on top.
+                        .setLayer(dividerLeash, Integer.MAX_VALUE));
             }
         } else if (taskInfo.taskId == getTaskId1()) {
             mTaskInfo1 = taskInfo;
@@ -242,4 +248,39 @@
     public String toString() {
         return TAG + "#" + getRootTaskId();
     }
+
+    @Override
+    public void onSnappedToDismiss(boolean snappedToEnd) {
+        unpair(snappedToEnd ? mTaskInfo1.token : mTaskInfo2.token /* toTopToken */);
+    }
+
+    @Override
+    public void onBoundsChanging(SplitLayout layout) {
+        final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
+        if (dividerLeash == null) return;
+        final Rect dividerBounds = layout.getDividerBounds();
+        final Rect bounds1 = layout.getBounds1();
+        final Rect bounds2 = layout.getBounds2();
+        mSyncQueue.runInSync(t -> t
+                .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top)
+                .setPosition(mTaskLeash1, bounds1.left, bounds1.top)
+                .setPosition(mTaskLeash2, bounds2.left, bounds2.top));
+    }
+
+    @Override
+    public void onBoundsChanged(SplitLayout layout) {
+        final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
+        if (dividerLeash == null) return;
+        final Rect dividerBounds = layout.getDividerBounds();
+        final Rect bounds1 = layout.getBounds1();
+        final Rect bounds2 = layout.getBounds2();
+        final WindowContainerTransaction wct = new WindowContainerTransaction();
+        wct.setBounds(mTaskInfo1.token, bounds1)
+                .setBounds(mTaskInfo2.token, bounds2);
+        mController.getTaskOrganizer().applyTransaction(wct);
+        mSyncQueue.runInSync(t -> t
+                .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top)
+                .setPosition(mTaskLeash1, bounds1.left, bounds1.top)
+                .setPosition(mTaskLeash2, bounds2.left, bounds2.top));
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairLayout.java
deleted file mode 100644
index 8c8655e..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairLayout.java
+++ /dev/null
@@ -1,211 +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 com.android.wm.shell.apppairs;
-
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
-import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
-import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
-
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.os.Binder;
-import android.os.IBinder;
-import android.view.Display;
-import android.view.IWindow;
-import android.view.LayoutInflater;
-import android.view.SurfaceControl;
-import android.view.SurfaceControlViewHost;
-import android.view.WindowManager;
-import android.view.WindowlessWindowManager;
-
-import com.android.wm.shell.R;
-
-/**
- * Records and handles layout of a pair of apps.
- */
-final class AppPairLayout {
-    private static final String DIVIDER_WINDOW_TITLE = "AppPairDivider";
-    private final Display mDisplay;
-    private final int mDividerWindowWidth;
-    private final int mDividerWindowInsets;
-    private final AppPairWindowManager mAppPairWindowManager;
-
-    private Context mContext;
-    private Rect mRootBounds;
-    private DIVIDE_POLICY mDividePolicy;
-
-    private SurfaceControlViewHost mViewHost;
-    private SurfaceControl mDividerLeash;
-
-    AppPairLayout(
-            Context context,
-            Display display,
-            Configuration configuration,
-            SurfaceControl rootLeash) {
-        mContext = context.createConfigurationContext(configuration);
-        mDisplay = display;
-        mRootBounds = configuration.windowConfiguration.getBounds();
-        mDividerWindowWidth = mContext.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.docked_stack_divider_thickness);
-        mDividerWindowInsets = mContext.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.docked_stack_divider_insets);
-
-        mAppPairWindowManager = new AppPairWindowManager(configuration, rootLeash);
-        mDividePolicy = DIVIDE_POLICY.MIDDLE;
-        mDividePolicy.update(mRootBounds, mDividerWindowWidth, mDividerWindowInsets);
-    }
-
-    boolean updateConfiguration(Configuration configuration) {
-        mAppPairWindowManager.setConfiguration(configuration);
-        final Rect rootBounds = configuration.windowConfiguration.getBounds();
-        if (isIdenticalBounds(mRootBounds, rootBounds)) {
-            return false;
-        }
-
-        mContext = mContext.createConfigurationContext(configuration);
-        mRootBounds = rootBounds;
-        mDividePolicy.update(mRootBounds, mDividerWindowWidth, mDividerWindowInsets);
-        release();
-        init();
-        return true;
-    }
-
-    Rect getBounds1() {
-        return mDividePolicy.mBounds1;
-    }
-
-    Rect getBounds2() {
-        return mDividePolicy.mBounds2;
-    }
-
-    Rect getDividerBounds() {
-        return mDividePolicy.mDividerBounds;
-    }
-
-    SurfaceControl getDividerLeash() {
-        return mDividerLeash;
-    }
-
-    void release() {
-        if (mViewHost == null) {
-            return;
-        }
-        mViewHost.release();
-        mDividerLeash = null;
-        mViewHost = null;
-    }
-
-    void init() {
-        if (mViewHost == null) {
-            mViewHost = new SurfaceControlViewHost(mContext, mDisplay, mAppPairWindowManager);
-        }
-
-        final DividerView dividerView = (DividerView) LayoutInflater.from(mContext)
-                .inflate(R.layout.split_divider, null);
-
-        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                mDividePolicy.mDividerBounds.width(),
-                mDividePolicy.mDividerBounds.height(),
-                TYPE_DOCK_DIVIDER,
-                FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL | FLAG_WATCH_OUTSIDE_TOUCH
-                        | FLAG_SPLIT_TOUCH | FLAG_SLIPPERY,
-                PixelFormat.TRANSLUCENT);
-        lp.token = new Binder();
-        lp.setTitle(DIVIDER_WINDOW_TITLE);
-        lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION;
-
-        mViewHost.setView(dividerView, lp);
-        mDividerLeash = mAppPairWindowManager.getSurfaceControl(mViewHost.getWindowToken());
-    }
-
-    private static boolean isIdenticalBounds(Rect bounds1, Rect bounds2) {
-        return bounds1.left == bounds2.left && bounds1.top == bounds2.top
-                && bounds1.right == bounds2.right && bounds1.bottom == bounds2.bottom;
-    }
-
-    /**
-     * Indicates the policy of placing divider bar and corresponding split-screens.
-     */
-    // TODO(172704238): add more divide policy and provide snap to resize feature for divider bar.
-    enum DIVIDE_POLICY {
-        MIDDLE;
-
-        void update(Rect rootBounds, int dividerWindowWidth, int dividerWindowInsets) {
-            final int dividerOffset = dividerWindowWidth / 2;
-            final int boundsOffset = dividerOffset - dividerWindowInsets;
-
-            mDividerBounds = new Rect(rootBounds);
-            mBounds1 = new Rect(rootBounds);
-            mBounds2 = new Rect(rootBounds);
-
-            switch (this) {
-                case MIDDLE:
-                default:
-                    if (isLandscape(rootBounds)) {
-                        mDividerBounds.left = rootBounds.width() / 2 - dividerOffset;
-                        mDividerBounds.right = rootBounds.width() / 2 + dividerOffset;
-                        mBounds1.left = rootBounds.width() / 2 + boundsOffset;
-                        mBounds2.right = rootBounds.width() / 2 - boundsOffset;
-                    } else {
-                        mDividerBounds.top = rootBounds.height() / 2 - dividerOffset;
-                        mDividerBounds.bottom = rootBounds.height() / 2 + dividerOffset;
-                        mBounds1.bottom = rootBounds.height() / 2 - boundsOffset;
-                        mBounds2.top = rootBounds.height() / 2 + boundsOffset;
-                    }
-            }
-        }
-
-        private boolean isLandscape(Rect bounds) {
-            return bounds.width() > bounds.height();
-        }
-
-        Rect mDividerBounds;
-        Rect mBounds1;
-        Rect mBounds2;
-    }
-
-    /**
-     * WindowManger for app pair. Holds view hierarchy for the root task.
-     */
-    private static final class AppPairWindowManager extends WindowlessWindowManager {
-        AppPairWindowManager(Configuration config, SurfaceControl rootSurface) {
-            super(config, rootSurface, null /* hostInputToken */);
-        }
-
-        @Override
-        public void setTouchRegion(IBinder window, Region region) {
-            super.setTouchRegion(window, region);
-        }
-
-        @Override
-        public SurfaceControl getSurfaceControl(IWindow window) {
-            return super.getSurfaceControl(window);
-        }
-
-        @Override
-        public void setConfiguration(Configuration configuration) {
-            super.setConfiguration(configuration);
-        }
-    }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java
index ef3e3e0..f5aa852 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java
@@ -20,11 +20,14 @@
 
 import androidx.annotation.NonNull;
 
+import com.android.wm.shell.common.annotations.ExternalThread;
+
 import java.io.PrintWriter;
 
 /**
  * Interface to engage app pairs feature.
  */
+@ExternalThread
 public interface AppPairs {
     /** Pairs indicated tasks. */
     boolean pair(int task1, int task2);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/DividerView.java
deleted file mode 100644
index 41b5e47..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/DividerView.java
+++ /dev/null
@@ -1,56 +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 com.android.wm.shell.apppairs;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-/**
- * Stack divider for app pair.
- */
-public class DividerView extends FrameLayout {
-    public DividerView(@NonNull Context context) {
-        super(context);
-    }
-
-    public DividerView(@NonNull Context context,
-            @Nullable AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public DividerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-    }
-
-    public DividerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
-            int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-    }
-
-    void show() {
-        post(() -> setVisibility(View.VISIBLE));
-    }
-
-    void hide() {
-        post(() -> setVisibility(View.INVISIBLE));
-    }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index aa7355b..40b41e1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -1213,7 +1213,7 @@
         @Override
         public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
             if (mStackView != null) {
-                mStackView.post(() -> mStackView.onImeVisibilityChanged(imeVisible, imeHeight));
+                mStackView.onImeVisibilityChanged(imeVisible, imeHeight);
             }
         }
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index 92d15c5..fa5ac44 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -30,6 +30,8 @@
 import androidx.annotation.IntDef;
 import androidx.annotation.Nullable;
 
+import com.android.wm.shell.common.annotations.ExternalThread;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -40,6 +42,7 @@
 /**
  * Interface to engage bubbles feature.
  */
+@ExternalThread
 public interface Bubbles {
 
     @Retention(SOURCE)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/AnimationThread.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/AnimationThread.java
deleted file mode 100644
index 96b9f86..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/AnimationThread.java
+++ /dev/null
@@ -1,61 +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 com.android.wm.shell.common;
-
-import static android.os.Process.THREAD_PRIORITY_DISPLAY;
-
-import android.annotation.NonNull;
-import android.os.HandlerThread;
-import android.util.Singleton;
-
-/**
- * A singleton thread for Shell to run animations on.
- */
-public class AnimationThread extends HandlerThread {
-    private ShellExecutor mExecutor;
-
-    private AnimationThread() {
-        super("wmshell.anim", THREAD_PRIORITY_DISPLAY);
-    }
-
-    /** Get the singleton instance of this thread */
-    public static AnimationThread instance() {
-        return sAnimationThreadSingleton.get();
-    }
-
-    /**
-     * @return a shared {@link ShellExecutor} associated with this thread
-     * @hide
-     */
-    @NonNull
-    public ShellExecutor getExecutor() {
-        if (mExecutor == null) {
-            mExecutor = new HandlerExecutor(getThreadHandler());
-        }
-        return mExecutor;
-    }
-
-    private static final Singleton<AnimationThread> sAnimationThreadSingleton =
-            new Singleton<AnimationThread>() {
-                @Override
-                protected AnimationThread create() {
-                    final AnimationThread animThread = new AnimationThread();
-                    animThread.start();
-                    return animThread;
-                }
-            };
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java
index 3263f79..cb4584c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java
@@ -23,6 +23,10 @@
 import android.view.IWindowManager;
 import android.window.WindowContainerTransaction;
 
+import androidx.annotation.BinderThread;
+
+import com.android.wm.shell.common.annotations.ShellMainThread;
+
 import java.util.ArrayList;
 
 /**
@@ -35,39 +39,18 @@
 
     private final Handler mHandler;
     private final IWindowManager mWmService;
+    private final IDisplayWindowRotationController mControllerImpl;
 
     private final ArrayList<OnDisplayChangingListener> mRotationListener =
             new ArrayList<>();
     private final ArrayList<OnDisplayChangingListener> mTmpListeners = new ArrayList<>();
 
-    private final IDisplayWindowRotationController mDisplayRotationController =
-            new IDisplayWindowRotationController.Stub() {
-                @Override
-                public void onRotateDisplay(int displayId, final int fromRotation,
-                        final int toRotation, IDisplayWindowRotationCallback callback) {
-                    mHandler.post(() -> {
-                        WindowContainerTransaction t = new WindowContainerTransaction();
-                        synchronized (mRotationListener) {
-                            mTmpListeners.clear();
-                            // Make a local copy in case the handlers add/remove themselves.
-                            mTmpListeners.addAll(mRotationListener);
-                        }
-                        for (OnDisplayChangingListener c : mTmpListeners) {
-                            c.onRotateDisplay(displayId, fromRotation, toRotation, t);
-                        }
-                        try {
-                            callback.continueRotateDisplay(toRotation, t);
-                        } catch (RemoteException e) {
-                        }
-                    });
-                }
-            };
-
     public DisplayChangeController(Handler mainHandler, IWindowManager wmService) {
         mHandler = mainHandler;
         mWmService = wmService;
+        mControllerImpl = new DisplayWindowRotationControllerImpl();
         try {
-            mWmService.setDisplayWindowRotationController(mDisplayRotationController);
+            mWmService.setDisplayWindowRotationController(mControllerImpl);
         } catch (RemoteException e) {
             throw new RuntimeException("Unable to register rotation controller");
         }
@@ -91,10 +74,41 @@
         }
     }
 
+    private void onRotateDisplay(int displayId, final int fromRotation, final int toRotation,
+            IDisplayWindowRotationCallback callback) {
+        WindowContainerTransaction t = new WindowContainerTransaction();
+        synchronized (mRotationListener) {
+            mTmpListeners.clear();
+            // Make a local copy in case the handlers add/remove themselves.
+            mTmpListeners.addAll(mRotationListener);
+        }
+        for (OnDisplayChangingListener c : mTmpListeners) {
+            c.onRotateDisplay(displayId, fromRotation, toRotation, t);
+        }
+        try {
+            callback.continueRotateDisplay(toRotation, t);
+        } catch (RemoteException e) {
+        }
+    }
+
+    @BinderThread
+    private class DisplayWindowRotationControllerImpl
+            extends IDisplayWindowRotationController.Stub {
+        @Override
+        public void onRotateDisplay(int displayId, final int fromRotation,
+                final int toRotation, IDisplayWindowRotationCallback callback) {
+            mHandler.post(() -> {
+                DisplayChangeController.this.onRotateDisplay(displayId, fromRotation, toRotation,
+                        callback);
+            });
+        }
+    }
+
     /**
      * Give a listener a chance to queue up configuration changes to execute as part of a
      * display rotation. The contents of {@link #onRotateDisplay} must run synchronously.
      */
+    @ShellMainThread
     public interface OnDisplayChangingListener {
         /**
          * Called before the display is rotated. Contents of this method must run synchronously.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
index 4189732..a413c05 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
@@ -28,7 +28,10 @@
 import android.view.IDisplayWindowListener;
 import android.view.IWindowManager;
 
+import androidx.annotation.BinderThread;
+
 import com.android.wm.shell.common.DisplayChangeController.OnDisplayChangingListener;
+import com.android.wm.shell.common.annotations.ShellMainThread;
 
 import java.util.ArrayList;
 
@@ -45,6 +48,7 @@
     private final Context mContext;
     private final IWindowManager mWmService;
     private final DisplayChangeController mChangeController;
+    private final IDisplayWindowListener mDisplayContainerListener;
 
     private final SparseArray<DisplayRecord> mDisplays = new SparseArray<>();
     private final ArrayList<OnDisplaysChangedListener> mDisplayChangedListeners = new ArrayList<>();
@@ -57,119 +61,13 @@
         return displayManager.getDisplay(displayId);
     }
 
-    private final IDisplayWindowListener mDisplayContainerListener =
-            new IDisplayWindowListener.Stub() {
-                @Override
-                public void onDisplayAdded(int displayId) {
-                    mHandler.post(() -> {
-                        synchronized (mDisplays) {
-                            if (mDisplays.get(displayId) != null) {
-                                return;
-                            }
-                            Display display = getDisplay(displayId);
-                            if (display == null) {
-                                // It's likely that the display is private to some app and thus not
-                                // accessible by system-ui.
-                                return;
-                            }
-                            DisplayRecord record = new DisplayRecord();
-                            record.mDisplayId = displayId;
-                            record.mContext = (displayId == Display.DEFAULT_DISPLAY) ? mContext
-                                    : mContext.createDisplayContext(display);
-                            record.mDisplayLayout = new DisplayLayout(record.mContext, display);
-                            mDisplays.put(displayId, record);
-                            for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
-                                mDisplayChangedListeners.get(i).onDisplayAdded(displayId);
-                            }
-                        }
-                    });
-                }
-
-                @Override
-                public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
-                    mHandler.post(() -> {
-                        synchronized (mDisplays) {
-                            DisplayRecord dr = mDisplays.get(displayId);
-                            if (dr == null) {
-                                Slog.w(TAG, "Skipping Display Configuration change on non-added"
-                                        + " display.");
-                                return;
-                            }
-                            Display display = getDisplay(displayId);
-                            if (display == null) {
-                                Slog.w(TAG, "Skipping Display Configuration change on invalid"
-                                        + " display. It may have been removed.");
-                                return;
-                            }
-                            Context perDisplayContext = mContext;
-                            if (displayId != Display.DEFAULT_DISPLAY) {
-                                perDisplayContext = mContext.createDisplayContext(display);
-                            }
-                            dr.mContext = perDisplayContext.createConfigurationContext(newConfig);
-                            dr.mDisplayLayout = new DisplayLayout(dr.mContext, display);
-                            for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
-                                mDisplayChangedListeners.get(i).onDisplayConfigurationChanged(
-                                        displayId, newConfig);
-                            }
-                        }
-                    });
-                }
-
-                @Override
-                public void onDisplayRemoved(int displayId) {
-                    mHandler.post(() -> {
-                        synchronized (mDisplays) {
-                            if (mDisplays.get(displayId) == null) {
-                                return;
-                            }
-                            for (int i = mDisplayChangedListeners.size() - 1; i >= 0; --i) {
-                                mDisplayChangedListeners.get(i).onDisplayRemoved(displayId);
-                            }
-                            mDisplays.remove(displayId);
-                        }
-                    });
-                }
-
-                @Override
-                public void onFixedRotationStarted(int displayId, int newRotation) {
-                    mHandler.post(() -> {
-                        synchronized (mDisplays) {
-                            if (mDisplays.get(displayId) == null || getDisplay(displayId) == null) {
-                                Slog.w(TAG, "Skipping onFixedRotationStarted on unknown"
-                                        + " display, displayId=" + displayId);
-                                return;
-                            }
-                            for (int i = mDisplayChangedListeners.size() - 1; i >= 0; --i) {
-                                mDisplayChangedListeners.get(i).onFixedRotationStarted(
-                                        displayId, newRotation);
-                            }
-                        }
-                    });
-                }
-
-                @Override
-                public void onFixedRotationFinished(int displayId) {
-                    mHandler.post(() -> {
-                        synchronized (mDisplays) {
-                            if (mDisplays.get(displayId) == null || getDisplay(displayId) == null) {
-                                Slog.w(TAG, "Skipping onFixedRotationFinished on unknown"
-                                        + " display, displayId=" + displayId);
-                                return;
-                            }
-                            for (int i = mDisplayChangedListeners.size() - 1; i >= 0; --i) {
-                                mDisplayChangedListeners.get(i).onFixedRotationFinished(displayId);
-                            }
-                        }
-                    });
-                }
-            };
-
     public DisplayController(Context context, Handler handler,
             IWindowManager wmService) {
         mHandler = handler;
         mContext = context;
         mWmService = wmService;
         mChangeController = new DisplayChangeController(mHandler, mWmService);
+        mDisplayContainerListener = new DisplayWindowListenerImpl();
         try {
             mWmService.registerDisplayWindowListener(mDisplayContainerListener);
         } catch (RemoteException e) {
@@ -232,18 +130,146 @@
         mChangeController.removeRotationListener(controller);
     }
 
+    private void onDisplayAdded(int displayId) {
+        synchronized (mDisplays) {
+            if (mDisplays.get(displayId) != null) {
+                return;
+            }
+            Display display = getDisplay(displayId);
+            if (display == null) {
+                // It's likely that the display is private to some app and thus not
+                // accessible by system-ui.
+                return;
+            }
+            DisplayRecord record = new DisplayRecord();
+            record.mDisplayId = displayId;
+            record.mContext = (displayId == Display.DEFAULT_DISPLAY) ? mContext
+                    : mContext.createDisplayContext(display);
+            record.mDisplayLayout = new DisplayLayout(record.mContext, display);
+            mDisplays.put(displayId, record);
+            for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
+                mDisplayChangedListeners.get(i).onDisplayAdded(displayId);
+            }
+        }
+    }
+
+    private void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+        synchronized (mDisplays) {
+            DisplayRecord dr = mDisplays.get(displayId);
+            if (dr == null) {
+                Slog.w(TAG, "Skipping Display Configuration change on non-added"
+                        + " display.");
+                return;
+            }
+            Display display = getDisplay(displayId);
+            if (display == null) {
+                Slog.w(TAG, "Skipping Display Configuration change on invalid"
+                        + " display. It may have been removed.");
+                return;
+            }
+            Context perDisplayContext = mContext;
+            if (displayId != Display.DEFAULT_DISPLAY) {
+                perDisplayContext = mContext.createDisplayContext(display);
+            }
+            dr.mContext = perDisplayContext.createConfigurationContext(newConfig);
+            dr.mDisplayLayout = new DisplayLayout(dr.mContext, display);
+            for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
+                mDisplayChangedListeners.get(i).onDisplayConfigurationChanged(
+                        displayId, newConfig);
+            }
+        }
+    }
+
+    private void onDisplayRemoved(int displayId) {
+        synchronized (mDisplays) {
+            if (mDisplays.get(displayId) == null) {
+                return;
+            }
+            for (int i = mDisplayChangedListeners.size() - 1; i >= 0; --i) {
+                mDisplayChangedListeners.get(i).onDisplayRemoved(displayId);
+            }
+            mDisplays.remove(displayId);
+        }
+    }
+
+    private void onFixedRotationStarted(int displayId, int newRotation) {
+        synchronized (mDisplays) {
+            if (mDisplays.get(displayId) == null || getDisplay(displayId) == null) {
+                Slog.w(TAG, "Skipping onFixedRotationStarted on unknown"
+                        + " display, displayId=" + displayId);
+                return;
+            }
+            for (int i = mDisplayChangedListeners.size() - 1; i >= 0; --i) {
+                mDisplayChangedListeners.get(i).onFixedRotationStarted(
+                        displayId, newRotation);
+            }
+        }
+    }
+
+    private void onFixedRotationFinished(int displayId) {
+        synchronized (mDisplays) {
+            if (mDisplays.get(displayId) == null || getDisplay(displayId) == null) {
+                Slog.w(TAG, "Skipping onFixedRotationFinished on unknown"
+                        + " display, displayId=" + displayId);
+                return;
+            }
+            for (int i = mDisplayChangedListeners.size() - 1; i >= 0; --i) {
+                mDisplayChangedListeners.get(i).onFixedRotationFinished(displayId);
+            }
+        }
+    }
+
     private static class DisplayRecord {
         int mDisplayId;
         Context mContext;
         DisplayLayout mDisplayLayout;
     }
 
+    @BinderThread
+    private class DisplayWindowListenerImpl extends IDisplayWindowListener.Stub {
+        @Override
+        public void onDisplayAdded(int displayId) {
+            mHandler.post(() -> {
+                DisplayController.this.onDisplayAdded(displayId);
+            });
+        }
+
+        @Override
+        public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+            mHandler.post(() -> {
+                DisplayController.this.onDisplayConfigurationChanged(displayId, newConfig);
+            });
+        }
+
+        @Override
+        public void onDisplayRemoved(int displayId) {
+            mHandler.post(() -> {
+                DisplayController.this.onDisplayRemoved(displayId);
+            });
+        }
+
+        @Override
+        public void onFixedRotationStarted(int displayId, int newRotation) {
+            mHandler.post(() -> {
+                DisplayController.this.onFixedRotationStarted(displayId, newRotation);
+            });
+        }
+
+        @Override
+        public void onFixedRotationFinished(int displayId) {
+            mHandler.post(() -> {
+                DisplayController.this.onFixedRotationFinished(displayId);
+            });
+        }
+    }
+
     /**
      * Gets notified when a display is added/removed to the WM hierarchy and when a display's
      * window-configuration changes.
      *
      * @see IDisplayWindowListener
      */
+    @ShellMainThread
     public interface OnDisplaysChangedListener {
         /**
          * Called when a display has been added to the WM hierarchy.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index ea18a19..3fbd7ed 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -24,7 +24,6 @@
 import android.content.res.Configuration;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.os.Handler;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Slog;
@@ -40,6 +39,8 @@
 import android.view.animation.Interpolator;
 import android.view.animation.PathInterpolator;
 
+import androidx.annotation.BinderThread;
+
 import com.android.internal.view.IInputMethodManager;
 
 import java.util.ArrayList;
@@ -197,6 +198,7 @@
             mRotation = initialRotation;
         }
 
+        @BinderThread
         @Override
         public void insetsChanged(InsetsState insetsState) {
             mExecutor.execute(() -> {
@@ -204,6 +206,8 @@
                     return;
                 }
 
+                mImeShowing = insetsState.getSourceOrDefaultVisibility(InsetsState.ITYPE_IME);
+
                 final InsetsSource newSource = insetsState.getSource(InsetsState.ITYPE_IME);
                 final Rect newFrame = newSource.getFrame();
                 final Rect oldFrame = mInsetsState.getSource(InsetsState.ITYPE_IME).getFrame();
@@ -216,6 +220,7 @@
             });
         }
 
+        @BinderThread
         @Override
         public void insetsControlChanged(InsetsState insetsState,
                 InsetsSourceControl[] activeControls) {
@@ -266,6 +271,7 @@
             }
         }
 
+        @BinderThread
         @Override
         public void showInsets(int types, boolean fromIme) {
             if ((types & WindowInsets.Type.ime()) == 0) {
@@ -275,6 +281,7 @@
             mExecutor.execute(() -> startAnimation(true /* show */, false /* forceRestart */));
         }
 
+        @BinderThread
         @Override
         public void hideInsets(int types, boolean fromIme) {
             if ((types & WindowInsets.Type.ime()) == 0) {
@@ -284,6 +291,7 @@
             mExecutor.execute(() -> startAnimation(false /* show */, false /* forceRestart */));
         }
 
+        @BinderThread
         @Override
         public void topFocusedWindowChanged(String packageName) {
             // no-op
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java
index cd75840..fa0a75c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/HandlerExecutor.java
@@ -28,6 +28,17 @@
     }
 
     @Override
+    public void execute(@NonNull Runnable command) {
+        if (mHandler.getLooper().isCurrentThread()) {
+            command.run();
+            return;
+        }
+        if (!mHandler.post(command)) {
+            throw new RuntimeException(mHandler + " is probably exiting");
+        }
+    }
+
+    @Override
     public void executeDelayed(@NonNull Runnable r, long delayMillis) {
         if (!mHandler.postDelayed(r, delayMillis)) {
             throw new RuntimeException(mHandler + " is probably exiting");
@@ -38,11 +49,4 @@
     public void removeCallbacks(@NonNull Runnable r) {
         mHandler.removeCallbacks(r);
     }
-
-    @Override
-    public void execute(@NonNull Runnable command) {
-        if (!mHandler.post(command)) {
-            throw new RuntimeException(mHandler + " is probably exiting");
-        }
-    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/PipInputConsumer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/PipInputConsumer.java
deleted file mode 100644
index 87ddb18..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/PipInputConsumer.java
+++ /dev/null
@@ -1,182 +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 com.android.wm.shell.common;
-
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.INPUT_CONSUMER_PIP;
-import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
-
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.util.Log;
-import android.view.BatchedInputEventReceiver;
-import android.view.Choreographer;
-import android.view.IWindowManager;
-import android.view.InputChannel;
-import android.view.InputEvent;
-import android.view.WindowManagerGlobal;
-
-import java.io.PrintWriter;
-
-/**
- * Manages the input consumer that allows the Shell to directly receive input.
- */
-public class PipInputConsumer {
-
-    private static final String TAG = PipInputConsumer.class.getSimpleName();
-
-    /**
-     * Listener interface for callers to subscribe to input events.
-     */
-    public interface InputListener {
-        /** Handles any input event. */
-        boolean onInputEvent(InputEvent ev);
-    }
-
-    /**
-     * Listener interface for callers to learn when this class is registered or unregistered with
-     * window manager
-     */
-    public interface RegistrationListener {
-        void onRegistrationChanged(boolean isRegistered);
-    }
-
-    /**
-     * Input handler used for the input consumer. Input events are batched and consumed with the
-     * SurfaceFlinger vsync.
-     */
-    private final class InputEventReceiver extends BatchedInputEventReceiver {
-
-        InputEventReceiver(InputChannel inputChannel, Looper looper,
-                Choreographer choreographer) {
-            super(inputChannel, looper, choreographer);
-        }
-
-        @Override
-        public void onInputEvent(InputEvent event) {
-            boolean handled = true;
-            try {
-                if (mListener != null) {
-                    handled = mListener.onInputEvent(event);
-                }
-            } finally {
-                finishInputEvent(event, handled);
-            }
-        }
-    }
-
-    private final IWindowManager mWindowManager;
-    private final IBinder mToken;
-    private final String mName;
-
-    private InputEventReceiver mInputEventReceiver;
-    private InputListener mListener;
-    private RegistrationListener mRegistrationListener;
-
-    /**
-     * @param name the name corresponding to the input consumer that is defined in the system.
-     */
-    public PipInputConsumer(IWindowManager windowManager, String name) {
-        mWindowManager = windowManager;
-        mToken = new Binder();
-        mName = name;
-    }
-
-    /**
-     * Sets the input listener.
-     */
-    public void setInputListener(InputListener listener) {
-        mListener = listener;
-    }
-
-    /**
-     * Sets the registration listener.
-     */
-    public void setRegistrationListener(RegistrationListener listener) {
-        mRegistrationListener = listener;
-        if (mRegistrationListener != null) {
-            mRegistrationListener.onRegistrationChanged(mInputEventReceiver != null);
-        }
-    }
-
-    /**
-     * Check if the InputConsumer is currently registered with WindowManager
-     *
-     * @return {@code true} if registered, {@code false} if not.
-     */
-    public boolean isRegistered() {
-        return mInputEventReceiver != null;
-    }
-
-    /**
-     * Registers the input consumer.
-     */
-    public void registerInputConsumer() {
-        registerInputConsumer(false);
-    }
-
-    /**
-     * Registers the input consumer.
-     * @param withSfVsync the flag set using sf vsync signal or no
-     */
-    public void registerInputConsumer(boolean withSfVsync) {
-        if (mInputEventReceiver != null) {
-            return;
-        }
-        final InputChannel inputChannel = new InputChannel();
-        try {
-            // TODO(b/113087003): Support Picture-in-picture in multi-display.
-            mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
-            mWindowManager.createInputConsumer(mToken, mName, DEFAULT_DISPLAY, inputChannel);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to create input consumer", e);
-        }
-        mInputEventReceiver = new InputEventReceiver(inputChannel, Looper.myLooper(),
-                withSfVsync ? Choreographer.getSfInstance() : Choreographer.getInstance());
-        if (mRegistrationListener != null) {
-            mRegistrationListener.onRegistrationChanged(true /* isRegistered */);
-        }
-    }
-
-    /**
-     * Unregisters the input consumer.
-     */
-    public void unregisterInputConsumer() {
-        if (mInputEventReceiver == null) {
-            return;
-        }
-        try {
-            // TODO(b/113087003): Support Picture-in-picture in multi-display.
-            mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to destroy input consumer", e);
-        }
-        mInputEventReceiver.dispose();
-        mInputEventReceiver = null;
-        if (mRegistrationListener != null) {
-            mRegistrationListener.onRegistrationChanged(false /* isRegistered */);
-        }
-    }
-
-    public void dump(PrintWriter pw, String prefix) {
-        final String innerPrefix = prefix + "  ";
-        pw.println(prefix + TAG);
-        pw.println(innerPrefix + "registered=" + (mInputEventReceiver != null));
-    }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java
index aafe240..22b831b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ShellExecutor.java
@@ -16,13 +16,40 @@
 
 package com.android.wm.shell.common;
 
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Super basic Executor interface that adds support for delayed execution and removing callbacks.
  * Intended to wrap Handler while better-supporting testing.
  */
 public interface ShellExecutor extends Executor {
+
+    /**
+     * Executes the given runnable. If the caller is running on the same looper as this executor,
+     * the runnable must be executed immediately.
+     */
+    @Override
+    void execute(Runnable runnable);
+
+    /**
+     * Executes the given runnable in a blocking call. If the caller is running on the same looper
+     * as this executor, the runnable must be executed immediately.
+     *
+     * @throws InterruptedException if runnable does not return in the time specified by
+     *                              {@param waitTimeout}
+     */
+    default void executeBlocking(Runnable runnable, int waitTimeout, TimeUnit waitTimeUnit)
+            throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        execute(() -> {
+            runnable.run();
+            latch.countDown();
+        });
+        latch.await(waitTimeout, waitTimeUnit);
+    }
+
     /**
      * See {@link android.os.Handler#postDelayed(Runnable, long)}.
      */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java
index 9cb1250..7321dc8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java
@@ -24,6 +24,10 @@
 import android.window.WindowContainerTransactionCallback;
 import android.window.WindowOrganizer;
 
+import androidx.annotation.BinderThread;
+
+import com.android.wm.shell.common.annotations.ShellMainThread;
+
 import java.util.ArrayList;
 
 /**
@@ -151,6 +155,7 @@
             mHandler.postDelayed(mOnReplyTimeout, REPLY_TIMEOUT);
         }
 
+        @BinderThread
         @Override
         public void onTransactionReady(int id,
                 @NonNull SurfaceControl.Transaction t) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java
index 0f6dd93..5e07718 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java
@@ -19,12 +19,10 @@
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ITaskStackListener;
-import android.app.TaskInfo;
 import android.content.ComponentName;
 import android.os.IBinder;
 
 import androidx.annotation.BinderThread;
-import androidx.annotation.MainThread;
 
 /**
  * An interface to track task stack changes. Classes should implement this instead of
@@ -32,85 +30,61 @@
  */
 public interface TaskStackListenerCallback {
 
-    @MainThread
     default void onRecentTaskListUpdated() { }
 
-    @MainThread
     default void onRecentTaskListFrozenChanged(boolean frozen) { }
 
     @BinderThread
     default void onTaskStackChangedBackground() { }
 
-    @MainThread
     default void onTaskStackChanged() { }
 
-    @MainThread
     default void onTaskProfileLocked(int taskId, int userId) { }
 
-    @MainThread
     default void onTaskDisplayChanged(int taskId, int newDisplayId) { }
 
-    @MainThread
     default void onTaskCreated(int taskId, ComponentName componentName) { }
 
-    @MainThread
     default void onTaskRemoved(int taskId) { }
 
-    @MainThread
     default void onTaskMovedToFront(int taskId) { }
 
-    @MainThread
     default void onTaskMovedToFront(RunningTaskInfo taskInfo) {
         onTaskMovedToFront(taskInfo.taskId);
     }
 
-    @MainThread
     default void onTaskDescriptionChanged(RunningTaskInfo taskInfo) { }
 
-    @MainThread
     default void onTaskSnapshotChanged(int taskId, ActivityManager.TaskSnapshot snapshot) { }
 
-    @MainThread
     default void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) { }
 
-    @MainThread
     default void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
             boolean clearedTask, boolean wasVisible) { }
 
-    @MainThread
     default void onActivityPinned(String packageName, int userId, int taskId, int stackId) { }
 
-    @MainThread
     default void onActivityUnpinned() { }
 
-    @MainThread
     default void onActivityForcedResizable(String packageName, int taskId, int reason) { }
 
-    @MainThread
     default void onActivityDismissingDockedStack() { }
 
-    @MainThread
     default void onActivityLaunchOnSecondaryDisplayFailed() { }
 
-    @MainThread
     default void onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo taskInfo) {
         onActivityLaunchOnSecondaryDisplayFailed();
     }
 
-    @MainThread
     default void onActivityLaunchOnSecondaryDisplayRerouted() { }
 
-    @MainThread
     default void onActivityLaunchOnSecondaryDisplayRerouted(RunningTaskInfo taskInfo) {
         onActivityLaunchOnSecondaryDisplayRerouted();
     }
 
-    @MainThread
     default void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) { }
 
-    @MainThread
     default void onActivityRotation(int displayId) { }
 
-    @MainThread
     default void onSizeCompatModeActivityChanged(int displayId, IBinder activityToken) { }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ChoreographerSfVsync.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ChoreographerSfVsync.java
new file mode 100644
index 0000000..4009ad2
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ChoreographerSfVsync.java
@@ -0,0 +1,18 @@
+package com.android.wm.shell.common.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import javax.inject.Qualifier;
+
+/**
+ * Annotates a method that or qualifies a provider runs aligned to the Choreographer SF vsync
+ * instead of the app vsync.
+ */
+@Documented
+@Inherited
+@Qualifier
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ChoreographerSfVsync {}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ExternalThread.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ExternalThread.java
new file mode 100644
index 0000000..7560f71
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ExternalThread.java
@@ -0,0 +1,15 @@
+package com.android.wm.shell.common.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import javax.inject.Qualifier;
+
+/** Annotates a method or class that is called from an external thread to the Shell threads. */
+@Documented
+@Inherited
+@Qualifier
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ExternalThread {}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ShellAnimationThread.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ShellAnimationThread.java
new file mode 100644
index 0000000..0479f87
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ShellAnimationThread.java
@@ -0,0 +1,15 @@
+package com.android.wm.shell.common.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import javax.inject.Qualifier;
+
+/** Annotates a method or qualifies a provider that runs on the Shell animation-thread */
+@Documented
+@Inherited
+@Qualifier
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ShellAnimationThread {}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ShellMainThread.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ShellMainThread.java
new file mode 100644
index 0000000..423f4ce
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/annotations/ShellMainThread.java
@@ -0,0 +1,15 @@
+package com.android.wm.shell.common.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import javax.inject.Qualifier;
+
+/** Annotates a method or qualifies a provider that runs on the Shell main-thread */
+@Documented
+@Inherited
+@Qualifier
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ShellMainThread {}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
new file mode 100644
index 0000000..50d9fe8
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -0,0 +1,171 @@
+/*
+ * 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.wm.shell.common.split;
+
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.SurfaceControlViewHost;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.policy.DividerSnapAlgorithm;
+
+/**
+ * Stack divider for app pair.
+ */
+// TODO(b/172704238): add handle view to indicate touching status.
+public class DividerView extends FrameLayout implements View.OnTouchListener {
+    private final int mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
+
+    private SplitLayout mSplitLayout;
+    private SurfaceControlViewHost mViewHost;
+    private DragListener mDragListener;
+
+    private VelocityTracker mVelocityTracker;
+    private boolean mMoving;
+    private int mStartPos;
+
+    public DividerView(@NonNull Context context) {
+        super(context);
+    }
+
+    public DividerView(@NonNull Context context,
+            @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public DividerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public DividerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    /** Sets up essential dependencies of the divider bar. */
+    public void setup(
+            SplitLayout layout,
+            SurfaceControlViewHost viewHost,
+            @Nullable DragListener dragListener) {
+        mSplitLayout = layout;
+        mViewHost = viewHost;
+        mDragListener = dragListener;
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        setOnTouchListener(this);
+    }
+
+    @Override
+    public boolean onTouch(View v, MotionEvent event) {
+        if (mSplitLayout == null) {
+            return false;
+        }
+
+        final int action = event.getAction() & MotionEvent.ACTION_MASK;
+        final boolean isLandscape = isLandscape();
+        // Using raw xy to prevent lost track of motion events while moving divider bar.
+        final int touchPos = isLandscape ? (int) event.getRawX() : (int) event.getRawY();
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+                mVelocityTracker = VelocityTracker.obtain();
+                mVelocityTracker.addMovement(event);
+                setSlippery(false);
+                mStartPos = touchPos;
+                mMoving = false;
+                break;
+            case MotionEvent.ACTION_MOVE:
+                mVelocityTracker.addMovement(event);
+                if (!mMoving && Math.abs(touchPos - mStartPos) > mTouchSlop) {
+                    mStartPos = touchPos;
+                    mMoving = true;
+                    if (mDragListener != null) {
+                        mDragListener.onDragStart();
+                    }
+                }
+                if (mMoving) {
+                    final int position = mSplitLayout.getDividePosition() + touchPos - mStartPos;
+                    mSplitLayout.updateDividePosition(position);
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                mVelocityTracker.addMovement(event);
+                mVelocityTracker.computeCurrentVelocity(1000 /* units */);
+                final float velocity = isLandscape
+                        ? mVelocityTracker.getXVelocity()
+                        : mVelocityTracker.getYVelocity();
+                setSlippery(true);
+                mMoving = false;
+                if (mDragListener != null) {
+                    mDragListener.onDragEnd();
+                }
+
+                final int position = mSplitLayout.getDividePosition() + touchPos - mStartPos;
+                final DividerSnapAlgorithm.SnapTarget snapTarget =
+                        mSplitLayout.findSnapTarget(position, velocity);
+                mSplitLayout.setSnapTarget(snapTarget);
+                break;
+        }
+        return true;
+    }
+
+    private void setSlippery(boolean slippery) {
+        if (mViewHost == null) {
+            return;
+        }
+
+        final WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams();
+        final boolean isSlippery = (lp.flags & FLAG_SLIPPERY) != 0;
+        if (isSlippery == slippery) {
+            return;
+        }
+
+        if (slippery) {
+            lp.flags |= FLAG_SLIPPERY;
+        } else {
+            lp.flags &= ~FLAG_SLIPPERY;
+        }
+        mViewHost.relayout(lp);
+    }
+
+    private boolean isLandscape() {
+        return getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE;
+    }
+
+    /** Monitors dragging action of the divider bar. */
+    // TODO(b/172704238): add listeners to deal with resizing state of the app windows.
+    public interface DragListener {
+        /** Called when start dragging. */
+        void onDragStart();
+        /** Called when stop dragging. */
+        void onDragEnd();
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
new file mode 100644
index 0000000..e11037f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -0,0 +1,205 @@
+/*
+ * 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.wm.shell.common.split;
+
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_TOP;
+
+import static com.android.internal.policy.DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_END;
+import static com.android.internal.policy.DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_START;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.view.SurfaceControl;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.policy.DividerSnapAlgorithm;
+
+/**
+ * Records and handles layout of splits. Helps to calculate proper bounds when configuration or
+ * divide position changes.
+ */
+public class SplitLayout {
+    private final int mDividerWindowWidth;
+    private final int mDividerInsets;
+    private final int mDividerSize;
+
+    private final Rect mRootBounds = new Rect();
+    private final Rect mDividerBounds = new Rect();
+    private final Rect mBounds1 = new Rect();
+    private final Rect mBounds2 = new Rect();
+    private final LayoutChangeListener mLayoutChangeListener;
+    private final SplitWindowManager mSplitWindowManager;
+
+    private Context mContext;
+    private DividerSnapAlgorithm mDividerSnapAlgorithm;
+    private int mDividePosition;
+
+    public SplitLayout(Context context, Configuration configuration,
+            LayoutChangeListener layoutChangeListener, SurfaceControl rootLeash) {
+        mContext = context.createConfigurationContext(configuration);
+        mLayoutChangeListener = layoutChangeListener;
+        mSplitWindowManager = new SplitWindowManager(mContext, configuration, rootLeash);
+
+        mDividerWindowWidth = context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.docked_stack_divider_thickness);
+        mDividerInsets = context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.docked_stack_divider_insets);
+        mDividerSize = mDividerWindowWidth - mDividerInsets * 2;
+
+        mRootBounds.set(configuration.windowConfiguration.getBounds());
+        mDividerSnapAlgorithm = getSnapAlgorithm(context.getResources(), mRootBounds);
+        mDividePosition = mDividerSnapAlgorithm.getMiddleTarget().position;
+        updateBounds(mDividePosition);
+    }
+
+    /** Gets bounds of the primary split. */
+    public Rect getBounds1() {
+        return mBounds1;
+    }
+
+    /** Gets bounds of the secondary split. */
+    public Rect getBounds2() {
+        return mBounds2;
+    }
+
+    /** Gets bounds of divider window. */
+    public Rect getDividerBounds() {
+        return mDividerBounds;
+    }
+
+    /** Returns leash of the current divider bar. */
+    @Nullable
+    public SurfaceControl getDividerLeash() {
+        return mSplitWindowManager == null ? null : mSplitWindowManager.getSurfaceControl();
+    }
+
+    int getDividePosition() {
+        return mDividePosition;
+    }
+
+    /** Applies new configuration, returns {@code false} if there's no effect to the layout. */
+    public boolean updateConfiguration(Configuration configuration) {
+        final Rect rootBounds = configuration.windowConfiguration.getBounds();
+        if (mRootBounds.equals(rootBounds)) {
+            return false;
+        }
+
+        mContext = mContext.createConfigurationContext(configuration);
+        mSplitWindowManager.setConfiguration(configuration);
+        mRootBounds.set(rootBounds);
+        mDividerSnapAlgorithm = getSnapAlgorithm(mContext.getResources(), mRootBounds);
+        mDividePosition = mDividerSnapAlgorithm.getMiddleTarget().position;
+        updateBounds(mDividePosition);
+        release();
+        init();
+        return true;
+    }
+
+    /** Updates recording bounds of divider window and both of the splits. */
+    private void updateBounds(int position) {
+        mDividerBounds.set(mRootBounds);
+        mBounds1.set(mRootBounds);
+        mBounds2.set(mRootBounds);
+        if (isLandscape(mRootBounds)) {
+            mDividerBounds.left = position - mDividerInsets;
+            mDividerBounds.right = mDividerBounds.left + mDividerWindowWidth;
+            mBounds1.right = mBounds1.left + position;
+            mBounds2.left = mBounds1.right + mDividerSize;
+        } else {
+            mDividerBounds.top = position - mDividerInsets;
+            mDividerBounds.bottom = mDividerBounds.top + mDividerWindowWidth;
+            mBounds1.bottom = mBounds1.top + position;
+            mBounds2.top = mBounds1.bottom + mDividerSize;
+        }
+    }
+
+    /** Inflates {@link DividerView} on the root surface. */
+    public void init() {
+        mSplitWindowManager.init(this);
+    }
+
+    /** Releases the surface holding the current {@link DividerView}. */
+    public void release() {
+        mSplitWindowManager.release();
+    }
+
+    /**
+     * Updates bounds with the passing position. Usually used to update recording bounds while
+     * performing animation or dragging divider bar to resize the splits.
+     */
+    public void updateDividePosition(int position) {
+        updateBounds(position);
+        mLayoutChangeListener.onBoundsChanging(this);
+    }
+
+    /**
+     * Sets new divide position and updates bounds correspondingly. Notifies listener if the new
+     * target indicates dismissing split.
+     */
+    public void setSnapTarget(DividerSnapAlgorithm.SnapTarget snapTarget) {
+        switch(snapTarget.flag) {
+            case FLAG_DISMISS_START:
+                mLayoutChangeListener.onSnappedToDismiss(false /* snappedToEnd */);
+                break;
+            case FLAG_DISMISS_END:
+                mLayoutChangeListener.onSnappedToDismiss(true /* snappedToEnd */);
+                break;
+            default:
+                mDividePosition = snapTarget.position;
+                updateBounds(mDividePosition);
+                mLayoutChangeListener.onBoundsChanged(this);
+                break;
+        }
+    }
+
+    /**
+     * Returns {@link DividerSnapAlgorithm.SnapTarget} which matches passing position and velocity.
+     */
+    public DividerSnapAlgorithm.SnapTarget findSnapTarget(int position, float velocity) {
+        return mDividerSnapAlgorithm.calculateSnapTarget(position, velocity);
+    }
+
+    private DividerSnapAlgorithm getSnapAlgorithm(Resources resources, Rect rootBounds) {
+        final boolean isLandscape = isLandscape(rootBounds);
+        return new DividerSnapAlgorithm(
+                resources,
+                rootBounds.width(),
+                rootBounds.height(),
+                mDividerSize,
+                !isLandscape,
+                new Rect() /* insets */,
+                isLandscape ? DOCKED_LEFT : DOCKED_TOP /* dockSide */);
+    }
+
+    private static boolean isLandscape(Rect bounds) {
+        return bounds.width() > bounds.height();
+    }
+
+    /** Listens layout change event. */
+    public interface LayoutChangeListener {
+        /** Calls when dismissing split. */
+        void onSnappedToDismiss(boolean snappedToEnd);
+        /** Calls when the bounds is changing due to animation or dragging divider bar. */
+        void onBoundsChanging(SplitLayout layout);
+        /** Calls when the target bounds changed. */
+        void onBoundsChanged(SplitLayout layout);
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
new file mode 100644
index 0000000..e412198
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
@@ -0,0 +1,116 @@
+/*
+ * 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.wm.shell.common.split;
+
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
+import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
+import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.os.Binder;
+import android.os.IBinder;
+import android.view.IWindow;
+import android.view.LayoutInflater;
+import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
+import android.view.WindowManager;
+import android.view.WindowlessWindowManager;
+
+import androidx.annotation.Nullable;
+
+import com.android.wm.shell.R;
+
+/**
+ * Holds view hierarchy of a root surface and helps to inflate {@link DividerView} for a split.
+ */
+public final class SplitWindowManager extends WindowlessWindowManager {
+    private static final String DIVIDER_WINDOW_TITLE = "SplitDivider";
+
+    private Context mContext;
+    private SurfaceControlViewHost mViewHost;
+
+    public SplitWindowManager(Context context, Configuration config, SurfaceControl rootSurface) {
+        super(config, rootSurface, null /* hostInputToken */);
+        mContext = context.createConfigurationContext(config);
+    }
+
+    @Override
+    public void setTouchRegion(IBinder window, Region region) {
+        super.setTouchRegion(window, region);
+    }
+
+    @Override
+    public SurfaceControl getSurfaceControl(IWindow window) {
+        return super.getSurfaceControl(window);
+    }
+
+    @Override
+    public void setConfiguration(Configuration configuration) {
+        super.setConfiguration(configuration);
+        mContext = mContext.createConfigurationContext(configuration);
+    }
+
+    /** Inflates {@link DividerView} on to the root surface. */
+    void init(SplitLayout splitLayout) {
+        if (mViewHost == null) {
+            mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
+        }
+
+        final Rect dividerBounds = splitLayout.getDividerBounds();
+        final DividerView dividerView = (DividerView) LayoutInflater.from(mContext)
+                .inflate(R.layout.split_divider, null /* root */);
+
+        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                dividerBounds.width(), dividerBounds.height(), TYPE_DOCK_DIVIDER,
+                FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL | FLAG_WATCH_OUTSIDE_TOUCH
+                        | FLAG_SPLIT_TOUCH | FLAG_SLIPPERY,
+                PixelFormat.TRANSLUCENT);
+        lp.token = new Binder();
+        lp.setTitle(DIVIDER_WINDOW_TITLE);
+        lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
+        mViewHost.setView(dividerView, lp);
+        dividerView.setup(splitLayout, mViewHost, null /* dragListener */);
+    }
+
+    /**
+     * Releases the surface control of the current {@link DividerView} and tear down the view
+     * hierarchy.
+     */
+    void release() {
+        if (mViewHost == null) return;
+        mViewHost.release();
+        mViewHost = null;
+    }
+
+    /**
+     * Gets {@link SurfaceControl} of the surface holding divider view. @return {@code null} if not
+     * feasible.
+     */
+    @Nullable
+    SurfaceControl getSurfaceControl() {
+        return mViewHost == null ? null : getSurfaceControl(mViewHost.getWindowToken());
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutout.java
index 38e0519..3a2f0da 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutout.java
@@ -20,11 +20,14 @@
 
 import androidx.annotation.NonNull;
 
+import com.android.wm.shell.common.annotations.ExternalThread;
+
 import java.io.PrintWriter;
 
 /**
  * Interface to engage hide display cutout feature.
  */
+@ExternalThread
 public interface HideDisplayCutout {
     /**
      * Notifies {@link Configuration} changed.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java
index 9bb709f..821a007 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java
@@ -18,6 +18,7 @@
 
 import androidx.annotation.NonNull;
 
+import com.android.wm.shell.common.annotations.ExternalThread;
 import com.android.wm.shell.onehanded.OneHandedGestureHandler.OneHandedGestureEventCallback;
 
 import java.io.PrintWriter;
@@ -25,6 +26,7 @@
 /**
  * Interface to engage one handed feature.
  */
+@ExternalThread
 public interface OneHanded {
     /**
      * Return one handed settings enabled or not.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java
index 993e0e7..5593268 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java
@@ -19,12 +19,16 @@
 import android.app.RemoteAction;
 import android.content.ComponentName;
 import android.content.pm.ParceledListSlice;
+import android.os.RemoteException;
 import android.view.DisplayInfo;
-import android.view.IPinnedStackController;
 import android.view.IPinnedStackListener;
+import android.view.WindowManagerGlobal;
+
+import androidx.annotation.BinderThread;
+
+import com.android.wm.shell.common.ShellExecutor;
 
 import java.util.ArrayList;
-import java.util.List;
 
 /**
  * PinnedStackListener that simply forwards all calls to each listener added via
@@ -32,8 +36,15 @@
  * {@link com.android.server.wm.WindowManagerService#registerPinnedStackListener} replaces any
  * previously set listener.
  */
-public class PinnedStackListenerForwarder extends IPinnedStackListener.Stub {
-    private List<PinnedStackListener> mListeners = new ArrayList<>();
+public class PinnedStackListenerForwarder {
+
+    private final IPinnedStackListener mListenerImpl = new PinnedStackListenerImpl();
+    private final ShellExecutor mShellMainExecutor;
+    private final ArrayList<PinnedStackListener> mListeners = new ArrayList<>();
+
+    public PinnedStackListenerForwarder(ShellExecutor shellMainExecutor) {
+        mShellMainExecutor = shellMainExecutor;
+    }
 
     /** Adds a listener to receive updates from the WindowManagerService. */
     public void addListener(PinnedStackListener listener) {
@@ -45,69 +56,110 @@
         mListeners.remove(listener);
     }
 
-    @Override
-    public void onListenerRegistered(IPinnedStackController controller) {
-        for (PinnedStackListener listener : mListeners) {
-            listener.onListenerRegistered(controller);
-        }
+    public void register(int displayId) throws RemoteException {
+        WindowManagerGlobal.getWindowManagerService().registerPinnedStackListener(
+                displayId, mListenerImpl);
     }
 
-    @Override
-    public void onMovementBoundsChanged(boolean fromImeAdjustment) {
+    private void onMovementBoundsChanged(boolean fromImeAdjustment) {
         for (PinnedStackListener listener : mListeners) {
             listener.onMovementBoundsChanged(fromImeAdjustment);
         }
     }
 
-    @Override
-    public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
+    private void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
         for (PinnedStackListener listener : mListeners) {
             listener.onImeVisibilityChanged(imeVisible, imeHeight);
         }
     }
 
-    @Override
-    public void onActionsChanged(ParceledListSlice<RemoteAction> actions) {
+    private void onActionsChanged(ParceledListSlice<RemoteAction> actions) {
         for (PinnedStackListener listener : mListeners) {
             listener.onActionsChanged(actions);
         }
     }
 
-    @Override
-    public void onActivityHidden(ComponentName componentName) {
+    private void onActivityHidden(ComponentName componentName) {
         for (PinnedStackListener listener : mListeners) {
             listener.onActivityHidden(componentName);
         }
     }
 
-    @Override
-    public void onDisplayInfoChanged(DisplayInfo displayInfo) {
+    private void onDisplayInfoChanged(DisplayInfo displayInfo) {
         for (PinnedStackListener listener : mListeners) {
             listener.onDisplayInfoChanged(displayInfo);
         }
     }
 
-    @Override
-    public void onConfigurationChanged() {
+    private void onConfigurationChanged() {
         for (PinnedStackListener listener : mListeners) {
             listener.onConfigurationChanged();
         }
     }
 
-    @Override
-    public void onAspectRatioChanged(float aspectRatio) {
+    private void onAspectRatioChanged(float aspectRatio) {
         for (PinnedStackListener listener : mListeners) {
             listener.onAspectRatioChanged(aspectRatio);
         }
     }
 
+    @BinderThread
+    private class PinnedStackListenerImpl extends IPinnedStackListener.Stub {
+        @Override
+        public void onMovementBoundsChanged(boolean fromImeAdjustment) {
+            mShellMainExecutor.execute(() -> {
+                PinnedStackListenerForwarder.this.onMovementBoundsChanged(fromImeAdjustment);
+            });
+        }
+
+        @Override
+        public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
+            mShellMainExecutor.execute(() -> {
+                PinnedStackListenerForwarder.this.onImeVisibilityChanged(imeVisible, imeHeight);
+            });
+        }
+
+        @Override
+        public void onActionsChanged(ParceledListSlice<RemoteAction> actions) {
+            mShellMainExecutor.execute(() -> {
+                PinnedStackListenerForwarder.this.onActionsChanged(actions);
+            });
+        }
+
+        @Override
+        public void onActivityHidden(ComponentName componentName) {
+            mShellMainExecutor.execute(() -> {
+                PinnedStackListenerForwarder.this.onActivityHidden(componentName);
+            });
+        }
+
+        @Override
+        public void onDisplayInfoChanged(DisplayInfo displayInfo) {
+            mShellMainExecutor.execute(() -> {
+                PinnedStackListenerForwarder.this.onDisplayInfoChanged(displayInfo);
+            });
+        }
+
+        @Override
+        public void onConfigurationChanged() {
+            mShellMainExecutor.execute(() -> {
+                PinnedStackListenerForwarder.this.onConfigurationChanged();
+            });
+        }
+
+        @Override
+        public void onAspectRatioChanged(float aspectRatio) {
+            mShellMainExecutor.execute(() -> {
+                PinnedStackListenerForwarder.this.onAspectRatioChanged(aspectRatio);
+            });
+        }
+    }
+
     /**
      * A counterpart of {@link IPinnedStackListener} with empty implementations.
      * Subclasses can ignore those methods they do not intend to take action upon.
      */
     public static class PinnedStackListener {
-        public void onListenerRegistered(IPinnedStackController controller) {}
-
         public void onMovementBoundsChanged(boolean fromImeAdjustment) {}
 
         public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
index 9fa222a..da9ce0a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
@@ -17,12 +17,12 @@
 package com.android.wm.shell.pip;
 
 import android.annotation.Nullable;
-import android.app.ActivityManager;
 import android.app.PictureInPictureParams;
 import android.content.ComponentName;
 import android.content.pm.ActivityInfo;
 import android.graphics.Rect;
 
+import com.android.wm.shell.common.annotations.ExternalThread;
 import com.android.wm.shell.pip.phone.PipTouchHandler;
 
 import java.io.PrintWriter;
@@ -31,6 +31,7 @@
 /**
  * Interface to engage picture in picture feature.
  */
+@ExternalThread
 public interface Pip {
     /**
      * Closes PIP (PIPed activity and PIP system UI).
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index d829462..fe01811 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -54,6 +54,7 @@
     public static final int TRANSITION_DIRECTION_LEAVE_PIP = 3;
     public static final int TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN = 4;
     public static final int TRANSITION_DIRECTION_REMOVE_STACK = 5;
+    public static final int TRANSITION_DIRECTION_SNAP_AFTER_RESIZE = 6;
 
     @IntDef(prefix = { "TRANSITION_DIRECTION_" }, value = {
             TRANSITION_DIRECTION_NONE,
@@ -61,7 +62,8 @@
             TRANSITION_DIRECTION_TO_PIP,
             TRANSITION_DIRECTION_LEAVE_PIP,
             TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN,
-            TRANSITION_DIRECTION_REMOVE_STACK
+            TRANSITION_DIRECTION_REMOVE_STACK,
+            TRANSITION_DIRECTION_SNAP_AFTER_RESIZE
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface TransitionDirection {}
@@ -109,13 +111,27 @@
     }
 
     @SuppressWarnings("unchecked")
+    /**
+     * Construct and return an animator that animates from the {@param startBounds} to the
+     * {@param endBounds} with the given {@param direction}. If {@param direction} is type
+     * {@link ANIM_TYPE_BOUNDS}, then {@param sourceHintRect} will be used to animate
+     * in a better, more smooth manner.
+     *
+     * In the case where one wants to start animation during an intermediate animation (for example,
+     * if the user is currently doing a pinch-resize, and upon letting go now PiP needs to animate
+     * to the correct snap fraction region), then provide the base bounds, which is current PiP
+     * leash bounds before transformation/any animation. This is so when we try to construct
+     * the different transformation matrices for the animation, we are constructing this based off
+     * the PiP original bounds, rather than the {@param startBounds}, which is post-transformed.
+     */
     @VisibleForTesting
-    public PipTransitionAnimator getAnimator(SurfaceControl leash, Rect startBounds, Rect endBounds,
-            Rect sourceHintRect, @PipAnimationController.TransitionDirection int direction) {
+    public PipTransitionAnimator getAnimator(SurfaceControl leash, Rect baseBounds,
+            Rect startBounds, Rect endBounds, Rect sourceHintRect,
+            @PipAnimationController.TransitionDirection int direction) {
         if (mCurrentAnimator == null) {
             mCurrentAnimator = setupPipTransitionAnimator(
-                    PipTransitionAnimator.ofBounds(leash, startBounds, endBounds, sourceHintRect,
-                            direction));
+                    PipTransitionAnimator.ofBounds(leash, startBounds, startBounds, endBounds,
+                            sourceHintRect, direction));
         } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA
                 && mCurrentAnimator.isRunning()) {
             // If we are still animating the fade into pip, then just move the surface and ensure
@@ -130,8 +146,8 @@
         } else {
             mCurrentAnimator.cancel();
             mCurrentAnimator = setupPipTransitionAnimator(
-                    PipTransitionAnimator.ofBounds(leash, startBounds, endBounds, sourceHintRect,
-                            direction));
+                    PipTransitionAnimator.ofBounds(leash, baseBounds, startBounds, endBounds,
+                            sourceHintRect, direction));
         }
         return mCurrentAnimator;
     }
@@ -180,6 +196,7 @@
         private final @AnimationType int mAnimationType;
         private final Rect mDestinationBounds = new Rect();
 
+        private T mBaseValue;
         protected T mCurrentValue;
         protected T mStartValue;
         private T mEndValue;
@@ -190,10 +207,11 @@
         private @TransitionDirection int mTransitionDirection;
 
         private PipTransitionAnimator(SurfaceControl leash, @AnimationType int animationType,
-                Rect destinationBounds, T startValue, T endValue) {
+                Rect destinationBounds, T baseValue, T startValue, T endValue) {
             mLeash = leash;
             mAnimationType = animationType;
             mDestinationBounds.set(destinationBounds);
+            mBaseValue = baseValue;
             mStartValue = startValue;
             mEndValue = endValue;
             addListener(this);
@@ -263,6 +281,10 @@
             return mStartValue;
         }
 
+        T getBaseValue() {
+            return mBaseValue;
+        }
+
         @VisibleForTesting
         public T getEndValue() {
             return mEndValue;
@@ -334,7 +356,7 @@
         static PipTransitionAnimator<Float> ofAlpha(SurfaceControl leash,
                 Rect destinationBounds, float startValue, float endValue) {
             return new PipTransitionAnimator<Float>(leash, ANIM_TYPE_ALPHA,
-                    destinationBounds, startValue, endValue) {
+                    destinationBounds, startValue, startValue, endValue) {
                 @Override
                 void applySurfaceControlTransaction(SurfaceControl leash,
                         SurfaceControl.Transaction tx, float fraction) {
@@ -367,7 +389,7 @@
         }
 
         static PipTransitionAnimator<Rect> ofBounds(SurfaceControl leash,
-                Rect startValue, Rect endValue, Rect sourceHintRect,
+                Rect baseValue, Rect startValue, Rect endValue, Rect sourceHintRect,
                 @PipAnimationController.TransitionDirection int direction) {
             // Just for simplicity we'll interpolate between the source rect hint insets and empty
             // insets to calculate the window crop
@@ -375,7 +397,7 @@
             if (isOutPipDirection(direction)) {
                 initialSourceValue = new Rect(endValue);
             } else {
-                initialSourceValue = new Rect(startValue);
+                initialSourceValue = new Rect(baseValue);
             }
 
             final Rect sourceHintRectInsets;
@@ -391,22 +413,24 @@
 
             // construct new Rect instances in case they are recycled
             return new PipTransitionAnimator<Rect>(leash, ANIM_TYPE_BOUNDS,
-                    endValue, new Rect(startValue), new Rect(endValue)) {
+                    endValue, new Rect(baseValue), new Rect(startValue), new Rect(endValue)) {
                 private final RectEvaluator mRectEvaluator = new RectEvaluator(new Rect());
                 private final RectEvaluator mInsetsEvaluator = new RectEvaluator(new Rect());
 
                 @Override
                 void applySurfaceControlTransaction(SurfaceControl leash,
                         SurfaceControl.Transaction tx, float fraction) {
+                    final Rect base = getBaseValue();
                     final Rect start = getStartValue();
                     final Rect end = getEndValue();
                     Rect bounds = mRectEvaluator.evaluate(fraction, start, end);
                     setCurrentValue(bounds);
                     if (inScaleTransition() || sourceHintRect == null) {
+
                         if (isOutPipDirection(direction)) {
                             getSurfaceTransactionHelper().scale(tx, leash, end, bounds);
                         } else {
-                            getSurfaceTransactionHelper().scale(tx, leash, start, bounds);
+                            getSurfaceTransactionHelper().scale(tx, leash, base, bounds);
                         }
                     } else {
                         final Rect insets;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 98ed822..167b9f9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -30,6 +30,7 @@
 import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_NONE;
 import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_REMOVE_STACK;
 import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_SAME;
+import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_SNAP_AFTER_RESIZE;
 import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
 import static com.android.wm.shell.pip.PipAnimationController.isInPipDirection;
 import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
@@ -814,6 +815,20 @@
                 TRANSITION_DIRECTION_NONE, duration, updateBoundsCallback);
     }
 
+    /**
+     * Animates resizing of the pinned stack given the duration and start bounds.
+     * This is used when the starting bounds is not the current PiP bounds.
+     */
+    public void scheduleAnimateResizePip(Rect fromBounds, Rect toBounds, int duration,
+            Consumer<Rect> updateBoundsCallback) {
+        if (mShouldDeferEnteringPip) {
+            Log.d(TAG, "skip scheduleAnimateResizePip, entering pip deferred");
+            return;
+        }
+        scheduleAnimateResizePip(fromBounds, toBounds, null /* sourceHintRect */,
+                TRANSITION_DIRECTION_SNAP_AFTER_RESIZE, duration, updateBoundsCallback);
+    }
+
     private void scheduleAnimateResizePip(Rect currentBounds, Rect destinationBounds,
             Rect sourceHintRect, @PipAnimationController.TransitionDirection int direction,
             int durationMs, Consumer<Rect> updateBoundsCallback) {
@@ -1073,8 +1088,11 @@
             Log.w(TAG, "Abort animation, invalid leash");
             return;
         }
+        Rect baseBounds = direction == TRANSITION_DIRECTION_SNAP_AFTER_RESIZE
+                ? mPipBoundsState.getBounds() : currentBounds;
         mPipAnimationController
-                .getAnimator(mLeash, currentBounds, destinationBounds, sourceHintRect, direction)
+                .getAnimator(mLeash, baseBounds, currentBounds, destinationBounds, sourceHintRect,
+                        direction)
                 .setTransitionDirection(direction)
                 .setPipAnimationCallback(mPipAnimationCallback)
                 .setDuration(durationMs)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
index f153aa5..7194fc7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java
@@ -20,15 +20,18 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.RemoteException;
 import android.view.MagnificationSpec;
+import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityWindowInfo;
 import android.view.accessibility.IAccessibilityInteractionConnection;
 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
 
+import androidx.annotation.BinderThread;
+
 import com.android.wm.shell.R;
+import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.pip.PipBoundsState;
 import com.android.wm.shell.pip.PipSnapAlgorithm;
 import com.android.wm.shell.pip.PipTaskOrganizer;
@@ -40,8 +43,7 @@
  * Expose the touch actions to accessibility as if this object were a window with a single view.
  * That pseudo-view exposes all of the actions this object can perform.
  */
-public class PipAccessibilityInteractionConnection
-        extends IAccessibilityInteractionConnection.Stub {
+public class PipAccessibilityInteractionConnection {
 
     public interface AccessibilityCallbacks {
         void onAccessibilityShowMenu();
@@ -50,14 +52,15 @@
     private static final long ACCESSIBILITY_NODE_ID = 1;
     private List<AccessibilityNodeInfo> mAccessibilityNodeInfoList;
 
-    private Context mContext;
-    private Handler mHandler;
+    private final Context mContext;
+    private final ShellExecutor mShellMainExcutor;
     private final @NonNull PipBoundsState mPipBoundsState;
-    private PipMotionHelper mMotionHelper;
-    private PipTaskOrganizer mTaskOrganizer;
-    private PipSnapAlgorithm mSnapAlgorithm;
-    private Runnable mUpdateMovementBoundCallback;
-    private AccessibilityCallbacks mCallbacks;
+    private final PipMotionHelper mMotionHelper;
+    private final PipTaskOrganizer mTaskOrganizer;
+    private final PipSnapAlgorithm mSnapAlgorithm;
+    private final Runnable mUpdateMovementBoundCallback;
+    private final AccessibilityCallbacks mCallbacks;
+    private final IAccessibilityInteractionConnection mConnectionImpl;
 
     private final Rect mNormalBounds = new Rect();
     private final Rect mExpandedBounds = new Rect();
@@ -69,19 +72,23 @@
             @NonNull PipBoundsState pipBoundsState, PipMotionHelper motionHelper,
             PipTaskOrganizer taskOrganizer, PipSnapAlgorithm snapAlgorithm,
             AccessibilityCallbacks callbacks, Runnable updateMovementBoundCallback,
-            Handler handler) {
+            ShellExecutor shellMainExcutor) {
         mContext = context;
-        mHandler = handler;
+        mShellMainExcutor = shellMainExcutor;
         mPipBoundsState = pipBoundsState;
         mMotionHelper = motionHelper;
         mTaskOrganizer = taskOrganizer;
         mSnapAlgorithm = snapAlgorithm;
         mUpdateMovementBoundCallback = updateMovementBoundCallback;
         mCallbacks = callbacks;
+        mConnectionImpl = new PipAccessibilityInteractionConnectionImpl();
     }
 
-    @Override
-    public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
+    public void register(AccessibilityManager am) {
+        am.setPictureInPictureActionReplacingConnection(mConnectionImpl);
+    }
+
+    private void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
             Region interactiveRegion, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, int flags,
             int interrogatingPid, long interrogatingTid, MagnificationSpec spec, Bundle args) {
@@ -94,8 +101,7 @@
         }
     }
 
-    @Override
-    public void performAccessibilityAction(long accessibilityNodeId, int action,
+    private void performAccessibilityAction(long accessibilityNodeId, int action,
             Bundle arguments, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, int flags,
             int interrogatingPid, long interrogatingTid) {
@@ -115,9 +121,7 @@
             } else {
                 switch (action) {
                     case AccessibilityNodeInfo.ACTION_CLICK:
-                        mHandler.post(() -> {
-                            mCallbacks.onAccessibilityShowMenu();
-                        });
+                        mCallbacks.onAccessibilityShowMenu();
                         result = true;
                         break;
                     case AccessibilityNodeInfo.ACTION_DISMISS:
@@ -172,8 +176,7 @@
         });
     }
 
-    @Override
-    public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
+    private void findAccessibilityNodeInfosByViewId(long accessibilityNodeId,
             String viewId, Region interactiveRegion, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, int flags,
             int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
@@ -185,8 +188,7 @@
         }
     }
 
-    @Override
-    public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
+    private void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
             Region interactiveRegion, int interactionId,
             IAccessibilityInteractionConnectionCallback callback, int flags,
             int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
@@ -198,8 +200,7 @@
         }
     }
 
-    @Override
-    public void findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion,
+    private void findFocus(long accessibilityNodeId, int focusType, Region interactiveRegion,
             int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
             int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
         // We have no view that can take focus
@@ -210,8 +211,7 @@
         }
     }
 
-    @Override
-    public void focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion,
+    private void focusSearch(long accessibilityNodeId, int direction, Region interactiveRegion,
             int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
             int interrogatingPid, long interrogatingTid, MagnificationSpec spec) {
         // We have no view that can take focus
@@ -222,16 +222,6 @@
         }
     }
 
-    @Override
-    public void clearAccessibilityFocus() {
-        // We should not be here.
-    }
-
-    @Override
-    public void notifyOutsideTouch() {
-        // Do nothing.
-    }
-
     /**
      * Update the normal and expanded bounds so they can be used for Resize.
      */
@@ -271,4 +261,95 @@
         mAccessibilityNodeInfoList.add(info);
         return mAccessibilityNodeInfoList;
     }
+
+    @BinderThread
+    private class PipAccessibilityInteractionConnectionImpl
+            extends IAccessibilityInteractionConnection.Stub {
+        @Override
+        public void findAccessibilityNodeInfoByAccessibilityId(long accessibilityNodeId,
+                Region bounds, int interactionId,
+                IAccessibilityInteractionConnectionCallback callback, int flags,
+                int interrogatingPid, long interrogatingTid, MagnificationSpec spec,
+                Bundle arguments) throws RemoteException {
+            mShellMainExcutor.execute(() -> {
+                PipAccessibilityInteractionConnection.this
+                        .findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId, bounds,
+                                interactionId, callback, flags, interrogatingPid, interrogatingTid,
+                                spec, arguments);
+            });
+        }
+
+        @Override
+        public void findAccessibilityNodeInfosByViewId(long accessibilityNodeId, String viewId,
+                Region bounds, int interactionId,
+                IAccessibilityInteractionConnectionCallback callback, int flags,
+                int interrogatingPid, long interrogatingTid, MagnificationSpec spec)
+                throws RemoteException {
+            mShellMainExcutor.execute(() -> {
+                PipAccessibilityInteractionConnection.this.findAccessibilityNodeInfosByViewId(
+                        accessibilityNodeId, viewId, bounds, interactionId, callback, flags,
+                        interrogatingPid, interrogatingTid, spec);
+            });
+        }
+
+        @Override
+        public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
+                Region bounds, int interactionId,
+                IAccessibilityInteractionConnectionCallback callback, int flags,
+                int interrogatingPid, long interrogatingTid, MagnificationSpec spec)
+                throws RemoteException {
+            mShellMainExcutor.execute(() -> {
+                PipAccessibilityInteractionConnection.this.findAccessibilityNodeInfosByText(
+                        accessibilityNodeId, text, bounds, interactionId, callback, flags,
+                        interrogatingPid, interrogatingTid, spec);
+            });
+        }
+
+        @Override
+        public void findFocus(long accessibilityNodeId, int focusType, Region bounds,
+                int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
+                int interrogatingPid, long interrogatingTid, MagnificationSpec spec)
+                throws RemoteException {
+            mShellMainExcutor.execute(() -> {
+                PipAccessibilityInteractionConnection.this.findFocus(accessibilityNodeId, focusType,
+                        bounds, interactionId, callback, flags, interrogatingPid, interrogatingTid,
+                        spec);
+            });
+        }
+
+        @Override
+        public void focusSearch(long accessibilityNodeId, int direction, Region bounds,
+                int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags,
+                int interrogatingPid, long interrogatingTid, MagnificationSpec spec)
+                throws RemoteException {
+            mShellMainExcutor.execute(() -> {
+                PipAccessibilityInteractionConnection.this.focusSearch(accessibilityNodeId,
+                        direction,
+                        bounds, interactionId, callback, flags, interrogatingPid, interrogatingTid,
+                        spec);
+            });
+        }
+
+        @Override
+        public void performAccessibilityAction(long accessibilityNodeId, int action,
+                Bundle arguments, int interactionId,
+                IAccessibilityInteractionConnectionCallback callback, int flags,
+                int interrogatingPid, long interrogatingTid) throws RemoteException {
+            mShellMainExcutor.execute(() -> {
+                PipAccessibilityInteractionConnection.this.performAccessibilityAction(
+                        accessibilityNodeId, action, arguments, interactionId, callback, flags,
+                        interrogatingPid, interrogatingTid);
+            });
+        }
+
+        @Override
+        public void clearAccessibilityFocus() throws RemoteException {
+            // Do nothing
+        }
+
+        @Override
+        public void notifyOutsideTouch() throws RemoteException {
+            // Do nothing
+        }
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index db02e28..3234ef6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -41,7 +41,6 @@
 import android.util.Pair;
 import android.util.Slog;
 import android.view.DisplayInfo;
-import android.view.IPinnedStackController;
 import android.view.WindowManagerGlobal;
 import android.window.WindowContainerTransaction;
 
@@ -52,7 +51,6 @@
 import com.android.wm.shell.common.DisplayChangeController;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.common.PipInputConsumer;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TaskStackListenerCallback;
 import com.android.wm.shell.common.TaskStackListenerImpl;
@@ -163,63 +161,50 @@
     private class PipControllerPinnedStackListener extends
             PinnedStackListenerForwarder.PinnedStackListener {
         @Override
-        public void onListenerRegistered(IPinnedStackController controller) {
-            mMainExecutor.execute(() -> mTouchHandler.setPinnedStackController(controller));
-        }
-
-        @Override
         public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
-            mMainExecutor.execute(() -> {
-                mPipBoundsState.setImeVisibility(imeVisible, imeHeight);
-                mTouchHandler.onImeVisibilityChanged(imeVisible, imeHeight);
-            });
+            mPipBoundsState.setImeVisibility(imeVisible, imeHeight);
+            mTouchHandler.onImeVisibilityChanged(imeVisible, imeHeight);
         }
 
         @Override
         public void onMovementBoundsChanged(boolean fromImeAdjustment) {
-            mMainExecutor.execute(() -> updateMovementBounds(null /* toBounds */,
+            updateMovementBounds(null /* toBounds */,
                     false /* fromRotation */, fromImeAdjustment, false /* fromShelfAdjustment */,
-                    null /* windowContainerTransaction */));
+                    null /* windowContainerTransaction */);
         }
 
         @Override
         public void onActionsChanged(ParceledListSlice<RemoteAction> actions) {
-            mMainExecutor.execute(() -> mMenuController.setAppActions(actions));
+            mMenuController.setAppActions(actions);
         }
 
         @Override
         public void onActivityHidden(ComponentName componentName) {
-            mMainExecutor.execute(() -> {
-                if (componentName.equals(mPipBoundsState.getLastPipComponentName())) {
-                    // The activity was removed, we don't want to restore to the reentry state
-                    // saved for this component anymore.
-                    mPipBoundsState.setLastPipComponentName(null);
-                }
-            });
+            if (componentName.equals(mPipBoundsState.getLastPipComponentName())) {
+                // The activity was removed, we don't want to restore to the reentry state
+                // saved for this component anymore.
+                mPipBoundsState.setLastPipComponentName(null);
+            }
         }
 
         @Override
         public void onDisplayInfoChanged(DisplayInfo displayInfo) {
-            mMainExecutor.execute(() -> mPipBoundsState.setDisplayInfo(displayInfo));
+            mPipBoundsState.setDisplayInfo(displayInfo);
         }
 
         @Override
         public void onConfigurationChanged() {
-            mMainExecutor.execute(() -> {
-                mPipBoundsAlgorithm.onConfigurationChanged(mContext);
-                mTouchHandler.onConfigurationChanged();
-                mPipBoundsState.onConfigurationChanged();
-            });
+            mPipBoundsAlgorithm.onConfigurationChanged(mContext);
+            mTouchHandler.onConfigurationChanged();
+            mPipBoundsState.onConfigurationChanged();
         }
 
         @Override
         public void onAspectRatioChanged(float aspectRatio) {
             // TODO(b/169373982): Remove this callback as it is redundant with PipTaskOrg params
             // change.
-            mMainExecutor.execute(() -> {
-                mPipBoundsState.setAspectRatio(aspectRatio);
-                mTouchHandler.onAspectRatioChanged();
-            });
+            mPipBoundsState.setAspectRatio(aspectRatio);
+            mTouchHandler.onAspectRatioChanged();
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
new file mode 100644
index 0000000..0c64c8c
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
@@ -0,0 +1,179 @@
+/*
+ * 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.wm.shell.pip.phone;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.BatchedInputEventReceiver;
+import android.view.Choreographer;
+import android.view.IWindowManager;
+import android.view.InputChannel;
+import android.view.InputEvent;
+
+import java.io.PrintWriter;
+
+/**
+ * Manages the input consumer that allows the Shell to directly receive input.
+ */
+public class PipInputConsumer {
+
+    private static final String TAG = PipInputConsumer.class.getSimpleName();
+
+    /**
+     * Listener interface for callers to subscribe to input events.
+     */
+    public interface InputListener {
+        /** Handles any input event. */
+        boolean onInputEvent(InputEvent ev);
+    }
+
+    /**
+     * Listener interface for callers to learn when this class is registered or unregistered with
+     * window manager
+     */
+    public interface RegistrationListener {
+        void onRegistrationChanged(boolean isRegistered);
+    }
+
+    /**
+     * Input handler used for the input consumer. Input events are batched and consumed with the
+     * SurfaceFlinger vsync.
+     */
+    private final class InputEventReceiver extends BatchedInputEventReceiver {
+
+        InputEventReceiver(InputChannel inputChannel, Looper looper,
+                Choreographer choreographer) {
+            super(inputChannel, looper, choreographer);
+        }
+
+        @Override
+        public void onInputEvent(InputEvent event) {
+            boolean handled = true;
+            try {
+                if (mListener != null) {
+                    handled = mListener.onInputEvent(event);
+                }
+            } finally {
+                finishInputEvent(event, handled);
+            }
+        }
+    }
+
+    private final IWindowManager mWindowManager;
+    private final IBinder mToken;
+    private final String mName;
+
+    private InputEventReceiver mInputEventReceiver;
+    private InputListener mListener;
+    private RegistrationListener mRegistrationListener;
+
+    /**
+     * @param name the name corresponding to the input consumer that is defined in the system.
+     */
+    public PipInputConsumer(IWindowManager windowManager, String name) {
+        mWindowManager = windowManager;
+        mToken = new Binder();
+        mName = name;
+    }
+
+    /**
+     * Sets the input listener.
+     */
+    public void setInputListener(InputListener listener) {
+        mListener = listener;
+    }
+
+    /**
+     * Sets the registration listener.
+     */
+    public void setRegistrationListener(RegistrationListener listener) {
+        mRegistrationListener = listener;
+        if (mRegistrationListener != null) {
+            mRegistrationListener.onRegistrationChanged(mInputEventReceiver != null);
+        }
+    }
+
+    /**
+     * Check if the InputConsumer is currently registered with WindowManager
+     *
+     * @return {@code true} if registered, {@code false} if not.
+     */
+    public boolean isRegistered() {
+        return mInputEventReceiver != null;
+    }
+
+    /**
+     * Registers the input consumer.
+     */
+    public void registerInputConsumer() {
+        registerInputConsumer(false);
+    }
+
+    /**
+     * Registers the input consumer.
+     * @param withSfVsync the flag set using sf vsync signal or no
+     */
+    public void registerInputConsumer(boolean withSfVsync) {
+        if (mInputEventReceiver != null) {
+            return;
+        }
+        final InputChannel inputChannel = new InputChannel();
+        try {
+            // TODO(b/113087003): Support Picture-in-picture in multi-display.
+            mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
+            mWindowManager.createInputConsumer(mToken, mName, DEFAULT_DISPLAY, inputChannel);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to create input consumer", e);
+        }
+        mInputEventReceiver = new InputEventReceiver(inputChannel, Looper.myLooper(),
+                withSfVsync ? Choreographer.getSfInstance() : Choreographer.getInstance());
+        if (mRegistrationListener != null) {
+            mRegistrationListener.onRegistrationChanged(true /* isRegistered */);
+        }
+    }
+
+    /**
+     * Unregisters the input consumer.
+     */
+    public void unregisterInputConsumer() {
+        if (mInputEventReceiver == null) {
+            return;
+        }
+        try {
+            // TODO(b/113087003): Support Picture-in-picture in multi-display.
+            mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to destroy input consumer", e);
+        }
+        mInputEventReceiver.dispose();
+        mInputEventReceiver = null;
+        if (mRegistrationListener != null) {
+            mRegistrationListener.onRegistrationChanged(false /* isRegistered */);
+        }
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        final String innerPrefix = prefix + "  ";
+        pw.println(prefix + TAG);
+        pw.println(innerPrefix + "registered=" + (mInputEventReceiver != null));
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 4e991f2..2e10fc9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -475,7 +475,7 @@
             final Intent settingsIntent = new Intent(ACTION_PICTURE_IN_PICTURE_SETTINGS,
                     Uri.fromParts("package", topPipActivityInfo.first.getPackageName(), null));
             settingsIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
-            mContext.startActivityAsUser(settingsIntent, UserHandle.CURRENT);
+            mContext.startActivityAsUser(settingsIntent, UserHandle.of(topPipActivityInfo.second));
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipPinchResizingAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipPinchResizingAlgorithm.java
new file mode 100644
index 0000000..28cbe35
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipPinchResizingAlgorithm.java
@@ -0,0 +1,123 @@
+/*
+ * 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.wm.shell.pip.phone;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+
+/**
+ * Helper class to calculate the new size given two-fingers pinch to resize.
+ */
+public class PipPinchResizingAlgorithm {
+    private static final Rect TMP_RECT = new Rect();
+    /**
+     * Given inputs and requirements and current PiP bounds, return the new size.
+     *
+     * @param x0 x-coordinate of the primary input.
+     * @param y0 y-coordinate of the primary input.
+     * @param x1 x-coordinate of the secondary input.
+     * @param y1 y-coordinate of the secondary input.
+     * @param downx0 x-coordinate of the original down point of the primary input.
+     * @param downy0 y-coordinate of the original down ponit of the primary input.
+     * @param downx1 x-coordinate of the original down point of the secondary input.
+     * @param downy1 y-coordinate of the original down point of the secondary input.
+     * @param currentPipBounds current PiP bounds.
+     * @param minVisibleWidth minimum visible width.
+     * @param minVisibleHeight minimum visible height.
+     * @param maxSize max size.
+     * @return The new resized PiP bounds, sharing the same center.
+     */
+    public static Rect pinchResize(float x0, float y0, float x1, float y1,
+            float downx0, float downy0, float downx1, float downy1, Rect currentPipBounds,
+            int minVisibleWidth, int minVisibleHeight, Point maxSize) {
+
+        int width = currentPipBounds.width();
+        int height = currentPipBounds.height();
+        int left = currentPipBounds.left;
+        int top = currentPipBounds.top;
+        int right = currentPipBounds.right;
+        int bottom = currentPipBounds.bottom;
+        final float aspect = (float) width / (float) height;
+        final int widthDelta = Math.round(Math.abs(x0 - x1) - Math.abs(downx0 - downx1));
+        final int heightDelta = Math.round(Math.abs(y0 - y1) - Math.abs(downy0 - downy1));
+
+        width = Math.max(minVisibleWidth, Math.min(width + widthDelta, maxSize.x));
+        height = Math.max(minVisibleHeight, Math.min(height + heightDelta, maxSize.y));
+
+        // Calculate 2 rectangles fulfilling all requirements for either X or Y being the major
+        // drag axis. What ever is producing the bigger rectangle will be chosen.
+        int width1;
+        int width2;
+        int height1;
+        int height2;
+        if (aspect > 1.0f) {
+            // Assuming that the width is our target we calculate the height.
+            width1 = Math.max(minVisibleWidth, Math.min(maxSize.x, width));
+            height1 = Math.round((float) width1 / aspect);
+            if (height1 < minVisibleHeight) {
+                // If the resulting height is too small we adjust to the minimal size.
+                height1 = minVisibleHeight;
+                width1 = Math.max(minVisibleWidth,
+                        Math.min(maxSize.x, Math.round((float) height1 * aspect)));
+            }
+            // Assuming that the height is our target we calculate the width.
+            height2 = Math.max(minVisibleHeight, Math.min(maxSize.y, height));
+            width2 = Math.round((float) height2 * aspect);
+            if (width2 < minVisibleWidth) {
+                // If the resulting width is too small we adjust to the minimal size.
+                width2 = minVisibleWidth;
+                height2 = Math.max(minVisibleHeight,
+                        Math.min(maxSize.y, Math.round((float) width2 / aspect)));
+            }
+        } else {
+            // Assuming that the width is our target we calculate the height.
+            width1 = Math.max(minVisibleWidth, Math.min(maxSize.x, width));
+            height1 = Math.round((float) width1 * aspect);
+            if (height1 < minVisibleHeight) {
+                // If the resulting height is too small we adjust to the minimal size.
+                height1 = minVisibleHeight;
+                width1 = Math.max(minVisibleWidth,
+                        Math.min(maxSize.x, Math.round((float) height1 / aspect)));
+            }
+            // Assuming that the height is our target we calculate the width.
+            height2 = Math.max(minVisibleHeight, Math.min(maxSize.y, height));
+            width2 = Math.round((float) height2 / aspect);
+            if (width2 < minVisibleWidth) {
+                // If the resulting width is too small we adjust to the minimal size.
+                width2 = minVisibleWidth;
+                height2 = Math.max(minVisibleHeight,
+                        Math.min(maxSize.y, Math.round((float) width2 * aspect)));
+            }
+        }
+
+        // Use the bigger of the two rectangles if the major change was positive, otherwise
+        // do the opposite.
+        final boolean grows = width > (right - left) || height > (bottom - top);
+        if (grows == (width1 * height1 > width2 * height2)) {
+            width = width1;
+            height = height1;
+        } else {
+            width = width2;
+            height = height2;
+        }
+
+        TMP_RECT.set(currentPipBounds.centerX() - width / 2,
+                currentPipBounds.centerY() - height / 2,
+                currentPipBounds.centerX() + width / 2,
+                currentPipBounds.centerY() + height / 2);
+        return TMP_RECT;
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
index bb545bd..88a1168 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
@@ -39,7 +39,6 @@
 import android.view.InputEventReceiver;
 import android.view.InputMonitor;
 import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
 import android.view.ViewConfiguration;
 
 import androidx.annotation.VisibleForTesting;
@@ -62,19 +61,21 @@
 public class PipResizeGestureHandler {
 
     private static final String TAG = "PipResizeGestureHandler";
-    private static final float PINCH_THRESHOLD = 0.05f;
-    private static final float STARTING_SCALE_FACTOR = 1.0f;
+    private static final int PINCH_RESIZE_SNAP_DURATION = 250;
 
     private final Context mContext;
     private final PipBoundsAlgorithm mPipBoundsAlgorithm;
     private final PipMotionHelper mMotionHelper;
     private final PipBoundsState mPipBoundsState;
+    private final PipTaskOrganizer mPipTaskOrganizer;
+    private final PhonePipMenuController mPhonePipMenuController;
+    private final PipUiEventLogger mPipUiEventLogger;
     private final int mDisplayId;
     private final Executor mMainExecutor;
-    private final ScaleGestureDetector mScaleGestureDetector;
     private final Region mTmpRegion = new Region();
 
     private final PointF mDownPoint = new PointF();
+    private final PointF mDownSecondaryPoint = new PointF();
     private final Point mMaxSize = new Point();
     private final Point mMinSize = new Point();
     private final Rect mLastResizeBounds = new Rect();
@@ -88,6 +89,7 @@
     private final Rect mDisplayBounds = new Rect();
     private final Function<Rect, Rect> mMovementBoundsSupplier;
     private final Runnable mUpdateMovementBoundsRunnable;
+    private final Handler mHandler;
 
     private int mDelta;
     private float mTouchSlop;
@@ -96,15 +98,17 @@
     private boolean mIsEnabled;
     private boolean mEnablePinchResize;
     private boolean mIsSysUiStateValid;
+    // For drag-resize
     private boolean mThresholdCrossed;
+    // For pinch-resize
+    private boolean mThresholdCrossed0;
+    private boolean mThresholdCrossed1;
     private boolean mUsingPinchToZoom = false;
-    private float mScaleFactor = STARTING_SCALE_FACTOR;
+    int mFirstIndex = -1;
+    int mSecondIndex = -1;
 
     private InputMonitor mInputMonitor;
     private InputEventReceiver mInputEventReceiver;
-    private PipTaskOrganizer mPipTaskOrganizer;
-    private PhonePipMenuController mPhonePipMenuController;
-    private PipUiEventLogger mPipUiEventLogger;
 
     private int mCtrlType;
 
@@ -124,66 +128,11 @@
         mUpdateMovementBoundsRunnable = updateMovementBoundsRunnable;
         mPhonePipMenuController = menuActivityController;
         mPipUiEventLogger = pipUiEventLogger;
+        mHandler = new Handler(Looper.getMainLooper());
 
         context.getDisplay().getRealSize(mMaxSize);
         reloadResources();
 
-        mScaleGestureDetector = new ScaleGestureDetector(context,
-                new ScaleGestureDetector.OnScaleGestureListener() {
-                    @Override
-                    public boolean onScale(ScaleGestureDetector detector) {
-                        mScaleFactor *= detector.getScaleFactor();
-
-                        if (!mThresholdCrossed
-                                && (mScaleFactor > (STARTING_SCALE_FACTOR + PINCH_THRESHOLD)
-                                || mScaleFactor < (STARTING_SCALE_FACTOR - PINCH_THRESHOLD))) {
-                            mThresholdCrossed = true;
-                            mInputMonitor.pilferPointers();
-                        }
-                        if (mThresholdCrossed) {
-                            int height = Math.min(mMaxSize.y, Math.max(mMinSize.y,
-                                    (int) (mScaleFactor * mLastDownBounds.height())));
-                            int width = Math.min(mMaxSize.x, Math.max(mMinSize.x,
-                                    (int) (mScaleFactor * mLastDownBounds.width())));
-                            int top, bottom, left, right;
-
-                            if ((mCtrlType & CTRL_TOP) != 0) {
-                                top = mLastDownBounds.bottom - height;
-                                bottom = mLastDownBounds.bottom;
-                            } else {
-                                top = mLastDownBounds.top;
-                                bottom = mLastDownBounds.top + height;
-                            }
-
-                            if ((mCtrlType & CTRL_LEFT) != 0) {
-                                left = mLastDownBounds.right - width;
-                                right = mLastDownBounds.right;
-                            } else {
-                                left = mLastDownBounds.left;
-                                right = mLastDownBounds.left + width;
-                            }
-
-                            mLastResizeBounds.set(left, top, right, bottom);
-                            mPipTaskOrganizer.scheduleUserResizePip(mLastDownBounds,
-                                    mLastResizeBounds,
-                                    null);
-                        }
-                        return true;
-                    }
-
-                    @Override
-                    public boolean onScaleBegin(ScaleGestureDetector detector) {
-                        setCtrlTypeForPinchToZoom();
-                        return true;
-                    }
-
-                    @Override
-                    public void onScaleEnd(ScaleGestureDetector detector) {
-                        mScaleFactor = STARTING_SCALE_FACTOR;
-                        finishResize();
-                    }
-                });
-
         mEnablePinchResize = DeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 PIP_PINCH_RESIZE,
@@ -274,7 +223,7 @@
 
         if (ev instanceof MotionEvent) {
             if (mUsingPinchToZoom) {
-                mScaleGestureDetector.onTouchEvent((MotionEvent) ev);
+                onPinchResize((MotionEvent) ev);
             } else {
                 onDragCornerResize((MotionEvent) ev);
             }
@@ -282,6 +231,13 @@
     }
 
     /**
+     * Checks if there is currently an on-going gesture, either drag-resize or pinch-resize.
+     */
+    public boolean hasOngoingGesture() {
+        return mCtrlType != CTRL_NONE || mUsingPinchToZoom;
+    }
+
+    /**
      * Check whether the current x,y coordinate is within the region in which drag-resize should
      * start.
      * This consists of 4 small squares on the 4 corners of the PIP window, a quarter of which
@@ -295,7 +251,7 @@
      * |_|_|_________|_|_|
      * |_|_|         |_|_|
      */
-    public boolean isWithinTouchRegion(int x, int y) {
+    public boolean isWithinDragResizeRegion(int x, int y) {
         final Rect currentPipBounds = mPipBoundsState.getBounds();
         if (currentPipBounds == null) {
             return false;
@@ -327,15 +283,14 @@
         if (isInValidSysUiState()) {
             switch (ev.getActionMasked()) {
                 case MotionEvent.ACTION_DOWN:
-                    // Always pass the DOWN event to the ScaleGestureDetector
-                    mScaleGestureDetector.onTouchEvent(ev);
-                    if (isWithinTouchRegion((int) ev.getRawX(), (int) ev.getRawY())) {
+                    if (isWithinDragResizeRegion((int) ev.getRawX(), (int) ev.getRawY())) {
                         return true;
                     }
                     break;
 
                 case MotionEvent.ACTION_POINTER_DOWN:
                     if (mEnablePinchResize && ev.getPointerCount() == 2) {
+                        onPinchResize(ev);
                         mUsingPinchToZoom = true;
                         return true;
                     }
@@ -348,33 +303,11 @@
         return false;
     }
 
-    private void setCtrlTypeForPinchToZoom() {
-        final Rect currentPipBounds = mPipBoundsState.getBounds();
-        mLastDownBounds.set(mPipBoundsState.getBounds());
-
-        Rect movementBounds = mMovementBoundsSupplier.apply(currentPipBounds);
-        mDisplayBounds.set(movementBounds.left,
-                movementBounds.top,
-                movementBounds.right + currentPipBounds.width(),
-                movementBounds.bottom + currentPipBounds.height());
-
-        if (currentPipBounds.left == mDisplayBounds.left) {
-            mCtrlType |= CTRL_RIGHT;
-        } else {
-            mCtrlType |= CTRL_LEFT;
-        }
-
-        if (currentPipBounds.top > mDisplayBounds.top + mDisplayBounds.height()) {
-            mCtrlType |= CTRL_TOP;
-        } else {
-            mCtrlType |= CTRL_BOTTOM;
-        }
-    }
-
     private void setCtrlType(int x, int y) {
         final Rect currentPipBounds = mPipBoundsState.getBounds();
 
         Rect movementBounds = mMovementBoundsSupplier.apply(currentPipBounds);
+
         mDisplayBounds.set(movementBounds.left,
                 movementBounds.top,
                 movementBounds.right + currentPipBounds.width(),
@@ -408,6 +341,78 @@
         return mIsSysUiStateValid;
     }
 
+    private void onPinchResize(MotionEvent ev) {
+        int action = ev.getActionMasked();
+
+        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+            mFirstIndex = -1;
+            mSecondIndex = -1;
+            finishResize();
+        }
+
+        if (ev.getPointerCount() != 2) {
+            return;
+        }
+
+        if (action == MotionEvent.ACTION_POINTER_DOWN) {
+            if (mFirstIndex == -1 && mSecondIndex == -1) {
+                mFirstIndex = 0;
+                mSecondIndex = 1;
+                mLastResizeBounds.setEmpty();
+                mDownPoint.set(ev.getRawX(mFirstIndex), ev.getRawY(mFirstIndex));
+                mDownSecondaryPoint.set(ev.getRawX(mSecondIndex), ev.getRawY(mSecondIndex));
+
+                mLastResizeBounds.setEmpty();
+                mLastDownBounds.set(mPipBoundsState.getBounds());
+            }
+        }
+
+        if (action == MotionEvent.ACTION_MOVE) {
+            if (mFirstIndex == -1 || mSecondIndex == -1) {
+                return;
+            }
+
+            float x0 = ev.getRawX(mFirstIndex);
+            float y0 = ev.getRawY(mFirstIndex);
+            float x1 = ev.getRawX(mSecondIndex);
+            float y1 = ev.getRawY(mSecondIndex);
+
+            double hypot0 = Math.hypot(x0 - mDownPoint.x, y0 - mDownPoint.y);
+            double hypot1 = Math.hypot(x1 - mDownSecondaryPoint.x, y1 - mDownSecondaryPoint.y);
+            // Capture inputs
+            if (hypot0 > mTouchSlop && !mThresholdCrossed0) {
+                mInputMonitor.pilferPointers();
+                mThresholdCrossed0 = true;
+                // Reset the down to begin resizing from this point
+                mDownPoint.set(x0, y0);
+            }
+            if (hypot1 > mTouchSlop && !mThresholdCrossed1) {
+                mInputMonitor.pilferPointers();
+                mThresholdCrossed1 = true;
+                // Reset the down to begin resizing from this point
+                mDownSecondaryPoint.set(x1, y1);
+            }
+            if (mThresholdCrossed0 || mThresholdCrossed1) {
+                if (mPhonePipMenuController.isMenuVisible()) {
+                    mPhonePipMenuController.hideMenu();
+                }
+
+                x0 = mThresholdCrossed0 ? x0 : mDownPoint.x;
+                y0 = mThresholdCrossed0 ? y0 : mDownPoint.y;
+                x1 = mThresholdCrossed1 ? x1 : mDownSecondaryPoint.x;
+                y1 = mThresholdCrossed1 ? y1 : mDownSecondaryPoint.y;
+
+                final Rect currentPipBounds = mPipBoundsState.getBounds();
+                mLastResizeBounds.set(PipPinchResizingAlgorithm.pinchResize(x0, y0, x1, y1,
+                        mDownPoint.x, mDownPoint.y, mDownSecondaryPoint.x, mDownSecondaryPoint.y,
+                        currentPipBounds, mMinSize.x, mMinSize.y, mMaxSize));
+
+                mPipTaskOrganizer.scheduleUserResizePip(mLastDownBounds, mLastResizeBounds,
+                        null);
+            }
+        }
+    }
+
     private void onDragCornerResize(MotionEvent ev) {
         int action = ev.getActionMasked();
         float x = ev.getX();
@@ -415,7 +420,7 @@
         if (action == MotionEvent.ACTION_DOWN) {
             final Rect currentPipBounds = mPipBoundsState.getBounds();
             mLastResizeBounds.setEmpty();
-            mAllowGesture = isInValidSysUiState() && isWithinTouchRegion((int) x, (int) y);
+            mAllowGesture = isInValidSysUiState() && isWithinDragResizeRegion((int) x, (int) y);
             if (mAllowGesture) {
                 setCtrlType((int) x, (int) y);
                 mDownPoint.set(x, y);
@@ -468,15 +473,30 @@
 
     private void finishResize() {
         if (!mLastResizeBounds.isEmpty()) {
-            mUserResizeBounds.set(mLastResizeBounds);
-            mPipTaskOrganizer.scheduleFinishResizePip(mLastResizeBounds,
-                    (Rect bounds) -> {
-                        new Handler(Looper.getMainLooper()).post(() -> {
-                            mMotionHelper.synchronizePinnedStackBounds();
-                            mUpdateMovementBoundsRunnable.run();
-                            resetState();
+            final Runnable callback = () -> {
+                mUserResizeBounds.set(mLastResizeBounds);
+                mMotionHelper.synchronizePinnedStackBounds();
+                mUpdateMovementBoundsRunnable.run();
+                resetState();
+            };
+
+            // Pinch-to-resize needs to re-calculate snap fraction and animate to the snapped
+            // position correctly. Drag-resize does not need to move, so just finalize resize.
+            if (mUsingPinchToZoom) {
+                final Rect startBounds = new Rect(mLastResizeBounds);
+                mPipBoundsAlgorithm.applySnapFraction(mLastResizeBounds,
+                        mPipBoundsAlgorithm.getSnapFraction(mPipBoundsState.getBounds()));
+                mPipTaskOrganizer.scheduleAnimateResizePip(startBounds, mLastResizeBounds,
+                        PINCH_RESIZE_SNAP_DURATION,
+                        (Rect rect) -> {
+                            mHandler.post(callback);
                         });
-                    });
+            } else {
+                mPipTaskOrganizer.scheduleFinishResizePip(mLastResizeBounds,
+                        (Rect bounds) -> {
+                            mHandler.post(callback);
+                        });
+            }
             mPipUiEventLogger.log(
                     PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_RESIZE);
         } else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 9917701..9281f58 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -31,11 +31,8 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.Handler;
-import android.os.RemoteException;
 import android.provider.DeviceConfig;
-import android.util.Log;
 import android.util.Size;
-import android.view.IPinnedStackController;
 import android.view.InputEvent;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
@@ -47,6 +44,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.wm.shell.R;
 import com.android.wm.shell.common.FloatingContentCoordinator;
+import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.pip.PipAnimationController;
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.pip.PipBoundsState;
@@ -75,7 +73,6 @@
     private final PipDismissTargetHandler mPipDismissTargetHandler;
 
     private PipResizeGestureHandler mPipResizeGestureHandler;
-    private IPinnedStackController mPinnedStackController;
     private WeakReference<Consumer<Rect>> mPipExclusionBoundsChangeListener;
 
     private final PhonePipMenuController mMenuController;
@@ -157,7 +154,8 @@
             @NonNull PipBoundsState pipBoundsState,
             PipTaskOrganizer pipTaskOrganizer,
             FloatingContentCoordinator floatingContentCoordinator,
-            PipUiEventLogger pipUiEventLogger) {
+            PipUiEventLogger pipUiEventLogger,
+            ShellExecutor shellMainExecutor) {
         // Initialize the Pip input consumer
         mContext = context;
         mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
@@ -188,7 +186,7 @@
         mFloatingContentCoordinator = floatingContentCoordinator;
         mConnection = new PipAccessibilityInteractionConnection(mContext, pipBoundsState,
                 mMotionHelper, pipTaskOrganizer, mPipBoundsAlgorithm.getSnapAlgorithm(),
-                this::onAccessibilityShowMenu, this::updateMovementBounds, mHandler);
+                this::onAccessibilityShowMenu, this::updateMovementBounds, shellMainExecutor);
 
         mPipUiEventLogger = pipUiEventLogger;
 
@@ -436,8 +434,11 @@
      * TODO Add appropriate description
      */
     public void onRegistrationChanged(boolean isRegistered) {
-        mAccessibilityManager.setPictureInPictureActionReplacingConnection(isRegistered
-                ? mConnection : null);
+        if (isRegistered) {
+            mConnection.register(mAccessibilityManager);
+        } else {
+            mAccessibilityManager.setPictureInPictureActionReplacingConnection(null);
+        }
         if (!isRegistered && mTouchState.isUserInteracting()) {
             // If the input consumer is unregistered while the user is interacting, then we may not
             // get the final TOUCH_UP event, so clean up the dismiss target as well
@@ -459,10 +460,6 @@
         if (!(inputEvent instanceof MotionEvent)) {
             return true;
         }
-        // Skip touch handling until we are bound to the controller
-        if (mPinnedStackController == null) {
-            return true;
-        }
 
         MotionEvent ev = (MotionEvent) inputEvent;
         if (!mPipBoundsState.isStashed() && mPipResizeGestureHandler.willStartResizeGesture(ev)) {
@@ -473,6 +470,11 @@
             return true;
         }
 
+        if (mPipResizeGestureHandler.hasOngoingGesture()) {
+            mPipDismissTargetHandler.hideDismissTargetMaybe();
+            return true;
+        }
+
         if ((ev.getAction() == MotionEvent.ACTION_DOWN || mTouchState.isUserInteracting())
                 && mPipDismissTargetHandler.maybeConsumeMotionEvent(ev)) {
             // If the first touch event occurs within the magnetic field, pass the ACTION_DOWN event
@@ -586,13 +588,6 @@
     }
 
     /**
-     * Sets the controller to update the system of changes from user interaction.
-     */
-    void setPinnedStackController(IPinnedStackController controller) {
-        mPinnedStackController = controller;
-    }
-
-    /**
      * Sets the menu visibility.
      */
     private void setMenuState(int menuState, boolean resize, Runnable callback) {
@@ -620,13 +615,9 @@
                     // bounds which are now stale.  In such a case we defer the animation to the
                     // normal bounds until after the next onMovementBoundsChanged() call to get the
                     // bounds in the new orientation
-                    try {
-                        int displayRotation = mPinnedStackController.getDisplayRotation();
-                        if (mDisplayRotation != displayRotation) {
-                            mDeferResizeToNormalBoundsUntilRotation = displayRotation;
-                        }
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Could not get display rotation from controller");
+                    int displayRotation = mContext.getDisplay().getRotation();
+                    if (mDisplayRotation != displayRotation) {
+                        mDeferResizeToNormalBoundsUntilRotation = displayRotation;
                     }
                 }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java
index 21715077..5f2327c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java
@@ -19,6 +19,7 @@
 import android.graphics.PointF;
 import android.os.Handler;
 import android.util.Log;
+import android.view.Display;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.ViewConfiguration;
@@ -64,6 +65,7 @@
     private boolean mStartedDragging = false;
     private boolean mAllowDraggingOffscreen = false;
     private int mActivePointerId;
+    private int mLastTouchDisplayId = Display.INVALID_DISPLAY;
 
     public PipTouchState(ViewConfiguration viewConfig, Handler handler,
             Runnable doubleTapTimeoutCallback, Runnable hoverExitTimeoutCallback) {
@@ -81,12 +83,14 @@
         mIsDragging = false;
         mStartedDragging = false;
         mIsUserInteracting = false;
+        mLastTouchDisplayId = Display.INVALID_DISPLAY;
     }
 
     /**
      * Processes a given touch event and updates the state.
      */
     public void onTouchEvent(MotionEvent ev) {
+        mLastTouchDisplayId = ev.getDisplayId();
         switch (ev.getActionMasked()) {
             case MotionEvent.ACTION_DOWN: {
                 if (!mAllowTouches) {
@@ -266,6 +270,13 @@
     }
 
     /**
+     * @return Display ID of the last touch event.
+     */
+    public int getLastTouchDisplayId() {
+        return mLastTouchDisplayId;
+    }
+
+    /**
      * Sets whether touching is currently allowed.
      */
     public void setAllowTouches(boolean allowTouches) {
@@ -378,6 +389,7 @@
         pw.println(prefix + TAG);
         pw.println(innerPrefix + "mAllowTouches=" + mAllowTouches);
         pw.println(innerPrefix + "mActivePointerId=" + mActivePointerId);
+        pw.println(innerPrefix + "mLastTouchDisplayId=" + mLastTouchDisplayId);
         pw.println(innerPrefix + "mDownTouch=" + mDownTouch);
         pw.println(innerPrefix + "mDownDelta=" + mDownDelta);
         pw.println(innerPrefix + "mLastTouch=" + mLastTouch);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
index 5d8d5e6..763370b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
@@ -179,40 +179,33 @@
             PinnedStackListenerForwarder.PinnedStackListener {
         @Override
         public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
-            mHandler.post(() -> {
-                mPipBoundsState.setImeVisibility(imeVisible, imeHeight);
-                if (mState == STATE_PIP) {
-                    if (mImeVisible != imeVisible) {
-                        if (imeVisible) {
-                            // Save the IME height adjustment, and offset to not occlude the IME
-                            mPipBoundsState.getNormalBounds().offset(0, -imeHeight);
-                            mImeHeightAdjustment = imeHeight;
-                        } else {
-                            // Apply the inverse adjustment when the IME is hidden
-                            mPipBoundsState.getNormalBounds().offset(0, mImeHeightAdjustment);
-                        }
-                        mImeVisible = imeVisible;
-                        resizePinnedStack(STATE_PIP);
+            mPipBoundsState.setImeVisibility(imeVisible, imeHeight);
+            if (mState == STATE_PIP) {
+                if (mImeVisible != imeVisible) {
+                    if (imeVisible) {
+                        // Save the IME height adjustment, and offset to not occlude the IME
+                        mPipBoundsState.getNormalBounds().offset(0, -imeHeight);
+                        mImeHeightAdjustment = imeHeight;
+                    } else {
+                        // Apply the inverse adjustment when the IME is hidden
+                        mPipBoundsState.getNormalBounds().offset(0, mImeHeightAdjustment);
                     }
+                    mImeVisible = imeVisible;
+                    resizePinnedStack(STATE_PIP);
                 }
-            });
+            }
         }
 
         @Override
         public void onMovementBoundsChanged(boolean fromImeAdjustment) {
-            mHandler.post(() -> {
-                mTmpDisplayInfo.copyFrom(mPipBoundsState.getDisplayInfo());
-
-                mPipBoundsAlgorithm.getInsetBounds(mTmpInsetBounds);
-            });
+            mTmpDisplayInfo.copyFrom(mPipBoundsState.getDisplayInfo());
+            mPipBoundsAlgorithm.getInsetBounds(mTmpInsetBounds);
         }
 
         @Override
         public void onActionsChanged(ParceledListSlice<RemoteAction> actions) {
             mCustomActions = actions;
-            mHandler.post(() -> {
-                mTvPipMenuController.setAppActions(mCustomActions);
-            });
+            mTvPipMenuController.setAppActions(mCustomActions);
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerWindowManager.java
index f2becc9..5078371 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerWindowManager.java
@@ -24,6 +24,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static android.view.WindowManager.SHELL_ROOT_LAYER_DIVIDER;
 
@@ -59,7 +60,7 @@
                 PixelFormat.TRANSLUCENT);
         mLp.token = new Binder();
         mLp.setTitle(WINDOW_TITLE);
-        mLp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION;
+        mLp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
         mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
         view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index e55f065..7c70a4efa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -19,6 +19,8 @@
 import android.graphics.Rect;
 import android.window.WindowContainerToken;
 
+import com.android.wm.shell.common.annotations.ExternalThread;
+
 import java.io.PrintWriter;
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
@@ -26,6 +28,7 @@
 /**
  * Interface to engage split screen feature.
  */
+@ExternalThread
 public interface SplitScreen {
     /** Called when keyguard showing state changed. */
     void onKeyguardVisibilityChanged(boolean isShowing);
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
index 101b5bf..1054c43 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
@@ -21,6 +21,8 @@
     <!-- Read and write traces from external storage -->
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <!-- Allow the test to write directly to /sdcard/ -->
+    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
     <!-- Write secure settings -->
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
     <!-- Capture screen contents -->
@@ -38,7 +40,8 @@
     <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>
     <!-- ATM.removeRootTasksWithActivityTypes() -->
     <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" />
-    <application>
+    <!-- Allow the test to write directly to /sdcard/ -->
+    <application android:requestLegacyExternalStorage="true">
         <uses-library android:name="android.test.runner"/>
 
         <service android:name=".NotificationListener"
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTestPhysicalDevices.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTestPhysicalDevices.xml
index 9dd9f42..23d7021 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidTestPhysicalDevices.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTestPhysicalDevices.xml
@@ -34,7 +34,7 @@
         <option name="hidden-api-checks" value="false" />
     </test>
     <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
-        <option name="directory-keys" value="/storage/emulated/0/Android/data/com.android.wm.shell.flicker/files" />
+        <option name="directory-keys" value="/sdcard/flicker" />
         <option name="collect-on-run-ended-only" value="true" />
         <option name="clean-up" value="true" />
     </metrics_collector>
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTestVirtualDevices.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTestVirtualDevices.xml
index afb1166..0738608 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidTestVirtualDevices.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTestVirtualDevices.xml
@@ -34,7 +34,7 @@
         <option name="hidden-api-checks" value="false" />
     </test>
     <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
-        <option name="directory-keys" value="/storage/emulated/0/Android/data/com.android.wm.shell.flicker/files" />
+        <option name="directory-keys" value="/sdcard/flicker" />
         <option name="collect-on-run-ended-only" value="true" />
         <option name="clean-up" value="true" />
     </metrics_collector>
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
index 0fb43e2..3ed53fb 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
@@ -18,78 +18,6 @@
 
 import com.android.server.wm.flicker.dsl.EventLogAssertion
 import com.android.server.wm.flicker.dsl.LayersAssertion
-import com.android.server.wm.flicker.dsl.WmAssertion
-import com.android.server.wm.flicker.helpers.WindowUtils
-
-@JvmOverloads
-fun WmAssertion.statusBarWindowIsAlwaysVisible(
-    bugId: Int = 0,
-    enabled: Boolean = bugId == 0
-) {
-    all("statusBarWindowIsAlwaysVisible", bugId, enabled) {
-        this.showsAboveAppWindow(FlickerTestBase.STATUS_BAR_WINDOW_TITLE)
-    }
-}
-
-@JvmOverloads
-fun WmAssertion.navBarWindowIsAlwaysVisible(
-    bugId: Int = 0,
-    enabled: Boolean = bugId == 0
-) {
-    all("navBarWindowIsAlwaysVisible", bugId, enabled) {
-        this.showsAboveAppWindow(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE)
-    }
-}
-
-@JvmOverloads
-fun LayersAssertion.noUncoveredRegions(
-    beginRotation: Int,
-    endRotation: Int = beginRotation,
-    allStates: Boolean = true,
-    bugId: Int = 0,
-    enabled: Boolean = bugId == 0
-) {
-    val startingBounds = WindowUtils.getDisplayBounds(beginRotation)
-    val endingBounds = WindowUtils.getDisplayBounds(endRotation)
-    if (allStates) {
-        all("noUncoveredRegions", bugId, enabled) {
-            if (startingBounds == endingBounds) {
-                this.coversAtLeastRegion(startingBounds)
-            } else {
-                this.coversAtLeastRegion(startingBounds)
-                        .then()
-                        .coversAtLeastRegion(endingBounds)
-            }
-        }
-    } else {
-        start("noUncoveredRegions_StartingPos") {
-            this.coversAtLeastRegion(startingBounds)
-        }
-        end("noUncoveredRegions_EndingPos") {
-            this.coversAtLeastRegion(endingBounds)
-        }
-    }
-}
-
-@JvmOverloads
-fun LayersAssertion.statusBarLayerIsAlwaysVisible(
-    bugId: Int = 0,
-    enabled: Boolean = bugId == 0
-) {
-    all("statusBarLayerIsAlwaysVisible", bugId, enabled) {
-        this.showsLayer(FlickerTestBase.STATUS_BAR_WINDOW_TITLE)
-    }
-}
-
-@JvmOverloads
-fun LayersAssertion.navBarLayerIsAlwaysVisible(
-    bugId: Int = 0,
-    enabled: Boolean = bugId == 0
-) {
-    all("navBarLayerIsAlwaysVisible", bugId, enabled) {
-        this.showsLayer(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE)
-    }
-}
 
 @JvmOverloads
 fun LayersAssertion.appPairsDividerIsVisible(
@@ -131,48 +59,6 @@
     }
 }
 
-@JvmOverloads
-fun LayersAssertion.navBarLayerRotatesAndScales(
-    beginRotation: Int,
-    endRotation: Int = beginRotation,
-    bugId: Int = 0,
-    enabled: Boolean = bugId == 0
-) {
-    val startingPos = WindowUtils.getNavigationBarPosition(beginRotation)
-    val endingPos = WindowUtils.getNavigationBarPosition(endRotation)
-
-    start("navBarLayerRotatesAndScales_StartingPos", bugId, enabled) {
-        this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, startingPos)
-    }
-    end("navBarLayerRotatesAndScales_EndingPost", bugId, enabled) {
-        this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, endingPos)
-    }
-
-    if (startingPos == endingPos) {
-        all("navBarLayerRotatesAndScales", bugId, enabled) {
-            this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, startingPos)
-        }
-    }
-}
-
-@JvmOverloads
-fun LayersAssertion.statusBarLayerRotatesScales(
-    beginRotation: Int,
-    endRotation: Int = beginRotation,
-    bugId: Int = 0,
-    enabled: Boolean = bugId == 0
-) {
-    val startingPos = WindowUtils.getStatusBarPosition(beginRotation)
-    val endingPos = WindowUtils.getStatusBarPosition(endRotation)
-
-    start("statusBarLayerRotatesScales_StartingPos", bugId, enabled) {
-        this.hasVisibleRegion(FlickerTestBase.STATUS_BAR_WINDOW_TITLE, startingPos)
-    }
-    end("statusBarLayerRotatesScales_EndingPos", bugId, enabled) {
-        this.hasVisibleRegion(FlickerTestBase.STATUS_BAR_WINDOW_TITLE, endingPos)
-    }
-}
-
 fun EventLogAssertion.focusChanges(
     vararg windows: String,
     bugId: Int = 0,
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTest.kt
index ced99de..7ac91b0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTest.kt
@@ -29,10 +29,10 @@
 import com.android.wm.shell.flicker.helpers.AppPairsHelper.Companion.TEST_REPETITIONS
 import com.android.wm.shell.flicker.appPairsDividerIsInvisible
 import com.android.wm.shell.flicker.appPairsDividerIsVisible
-import com.android.wm.shell.flicker.navBarLayerIsAlwaysVisible
-import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
index 0663eb3..c9396aa 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
@@ -23,10 +23,10 @@
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
 import com.android.wm.shell.flicker.helpers.FixedAppHelper
 import com.android.wm.shell.flicker.helpers.PipAppHelper
-import com.android.wm.shell.flicker.navBarLayerIsAlwaysVisible
-import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
 import org.junit.FixMethodOrder
 import org.junit.Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipOrientationTest.kt
index 322034c..76aabc1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipOrientationTest.kt
@@ -24,10 +24,10 @@
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
 import com.android.wm.shell.flicker.helpers.FixedAppHelper
 import com.android.wm.shell.flicker.helpers.PipAppHelper
-import com.android.wm.shell.flicker.navBarLayerIsAlwaysVisible
-import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import com.android.wm.shell.flicker.testapp.Components.PipActivity.ACTION_ENTER_PIP
 import com.android.wm.shell.flicker.testapp.Components.PipActivity.ACTION_SET_REQUESTED_ORIENTATION
 import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
index 96d98d5..a67b3b7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
@@ -31,13 +31,13 @@
 import com.android.server.wm.flicker.startRotation
 import com.android.wm.shell.flicker.helpers.FixedAppHelper
 import com.android.wm.shell.flicker.helpers.PipAppHelper
-import com.android.wm.shell.flicker.navBarLayerIsAlwaysVisible
-import com.android.wm.shell.flicker.navBarLayerRotatesAndScales
-import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.noUncoveredRegions
-import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarLayerRotatesScales
-import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
 import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
 import org.junit.FixMethodOrder
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipSplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipSplitScreenTest.kt
index d20552f..f79b21f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipSplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipSplitScreenTest.kt
@@ -28,10 +28,10 @@
 import com.android.wm.shell.flicker.helpers.ImeAppHelper
 import com.android.wm.shell.flicker.helpers.FixedAppHelper
 import com.android.wm.shell.flicker.helpers.PipAppHelper
-import com.android.wm.shell.flicker.navBarLayerIsAlwaysVisible
-import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
 import org.junit.FixMethodOrder
 import org.junit.Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenTest.kt
index c61a0f1..5570a56 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenTest.kt
@@ -25,10 +25,10 @@
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
 import com.android.wm.shell.flicker.dockedStackDividerIsVisible
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper.Companion.TEST_REPETITIONS
-import com.android.wm.shell.flicker.navBarLayerIsAlwaysVisible
-import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/ExitSplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/ExitSplitScreenTest.kt
index bf92869..7c47d1f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/ExitSplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/ExitSplitScreenTest.kt
@@ -29,8 +29,8 @@
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
 import com.android.wm.shell.flicker.dockedStackDividerIsInvisible
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper.Companion.TEST_REPETITIONS
-import com.android.wm.shell.flicker.navBarWindowIsAlwaysVisible
-import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairLayoutTests.java
deleted file mode 100644
index c9d32c4..0000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairLayoutTests.java
+++ /dev/null
@@ -1,89 +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 com.android.wm.shell.apppairs;
-
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.view.Display;
-import android.view.SurfaceControl;
-
-import androidx.test.annotation.UiThreadTest;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.wm.shell.ShellTestCase;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/** Tests for {@link AppPairLayout} */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class AppPairLayoutTests extends ShellTestCase {
-    @Mock SurfaceControl mSurfaceControl;
-    private Display mDisplay;
-    private Configuration mConfiguration;
-    private AppPairLayout mAppPairLayout;
-
-    @Before
-    public void setup() {
-        MockitoAnnotations.initMocks(this);
-        mConfiguration = getConfiguration(false);
-        mDisplay = mContext.getDisplay();
-        mAppPairLayout = new AppPairLayout(mContext, mDisplay, mConfiguration, mSurfaceControl);
-    }
-
-    @After
-    @UiThreadTest
-    public void tearDown() {
-        mAppPairLayout.release();
-    }
-
-    @Test
-    @UiThreadTest
-    public void testUpdateConfiguration() {
-        assertThat(mAppPairLayout.updateConfiguration(getConfiguration(false))).isFalse();
-        assertThat(mAppPairLayout.updateConfiguration(getConfiguration(true))).isTrue();
-    }
-
-    @Test
-    @UiThreadTest
-    public void testInitRelease() {
-        mAppPairLayout.init();
-        assertThat(mAppPairLayout.getDividerLeash()).isNotNull();
-        mAppPairLayout.release();
-        assertThat(mAppPairLayout.getDividerLeash()).isNull();
-    }
-
-    private static Configuration getConfiguration(boolean isLandscape) {
-        final Configuration configuration = new Configuration();
-        configuration.unset();
-        configuration.orientation = isLandscape ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
-        configuration.windowConfiguration.setBounds(
-                new Rect(0, 0, isLandscape ? 2160 : 1080, isLandscape ? 1080 : 2160));
-        return configuration;
-    }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java
index f12648a..8dbc1d5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java
@@ -55,13 +55,13 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+        when(mDisplayController.getDisplayContext(anyInt())).thenReturn(mContext);
+        when(mDisplayController.getDisplay(anyInt())).thenReturn(
+                mContext.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY));
         mController = new TestAppPairsController(
                 mTaskOrganizer,
                 mSyncQueue,
                 mDisplayController);
-        when(mDisplayController.getDisplayContext(anyInt())).thenReturn(mContext);
-        when(mDisplayController.getDisplay(anyInt())).thenReturn(
-                mContext.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY));
     }
 
     @After
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java
index f8c68d2..fada694 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java
@@ -55,14 +55,14 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+        when(mDisplayController.getDisplayContext(anyInt())).thenReturn(mContext);
+        when(mDisplayController.getDisplay(anyInt())).thenReturn(
+                mContext.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY));
         mController = new TestAppPairsController(
                 mTaskOrganizer,
                 mSyncQueue,
                 mDisplayController);
         mPool = mController.getPool();
-        when(mDisplayController.getDisplayContext(anyInt())).thenReturn(mContext);
-        when(mDisplayController.getDisplay(anyInt())).thenReturn(
-                mContext.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY));
     }
 
     @After
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java
index 8ece913..a3f134e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java
@@ -18,10 +18,14 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
+
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.SyncTransactionQueue;
 
@@ -35,7 +39,7 @@
 /** Tests for {@link AppPairsPool} */
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class AppPairsPoolTests {
+public class AppPairsPoolTests extends ShellTestCase {
     private TestAppPairsController mController;
     private TestAppPairsPool mPool;
     @Mock private SyncTransactionQueue mSyncQueue;
@@ -45,6 +49,7 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+        when(mDisplayController.getDisplayContext(anyInt())).thenReturn(mContext);
         mController = new TestAppPairsController(
                 mTaskOrganizer,
                 mSyncQueue,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
index 080cddc..5e0d518 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
@@ -20,12 +20,15 @@
 import static android.view.InsetsState.ITYPE_IME;
 import static android.view.Surface.ROTATION_0;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 
 import android.graphics.Point;
+import android.view.InsetsSource;
 import android.view.InsetsSourceControl;
 import android.view.InsetsState;
 import android.view.SurfaceControl;
@@ -68,19 +71,31 @@
     @Test
     public void reappliesVisibilityToChangedLeash() {
         verifyZeroInteractions(mT);
+        mPerDisplay.mImeShowing = true;
 
-        mPerDisplay.mImeShowing = false;
-        mPerDisplay.insetsControlChanged(new InsetsState(), new InsetsSourceControl[] {
-                new InsetsSourceControl(ITYPE_IME, mock(SurfaceControl.class), new Point(0, 0))
-        });
+        mPerDisplay.insetsControlChanged(insetsStateWithIme(false), insetsSourceControl());
 
+        assertFalse(mPerDisplay.mImeShowing);
         verify(mT).hide(any());
 
         mPerDisplay.mImeShowing = true;
-        mPerDisplay.insetsControlChanged(new InsetsState(), new InsetsSourceControl[] {
-                new InsetsSourceControl(ITYPE_IME, mock(SurfaceControl.class), new Point(0, 0))
-        });
+        mPerDisplay.insetsControlChanged(insetsStateWithIme(true), insetsSourceControl());
 
+        assertTrue(mPerDisplay.mImeShowing);
         verify(mT).show(any());
     }
+
+    private InsetsSourceControl[] insetsSourceControl() {
+        return new InsetsSourceControl[]{
+                new InsetsSourceControl(ITYPE_IME, mock(SurfaceControl.class), new Point(0, 0))
+        };
+    }
+
+    private InsetsState insetsStateWithIme(boolean visible) {
+        InsetsState state = new InsetsState();
+        state.addSource(new InsetsSource(ITYPE_IME));
+        state.setSourceVisible(ITYPE_IME, visible);
+        return state;
+    }
+
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
new file mode 100644
index 0000000..d87f4c6
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
@@ -0,0 +1,106 @@
+/*
+ * 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.wm.shell.common.split;
+
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.view.SurfaceControl;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.policy.DividerSnapAlgorithm;
+import com.android.wm.shell.ShellTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Tests for {@link SplitLayout} */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SplitLayoutTests extends ShellTestCase {
+    @Mock SplitLayout.LayoutChangeListener mLayoutChangeListener;
+    @Mock SurfaceControl mRootLeash;
+    private SplitLayout mSplitLayout;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mSplitLayout = new SplitLayout(
+                mContext,
+                getConfiguration(false),
+                mLayoutChangeListener,
+                mRootLeash);
+    }
+
+    @Test
+    @UiThreadTest
+    public void testUpdateConfiguration() {
+        assertThat(mSplitLayout.updateConfiguration(getConfiguration(false))).isFalse();
+        assertThat(mSplitLayout.updateConfiguration(getConfiguration(true))).isTrue();
+    }
+
+    @Test
+    public void testUpdateDividePosition() {
+        mSplitLayout.updateDividePosition(anyInt());
+        verify(mLayoutChangeListener).onBoundsChanging(any(SplitLayout.class));
+    }
+
+    @Test
+    public void testSetSnapTarget() {
+        DividerSnapAlgorithm.SnapTarget snapTarget = getSnapTarget(0,
+                DividerSnapAlgorithm.SnapTarget.FLAG_NONE);
+        mSplitLayout.setSnapTarget(snapTarget);
+        verify(mLayoutChangeListener).onBoundsChanged(any(SplitLayout.class));
+
+        // verify it callbacks properly when the snap target indicates dismissing split.
+        snapTarget = getSnapTarget(0, DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_START);
+        mSplitLayout.setSnapTarget(snapTarget);
+        verify(mLayoutChangeListener).onSnappedToDismiss(eq(false));
+        snapTarget = getSnapTarget(0, DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_END);
+        mSplitLayout.setSnapTarget(snapTarget);
+        verify(mLayoutChangeListener).onSnappedToDismiss(eq(true));
+    }
+
+    private static Configuration getConfiguration(boolean isLandscape) {
+        final Configuration configuration = new Configuration();
+        configuration.unset();
+        configuration.orientation = isLandscape ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
+        configuration.windowConfiguration.setBounds(
+                new Rect(0, 0, isLandscape ? 2160 : 1080, isLandscape ? 1080 : 2160));
+        return configuration;
+    }
+
+    private static DividerSnapAlgorithm.SnapTarget getSnapTarget(int position, int flag) {
+        return new DividerSnapAlgorithm.SnapTarget(
+                position /* position */, position /* taskPosition */, flag);
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
new file mode 100644
index 0000000..aa0eb2f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
@@ -0,0 +1,66 @@
+/*
+ * 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.wm.shell.common.split;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.view.SurfaceControl;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.ShellTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Tests for {@link SplitWindowManager} */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SplitWindowManagerTests extends ShellTestCase {
+    @Mock SurfaceControl mSurfaceControl;
+    @Mock SplitLayout mSplitLayout;
+    private SplitWindowManager mSplitWindowManager;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        final Configuration configuration = new Configuration();
+        configuration.setToDefaults();
+        mSplitWindowManager = new SplitWindowManager(mContext, configuration, mSurfaceControl);
+        when(mSplitLayout.getDividerBounds()).thenReturn(
+                new Rect(0, 0, configuration.windowConfiguration.getBounds().width(),
+                        configuration.windowConfiguration.getBounds().height()));
+    }
+
+    @Test
+    @UiThreadTest
+    public void testInitRelease() {
+        mSplitWindowManager.init(mSplitLayout);
+        assertThat(mSplitWindowManager.getSurfaceControl()).isNotNull();
+        mSplitWindowManager.release();
+        assertThat(mSplitWindowManager.getSurfaceControl()).isNull();
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
index 55e7a35..7f280cd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
@@ -79,7 +79,8 @@
     @Test
     public void getAnimator_withBounds_returnBoundsAnimator() {
         final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
-                .getAnimator(mLeash, new Rect(), new Rect(), null, TRANSITION_DIRECTION_TO_PIP);
+                .getAnimator(mLeash, new Rect(), new Rect(), new Rect(), null,
+                        TRANSITION_DIRECTION_TO_PIP);
 
         assertEquals("Expect ANIM_TYPE_BOUNDS animation",
                 animator.getAnimationType(), PipAnimationController.ANIM_TYPE_BOUNDS);
@@ -87,16 +88,19 @@
 
     @Test
     public void getAnimator_whenSameTypeRunning_updateExistingAnimator() {
+        final Rect baseValue = new Rect(0, 0, 100, 100);
         final Rect startValue = new Rect(0, 0, 100, 100);
         final Rect endValue1 = new Rect(100, 100, 200, 200);
         final Rect endValue2 = new Rect(200, 200, 300, 300);
         final PipAnimationController.PipTransitionAnimator oldAnimator = mPipAnimationController
-                .getAnimator(mLeash, startValue, endValue1, null, TRANSITION_DIRECTION_TO_PIP);
+                .getAnimator(mLeash, baseValue, startValue, endValue1, null,
+                        TRANSITION_DIRECTION_TO_PIP);
         oldAnimator.setSurfaceControlTransactionFactory(DummySurfaceControlTx::new);
         oldAnimator.start();
 
         final PipAnimationController.PipTransitionAnimator newAnimator = mPipAnimationController
-                .getAnimator(mLeash, startValue, endValue2, null, TRANSITION_DIRECTION_TO_PIP);
+                .getAnimator(mLeash, baseValue, startValue, endValue2, null,
+                        TRANSITION_DIRECTION_TO_PIP);
 
         assertEquals("getAnimator with same type returns same animator",
                 oldAnimator, newAnimator);
@@ -122,11 +126,13 @@
     @Test
     @SuppressWarnings("unchecked")
     public void pipTransitionAnimator_updateEndValue() {
+        final Rect baseValue = new Rect(0, 0, 100, 100);
         final Rect startValue = new Rect(0, 0, 100, 100);
         final Rect endValue1 = new Rect(100, 100, 200, 200);
         final Rect endValue2 = new Rect(200, 200, 300, 300);
         final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
-                .getAnimator(mLeash, startValue, endValue1, null, TRANSITION_DIRECTION_TO_PIP);
+                .getAnimator(mLeash, baseValue, startValue, endValue1, null,
+                        TRANSITION_DIRECTION_TO_PIP);
 
         animator.updateEndValue(endValue2);
 
@@ -135,10 +141,12 @@
 
     @Test
     public void pipTransitionAnimator_setPipAnimationCallback() {
+        final Rect baseValue = new Rect(0, 0, 100, 100);
         final Rect startValue = new Rect(0, 0, 100, 100);
         final Rect endValue = new Rect(100, 100, 200, 200);
         final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
-                .getAnimator(mLeash, startValue, endValue, null, TRANSITION_DIRECTION_TO_PIP);
+                .getAnimator(mLeash, baseValue, startValue, endValue, null,
+                        TRANSITION_DIRECTION_TO_PIP);
         animator.setSurfaceControlTransactionFactory(DummySurfaceControlTx::new);
 
         animator.setPipAnimationCallback(mPipAnimationCallback);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
index e602219..4efaebf 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
@@ -33,6 +33,7 @@
 import com.android.wm.shell.R;
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.common.FloatingContentCoordinator;
+import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.pip.PipBoundsState;
 import com.android.wm.shell.pip.PipSnapAlgorithm;
@@ -71,6 +72,9 @@
     @Mock
     private PipUiEventLogger mPipUiEventLogger;
 
+    @Mock
+    private ShellExecutor mShellMainExecutor;
+
     private PipBoundsState mPipBoundsState;
     private PipBoundsAlgorithm mPipBoundsAlgorithm;
     private PipSnapAlgorithm mPipSnapAlgorithm;
@@ -94,7 +98,7 @@
         mPipSnapAlgorithm = new PipSnapAlgorithm();
         mPipTouchHandler = new PipTouchHandler(mContext, mPhonePipMenuController,
                 mPipBoundsAlgorithm, mPipBoundsState, mPipTaskOrganizer,
-                mFloatingContentCoordinator, mPipUiEventLogger);
+                mFloatingContentCoordinator, mPipUiEventLogger, mShellMainExecutor);
         mMotionHelper = Mockito.spy(mPipTouchHandler.getMotionHelper());
         mPipResizeGestureHandler = Mockito.spy(mPipTouchHandler.getPipResizeGestureHandler());
         mPipTouchHandler.setPipMotionHelper(mMotionHelper);
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index cd53217..1ff1978 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -333,6 +333,7 @@
         "jni/YuvToJpegEncoder.cpp",
         "jni/fonts/Font.cpp",
         "jni/fonts/FontFamily.cpp",
+        "jni/fonts/NativeFont.cpp",
         "jni/text/LineBreaker.cpp",
         "jni/text/MeasuredText.cpp",
         "jni/text/TextShaper.cpp",
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index c174c24..f4c633f 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -18,6 +18,7 @@
 
 #include "renderstate/RenderState.h"
 #include "utils/Color.h"
+#include "utils/MathUtils.h"
 
 namespace android {
 namespace uirenderer {
@@ -52,5 +53,90 @@
     }
 }
 
+static inline SkScalar isIntegerAligned(SkScalar x) {
+    return fabsf(roundf(x) - x) <= NON_ZERO_EPSILON;
+}
+
+// Disable filtering when there is no scaling in screen coordinates and the corners have the same
+// fraction (for translate) or zero fraction (for any other rect-to-rect transform).
+static bool shouldFilterRect(const SkMatrix& matrix, const SkRect& srcRect, const SkRect& dstRect) {
+    if (!matrix.rectStaysRect()) return true;
+    SkRect dstDevRect = matrix.mapRect(dstRect);
+    float dstW, dstH;
+    if (MathUtils::isZero(matrix.getScaleX()) && MathUtils::isZero(matrix.getScaleY())) {
+        // Has a 90 or 270 degree rotation, although total matrix may also have scale factors
+        // in m10 and m01. Those scalings are automatically handled by mapRect so comparing
+        // dimensions is sufficient, but swap width and height comparison.
+        dstW = dstDevRect.height();
+        dstH = dstDevRect.width();
+    } else {
+        // Handle H/V flips or 180 rotation matrices. Axes may have been mirrored, but
+        // dimensions are still safe to compare directly.
+        dstW = dstDevRect.width();
+        dstH = dstDevRect.height();
+    }
+    if (!(MathUtils::areEqual(dstW, srcRect.width()) &&
+          MathUtils::areEqual(dstH, srcRect.height()))) {
+        return true;
+    }
+    // Device rect and source rect should be integer aligned to ensure there's no difference
+    // in how nearest-neighbor sampling is resolved.
+    return !(isIntegerAligned(srcRect.x()) &&
+             isIntegerAligned(srcRect.y()) &&
+             isIntegerAligned(dstDevRect.x()) &&
+             isIntegerAligned(dstDevRect.y()));
+}
+
+void Layer::draw(SkCanvas* canvas) {
+    GrRecordingContext* context = canvas->recordingContext();
+    if (context == nullptr) {
+        SkDEBUGF(("Attempting to draw LayerDrawable into an unsupported surface"));
+        return;
+    }
+    SkMatrix layerTransform = getTransform();
+    //sk_sp<SkImage> layerImage = getImage();
+    const int layerWidth = getWidth();
+    const int layerHeight = getHeight();
+    if (layerImage) {
+        SkMatrix textureMatrixInv;
+        textureMatrixInv = getTexTransform();
+        // TODO: after skia bug https://bugs.chromium.org/p/skia/issues/detail?id=7075 is fixed
+        // use bottom left origin and remove flipV and invert transformations.
+        SkMatrix flipV;
+        flipV.setAll(1, 0, 0, 0, -1, 1, 0, 0, 1);
+        textureMatrixInv.preConcat(flipV);
+        textureMatrixInv.preScale(1.0f / layerWidth, 1.0f / layerHeight);
+        textureMatrixInv.postScale(layerImage->width(), layerImage->height());
+        SkMatrix textureMatrix;
+        if (!textureMatrixInv.invert(&textureMatrix)) {
+            textureMatrix = textureMatrixInv;
+        }
+
+        SkMatrix matrix;
+        matrix = SkMatrix::Concat(layerTransform, textureMatrix);
+
+        SkPaint paint;
+        paint.setAlpha(getAlpha());
+        paint.setBlendMode(getMode());
+        paint.setColorFilter(getColorFilter());
+        const bool nonIdentityMatrix = !matrix.isIdentity();
+        if (nonIdentityMatrix) {
+            canvas->save();
+            canvas->concat(matrix);
+        }
+        const SkMatrix& totalMatrix = canvas->getTotalMatrix();
+
+        SkRect imageRect = SkRect::MakeIWH(layerImage->width(), layerImage->height());
+        if (getForceFilter() || shouldFilterRect(totalMatrix, imageRect, imageRect)) {
+            paint.setFilterQuality(kLow_SkFilterQuality);
+        }
+        canvas->drawImage(layerImage.get(), 0, 0, &paint);
+        // restore the original matrix
+        if (nonIdentityMatrix) {
+            canvas->restore();
+        }
+    }
+}
+
 }  // namespace uirenderer
 }  // namespace android
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index ea3bfc9..e99e762 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -21,6 +21,7 @@
 #include <SkBlendMode.h>
 #include <SkColorFilter.h>
 #include <SkColorSpace.h>
+#include <SkCanvas.h>
 #include <SkPaint.h>
 #include <SkImage.h>
 #include <SkMatrix.h>
@@ -87,6 +88,8 @@
 
     inline sk_sp<SkImage> getImage() const { return this->layerImage; }
 
+    void draw(SkCanvas* canvas);
+
 protected:
 
     RenderState& mRenderState;
diff --git a/libs/hwui/apex/jni_runtime.cpp b/libs/hwui/apex/jni_runtime.cpp
index e1f5abd7..0fad2d5 100644
--- a/libs/hwui/apex/jni_runtime.cpp
+++ b/libs/hwui/apex/jni_runtime.cpp
@@ -69,6 +69,7 @@
 extern int register_android_graphics_drawable_VectorDrawable(JNIEnv* env);
 extern int register_android_graphics_fonts_Font(JNIEnv* env);
 extern int register_android_graphics_fonts_FontFamily(JNIEnv* env);
+extern int register_android_graphics_fonts_NativeFont(JNIEnv* env);
 extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env);
 extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env);
 extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
@@ -135,6 +136,7 @@
     REG_JNI(register_android_graphics_drawable_VectorDrawable),
     REG_JNI(register_android_graphics_fonts_Font),
     REG_JNI(register_android_graphics_fonts_FontFamily),
+    REG_JNI(register_android_graphics_fonts_NativeFont),
     REG_JNI(register_android_graphics_pdf_PdfDocument),
     REG_JNI(register_android_graphics_pdf_PdfEditor),
     REG_JNI(register_android_graphics_pdf_PdfRenderer),
diff --git a/libs/hwui/canvas/CanvasOpRasterizer.cpp b/libs/hwui/canvas/CanvasOpRasterizer.cpp
index 25129f6..0093c38 100644
--- a/libs/hwui/canvas/CanvasOpRasterizer.cpp
+++ b/libs/hwui/canvas/CanvasOpRasterizer.cpp
@@ -33,7 +33,11 @@
     SkMatrix& currentGlobalTransform = globalMatrixStack.emplace_back(SkMatrix::I());
 
     source.for_each([&]<CanvasOpType T>(const CanvasOpContainer<T> * op) {
-        if constexpr (T == CanvasOpType::BeginZ || T == CanvasOpType::EndZ) {
+        if constexpr (
+            T == CanvasOpType::BeginZ ||
+            T == CanvasOpType::EndZ   ||
+            T == CanvasOpType::DrawLayer
+        ) {
             // Do beginZ or endZ
             LOG_ALWAYS_FATAL("TODO");
             return;
diff --git a/libs/hwui/canvas/CanvasOpTypes.h b/libs/hwui/canvas/CanvasOpTypes.h
index f9df2f7..f0aa777 100644
--- a/libs/hwui/canvas/CanvasOpTypes.h
+++ b/libs/hwui/canvas/CanvasOpTypes.h
@@ -47,14 +47,17 @@
     DrawArc,
     DrawPaint,
     DrawPoint,
+    DrawPoints,
     DrawPath,
     DrawLine,
+    DrawLines,
     DrawVertices,
     DrawImage,
     DrawImageRect,
     // DrawImageLattice also used to draw 9 patches
     DrawImageLattice,
     DrawPicture,
+    DrawLayer,
 
     // TODO: Rest
 
diff --git a/libs/hwui/canvas/CanvasOps.h b/libs/hwui/canvas/CanvasOps.h
index 8c7113d..242dbdb 100644
--- a/libs/hwui/canvas/CanvasOps.h
+++ b/libs/hwui/canvas/CanvasOps.h
@@ -26,8 +26,10 @@
 #include <hwui/Bitmap.h>
 #include <log/log.h>
 #include "CanvasProperty.h"
+#include "Points.h"
 
 #include "CanvasOpTypes.h"
+#include "Layer.h"
 
 #include <experimental/type_traits>
 #include <utility>
@@ -165,6 +167,22 @@
 };
 
 template <>
+struct CanvasOp<CanvasOpType::DrawPoints> {
+    size_t count;
+    SkPaint paint;
+    sk_sp<Points> points;
+    void draw(SkCanvas* canvas) const {
+        canvas->drawPoints(
+            SkCanvas::kPoints_PointMode,
+            count,
+            points->data(),
+            paint
+        );
+    }
+    ASSERT_DRAWABLE()
+};
+
+template <>
 struct CanvasOp<CanvasOpType::DrawRect> {
     SkRect rect;
     SkPaint paint;
@@ -263,6 +281,22 @@
 };
 
 template<>
+struct CanvasOp<CanvasOpType::DrawLines> {
+    size_t count;
+    SkPaint paint;
+    sk_sp<Points> points;
+    void draw(SkCanvas* canvas) const {
+        canvas->drawPoints(
+            SkCanvas::kLines_PointMode,
+            count,
+            points->data(),
+            paint
+        );
+    }
+    ASSERT_DRAWABLE()
+};
+
+template<>
 struct CanvasOp<CanvasOpType::DrawVertices> {
     sk_sp<SkVertices> vertices;
     SkBlendMode mode;
@@ -364,6 +398,11 @@
     }
 };
 
+template<>
+struct CanvasOp<CanvasOpType::DrawLayer> {
+    sp<Layer> layer;
+};
+
 // cleanup our macros
 #undef ASSERT_DRAWABLE
 
diff --git a/libs/hwui/canvas/Points.h b/libs/hwui/canvas/Points.h
new file mode 100644
index 0000000..05e6a7d
--- /dev/null
+++ b/libs/hwui/canvas/Points.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+#include <ui/FatVector.h>
+#include "SkPoint.h"
+#include "SkRefCnt.h"
+
+/**
+ * Collection of points that are ref counted and to be used with
+ * various drawing calls that consume SkPoint as inputs like
+ * drawLines/drawPoints
+ */
+class Points: public SkNVRefCnt<SkPoint> {
+public:
+  Points(int size){
+      skPoints.resize(size);
+  }
+
+  Points(std::initializer_list<SkPoint> init): skPoints(init) { }
+
+  SkPoint& operator[](int index) {
+      return skPoints[index];
+  }
+
+  const SkPoint* data() const {
+      return skPoints.data();
+  }
+
+  size_t size() const {
+      return skPoints.size();
+  }
+private:
+  // Initialize the size to contain 2 SkPoints on the stack for optimized
+  // drawLine calls that require 2 SkPoints for start/end points of the line
+  android::FatVector<SkPoint, 2> skPoints;
+};
diff --git a/libs/hwui/jni/fonts/Font.cpp b/libs/hwui/jni/fonts/Font.cpp
index f0c7793..f612bce 100644
--- a/libs/hwui/jni/fonts/Font.cpp
+++ b/libs/hwui/jni/fonts/Font.cpp
@@ -187,38 +187,6 @@
 }
 
 // Critical Native
-static jlong Font_getFontInfo(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
-    const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
-    MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->typeface().get());
-
-    uint64_t result = font->style().weight();
-    result |= font->style().slant() == minikin::FontStyle::Slant::ITALIC ? 0x10000 : 0x00000;
-    result |= ((static_cast<uint64_t>(minikinSkia->GetFontIndex())) << 32);
-    result |= ((static_cast<uint64_t>(minikinSkia->GetAxes().size())) << 48);
-    return result;
-}
-
-// Critical Native
-static jlong Font_getAxisInfo(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle, jint index) {
-    const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
-    MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->typeface().get());
-    const minikin::FontVariation& var = minikinSkia->GetAxes().at(index);
-    uint32_t floatBinary = *reinterpret_cast<const uint32_t*>(&var.value);
-    return (static_cast<uint64_t>(var.axisTag) << 32) | static_cast<uint64_t>(floatBinary);
-}
-
-// FastNative
-static jstring Font_getFontPath(JNIEnv* env, jobject, jlong fontHandle) {
-    const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
-    MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->typeface().get());
-    const std::string& filePath = minikinSkia->getFilePath();
-    if (filePath.empty()) {
-        return nullptr;
-    }
-    return env->NewStringUTF(filePath.c_str());
-}
-
-// Critical Native
 static jlong Font_getNativeFontPtr(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
     FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
     return reinterpret_cast<jlong>(font->font.get());
@@ -276,9 +244,6 @@
 static const JNINativeMethod gFontMethods[] = {
     { "nGetGlyphBounds", "(JIJLandroid/graphics/RectF;)F", (void*) Font_getGlyphBounds },
     { "nGetFontMetrics", "(JJLandroid/graphics/Paint$FontMetrics;)F", (void*) Font_getFontMetrics },
-    { "nGetFontInfo", "(J)J", (void*) Font_getFontInfo },
-    { "nGetAxisInfo", "(JI)J", (void*) Font_getAxisInfo },
-    { "nGetFontPath", "(J)Ljava/lang/String;", (void*) Font_getFontPath },
     { "nGetNativeFontPtr", "(J)J", (void*) Font_getNativeFontPtr },
     { "nGetFontBufferAddress", "(J)J", (void*) Font_GetBufferAddress },
 };
diff --git a/libs/hwui/jni/fonts/NativeFont.cpp b/libs/hwui/jni/fonts/NativeFont.cpp
new file mode 100644
index 0000000..c5c5d46
--- /dev/null
+++ b/libs/hwui/jni/fonts/NativeFont.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "Minikin"
+
+#include "Font.h"
+#include "SkData.h"
+#include "SkFont.h"
+#include "SkFontMetrics.h"
+#include "SkFontMgr.h"
+#include "SkRefCnt.h"
+#include "SkTypeface.h"
+#include "GraphicsJNI.h"
+#include <nativehelper/ScopedUtfChars.h>
+#include "Utils.h"
+#include "FontUtils.h"
+
+#include <hwui/MinikinSkia.h>
+#include <hwui/Paint.h>
+#include <hwui/Typeface.h>
+#include <minikin/FontFamily.h>
+#include <minikin/LocaleList.h>
+#include <ui/FatVector.h>
+
+#include <memory>
+
+namespace android {
+
+// Critical Native
+static jint NativeFont_getFamilyCount(CRITICAL_JNI_PARAMS_COMMA jlong typefaceHandle) {
+    Typeface* tf = reinterpret_cast<Typeface*>(typefaceHandle);
+    return tf->fFontCollection->getFamilies().size();
+}
+
+// Critical Native
+static jlong NativeFont_getFamily(CRITICAL_JNI_PARAMS_COMMA jlong typefaceHandle, jint index) {
+    Typeface* tf = reinterpret_cast<Typeface*>(typefaceHandle);
+    return reinterpret_cast<jlong>(tf->fFontCollection->getFamilies()[index].get());
+
+}
+
+// Fast Native
+static jstring NativeFont_getLocaleList(JNIEnv* env, jobject, jlong familyHandle) {
+    minikin::FontFamily* family = reinterpret_cast<minikin::FontFamily*>(familyHandle);
+    uint32_t localeListId = family->localeListId();
+    return env->NewStringUTF(minikin::getLocaleString(localeListId).c_str());
+}
+
+// Critical Native
+static jint NativeFont_getFontCount(CRITICAL_JNI_PARAMS_COMMA jlong familyHandle) {
+    minikin::FontFamily* family = reinterpret_cast<minikin::FontFamily*>(familyHandle);
+    return family->getNumFonts();
+}
+
+// Critical Native
+static jlong NativeFont_getFont(CRITICAL_JNI_PARAMS_COMMA jlong familyHandle, jint index) {
+    minikin::FontFamily* family = reinterpret_cast<minikin::FontFamily*>(familyHandle);
+    return reinterpret_cast<jlong>(family->getFont(index));
+}
+
+// Critical Native
+static jlong NativeFont_getFontInfo(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
+    const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
+    MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->typeface().get());
+
+    uint64_t result = font->style().weight();
+    result |= font->style().slant() == minikin::FontStyle::Slant::ITALIC ? 0x10000 : 0x00000;
+    result |= ((static_cast<uint64_t>(minikinSkia->GetFontIndex())) << 32);
+    result |= ((static_cast<uint64_t>(minikinSkia->GetAxes().size())) << 48);
+    return result;
+}
+
+// Critical Native
+static jlong NativeFont_getAxisInfo(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle, jint index) {
+    const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
+    MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->typeface().get());
+    const minikin::FontVariation& var = minikinSkia->GetAxes().at(index);
+    uint32_t floatBinary = *reinterpret_cast<const uint32_t*>(&var.value);
+    return (static_cast<uint64_t>(var.axisTag) << 32) | static_cast<uint64_t>(floatBinary);
+}
+
+// FastNative
+static jstring NativeFont_getFontPath(JNIEnv* env, jobject, jlong fontHandle) {
+    const minikin::Font* font = reinterpret_cast<minikin::Font*>(fontHandle);
+    MinikinFontSkia* minikinSkia = static_cast<MinikinFontSkia*>(font->typeface().get());
+    const std::string& filePath = minikinSkia->getFilePath();
+    if (filePath.empty()) {
+        return nullptr;
+    }
+    return env->NewStringUTF(filePath.c_str());
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static const JNINativeMethod gNativeFontMethods[] = {
+    { "nGetFamilyCount", "(J)I", (void*) NativeFont_getFamilyCount },
+    { "nGetFamily", "(JI)J", (void*) NativeFont_getFamily },
+    { "nGetLocaleList", "(J)Ljava/lang/String;", (void*) NativeFont_getLocaleList },
+    { "nGetFontCount", "(J)I", (void*) NativeFont_getFontCount },
+    { "nGetFont", "(JI)J", (void*) NativeFont_getFont },
+    { "nGetFontInfo", "(J)J", (void*) NativeFont_getFontInfo },
+    { "nGetAxisInfo", "(JI)J", (void*) NativeFont_getAxisInfo },
+    { "nGetFontPath", "(J)Ljava/lang/String;", (void*) NativeFont_getFontPath },
+};
+
+int register_android_graphics_fonts_NativeFont(JNIEnv* env) {
+    return RegisterMethodsOrDie(env, "android/graphics/fonts/NativeFont", gNativeFontMethods,
+            NELEM(gNativeFontMethods));
+}
+
+}  // namespace android
diff --git a/libs/hwui/tests/unit/CanvasOpTests.cpp b/libs/hwui/tests/unit/CanvasOpTests.cpp
index f186e55..033a587 100644
--- a/libs/hwui/tests/unit/CanvasOpTests.cpp
+++ b/libs/hwui/tests/unit/CanvasOpTests.cpp
@@ -245,6 +245,31 @@
     EXPECT_EQ(1, canvas.sumTotalDrawCalls());
 }
 
+TEST(CanvasOp, simpleDrawPoints) {
+    CanvasOpBuffer buffer;
+    EXPECT_EQ(buffer.size(), 0);
+    size_t numPts = 3;
+    auto pts = sk_ref_sp(
+          new Points({
+              {32, 16},
+              {48, 48},
+              {16, 32}
+          })
+    );
+
+    buffer.push(CanvasOp<Op::DrawPoints> {
+        .count = numPts,
+        .paint = SkPaint{},
+        .points = pts
+    });
+
+    CallCountingCanvas canvas;
+    EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+    rasterizeCanvasBuffer(buffer, &canvas);
+    EXPECT_EQ(1, canvas.drawPoints);
+    EXPECT_EQ(1, canvas.sumTotalDrawCalls());
+}
+
 TEST(CanvasOp, simpleDrawLine) {
     CanvasOpBuffer buffer;
     EXPECT_EQ(buffer.size(), 0);
@@ -263,6 +288,30 @@
     EXPECT_EQ(1, canvas.sumTotalDrawCalls());
 }
 
+TEST(CanvasOp, simpleDrawLines) {
+    CanvasOpBuffer buffer;
+    EXPECT_EQ(buffer.size(), 0);
+    size_t numPts = 3;
+    auto pts = sk_ref_sp(
+        new Points({
+               {32, 16},
+               {48, 48},
+               {16, 32}
+          })
+        );
+    buffer.push(CanvasOp<Op::DrawLines> {
+        .count = numPts,
+        .paint = SkPaint{},
+        .points = pts
+    });
+
+    CallCountingCanvas canvas;
+    EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+    rasterizeCanvasBuffer(buffer, &canvas);
+    EXPECT_EQ(1, canvas.drawPoints);
+    EXPECT_EQ(1, canvas.sumTotalDrawCalls());
+}
+
 TEST(CanvasOp, simpleDrawRect) {
     CanvasOpBuffer buffer;
     EXPECT_EQ(buffer.size(), 0);
diff --git a/libs/incident/OWNERS b/libs/incident/OWNERS
new file mode 100644
index 0000000..f766115
--- /dev/null
+++ b/libs/incident/OWNERS
@@ -0,0 +1 @@
+include /cmds/incidentd/OWNERS
diff --git a/libs/input/OWNERS b/libs/input/OWNERS
new file mode 100644
index 0000000..d701f23
--- /dev/null
+++ b/libs/input/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/hardware/input/OWNERS
diff --git a/libs/storage/OWNERS b/libs/storage/OWNERS
new file mode 100644
index 0000000..6f9dbea
--- /dev/null
+++ b/libs/storage/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/os/storage/OWNERS
diff --git a/libs/usb/OWNERS b/libs/usb/OWNERS
new file mode 100644
index 0000000..f7b2a37
--- /dev/null
+++ b/libs/usb/OWNERS
@@ -0,0 +1 @@
+include /services/usb/OWNERS
diff --git a/location/OWNERS b/location/OWNERS
new file mode 100644
index 0000000..5ac6028
--- /dev/null
+++ b/location/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/location/OWNERS
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index d3dc3b3..92e2136 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -30,6 +30,7 @@
 import android.location.IGnssNavigationMessageListener;
 import android.location.ILocationCallback;
 import android.location.ILocationListener;
+import android.location.LastLocationRequest;
 import android.location.Location;
 import android.location.LocationRequest;
 import android.location.LocationTime;
@@ -45,7 +46,7 @@
  */
 interface ILocationManager
 {
-    @nullable Location getLastLocation(String provider, String packageName, String attributionTag);
+    @nullable Location getLastLocation(String provider, in LastLocationRequest request, String packageName, String attributionTag);
     @nullable ICancellationSignal getCurrentLocation(String provider, in LocationRequest request, in ILocationCallback callback, String packageName, String attributionTag, String listenerId);
 
     void registerLocationListener(String provider, in LocationRequest request, in ILocationListener listener, String packageName, String attributionTag, String listenerId);
diff --git a/location/java/android/location/LastLocationRequest.aidl b/location/java/android/location/LastLocationRequest.aidl
new file mode 100644
index 0000000..30c90a9
--- /dev/null
+++ b/location/java/android/location/LastLocationRequest.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.location;
+
+parcelable LastLocationRequest;
diff --git a/location/java/android/location/LastLocationRequest.java b/location/java/android/location/LastLocationRequest.java
new file mode 100644
index 0000000..9ea8048
--- /dev/null
+++ b/location/java/android/location/LastLocationRequest.java
@@ -0,0 +1,192 @@
+/*
+ * 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.location;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * An encapsulation of various parameters for requesting last location via {@link LocationManager}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class LastLocationRequest implements Parcelable {
+
+    private final boolean mHiddenFromAppOps;
+    private final boolean mLocationSettingsIgnored;
+
+    private LastLocationRequest(
+            boolean hiddenFromAppOps,
+            boolean locationSettingsIgnored) {
+        mHiddenFromAppOps = hiddenFromAppOps;
+        mLocationSettingsIgnored = locationSettingsIgnored;
+    }
+
+    /**
+     * Returns true if this last location request should be ignored while updating app ops with
+     * location usage. This implies that someone else (usually the creator of the last location
+     * request) is responsible for updating app ops.
+     *
+     * @return true if this request should be ignored while updating app ops with location usage
+     *
+     */
+    public boolean isHiddenFromAppOps() {
+        return mHiddenFromAppOps;
+    }
+
+    /**
+     * Returns true if location settings, throttling, background location limits, and any other
+     * possible limiting factors will be ignored in order to satisfy this last location request.
+     *
+     * @return true if all limiting factors will be ignored to satisfy this request
+     */
+    public boolean isLocationSettingsIgnored() {
+        return mLocationSettingsIgnored;
+    }
+
+    public static final @NonNull Parcelable.Creator<LastLocationRequest> CREATOR =
+            new Parcelable.Creator<LastLocationRequest>() {
+                @Override
+                public LastLocationRequest createFromParcel(Parcel in) {
+                    return new LastLocationRequest(
+                            /* hiddenFromAppOps= */ in.readBoolean(),
+                            /* locationSettingsIgnored= */ in.readBoolean());
+                }
+                @Override
+                public LastLocationRequest[] newArray(int size) {
+                    return new LastLocationRequest[size];
+                }
+            };
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel parcel, int flags) {
+        parcel.writeBoolean(mHiddenFromAppOps);
+        parcel.writeBoolean(mLocationSettingsIgnored);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        LastLocationRequest that = (LastLocationRequest) o;
+        return mHiddenFromAppOps == that.mHiddenFromAppOps
+                && mLocationSettingsIgnored == that.mLocationSettingsIgnored;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mHiddenFromAppOps, mLocationSettingsIgnored);
+    }
+
+    @NonNull
+    @Override
+    public String toString() {
+        StringBuilder s = new StringBuilder();
+        s.append("LastLocationRequest[");
+        if (mHiddenFromAppOps) {
+            s.append("hiddenFromAppOps, ");
+        }
+        if (mLocationSettingsIgnored) {
+            s.append("locationSettingsIgnored, ");
+        }
+        if (s.length() > "LastLocationRequest[".length()) {
+            s.setLength(s.length() - 2);
+        }
+        s.append(']');
+        return s.toString();
+    }
+
+    /**
+     * A builder class for {@link LastLocationRequest}.
+     */
+    public static final class Builder {
+
+        private boolean mHiddenFromAppOps;
+        private boolean mLocationSettingsIgnored;
+
+        /**
+         * Creates a new Builder.
+         */
+        public Builder() {
+            mHiddenFromAppOps = false;
+            mLocationSettingsIgnored = false;
+        }
+
+        /**
+         * Creates a new Builder with all parameters copied from the given last location request.
+         */
+        public Builder(@NonNull LastLocationRequest lastLocationRequest) {
+            mHiddenFromAppOps = lastLocationRequest.mHiddenFromAppOps;
+            mLocationSettingsIgnored = lastLocationRequest.mLocationSettingsIgnored;
+        }
+
+        /**
+         * If set to true, indicates that app ops should not be updated with location usage due to
+         * this request. This implies that someone else (usually the creator of the last location
+         * request) is responsible for updating app ops as appropriate. Defaults to false.
+         *
+         * <p>Permissions enforcement occurs when resulting last location request is actually used,
+         * not when this method is invoked.
+         */
+        @RequiresPermission(Manifest.permission.UPDATE_APP_OPS_STATS)
+        public @NonNull Builder setHiddenFromAppOps(boolean hiddenFromAppOps) {
+            mHiddenFromAppOps = hiddenFromAppOps;
+            return this;
+        }
+
+        /**
+         * If set to true, indicates that location settings, throttling, background location limits,
+         * and any other possible limiting factors should be ignored in order to satisfy this
+         * last location request. This is only intended for use in user initiated emergency
+         * situations, and should be used extremely cautiously. Defaults to false.
+         *
+         * <p>Permissions enforcement occurs when resulting last location request is actually used,
+         * not when this method is invoked.
+         */
+        @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+        public @NonNull Builder setLocationSettingsIgnored(boolean locationSettingsIgnored) {
+            mLocationSettingsIgnored = locationSettingsIgnored;
+            return this;
+        }
+
+        /**
+         * Builds a last location request from this builder.
+         *
+         * @return a new last location request
+         */
+        public @NonNull LastLocationRequest build() {
+            return new LastLocationRequest(
+                    mHiddenFromAppOps,
+                    mLocationSettingsIgnored);
+        }
+    }
+}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 047b809..7085a75 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -683,6 +683,7 @@
      * location should always be checked.
      *
      * @return the last known location, or null if not available
+     *
      * @throws SecurityException if no suitable location permission is present
      *
      * @hide
@@ -706,18 +707,50 @@
      * in the course of the attempt as compared to this method.
      *
      * @param provider a provider listed by {@link #getAllProviders()}
+     *
      * @return the last known location for the given provider, or null if not available
+     *
      * @throws SecurityException if no suitable permission is present
      * @throws IllegalArgumentException if provider is null or doesn't exist
      */
     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
     @Nullable
     public Location getLastKnownLocation(@NonNull String provider) {
+        return getLastKnownLocation(provider, new LastLocationRequest.Builder().build());
+    }
+
+    /**
+     * Gets the last known location from the given provider, or null if there is no last known
+     * location.
+     *
+     * <p>See {@link LastLocationRequest} documentation for an explanation of various request
+     * parameters and how they can affect the returned location.
+     *
+     * <p>See {@link #getLastKnownLocation(String)} for more detail on how this method works.
+     *
+     * @param provider            a provider listed by {@link #getAllProviders()}
+     * @param lastLocationRequest the last location request containing location parameters
+     *
+     * @return the last known location for the given provider, or null if not available
+     *
+     * @throws SecurityException if no suitable permission is present
+     * @throws IllegalArgumentException if provider is null or doesn't exist
+     * @throws IllegalArgumentException if lastLocationRequest is null
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
+    @Nullable
+    public Location getLastKnownLocation(@NonNull String provider,
+            @NonNull LastLocationRequest lastLocationRequest) {
         Preconditions.checkArgument(provider != null, "invalid null provider");
+        Preconditions.checkArgument(lastLocationRequest != null,
+                "invalid null last location request");
 
         try {
-            return mService.getLastLocation(provider, mContext.getPackageName(),
-                    mContext.getAttributionTag());
+            return mService.getLastLocation(provider, lastLocationRequest,
+                    mContext.getPackageName(), mContext.getAttributionTag());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1509,8 +1542,15 @@
     }
 
     /**
-     * Removes location updates for the specified {@link LocationListener}. Following this call,
-     * the listener will not receive any more invocations of any kind.
+     * Removes all location updates for the specified {@link LocationListener}. The given listener
+     * is guaranteed not to receive any invocations that <b>happens-after</b> this method is
+     * invoked.
+     *
+     * <p>If the given listener has any batched requests, this method will not flush any incomplete
+     * location batches before stopping location updates. If you wish to flush any pending locations
+     * before stopping, you must first call {@link #requestFlush(String, LocationListener, int)} and
+     * then call this method once the flush is complete. If this method is invoked before the flush
+     * is complete, you may not receive the flushed locations.
      *
      * @param listener listener that no longer needs location updates
      *
@@ -1537,6 +1577,8 @@
      * Removes location updates for the specified {@link PendingIntent}. Following this call, the
      * PendingIntent will no longer receive location updates.
      *
+     * <p>See {@link #removeUpdates(LocationListener)} for more detail on how this method works.
+     *
      * @param pendingIntent pending intent that no longer needs location updates
      *
      * @throws IllegalArgumentException if pendingIntent is null
diff --git a/location/java/android/location/OWNERS b/location/java/android/location/OWNERS
new file mode 100644
index 0000000..383321b
--- /dev/null
+++ b/location/java/android/location/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 880425
+
+mstogaitis@google.com
+wyattriley@google.com
+etn@google.com
+weiwa@google.com
diff --git a/media/OWNERS b/media/OWNERS
index e741490..b2875e7 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -10,7 +10,7 @@
 jaewan@google.com
 jinpark@google.com
 jmtrivi@google.com
-jsharkey@android.com
+jsharkey@google.com
 klhyun@google.com
 lajos@google.com
 marcone@google.com
diff --git a/media/java/android/media/AudioPlaybackConfiguration.java b/media/java/android/media/AudioPlaybackConfiguration.java
index 515e9d0..17305a5 100644
--- a/media/java/android/media/AudioPlaybackConfiguration.java
+++ b/media/java/android/media/AudioPlaybackConfiguration.java
@@ -89,9 +89,8 @@
     /**
      * @hide
      * Player backed an AAudio player.
-     * Note this type is not in System API so it will not be returned in public API calls
      */
-    // TODO unhide for SystemApi, update getPlayerType()
+    @SystemApi
     public static final int PLAYER_TYPE_AAUDIO = 13;
 
     /**
@@ -280,10 +279,7 @@
 
     /**
      * @hide
-     * Return the type of player linked to this configuration. The return value is one of
-     * {@link #PLAYER_TYPE_JAM_AUDIOTRACK}, {@link #PLAYER_TYPE_JAM_MEDIAPLAYER},
-     * {@link #PLAYER_TYPE_JAM_SOUNDPOOL}, {@link #PLAYER_TYPE_SLES_AUDIOPLAYER_BUFFERQUEUE},
-     * {@link #PLAYER_TYPE_SLES_AUDIOPLAYER_URI_FD}, or {@link #PLAYER_TYPE_UNKNOWN}.
+     * Return the type of player linked to this configuration.
      * <br>Note that player types not exposed in the system API will be represented as
      * {@link #PLAYER_TYPE_UNKNOWN}.
      * @return the type of the player.
@@ -291,7 +287,6 @@
     @SystemApi
     public @PlayerType int getPlayerType() {
         switch (mPlayerType) {
-            case PLAYER_TYPE_AAUDIO:
             case PLAYER_TYPE_HW_SOURCE:
             case PLAYER_TYPE_EXTERNAL_PROXY:
                 return PLAYER_TYPE_UNKNOWN;
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 39bdf95..bd27f6d 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
 import android.annotation.TestApi;
 import android.bluetooth.BluetoothCodecConfig;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -1550,9 +1551,11 @@
 
     /** @hide returns master balance value in range -1.f -> 1.f, where 0.f is dead center. */
     @TestApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
     public static native float getMasterBalance();
     /** @hide Changes the audio balance of the device. */
     @TestApi
+    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
     public static native int setMasterBalance(float balance);
 
     // helpers for android.media.AudioManager.getProperty(), see description there for meaning
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 4b11e32..f8311cd 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -4232,8 +4232,10 @@
      * @see OnRtpRxNoticeListener
      *
      * @param listener the listener called after a notice from RTP Rx
-     * @param handler the {@link Handler} that receives RTP Tx events
-     *
+     * @param handler the {@link Handler} that receives RTP Tx events. If null is passed,
+     *                notifications will be posted on the thread that created this MediaPlayer
+     *                instance. If the creating thread does not have a {@link Looper}, then
+     *                notifications will be posted on the main thread.
      * @hide
      */
     @SystemApi
diff --git a/media/java/android/media/OWNERS b/media/java/android/media/OWNERS
new file mode 100644
index 0000000..cbc9ab7
--- /dev/null
+++ b/media/java/android/media/OWNERS
@@ -0,0 +1,8 @@
+# Bug component: 1344
+
+fgoldfain@google.com
+elaurent@google.com
+lajos@google.com
+olly@google.com
+andrewlewis@google.com
+sungsoo@google.com
diff --git a/media/java/android/media/audiofx/OWNERS b/media/java/android/media/audiofx/OWNERS
new file mode 100644
index 0000000..189fe0f
--- /dev/null
+++ b/media/java/android/media/audiofx/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 48436
+
+elaurent@google.com
diff --git a/media/java/android/media/audiopolicy/OWNERS b/media/java/android/media/audiopolicy/OWNERS
new file mode 100644
index 0000000..189fe0f
--- /dev/null
+++ b/media/java/android/media/audiopolicy/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 48436
+
+elaurent@google.com
diff --git a/media/java/android/media/browse/OWNERS b/media/java/android/media/browse/OWNERS
new file mode 100644
index 0000000..916fc36
--- /dev/null
+++ b/media/java/android/media/browse/OWNERS
@@ -0,0 +1,8 @@
+# Bug component: 137631
+
+hdmoon@google.com
+insun@google.com
+jaewan@google.com
+jinpark@google.com
+klhyun@google.com
+gyumin@google.com
diff --git a/media/java/android/media/midi/OWNERS b/media/java/android/media/midi/OWNERS
new file mode 100644
index 0000000..6a351d3
--- /dev/null
+++ b/media/java/android/media/midi/OWNERS
@@ -0,0 +1 @@
+elaurent@google.com
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index e9bb7f8..1da41fb 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -46,6 +46,8 @@
 import android.util.Log;
 import android.view.KeyEvent;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
@@ -437,7 +439,7 @@
         }
 
         if (mSessionInfo == null) {
-            Log.w(TAG, "sessionInfo shouldn't be null.");
+            Log.d(TAG, "sessionInfo is not set.");
             mSessionInfo = Bundle.EMPTY;
         } else if (MediaSession.hasCustomParcelable(mSessionInfo)) {
             Log.w(TAG, "sessionInfo contains custom parcelable. Ignoring.");
@@ -514,6 +516,17 @@
         return success;
     }
 
+    /**
+     * Gets associated handler for the given callback.
+     * @hide
+     */
+    @VisibleForTesting
+    public Handler getHandlerForCallback(Callback cb) {
+        synchronized (mLock) {
+            return getHandlerForCallbackLocked(cb);
+        }
+    }
+
     private MessageHandler getHandlerForCallbackLocked(Callback cb) {
         if (cb == null) {
             throw new IllegalArgumentException("Callback cannot be null");
diff --git a/media/java/android/media/session/OWNERS b/media/java/android/media/session/OWNERS
new file mode 100644
index 0000000..916fc36
--- /dev/null
+++ b/media/java/android/media/session/OWNERS
@@ -0,0 +1,8 @@
+# Bug component: 137631
+
+hdmoon@google.com
+insun@google.com
+jaewan@google.com
+jinpark@google.com
+klhyun@google.com
+gyumin@google.com
diff --git a/media/java/android/media/soundtrigger/OWNERS b/media/java/android/media/soundtrigger/OWNERS
new file mode 100644
index 0000000..6a351d3
--- /dev/null
+++ b/media/java/android/media/soundtrigger/OWNERS
@@ -0,0 +1 @@
+elaurent@google.com
diff --git a/media/java/android/media/tv/OWNERS b/media/java/android/media/tv/OWNERS
index a891154..8bccc9a 100644
--- a/media/java/android/media/tv/OWNERS
+++ b/media/java/android/media/tv/OWNERS
@@ -1,9 +1,6 @@
-amyjojo@google.com
 nchalko@google.com
-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/Descrambler.java b/media/java/android/media/tv/tuner/Descrambler.java
index 2217eb3..700e7be 100644
--- a/media/java/android/media/tv/tuner/Descrambler.java
+++ b/media/java/android/media/tv/tuner/Descrambler.java
@@ -110,14 +110,16 @@
     }
 
     /**
-     * Set a key token to link descrambler to a key slot
+     * Set a key token to link descrambler to a key slot. Use {@link isValidKeyToken(byte[])} to
+     * validate the key token format. Invalid key token would cause no-op and return
+     * {@link Tuner.RESULT_INVALID_ARGUMENT}.
      *
      * <p>A descrambler instance can have only one key slot to link, but a key slot can hold a few
-     * keys for different purposes.
+     * keys for different purposes. {@link Tuner.VOID_KEYTOKEN} is considered valid.
      *
-     * @param keyToken the token to be used to link the key slot. Use {@link Tuner.INVALID_KEYTOKEN}
+     * @param keyToken the token to be used to link the key slot. Use {@link Tuner.VOID_KEYTOKEN}
      *        to remove the current key from descrambler. If the current keyToken comes from a
-     *        MediaCas session, use {@link Tuner.INVALID_KEYTOKEN} to remove current key before
+     *        MediaCas session, use {@link Tuner.VOID_KEYTOKEN} to remove current key before
      *        closing the MediaCas session.
      * @return result status of the operation.
      */
@@ -134,6 +136,22 @@
     }
 
     /**
+     * Validate the key token format as the parameter of {@link setKeyToken(byte[])}.
+     *
+     * <p>The key token is expected to be less than 128 bits.
+     *
+     * @param keyToken the token to be validated.
+     * @return true if the given key token is a valid one.
+     */
+    public static boolean isValidKeyToken(@NonNull byte[] keyToken) {
+        if (keyToken.length == 0 || keyToken.length > 16) {
+            Log.d(TAG, "Invalid key token size: " + (keyToken.length * 8) + " bit.");
+            return false;
+        }
+        return true;
+    }
+
+    /**
      * Release the descrambler instance.
      */
     @Override
@@ -150,18 +168,4 @@
             }
         }
     }
-
-    private boolean isValidKeyToken(byte[] keyToken) {
-        if (keyToken.length == 0 || keyToken.length > 16) {
-            Log.d(TAG, "Invalid key token size: " + (keyToken.length * 8) + " bit.");
-            return false;
-        }
-        for (int i = 0; i < keyToken.length; i++) {
-            if (keyToken[i] < 0) {
-                Log.d(TAG, "Invalid key token.");
-                return false;
-            }
-        }
-        return true;
-    }
 }
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index c261371..d094c2c 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -60,6 +60,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -166,13 +167,13 @@
     public static final int INVALID_LNB_ID =
             android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_LNB_ID;
     /**
-     * Invalid key token. It is used to remove the current key from descrambler.
+     * A void key token. It is used to remove the current key from descrambler.
      *
      * <p>If the current keyToken comes from a MediaCas session, App is recommended to
      * to use this constant to remove current key before closing MediaCas session.
      */
     @NonNull
-    public static final byte[] INVALID_KEYTOKEN =
+    public static final byte[] VOID_KEYTOKEN =
             {android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_KEYTOKEN};
 
     /** @hide */
@@ -296,8 +297,8 @@
     private Executor mOnResourceLostListenerExecutor;
 
     private Integer mDemuxHandle;
-    private Map<Integer, Descrambler> mDescramblers = new HashMap<>();
-    private List<Filter> mFilters = new ArrayList<>();
+    private Map<Integer, WeakReference<Descrambler>> mDescramblers = new HashMap<>();
+    private List<WeakReference<Filter>> mFilters = new ArrayList<WeakReference<Filter>>();
 
     private final TunerResourceManager.ResourcesReclaimListener mResourceListener =
             new TunerResourceManager.ResourcesReclaimListener() {
@@ -486,18 +487,28 @@
         if (mLnb != null) {
             mLnb.close();
         }
-        if (!mDescramblers.isEmpty()) {
-            for (Map.Entry<Integer, Descrambler> d : mDescramblers.entrySet()) {
-                d.getValue().close();
-                mTunerResourceManager.releaseDescrambler(d.getKey(), mClientId);
+        synchronized (mDescramblers) {
+            if (!mDescramblers.isEmpty()) {
+                for (Map.Entry<Integer, WeakReference<Descrambler>> d : mDescramblers.entrySet()) {
+                    Descrambler descrambler = d.getValue().get();
+                    if (descrambler != null) {
+                        descrambler.close();
+                    }
+                    mTunerResourceManager.releaseDescrambler(d.getKey(), mClientId);
+                }
+                mDescramblers.clear();
             }
-            mDescramblers.clear();
         }
-        if (!mFilters.isEmpty()) {
-            for (Filter f : mFilters) {
-                f.close();
+        synchronized (mFilters) {
+            if (!mFilters.isEmpty()) {
+                for (WeakReference<Filter> weakFilter : mFilters) {
+                    Filter filter = weakFilter.get();
+                    if (filter != null) {
+                        filter.close();
+                    }
+                }
+                mFilters.clear();
             }
-            mFilters.clear();
         }
         if (mDemuxHandle != null) {
             int res = nativeCloseDemux(mDemuxHandle);
@@ -1183,7 +1194,10 @@
             if (mHandler == null) {
                 mHandler = createEventHandler();
             }
-            mFilters.add(filter);
+            synchronized (mFilters) {
+                WeakReference<Filter> weakFilter = new WeakReference<Filter>(filter);
+                mFilters.add(weakFilter);
+            }
         }
         return filter;
     }
@@ -1351,7 +1365,10 @@
         int handle = descramblerHandle[0];
         Descrambler descrambler = nativeOpenDescramblerByHandle(handle);
         if (descrambler != null) {
-            mDescramblers.put(handle, descrambler);
+            synchronized (mDescramblers) {
+                WeakReference weakDescrambler = new WeakReference<Descrambler>(descrambler);
+                mDescramblers.put(handle, weakDescrambler);
+            }
         } else {
             mTunerResourceManager.releaseDescrambler(handle, mClientId);
         }
diff --git a/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
index 98f8096..a2a602a 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
@@ -341,13 +341,13 @@
         return mScanType;
     }
     /**
-     * Get if the client could handle the Diseqc Rx Message or not. Default value is false.
+     * Get if the client can handle the Diseqc Rx Message or not. Default value is false.
      *
-     * The setter {@link Builder#setCouldHandleDiseqcRxMessage(boolean)} is only supported with
+     * The setter {@link Builder#setCanHandleDiseqcRxMessage(boolean)} is only supported with
      * Tuner HAL 1.1 or higher. Use {@link TunerVersionChecker.getTunerVersion()} to check the
      * version.
      */
-    public boolean getCouldHandleDiseqcRxMessage() {
+    public boolean canHandleDiseqcRxMessage() {
         return mIsDiseqcRxMessage;
     }
 
@@ -409,7 +409,7 @@
         }
 
         /**
-         * Set true to indicate the client could handle the Diseqc Messages. Note that it's still
+         * Set true to indicate the client can handle the Diseqc Messages. Note that it's still
          * possible that the client won't receive the messages when HAL is not able to setup Rx
          * channel in the hardware layer.
          *
@@ -417,10 +417,10 @@
          * no-op. Use {@link TunerVersionChecker.getTunerVersion()} to check the version.
          */
         @NonNull
-        public Builder setCouldHandleDiseqcRxMessage(boolean couldReceiveDiseqcMessage) {
+        public Builder setCanHandleDiseqcRxMessage(boolean canHandleDiseqcMessage) {
             if (TunerVersionChecker.checkHigherOrEqualVersionTo(
-                        TunerVersionChecker.TUNER_VERSION_1_1, "setCouldHandleDiseqcRxMessage")) {
-                mIsDiseqcRxMessage = couldReceiveDiseqcMessage;
+                        TunerVersionChecker.TUNER_VERSION_1_1, "setCanHandleDiseqcRxMessage")) {
+                mIsDiseqcRxMessage = canHandleDiseqcMessage;
             }
             return this;
         }
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
index af1ff01..c762da6 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
@@ -28,7 +28,7 @@
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * Frontend status.
+ * A Frontend Status class that contains the metrics of the active frontend.
  *
  * @hide
  */
@@ -461,7 +461,7 @@
     }
 
     /**
-     * Lock status for Demod.
+     * Gets if the demod is currently locked or not.
      */
     public boolean isDemodLocked() {
         if (mIsDemodLocked == null) {
@@ -470,7 +470,7 @@
         return mIsDemodLocked;
     }
     /**
-     * Gets Signal to Noise Ratio in thousandths of a deciBel (0.001dB).
+     * Gets the current Signal to Noise Ratio in thousandths of a deciBel (0.001dB).
      */
     public int getSnr() {
         if (mSnr == null) {
@@ -479,7 +479,7 @@
         return mSnr;
     }
     /**
-     * Gets Bit Error Ratio.
+     * Gets the current Bit Error Ratio.
      *
      * <p>The number of error bit per 1 billion bits.
      */
@@ -491,7 +491,7 @@
     }
 
     /**
-     * Gets Packages Error Ratio.
+     * Gets the current Packages Error Ratio.
      *
      * <p>The number of error package per 1 billion packages.
      */
@@ -502,7 +502,7 @@
         return mPer;
     }
     /**
-     * Gets Bit Error Ratio before Forward Error Correction (FEC).
+     * Gets the current Bit Error Ratio before Forward Error Correction (FEC).
      *
      * <p>The number of error bit per 1 billion bits before FEC.
      */
@@ -513,7 +513,7 @@
         return mPerBer;
     }
     /**
-     * Gets Signal Quality in percent.
+     * Gets the current Signal Quality in percent.
      */
     public int getSignalQuality() {
         if (mSignalQuality == null) {
@@ -522,7 +522,7 @@
         return mSignalQuality;
     }
     /**
-     * Gets Signal Strength in thousandths of a dBm (0.001dBm).
+     * Gets the current Signal Strength in thousandths of a dBm (0.001dBm).
      */
     public int getSignalStrength() {
         if (mSignalStrength == null) {
@@ -531,7 +531,7 @@
         return mSignalStrength;
     }
     /**
-     * Gets symbol rate in symbols per second.
+     * Gets the current symbol rate in symbols per second.
      */
     public int getSymbolRate() {
         if (mSymbolRate == null) {
@@ -540,7 +540,7 @@
         return mSymbolRate;
     }
     /**
-     *  Gets Inner Forward Error Correction type as specified in ETSI EN 300 468 V1.15.1
+     *  Gets the current Inner Forward Error Correction type as specified in ETSI EN 300 468 V1.15.1
      *  and ETSI EN 302 307-2 V1.1.1.
      */
     @FrontendSettings.InnerFec
@@ -551,7 +551,7 @@
         return mInnerFec;
     }
     /**
-     * Gets modulation.
+     * Gets the currently modulation information.
      */
     @FrontendModulation
     public int getModulation() {
@@ -561,7 +561,7 @@
         return mModulation;
     }
     /**
-     * Gets Spectral Inversion for DVBC.
+     * Gets the currently Spectral Inversion information for DVBC.
      */
     @FrontendSettings.FrontendSpectralInversion
     public int getSpectralInversion() {
@@ -571,7 +571,7 @@
         return mInversion;
     }
     /**
-     * Gets Power Voltage Type for LNB.
+     * Gets the current Power Voltage Type for LNB.
      */
     @Lnb.Voltage
     public int getLnbVoltage() {
@@ -581,7 +581,7 @@
         return mLnbVoltage;
     }
     /**
-     * Gets Physical Layer Pipe ID.
+     * Gets the current Physical Layer Pipe ID.
      */
     public int getPlpId() {
         if (mPlpId == null) {
@@ -599,7 +599,7 @@
         return mIsEwbs;
     }
     /**
-     * Gets Automatic Gain Control value which is normalized from 0 to 255.
+     * Gets the current Automatic Gain Control value which is normalized from 0 to 255.
      */
     public int getAgc() {
         if (mAgc == null) {
@@ -617,7 +617,7 @@
         return mIsLnaOn;
     }
     /**
-     * Gets Error status by layer.
+     * Gets the current Error information by layer.
      */
     @NonNull
     public boolean[] getLayerErrors() {
@@ -627,7 +627,7 @@
         return mIsLayerErrors;
     }
     /**
-     * Gets Modulation Error Ratio in thousandths of a deciBel (0.001dB).
+     * Gets the current Modulation Error Ratio in thousandths of a deciBel (0.001dB).
      */
     public int getMer() {
         if (mMer == null) {
@@ -636,7 +636,7 @@
         return mMer;
     }
     /**
-     * Gets frequency difference in Hz.
+     * Gets the current frequency difference in Hz.
      *
      * <p>Difference between tuning frequency and actual locked frequency.
      */
@@ -647,7 +647,7 @@
         return mFreqOffset;
     }
     /**
-     * Gets hierarchy Type for DVBT.
+     * Gets the current hierarchy Type for DVBT.
      */
     @DvbtFrontendSettings.Hierarchy
     public int getHierarchy() {
@@ -657,7 +657,7 @@
         return mHierarchy;
     }
     /**
-     * Gets lock status for RF.
+     * Gets if the RF is locked or not.
      */
     public boolean isRfLocked() {
         if (mIsRfLocked == null) {
@@ -666,7 +666,7 @@
         return mIsRfLocked;
     }
     /**
-     * Gets an array of PLP status for tuned PLPs for ATSC3 frontend.
+     * Gets an array of the current tuned PLPs information of ATSC3 frontend.
      */
     @NonNull
     public Atsc3PlpTuningInfo[] getAtsc3PlpTuningInfo() {
@@ -677,9 +677,9 @@
     }
 
     /**
-     * Gets an array of extended bit error ratio status.
+     * Gets an array of the current extended bit error ratio.
      *
-     * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+     * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
      * {@link TunerVersionChecker.getTunerVersion()} to check the version.
      */
     @NonNull
@@ -693,10 +693,9 @@
     }
 
     /**
-     * Gets an array of code rates status. The {@link FrontendSettings.InnerFec} would be used to
-     * show the code rate.
+     * Gets an array of the current code rates.
      *
-     * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+     * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
      * {@link TunerVersionChecker.getTunerVersion()} to check the version.
      */
     @NonNull
@@ -711,9 +710,9 @@
     }
 
     /**
-     * Gets bandwidth status.
+     * Gets the current bandwidth information.
      *
-     * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+     * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
      * {@link TunerVersionChecker.getTunerVersion()} to check the version.
      */
     @FrontendBandwidth
@@ -727,9 +726,9 @@
     }
 
     /**
-     * Gets guard interval status.
+     * Gets the current guard interval information.
      *
-     * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+     * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
      * {@link TunerVersionChecker.getTunerVersion()} to check the version.
      */
     @FrontendGuardInterval
@@ -743,9 +742,9 @@
     }
 
     /**
-     * Gets tansmission mode status.
+     * Gets the current transmission mode information.
      *
-     * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+     * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
      * {@link TunerVersionChecker.getTunerVersion()} to check the version.
      */
     @FrontendTransmissionMode
@@ -759,10 +758,10 @@
     }
 
     /**
-     * Gets the Uncorrectable Error Counts of the frontend's Physical Layer Pipe (PLP) since the
-     * last tune operation.
+     * Gets the current Uncorrectable Error Counts of the frontend's Physical Layer Pipe (PLP)
+     * since the last tune operation.
      *
-     * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+     * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
      * {@link TunerVersionChecker.getTunerVersion()} to check the version.
      */
     public int getUec() {
@@ -775,9 +774,9 @@
     }
 
     /**
-     * Gets the current DVB-T2 system id status.
+     * Gets the current DVB-T2 system id.
      *
-     * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+     * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
      * {@link TunerVersionChecker.getTunerVersion()} to check the version.
      */
     @IntRange(from = 0, to = 0xffff)
@@ -791,10 +790,9 @@
     }
 
     /**
-     * Gets an array of interleaving status. Array value should be within {@link
-     * FrontendInterleaveMode}.
+     * Gets an array of the current interleaving mode information.
      *
-     * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+     * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
      * {@link TunerVersionChecker.getTunerVersion()} to check the version.
      */
     @NonNull
@@ -809,9 +807,10 @@
     }
 
     /**
-     * Gets an array of the segments status in ISDB-T Specification of all the channels.
+     * Gets an array of the current segments information in ISDB-T Specification of all the
+     * channels.
      *
-     * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+     * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
      * {@link TunerVersionChecker.getTunerVersion()} to check the version.
      */
     @NonNull
@@ -828,7 +827,7 @@
     /**
      * Gets an array of the Transport Stream Data Rate in BPS of the current channel.
      *
-     * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+     * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
      * {@link TunerVersionChecker.getTunerVersion()} to check the version.
      */
     @NonNull
@@ -842,13 +841,13 @@
     }
 
     /**
-     * Gets an array of the extended modulations status. Array value should be withink {@link
-     * FrontendModulation}.
+     * Gets an array of the current extended modulations information.
      *
-     * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+     * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
      * {@link TunerVersionChecker.getTunerVersion()} to check the version.
      */
     @NonNull
+    @FrontendModulation
     public int[] getExtendedModulations() {
         TunerVersionChecker.checkHigherOrEqualVersionTo(
                 TunerVersionChecker.TUNER_VERSION_1_1, "getExtendedModulations status");
@@ -859,9 +858,9 @@
     }
 
     /**
-     * Gets roll off status.
+     * Gets the current roll off information.
      *
-     * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+     * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
      * {@link TunerVersionChecker.getTunerVersion()} to check the version.
      */
     @FrontendRollOff
@@ -875,9 +874,9 @@
     }
 
     /**
-     * Gets is MISO enabled status.
+     * Gets is MISO enabled or not.
      *
-     * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+     * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
      * {@link TunerVersionChecker.getTunerVersion()} to check the version.
      */
     public boolean isMisoEnabled() {
@@ -890,9 +889,9 @@
     }
 
     /**
-     * Gets is the Code Rate of the frontend is linear or not status.
+     * Gets is the Code Rate of the frontend is linear or not.
      *
-     * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+     * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
      * {@link TunerVersionChecker.getTunerVersion()} to check the version.
      */
     public boolean isLinear() {
@@ -905,9 +904,9 @@
     }
 
     /**
-     * Gets is the Short Frames enabled or not status.
+     * Gets is the Short Frames enabled or not.
      *
-     * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+     * <p>This query is only supported by Tuner HAL 1.1 or higher. Use
      * {@link TunerVersionChecker.getTunerVersion()} to check the version.
      */
     public boolean isShortFramesEnabled() {
@@ -920,7 +919,7 @@
     }
 
     /**
-     * Status for each tuning Physical Layer Pipes.
+     * Information of each tuning Physical Layer Pipes.
      */
     public static class Atsc3PlpTuningInfo {
         private final int mPlpId;
diff --git a/media/java/android/mtp/OWNERS b/media/java/android/mtp/OWNERS
index 1928ba8..e27d06f 100644
--- a/media/java/android/mtp/OWNERS
+++ b/media/java/android/mtp/OWNERS
@@ -1,7 +1,7 @@
 set noparent
 
 marcone@google.com
-jsharkey@android.com
+jsharkey@google.com
 jameswei@google.com
 rmojumder@google.com
 
diff --git a/media/jni/OWNERS b/media/jni/OWNERS
index f1b0237..e6e4f86 100644
--- a/media/jni/OWNERS
+++ b/media/jni/OWNERS
@@ -1,5 +1,5 @@
 # extra for MTP related files
-per-file android_mtp_*.cpp=marcone@google.com,jsharkey@android.com,jameswei@google.com,rmojumder@google.com
+per-file android_mtp_*.cpp=marcone@google.com,jsharkey@google.com,jameswei@google.com,rmojumder@google.com
 
 # extra for TV related files
 per-file android_media_tv_*=nchalko@google.com,quxiangfang@google.com
diff --git a/media/jni/android_media_MediaCodecLinearBlock.h b/media/jni/android_media_MediaCodecLinearBlock.h
index 8f1d2fa..ae2d3a2 100644
--- a/media/jni/android_media_MediaCodecLinearBlock.h
+++ b/media/jni/android_media_MediaCodecLinearBlock.h
@@ -49,7 +49,14 @@
             if (offset == 0 && size == block.capacity()) {
                 return mBuffer;
             }
-            return C2Buffer::CreateLinearBuffer(block.subBlock(offset, size));
+
+            std::shared_ptr<C2Buffer> buffer =
+                C2Buffer::CreateLinearBuffer(block.subBlock(offset, size));
+            for (const std::shared_ptr<const C2Info> &info : mBuffer->info()) {
+                std::shared_ptr<C2Param> param = std::move(C2Param::Copy(*info));
+                buffer->setInfo(std::static_pointer_cast<C2Info>(param));
+            }
+            return buffer;
         }
         if (mBlock) {
             return C2Buffer::CreateLinearBuffer(mBlock->share(offset, size, C2Fence{}));
diff --git a/media/mca/effect/java/android/media/effect/OWNERS b/media/mca/effect/java/android/media/effect/OWNERS
new file mode 100644
index 0000000..6a351d3
--- /dev/null
+++ b/media/mca/effect/java/android/media/effect/OWNERS
@@ -0,0 +1 @@
+elaurent@google.com
diff --git a/media/mca/effect/java/android/media/effect/effects/OWNERS b/media/mca/effect/java/android/media/effect/effects/OWNERS
new file mode 100644
index 0000000..6a351d3
--- /dev/null
+++ b/media/mca/effect/java/android/media/effect/effects/OWNERS
@@ -0,0 +1 @@
+elaurent@google.com
diff --git a/media/mca/filterfw/java/android/filterfw/OWNERS b/media/mca/filterfw/java/android/filterfw/OWNERS
new file mode 100644
index 0000000..5d351ef
--- /dev/null
+++ b/media/mca/filterfw/java/android/filterfw/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 50018
+
+elaurent@google.com
diff --git a/media/mca/filterfw/java/android/filterfw/samples/OWNERS b/media/mca/filterfw/java/android/filterfw/samples/OWNERS
new file mode 100644
index 0000000..5d351ef
--- /dev/null
+++ b/media/mca/filterfw/java/android/filterfw/samples/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 50018
+
+elaurent@google.com
diff --git a/media/tests/MtpTests/OWNERS b/media/tests/MtpTests/OWNERS
index 1928ba8..e27d06f 100644
--- a/media/tests/MtpTests/OWNERS
+++ b/media/tests/MtpTests/OWNERS
@@ -1,7 +1,7 @@
 set noparent
 
 marcone@google.com
-jsharkey@android.com
+jsharkey@google.com
 jameswei@google.com
 rmojumder@google.com
 
diff --git a/mime/OWNERS b/mime/OWNERS
new file mode 100644
index 0000000..6f9dbea
--- /dev/null
+++ b/mime/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/os/storage/OWNERS
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 7793d6c..6db4da9 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -36,6 +36,7 @@
     defaults: ["libandroid_defaults"],
 
     srcs: [
+        "activity_manager.cpp",
         "asset_manager.cpp",
         "choreographer.cpp",
         "configuration.cpp",
@@ -95,6 +96,10 @@
 
     include_dirs: ["bionic/libc/dns/include"],
 
+    local_include_dirs: [ "include_platform", ],
+
+    export_include_dirs: [ "include_platform", ],
+
     version_script: "libandroid.map.txt",
     stubs: {
         symbol_file: "libandroid.map.txt",
diff --git a/native/android/activity_manager.cpp b/native/android/activity_manager.cpp
new file mode 100644
index 0000000..82f4569
--- /dev/null
+++ b/native/android/activity_manager.cpp
@@ -0,0 +1,226 @@
+/*
+ * 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.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "AActivityManager"
+#include <utils/Log.h>
+
+#include <android/activity_manager.h>
+#include <binder/ActivityManager.h>
+
+namespace android {
+namespace activitymanager {
+
+// Global instance of ActivityManager, service is obtained only on first use.
+static ActivityManager gAm;
+// String tag used with ActivityManager.
+static const String16& getTag() {
+    static String16 tag("libandroid");
+    return tag;
+}
+
+struct UidObserver : public BnUidObserver, public virtual IBinder::DeathRecipient {
+    explicit UidObserver(const AActivityManager_onUidImportance& cb,
+                         int32_t cutpoint, void* cookie)
+          : mCallback(cb), mImportanceCutpoint(cutpoint), mCookie(cookie), mRegistered(false) {}
+    bool registerSelf();
+    void unregisterSelf();
+
+    // IUidObserver
+    void onUidGone(uid_t uid, bool disabled) override;
+    void onUidActive(uid_t uid) override;
+    void onUidIdle(uid_t uid, bool disabled) override;
+    void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq,
+                           int32_t capability) override;
+
+    // IBinder::DeathRecipient implementation
+    void binderDied(const wp<IBinder>& who) override;
+
+    static int32_t procStateToImportance(int32_t procState);
+    static int32_t importanceToProcState(int32_t importance);
+
+    AActivityManager_onUidImportance mCallback;
+    int32_t mImportanceCutpoint;
+    void* mCookie;
+    std::mutex mRegisteredLock;
+    bool mRegistered GUARDED_BY(mRegisteredLock);
+};
+
+//static
+int32_t UidObserver::procStateToImportance(int32_t procState) {
+    // TODO: remove this after adding Importance to onUidStateChanged callback.
+    if (procState == ActivityManager::PROCESS_STATE_NONEXISTENT) {
+        return AACTIVITYMANAGER_IMPORTANCE_GONE;
+    } else if (procState >= ActivityManager::PROCESS_STATE_HOME) {
+        return AACTIVITYMANAGER_IMPORTANCE_CACHED;
+    } else if (procState == ActivityManager::PROCESS_STATE_HEAVY_WEIGHT) {
+        return AACTIVITYMANAGER_IMPORTANCE_CANT_SAVE_STATE;
+    } else if (procState >= ActivityManager::PROCESS_STATE_TOP_SLEEPING) {
+        return AACTIVITYMANAGER_IMPORTANCE_TOP_SLEEPING;
+    } else if (procState >= ActivityManager::PROCESS_STATE_SERVICE) {
+        return AACTIVITYMANAGER_IMPORTANCE_SERVICE;
+    } else if (procState >= ActivityManager::PROCESS_STATE_TRANSIENT_BACKGROUND) {
+        return AACTIVITYMANAGER_IMPORTANCE_PERCEPTIBLE;
+    } else if (procState >= ActivityManager::PROCESS_STATE_IMPORTANT_FOREGROUND) {
+        return AACTIVITYMANAGER_IMPORTANCE_VISIBLE;
+    } else if (procState >= ActivityManager::PROCESS_STATE_FOREGROUND_SERVICE) {
+        return AACTIVITYMANAGER_IMPORTANCE_FOREGROUND_SERVICE;
+    } else {
+        return AACTIVITYMANAGER_IMPORTANCE_FOREGROUND;
+    }
+}
+
+//static
+int32_t UidObserver::importanceToProcState(int32_t importance) {
+    // TODO: remove this after adding Importance to onUidStateChanged callback.
+    if (importance == AACTIVITYMANAGER_IMPORTANCE_GONE) {
+        return ActivityManager::PROCESS_STATE_NONEXISTENT;
+    } else if (importance >= AACTIVITYMANAGER_IMPORTANCE_CACHED) {
+        return ActivityManager::PROCESS_STATE_HOME;
+    } else if (importance >= AACTIVITYMANAGER_IMPORTANCE_CANT_SAVE_STATE) {
+        return ActivityManager::PROCESS_STATE_HEAVY_WEIGHT;
+    } else if (importance >= AACTIVITYMANAGER_IMPORTANCE_TOP_SLEEPING) {
+        return ActivityManager::PROCESS_STATE_TOP_SLEEPING;
+    } else if (importance >= AACTIVITYMANAGER_IMPORTANCE_SERVICE) {
+        return ActivityManager::PROCESS_STATE_SERVICE;
+    } else if (importance >= AACTIVITYMANAGER_IMPORTANCE_PERCEPTIBLE) {
+        return ActivityManager::PROCESS_STATE_TRANSIENT_BACKGROUND;
+    } else if (importance >= AACTIVITYMANAGER_IMPORTANCE_VISIBLE) {
+        return ActivityManager::PROCESS_STATE_IMPORTANT_FOREGROUND;
+    } else if (importance >= AACTIVITYMANAGER_IMPORTANCE_FOREGROUND_SERVICE) {
+        return ActivityManager::PROCESS_STATE_FOREGROUND_SERVICE;
+    } else {
+        return ActivityManager::PROCESS_STATE_TOP;
+    }
+}
+
+
+void UidObserver::onUidGone(uid_t uid, bool disabled __unused) {
+    std::scoped_lock lock{mRegisteredLock};
+
+    if (mRegistered && mCallback) {
+        mCallback(uid, AACTIVITYMANAGER_IMPORTANCE_GONE, mCookie);
+    }
+}
+
+void UidObserver::onUidActive(uid_t uid __unused) {}
+
+void UidObserver::onUidIdle(uid_t uid __unused, bool disabled __unused) {}
+
+void UidObserver::onUidStateChanged(uid_t uid, int32_t procState,
+                                    int64_t procStateSeq __unused,
+                                    int32_t capability __unused) {
+    std::scoped_lock lock{mRegisteredLock};
+
+    if (mRegistered && mCallback) {
+        mCallback(uid, procStateToImportance(procState), mCookie);
+    }
+}
+
+void UidObserver::binderDied(const wp<IBinder>& /*who*/) {
+    // ActivityManager is dead, try to re-register.
+    {
+        std::scoped_lock lock{mRegisteredLock};
+        // If client already unregistered, don't try to re-register.
+        if (!mRegistered) {
+            return;
+        }
+        // Clear mRegistered to re-register.
+        mRegistered = false;
+    }
+    registerSelf();
+}
+
+bool UidObserver::registerSelf() {
+    std::scoped_lock lock{mRegisteredLock};
+    if (mRegistered) {
+        return true;
+    }
+
+    status_t res = gAm.linkToDeath(this);
+    if (res != OK) {
+        ALOGE("UidObserver: Failed to linkToDeath with ActivityManager (err %d)", res);
+        return false;
+    }
+
+    // TODO: it seems only way to get all changes is to set cutoff to PROCESS_STATE_UNKNOWN.
+    // But there is no equivalent of PROCESS_STATE_UNKNOWN in the UidImportance.
+    // If mImportanceCutpoint is < 0, use PROCESS_STATE_UNKNOWN instead.
+    res = gAm.registerUidObserver(
+            this,
+            ActivityManager::UID_OBSERVER_GONE | ActivityManager::UID_OBSERVER_PROCSTATE,
+            (mImportanceCutpoint < 0) ? ActivityManager::PROCESS_STATE_UNKNOWN
+                                      : importanceToProcState(mImportanceCutpoint),
+            getTag());
+    if (res != OK) {
+        ALOGE("UidObserver: Failed to register with ActivityManager (err %d)", res);
+        gAm.unlinkToDeath(this);
+        return false;
+    }
+
+    mRegistered = true;
+    ALOGV("UidObserver: Registered with ActivityManager");
+    return true;
+}
+
+void UidObserver::unregisterSelf() {
+    std::scoped_lock lock{mRegisteredLock};
+
+    if (mRegistered) {
+        gAm.unregisterUidObserver(this);
+        gAm.unlinkToDeath(this);
+        mRegistered = false;
+    }
+
+    ALOGV("UidObserver: Unregistered with ActivityManager");
+}
+
+} // activitymanager
+} // android
+
+using namespace android;
+using namespace activitymanager;
+
+struct AActivityManager_UidImportanceListener : public UidObserver {
+};
+
+AActivityManager_UidImportanceListener* AActivityManager_addUidImportanceListener(
+        AActivityManager_onUidImportance onUidImportance, int32_t importanceCutpoint, void* cookie) {
+    sp<UidObserver> observer(new UidObserver(onUidImportance, importanceCutpoint, cookie));
+    if (observer == nullptr || !observer->registerSelf()) {
+        return nullptr;
+    }
+    observer->incStrong((void *)AActivityManager_addUidImportanceListener);
+    return static_cast<AActivityManager_UidImportanceListener*>(observer.get());
+}
+
+void AActivityManager_removeUidImportanceListener(
+        AActivityManager_UidImportanceListener* listener) {
+    if (listener != nullptr) {
+        UidObserver* observer = static_cast<UidObserver*>(listener);
+        observer->unregisterSelf();
+        observer->decStrong((void *)AActivityManager_addUidImportanceListener);
+    }
+}
+
+bool AActivityManager_isUidActive(uid_t uid) {
+    return gAm.isUidActive(uid, getTag());
+}
+
+int32_t AActivityManager_getUidImportance(uid_t uid) {
+    return UidObserver::procStateToImportance(gAm.getUidProcessState(uid, getTag()));
+}
+
diff --git a/native/android/aidl/com/android/internal/compat/OWNERS b/native/android/aidl/com/android/internal/compat/OWNERS
new file mode 100644
index 0000000..f8c3520
--- /dev/null
+++ b/native/android/aidl/com/android/internal/compat/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/compat/OWNERS
diff --git a/native/android/include_platform/android/activity_manager.h b/native/android/include_platform/android/activity_manager.h
new file mode 100644
index 0000000..0ecd56d
--- /dev/null
+++ b/native/android/include_platform/android/activity_manager.h
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+
+#ifndef __AACTIVITYMANAGER_H__
+#define __AACTIVITYMANAGER_H__
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+struct AActivityManager_UidImportanceListener;
+typedef struct AActivityManager_UidImportanceListener AActivityManager_UidImportanceListener;
+
+/**
+ * Callback interface when Uid Importance has changed for a uid.
+ *
+ * This callback will be called on an arbitrary thread. Calls to a given listener will be
+ * serialized.
+ *
+ * @param uid the uid for which the importance has changed.
+ * @param uidImportance the new uidImportance for the uid.
+ * @cookie the same cookie when the UidImportanceListener was added.
+ *
+ * Introduced in API 31.
+ */
+typedef void (*AActivityManager_onUidImportance)(uid_t uid, int32_t uidImportance, void* cookie);
+
+/**
+ * ActivityManager Uid Importance constants.
+ *
+ * Introduced in API 31.
+ */
+enum {
+    /**
+     * Constant for Uid Importance: This process is running the
+     * foreground UI; that is, it is the thing currently at the top of the screen
+     * that the user is interacting with.
+     */
+    AACTIVITYMANAGER_IMPORTANCE_FOREGROUND = 100,
+
+    /**
+     * Constant for Uid Importance: This process is running a foreground
+     * service, for example to perform music playback even while the user is
+     * not immediately in the app.  This generally indicates that the process
+     * is doing something the user actively cares about.
+     */
+    AACTIVITYMANAGER_IMPORTANCE_FOREGROUND_SERVICE = 125,
+
+    /**
+     * Constant for Uid Importance: This process is running something
+     * that is actively visible to the user, though not in the immediate
+     * foreground.  This may be running a window that is behind the current
+     * foreground (so paused and with its state saved, not interacting with
+     * the user, but visible to them to some degree); it may also be running
+     * other services under the system's control that it inconsiders important.
+     */
+    AACTIVITYMANAGER_IMPORTANCE_VISIBLE = 200,
+
+    /**
+     * Constant for Uid Importance: This process is not something the user
+     * is directly aware of, but is otherwise perceptible to them to some degree.
+     */
+    AACTIVITYMANAGER_IMPORTANCE_PERCEPTIBLE = 230,
+
+    /**
+     * Constant for Uid Importance: This process contains services
+     * that should remain running.  These are background services apps have
+     * started, not something the user is aware of, so they may be killed by
+     * the system relatively freely (though it is generally desired that they
+     * stay running as long as they want to).
+     */
+    AACTIVITYMANAGER_IMPORTANCE_SERVICE = 300,
+
+    /**
+     * Constant for Uid Importance: This process is running the foreground
+     * UI, but the device is asleep so it is not visible to the user.  Though the
+     * system will try hard to keep its process from being killed, in all other
+     * ways we consider it a kind of cached process, with the limitations that go
+     * along with that state: network access, running background services, etc.
+     */
+    AACTIVITYMANAGER_IMPORTANCE_TOP_SLEEPING = 325,
+
+    /**
+     * Constant for Uid Importance: This process is running an
+     * application that can not save its state, and thus can't be killed
+     * while in the background.  This will be used with apps that have
+     * {@link android.R.attr#cantSaveState} set on their application tag.
+     */
+    AACTIVITYMANAGER_IMPORTANCE_CANT_SAVE_STATE = 350,
+
+    /**
+     * Constant for Uid Importance: This process process contains
+     * cached code that is expendable, not actively running any app components
+     * we care about.
+     */
+    AACTIVITYMANAGER_IMPORTANCE_CACHED = 400,
+
+    /**
+     * Constant for Uid Importance: This process does not exist.
+     */
+    AACTIVITYMANAGER_IMPORTANCE_GONE = 1000,
+};
+
+#if __ANDROID_API__ >= 31
+
+/**
+ * Adds a UidImportanceListener to the ActivityManager.
+ *
+ * This API requires android.Manifest.permission.PACKAGE_USAGE_STATS permission.
+ *
+ * @param onUidImportance the listener callback that will receive change reports.
+ *
+ * @param importanceCutpoint the level of importance in which the caller is interested
+ * in differences. For example, if AACTIVITYMANAGER_IMPORTANCE_PERCEPTIBLE is used
+ * here, you will receive a call each time a uid's importance transitions between being
+ * <= AACTIVITYMANAGER_IMPORTANCE_PERCEPTIBLE and > AACTIVITYMANAGER_IMPORTANCE_PERCEPTIBLE.
+ *
+ * @param cookie a cookie that will be passed back to the listener callback.
+ *
+ * @return an opaque pointer of AActivityManager_UidImportanceListener, or nullptr
+ * upon failure. Upon success, the returned AActivityManager_UidImportanceListener pointer
+ * must be removed and released through AActivityManager_removeUidImportanceListener.
+ */
+AActivityManager_UidImportanceListener* AActivityManager_addUidImportanceListener(
+        AActivityManager_onUidImportance onUidImportance,
+        int32_t importanceCutpoint,
+        void* cookie) __INTRODUCED_IN(31);
+
+/**
+ * Removes a UidImportanceListener that was added with AActivityManager_addUidImportanceListener.
+ *
+ * When this returns, it's guaranteed the listener callback will no longer be invoked.
+ *
+ * @param listener the UidImportanceListener to be removed.
+ */
+void AActivityManager_removeUidImportanceListener(
+        AActivityManager_UidImportanceListener* listener) __INTRODUCED_IN(31);
+
+/**
+ * Queries if a uid is currently active.
+ *
+ * This API requires android.Manifest.permission.PACKAGE_USAGE_STATS permission.
+ *
+ * @return true if the uid is active, false otherwise.
+ */
+bool AActivityManager_isUidActive(uid_t uid) __INTRODUCED_IN(31);
+
+/**
+ * Queries the current Uid Importance value of a uid.
+ *
+ * This API requires android.Manifest.permission.PACKAGE_USAGE_STATS permission.
+ *
+ * @param uid the uid for which the importance value is queried.
+ * @return the current uid importance value for uid.
+ */
+int32_t AActivityManager_getUidImportance(uid_t uid) __INTRODUCED_IN(31);
+
+#endif // __ANDROID_API__ >= 31
+
+__END_DECLS
+
+#endif  // __AACTIVITYMANAGER_H__
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index eca67bd..8fa3acf 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -1,5 +1,9 @@
 LIBANDROID {
   global:
+    AActivityManager_addUidImportanceListener; # apex # introduced=31
+    AActivityManager_removeUidImportanceListener; # apex # introduced=31
+    AActivityManager_isUidActive; # apex # introduced=31
+    AActivityManager_getUidImportance; # apex # introduced=31
     AAssetDir_close;
     AAssetDir_getNextFileName;
     AAssetDir_rewind;
diff --git a/native/android/tests/activitymanager/UidImportanceHelperApps/Android.bp b/native/android/tests/activitymanager/UidImportanceHelperApps/Android.bp
new file mode 100644
index 0000000..1a51218
--- /dev/null
+++ b/native/android/tests/activitymanager/UidImportanceHelperApps/Android.bp
@@ -0,0 +1,11 @@
+android_test_helper_app {
+    name: "UidImportanceHelperApp",
+    manifest: "HelperAppManifest.xml",
+    static_libs: ["androidx.test.rules"],
+    sdk_version: "test_current",
+    srcs: ["src/**/*.java"],
+    test_suites: [
+        "general-tests",
+    ],
+}
+
diff --git a/native/android/tests/activitymanager/UidImportanceHelperApps/HelperAppManifest.xml b/native/android/tests/activitymanager/UidImportanceHelperApps/HelperAppManifest.xml
new file mode 100644
index 0000000..3583b33
--- /dev/null
+++ b/native/android/tests/activitymanager/UidImportanceHelperApps/HelperAppManifest.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.tests.UidImportanceHelper"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <application android:label="UidImportanceHelper">
+        <activity android:name="com.android.tests.UidImportanceHelper.MainActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT"/>
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
+
diff --git a/native/android/tests/activitymanager/UidImportanceHelperApps/src/com/android/tests/UidImportanceHelper/MainActivity.java b/native/android/tests/activitymanager/UidImportanceHelperApps/src/com/android/tests/UidImportanceHelper/MainActivity.java
new file mode 100644
index 0000000..db0f2b5
--- /dev/null
+++ b/native/android/tests/activitymanager/UidImportanceHelperApps/src/com/android/tests/UidImportanceHelper/MainActivity.java
@@ -0,0 +1,107 @@
+/*
+ * 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.tests.UidImportanceHelper;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+/**
+ * This is an empty activity for testing the UID policy of media transcoding service.
+ */
+public class MainActivity extends Activity {
+    private static final String TAG = "MainActivity";
+
+    // Called at the start of the full lifetime.
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        // Initialize Activity and inflate the UI.
+    }
+
+    // Called after onCreate has finished, use to restore UI state
+    @Override
+    public void onRestoreInstanceState(Bundle savedInstanceState) {
+        super.onRestoreInstanceState(savedInstanceState);
+        // Restore UI state from the savedInstanceState.
+        // This bundle has also been passed to onCreate.
+        // Will only be called if the Activity has been
+        // killed by the system since it was last visible.
+    }
+
+    // Called before subsequent visible lifetimes
+    // for an activity process.
+    @Override
+    public void onRestart() {
+        super.onRestart();
+        // Load changes knowing that the Activity has already
+        // been visible within this process.
+    }
+
+    // Called at the start of the visible lifetime.
+    @Override
+    public void onStart() {
+        super.onStart();
+        // Apply any required UI change now that the Activity is visible.
+    }
+
+    // Called at the start of the active lifetime.
+    @Override
+    public void onResume() {
+        super.onResume();
+        // Resume any paused UI updates, threads, or processes required
+        // by the Activity but suspended when it was inactive.
+    }
+
+    // Called to save UI state changes at the
+    // end of the active lifecycle.
+    @Override
+    public void onSaveInstanceState(Bundle savedInstanceState) {
+        // Save UI state changes to the savedInstanceState.
+        // This bundle will be passed to onCreate and
+        // onRestoreInstanceState if the process is
+        // killed and restarted by the run time.
+        super.onSaveInstanceState(savedInstanceState);
+    }
+
+    // Called at the end of the active lifetime.
+    @Override
+    public void onPause() {
+        // Suspend UI updates, threads, or CPU intensive processes
+        // that don't need to be updated when the Activity isn't
+        // the active foreground Activity.
+        super.onPause();
+    }
+
+    // Called at the end of the visible lifetime.
+    @Override
+    public void onStop() {
+        // Suspend remaining UI updates, threads, or processing
+        // that aren't required when the Activity isn't visible.
+        // Persist all edits or state changes
+        // as after this call the process is likely to be killed.
+        super.onStop();
+    }
+
+    // Sometimes called at the end of the full lifetime.
+    @Override
+    public void onDestroy() {
+        // Clean up any resources including ending threads,
+        // closing database connections etc.
+        super.onDestroy();
+    }
+}
diff --git a/native/android/tests/activitymanager/nativeTests/Android.bp b/native/android/tests/activitymanager/nativeTests/Android.bp
new file mode 100644
index 0000000..d4b5015
--- /dev/null
+++ b/native/android/tests/activitymanager/nativeTests/Android.bp
@@ -0,0 +1,39 @@
+cc_test {
+    name: "ActivityManagerNativeTestCases",
+
+    multilib: {
+        lib32: {
+            suffix: "32",
+        },
+        lib64: {
+            suffix: "64",
+        },
+    },
+
+    srcs: ["src/ActivityManagerNativeTest.cpp"],
+
+    shared_libs: [
+        "liblog",
+        "libutils",
+        "libandroid",
+        "libbinder",
+    ],
+
+    static_libs: [
+        "libbase",
+        "libgtest",
+    ],
+    stl: "c++_shared",
+
+    test_suites: [
+        "general-tests",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+    required: [
+        "UidImportanceHelperApp",
+    ],
+}
diff --git a/native/android/tests/activitymanager/nativeTests/AndroidTest.xml b/native/android/tests/activitymanager/nativeTests/AndroidTest.xml
new file mode 100644
index 0000000..bf6287ad
--- /dev/null
+++ b/native/android/tests/activitymanager/nativeTests/AndroidTest.xml
@@ -0,0 +1,53 @@
+<?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.
+-->
+<configuration description="Config for ActivityManager native test cases">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+    <option name="config-descriptor:metadata" key="component" value="framework" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+
+    <!-- Force root to allow registering UidImportanceListener from native test -->
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+        <option name="force-root" value="true" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="input keyevent KEYCODE_WAKEUP" />
+        <option name="run-command" value="wm dismiss-keyguard" />
+    </target_preparer>
+    <!-- Install the helper apk -->
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="UidImportanceHelperApp.apk" />
+    </target_preparer>
+
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="cleanup" value="true" />
+        <option name="push" value="ActivityManagerNativeTestCases->/data/local/tmp/ActivityManagerNativeTestCases" />
+        <option name="append-bitness" value="true" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="ActivityManagerNativeTestCases" />
+        <option name="runtime-hint" value="1m" />
+    </test>
+
+    <!-- Controller that will skip the module if a native bridge situation is detected -->
+    <!-- For example: module wants to run arm and device is x86 -->
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.NativeBridgeModuleController" />
+</configuration>
diff --git a/native/android/tests/activitymanager/nativeTests/src/ActivityManagerNativeTest.cpp b/native/android/tests/activitymanager/nativeTests/src/ActivityManagerNativeTest.cpp
new file mode 100644
index 0000000..75ba0ff
--- /dev/null
+++ b/native/android/tests/activitymanager/nativeTests/src/ActivityManagerNativeTest.cpp
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ActivityManagerNativeTest"
+
+#include <android-base/logging.h>
+#include <android/activity_manager.h>
+#include <binder/PermissionController.h>
+#include <binder/ProcessState.h>
+#include <gtest/gtest.h>
+
+constexpr const char* kTestPackage = "com.android.tests.UidImportanceHelper";
+constexpr const char* kTestActivity = "com.android.tests.UidImportanceHelper.MainActivity";
+constexpr int64_t kEventTimeoutUs = 500000;
+
+//-----------------------------------------------------------------
+class ActivityManagerNativeTest : public ::testing::Test {
+protected:
+    ActivityManagerNativeTest() : mUidObserver(nullptr), mTestAppUid(-1), mLastUidImportance(-1) {}
+
+    virtual ~ActivityManagerNativeTest() {}
+
+    /* Test setup*/
+    virtual void SetUp() { android::ProcessState::self()->startThreadPool(); }
+
+    /* Test tear down */
+    virtual void TearDown() {}
+
+    bool waitForImportance(int32_t val, int64_t timeoutUs) {
+        std::unique_lock lock(mLock);
+
+        if (mLastUidImportance != val && timeoutUs > 0) {
+            mCondition.wait_for(lock, std::chrono::microseconds(timeoutUs));
+        }
+
+        return mLastUidImportance == val;
+    }
+
+    void onUidImportanceChanged(uid_t uid, int32_t uidImportance) {
+        LOG(ERROR) << "OnUidImportance: uid " << uid << ", importance " << uidImportance;
+        std::unique_lock lock(mLock);
+
+        if (uid == mTestAppUid) {
+            mLastUidImportance = uidImportance;
+            mCondition.notify_one();
+        }
+    }
+
+    static void OnUidImportance(uid_t uid, int32_t uidImportance, void* cookie) {
+        ActivityManagerNativeTest* owner = reinterpret_cast<ActivityManagerNativeTest*>(cookie);
+        owner->onUidImportanceChanged(uid, uidImportance);
+    }
+
+    AActivityManager_UidImportanceListener* mUidObserver;
+    uid_t mTestAppUid;
+    std::mutex mLock;
+    std::condition_variable mCondition;
+    int32_t mLastUidImportance;
+};
+
+static bool getUidForPackage(const char* packageName, /*inout*/ uid_t& uid) {
+    android::PermissionController pc;
+    uid = pc.getPackageUid(android::String16(packageName), 0);
+    if (uid <= 0) {
+        ALOGE("Unknown package: '%s'", packageName);
+        return false;
+    }
+    return true;
+}
+
+struct ShellHelper {
+    static bool RunCmd(const std::string& cmdStr) {
+        int ret = system(cmdStr.c_str());
+        if (ret != 0) {
+            LOG(ERROR) << "Failed to run cmd: " << cmdStr << ", exitcode " << ret;
+            return false;
+        }
+        return true;
+    }
+
+    static bool Start(const char* packageName, const char* activityName) {
+        return RunCmd("am start -W " + std::string(packageName) + "/" + std::string(activityName) +
+                      " &> /dev/null");
+    }
+
+    static bool Stop(const char* packageName) {
+        return RunCmd("am force-stop " + std::string(packageName));
+    }
+};
+
+//-------------------------------------------------------------------------------------------------
+TEST_F(ActivityManagerNativeTest, testUidImportance) {
+    pid_t selfPid = ::getpid();
+    uid_t selfUid = ::getuid();
+
+    uid_t testAppUid;
+    EXPECT_TRUE(getUidForPackage(kTestPackage, testAppUid));
+    LOG(INFO) << "testUidImportance: uidselfUid" << selfUid << ", selfPid " << selfPid
+              << ", testAppUid " << testAppUid;
+    mTestAppUid = testAppUid;
+
+    // Expect the initial UidImportance to be GONE.
+    EXPECT_FALSE(AActivityManager_isUidActive(testAppUid));
+    EXPECT_EQ(AActivityManager_getUidImportance(testAppUid), AACTIVITYMANAGER_IMPORTANCE_GONE);
+
+    mUidObserver = AActivityManager_addUidImportanceListener(&OnUidImportance,
+                                                             AACTIVITYMANAGER_IMPORTANCE_FOREGROUND,
+                                                             (void*)this);
+    EXPECT_TRUE(mUidObserver != nullptr);
+
+    // Start the test activity, and expect to receive UidImportance change to FOREGROUND.
+    EXPECT_TRUE(ShellHelper::Start(kTestPackage, kTestActivity));
+    EXPECT_TRUE(waitForImportance(AACTIVITYMANAGER_IMPORTANCE_FOREGROUND, kEventTimeoutUs));
+    EXPECT_TRUE(AActivityManager_isUidActive(testAppUid));
+    EXPECT_EQ(AActivityManager_getUidImportance(testAppUid),
+              AACTIVITYMANAGER_IMPORTANCE_FOREGROUND);
+
+    // Stop the test activity, and expect to receive UidImportance change to GONE.
+    EXPECT_TRUE(ShellHelper::Stop(kTestPackage));
+    EXPECT_TRUE(waitForImportance(AACTIVITYMANAGER_IMPORTANCE_GONE, kEventTimeoutUs));
+    EXPECT_FALSE(AActivityManager_isUidActive(testAppUid));
+    EXPECT_EQ(AActivityManager_getUidImportance(testAppUid), AACTIVITYMANAGER_IMPORTANCE_GONE);
+
+    AActivityManager_removeUidImportanceListener(mUidObserver);
+    mUidObserver = nullptr;
+}
diff --git a/native/graphics/OWNERS b/native/graphics/OWNERS
new file mode 100644
index 0000000..a6d1bc3
--- /dev/null
+++ b/native/graphics/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/graphics/OWNERS
diff --git a/opengl/java/android/opengl/OWNERS b/opengl/java/android/opengl/OWNERS
new file mode 100644
index 0000000..9c6c610
--- /dev/null
+++ b/opengl/java/android/opengl/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 25421
+
+sumir@google.com
+prahladk@google.com
diff --git a/packages/AppPredictionLib/OWNERS b/packages/AppPredictionLib/OWNERS
new file mode 100644
index 0000000..3a5d23d
--- /dev/null
+++ b/packages/AppPredictionLib/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/appprediction/OWNERS
diff --git a/packages/Backup/OWNERS b/packages/Backup/OWNERS
new file mode 100644
index 0000000..d99779e
--- /dev/null
+++ b/packages/Backup/OWNERS
@@ -0,0 +1 @@
+include /services/backup/OWNERS
diff --git a/packages/BackupEncryption/OWNERS b/packages/BackupEncryption/OWNERS
new file mode 100644
index 0000000..d99779e
--- /dev/null
+++ b/packages/BackupEncryption/OWNERS
@@ -0,0 +1 @@
+include /services/backup/OWNERS
diff --git a/packages/BackupRestoreConfirmation/OWNERS b/packages/BackupRestoreConfirmation/OWNERS
new file mode 100644
index 0000000..d99779e
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/OWNERS
@@ -0,0 +1 @@
+include /services/backup/OWNERS
diff --git a/packages/CompanionDeviceManager/AndroidManifest.xml b/packages/CompanionDeviceManager/AndroidManifest.xml
index 5247ac9..91bad7b 100644
--- a/packages/CompanionDeviceManager/AndroidManifest.xml
+++ b/packages/CompanionDeviceManager/AndroidManifest.xml
@@ -31,6 +31,7 @@
     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
     <uses-permission android:name="android.permission.RADIO_SCAN_WITHOUT_LOCATION"/>
     <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+    <uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS"/>
 
     <application
         android:allowClearUserData="true"
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
index 2fe351e..fd71670 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
@@ -321,7 +321,8 @@
     }
 
     void onDeviceSelected(String callingPackage, String deviceAddress) {
-        mServiceCallback.complete(new Association(getUserId(), deviceAddress, callingPackage));
+        mServiceCallback.complete(new Association(
+                getUserId(), deviceAddress, callingPackage, mRequest.getDeviceProfile(), false));
     }
 
     void onCancel() {
diff --git a/packages/EasterEgg/OWNERS b/packages/EasterEgg/OWNERS
new file mode 100644
index 0000000..2e96c97
--- /dev/null
+++ b/packages/EasterEgg/OWNERS
@@ -0,0 +1 @@
+include /packages/SystemUI/OWNERS
diff --git a/packages/ExternalStorageProvider/OWNERS b/packages/ExternalStorageProvider/OWNERS
new file mode 100644
index 0000000..6f9dbea
--- /dev/null
+++ b/packages/ExternalStorageProvider/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/os/storage/OWNERS
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 11d1b0a..087275e 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -322,6 +322,11 @@
                 return true;
             }
 
+            if (TextUtils.equals(Environment.DIRECTORY_ANDROID.toLowerCase(),
+                    path.toLowerCase())) {
+                return true;
+            }
+
             return false;
         } catch (IOException e) {
             throw new IllegalArgumentException(
diff --git a/packages/FusedLocation/OWNERS b/packages/FusedLocation/OWNERS
new file mode 100644
index 0000000..5ac6028
--- /dev/null
+++ b/packages/FusedLocation/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/location/OWNERS
diff --git a/packages/MtpDocumentsProvider/OWNERS b/packages/MtpDocumentsProvider/OWNERS
new file mode 100644
index 0000000..6f9dbea
--- /dev/null
+++ b/packages/MtpDocumentsProvider/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/os/storage/OWNERS
diff --git a/packages/PrintRecommendationService/OWNERS b/packages/PrintRecommendationService/OWNERS
new file mode 100644
index 0000000..2c7b881
--- /dev/null
+++ b/packages/PrintRecommendationService/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/print/OWNERS
diff --git a/packages/PrintSpooler/OWNERS b/packages/PrintSpooler/OWNERS
new file mode 100644
index 0000000..2c7b881
--- /dev/null
+++ b/packages/PrintSpooler/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/print/OWNERS
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index e6492aa..23cb36f 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -54,6 +54,7 @@
         "SettingsLibEmergencyNumber",
         "SettingsLibTopIntroPreference",
         "SettingsLibBannerMessagePreference",
+        "SettingsLibFooterPreference",
     ],
 }
 
diff --git a/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java b/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java
index 12d21ca..1c0e718 100644
--- a/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java
+++ b/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java
@@ -84,8 +84,9 @@
     }
 
     private List<EmergencyNumber> getPromotedEmergencyNumbers(int categories) {
-        Map<Integer, List<EmergencyNumber>> allLists = mTelephonyManager.getEmergencyNumberList(
-                categories);
+        // TODO(b/171542607): Use platform API when its bug is fixed.
+        Map<Integer, List<EmergencyNumber>> allLists = filterEmergencyNumbersByCategories(
+                mTelephonyManager.getEmergencyNumberList(), categories);
         if (allLists == null || allLists.isEmpty()) {
             Log.w(TAG, "Unable to retrieve emergency number lists!");
             return new ArrayList<>();
@@ -130,4 +131,28 @@
         }
         return promotedEmergencyNumberLists.get(SubscriptionManager.getDefaultSubscriptionId());
     }
+
+    /**
+     * Filter emergency numbers with categories.
+     */
+    private Map<Integer, List<EmergencyNumber>> filterEmergencyNumbersByCategories(
+            Map<Integer, List<EmergencyNumber>> emergencyNumberList, int categories) {
+        Map<Integer, List<EmergencyNumber>> filteredMap = new ArrayMap<>();
+        if (emergencyNumberList == null) {
+            return filteredMap;
+        }
+        for (Integer subscriptionId : emergencyNumberList.keySet()) {
+            List<EmergencyNumber> allNumbersForSub = emergencyNumberList.get(
+                    subscriptionId);
+            List<EmergencyNumber> numbersForCategoriesPerSub = new ArrayList<>();
+            for (EmergencyNumber number : allNumbersForSub) {
+                if (number.isInEmergencyServiceCategories(categories)) {
+                    numbersForCategoriesPerSub.add(number);
+                }
+            }
+            filteredMap.put(
+                    subscriptionId, numbersForCategoriesPerSub);
+        }
+        return filteredMap;
+    }
 }
diff --git a/packages/SettingsLib/FooterPreference/Android.bp b/packages/SettingsLib/FooterPreference/Android.bp
new file mode 100644
index 0000000..30d9bd2
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/Android.bp
@@ -0,0 +1,13 @@
+android_library {
+    name: "SettingsLibFooterPreference",
+
+    srcs: ["src/**/*.java"],
+    resource_dirs: ["res"],
+
+    static_libs: [
+        "androidx.annotation_annotation",
+        "androidx.preference_preference",
+    ],
+    sdk_version: "system_current",
+    min_sdk_version: "21",
+}
diff --git a/packages/SettingsLib/FooterPreference/AndroidManifest.xml b/packages/SettingsLib/FooterPreference/AndroidManifest.xml
new file mode 100644
index 0000000..96d9e51
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.settingslib.widget">
+
+    <uses-sdk android:minSdkVersion="21" />
+
+</manifest>
diff --git a/packages/SettingsLib/FooterPreference/res/drawable/ic_info_outline_24.xml b/packages/SettingsLib/FooterPreference/res/drawable/ic_info_outline_24.xml
new file mode 100644
index 0000000..d9afeb0
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/drawable/ic_info_outline_24.xml
@@ -0,0 +1,27 @@
+<?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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"
+        android:tint="?android:attr/colorControlNormal">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
+</vector>
diff --git a/packages/SettingsLib/FooterPreference/res/values/attrs.xml b/packages/SettingsLib/FooterPreference/res/values/attrs.xml
new file mode 100644
index 0000000..deba3af
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values/attrs.xml
@@ -0,0 +1,19 @@
+<?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>
+    <attr name="footerPreferenceStyle" format="reference" />
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
new file mode 100644
index 0000000..15301f6
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
@@ -0,0 +1,139 @@
+/*
+ * 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.settingslib.widget;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.text.method.LinkMovementMethod;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
+import androidx.core.content.res.TypedArrayUtils;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+/**
+ * A custom preference acting as "footer" of a page. It has a field for icon and text. It is added
+ * to screen as the last preference.
+ */
+public class FooterPreference extends Preference {
+
+    public static final String KEY_FOOTER = "footer_preference";
+    static final int ORDER_FOOTER = Integer.MAX_VALUE - 1;
+
+    public FooterPreference(Context context, AttributeSet attrs) {
+        super(context, attrs, TypedArrayUtils.getAttr(
+                context, R.attr.footerPreferenceStyle, android.R.attr.preferenceStyle));
+        init();
+    }
+
+    public FooterPreference(Context context) {
+        this(context, null);
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+        TextView title = holder.itemView.findViewById(android.R.id.title);
+        title.setMovementMethod(new LinkMovementMethod());
+        title.setClickable(false);
+        title.setLongClickable(false);
+    }
+
+    @Override
+    public void setSummary(CharSequence summary) {
+        setTitle(summary);
+    }
+
+    @Override
+    public void setSummary(int summaryResId) {
+        setTitle(summaryResId);
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        return getTitle();
+    }
+
+    private void init() {
+        if (getIcon() == null) {
+            setIcon(R.drawable.ic_info_outline_24);
+        }
+        setOrder(ORDER_FOOTER);
+        if (TextUtils.isEmpty(getKey())) {
+            setKey(KEY_FOOTER);
+        }
+    }
+
+    /**
+     * The builder is convenient to creat a dynamic FooterPreference.
+     */
+    public static class Builder {
+        private Context mContext;
+        private String mKey;
+        private CharSequence mTitle;
+
+        public Builder(@NonNull Context context) {
+            mContext = context;
+        }
+
+        /**
+         * To set the key value of the {@link FooterPreference}.
+         * @param key The key value.
+         */
+        public Builder setKey(@NonNull String key) {
+            mKey = key;
+            return this;
+        }
+
+        /**
+         * To set the title of the {@link FooterPreference}.
+         * @param title The title.
+         */
+        public Builder setTitle(CharSequence title) {
+            mTitle = title;
+            return this;
+        }
+
+        /**
+         * To set the title of the {@link FooterPreference}.
+         * @param titleResId The resource id of the title.
+         */
+        public Builder setTitle(@StringRes int titleResId) {
+            mTitle = mContext.getText(titleResId);
+            return this;
+        }
+
+        /**
+         * To generate the {@link FooterPreference}.
+         */
+        public FooterPreference build() {
+            final FooterPreference footerPreference = new FooterPreference(mContext);
+            footerPreference.setSelectable(false);
+            if (TextUtils.isEmpty(mTitle)) {
+                throw new IllegalArgumentException("Footer title cannot be empty!");
+            }
+            footerPreference.setTitle(mTitle);
+            if (!TextUtils.isEmpty(mKey)) {
+                footerPreference.setKey(mKey);
+            }
+            return footerPreference;
+        }
+    }
+}
diff --git a/packages/SettingsLib/OWNERS b/packages/SettingsLib/OWNERS
index 8eafbdf..30c10d3 100644
--- a/packages/SettingsLib/OWNERS
+++ b/packages/SettingsLib/OWNERS
@@ -1,5 +1,5 @@
 # People who can approve changes for submission
-dsandler@android.com
+dsandler@google.com
 edgarwang@google.com
 emilychuang@google.com
 evanlaird@google.com
diff --git a/packages/SettingsLib/res/drawable/ic_info_outline_24.xml b/packages/SettingsLib/res/drawable/ic_info_outline_24.xml
deleted file mode 100644
index 317e43b..0000000
--- a/packages/SettingsLib/res/drawable/ic_info_outline_24.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  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.
-  -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
-</vector>
diff --git a/packages/SettingsLib/res/values/attrs.xml b/packages/SettingsLib/res/values/attrs.xml
index 9aed54e..1e6cb33 100644
--- a/packages/SettingsLib/res/values/attrs.xml
+++ b/packages/SettingsLib/res/values/attrs.xml
@@ -46,8 +46,6 @@
     <attr name="wifi_signal" format="reference" />
     <attr name="wifi_friction" format="reference" />
 
-    <attr name="footerPreferenceStyle" format="reference" />
-
     <!-- Workaround for b/74248169. These are duplicates of attrs in AndroidX preferences. -->
     <attr name="preferenceStyle" format="reference" />
     <attr name="switchPreferenceStyle" format="reference" />
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 9f1c96d..22213cb 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -995,8 +995,14 @@
     <!-- Settings item title for media transcoding settings. [CHAR LIMIT=85] -->
     <string name="transcode_settings_title">Media transcoding settings</string>
 
-    <!-- Settings item title to disable transcoding globally. [CHAR LIMIT=85] -->
-    <string name="transcode_enable_all">Disable transcoding</string>
+    <!-- Settings item title to enable user's control over further transcoding preferences. [CHAR LIMIT=85] -->
+    <string name="transcode_user_control">Override transcoding defaults</string>
+
+    <!-- Settings item title to enable transcoding globally. [CHAR LIMIT=85] -->
+    <string name="transcode_enable_all">Enable transcoding</string>
+
+    <!-- Settings item title to select the default behavior for transcoding if an encodig is not supported by an app. [CHAR LIMIT=85] -->
+    <string name="transcode_default">Assume apps support modern formats</string>
 
     <!-- Settings category title for selecting apps to be enabled for transcoding. [CHAR LIMIT=85] -->
     <string name="transcode_skip_apps">Enable transcoding for apps</string>
@@ -1110,7 +1116,7 @@
     <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
     <string name="power_charging_duration"><xliff:g id="level">%1$s</xliff:g> - <xliff:g id="time">%2$s</xliff:g> until charged</string>
     <!-- [CHAR_LIMIT=40] Label for battery level chart when charge been limited -->
-    <string name="power_charging_limited"><xliff:g id="level">%1$s</xliff:g> - Battery limited temporarily</string>
+    <string name="power_charging_limited"><xliff:g id="level">%1$s</xliff:g> - Optimizing for battery health</string>
 
     <!-- Battery Info screen. Value for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
     <string name="battery_info_status_unknown">Unknown</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
index f9bb90e..b3205d7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
@@ -16,6 +16,7 @@
 
 package com.android.settingslib.fuelgauge;
 
+import static android.os.BatteryManager.BATTERY_HEALTH_OVERHEAT;
 import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN;
 import static android.os.BatteryManager.BATTERY_STATUS_FULL;
 import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
@@ -128,6 +129,15 @@
     }
 
     /**
+     * Whether battery is overheated.
+     *
+     * @return true if battery is overheated
+     */
+    public boolean isOverheated() {
+        return health == BATTERY_HEALTH_OVERHEAT;
+    }
+
+    /**
      * Return current chargin speed is fast, slow or normal.
      *
      * @return the charing speed
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
index 41d6afc..f21c359 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
@@ -38,6 +38,7 @@
 import android.media.MediaRoute2Info;
 import android.media.MediaRouter2Manager;
 import android.text.TextUtils;
+import android.util.Log;
 
 import androidx.annotation.IntDef;
 import androidx.annotation.VisibleForTesting;
@@ -46,6 +47,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -199,6 +201,10 @@
      */
 
     public void requestSetVolume(int volume) {
+        if (mRouteInfo == null) {
+            Log.w(TAG, "Unable to set volume. RouteInfo is empty");
+            return;
+        }
         mRouterManager.setRouteVolume(mRouteInfo, volume);
     }
 
@@ -208,6 +214,10 @@
      * @return max volume.
      */
     public int getMaxVolume() {
+        if (mRouteInfo == null) {
+            Log.w(TAG, "Unable to get max volume. RouteInfo is empty");
+            return 0;
+        }
         return mRouteInfo.getVolumeMax();
     }
 
@@ -217,6 +227,10 @@
      * @return current volume.
      */
     public int getCurrentVolume() {
+        if (mRouteInfo == null) {
+            Log.w(TAG, "Unable to get current volume. RouteInfo is empty");
+            return 0;
+        }
         return mRouteInfo.getVolume();
     }
 
@@ -226,6 +240,10 @@
      * @return package name.
      */
     public String getClientPackageName() {
+        if (mRouteInfo == null) {
+            Log.w(TAG, "Unable to get client package name. RouteInfo is empty");
+            return null;
+        }
         return mRouteInfo.getClientPackageName();
     }
 
@@ -244,6 +262,10 @@
      * @return result of transfer media
      */
     public boolean connect() {
+        if (mRouteInfo == null) {
+            Log.w(TAG, "Unable to connect. RouteInfo is empty");
+            return false;
+        }
         setConnectedRecord();
         mRouterManager.selectRoute(mPackageName, mRouteInfo);
         return true;
@@ -358,6 +380,10 @@
      * Gets the supported features of the route.
      */
     public List<String> getFeatures() {
+        if (mRouteInfo == null) {
+            Log.w(TAG, "Unable to get features. RouteInfo is empty");
+            return new ArrayList<>();
+        }
         return mRouteInfo.getFeatures();
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
deleted file mode 100644
index 1557618..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2016 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.settingslib.widget;
-
-import android.annotation.StringRes;
-import android.content.Context;
-import android.text.TextUtils;
-import android.text.method.LinkMovementMethod;
-import android.util.AttributeSet;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.core.content.res.TypedArrayUtils;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceViewHolder;
-
-import com.android.settingslib.R;
-
-/**
- * A custom preference acting as "footer" of a page. It has a field for icon and text. It is added
- * to screen as the last preference.
- */
-public class FooterPreference extends Preference {
-
-    static final int ORDER_FOOTER = Integer.MAX_VALUE - 1;
-    public static final String KEY_FOOTER = "footer_preference";
-
-    public FooterPreference(Context context, AttributeSet attrs) {
-        super(context, attrs, TypedArrayUtils.getAttr(
-                context, R.attr.footerPreferenceStyle, android.R.attr.preferenceStyle));
-        init();
-    }
-
-    public FooterPreference(Context context) {
-        this(context, null);
-    }
-
-    @Override
-    public void onBindViewHolder(PreferenceViewHolder holder) {
-        super.onBindViewHolder(holder);
-        TextView title = holder.itemView.findViewById(android.R.id.title);
-        title.setMovementMethod(new LinkMovementMethod());
-        title.setClickable(false);
-        title.setLongClickable(false);
-    }
-
-    @Override
-    public void setSummary(CharSequence summary) {
-        setTitle(summary);
-    }
-
-    @Override
-    public void setSummary(int summaryResId) {
-        setTitle(summaryResId);
-    }
-
-    @Override
-    public CharSequence getSummary() {
-        return getTitle();
-    }
-
-    private void init() {
-        if (getIcon() == null) {
-            setIcon(R.drawable.ic_info_outline_24);
-        }
-        setOrder(ORDER_FOOTER);
-        if (TextUtils.isEmpty(getKey())) {
-            setKey(KEY_FOOTER);
-        }
-    }
-
-    /**
-     * The builder is convenient to creat a dynamic FooterPreference.
-     */
-    public static class Builder {
-        private Context mContext;
-        private String mKey;
-        private CharSequence mTitle;
-
-        public Builder(@NonNull Context context) {
-            mContext = context;
-        }
-
-        /**
-         * To set the key value of the {@link FooterPreference}.
-         * @param key The key value.
-         */
-        public Builder setKey(@NonNull String key) {
-            mKey = key;
-            return this;
-        }
-
-        /**
-         * To set the title of the {@link FooterPreference}.
-         * @param title The title.
-         */
-        public Builder setTitle(CharSequence title) {
-            mTitle = title;
-            return this;
-        }
-
-        /**
-         * To set the title of the {@link FooterPreference}.
-         * @param titleResId The resource id of the title.
-         */
-        public Builder setTitle(@StringRes int titleResId) {
-            mTitle = mContext.getText(titleResId);
-            return this;
-        }
-
-        /**
-         * To generate the {@link FooterPreference}.
-         */
-        public FooterPreference build() {
-            final FooterPreference footerPreference = new FooterPreference(mContext);
-            footerPreference.setSelectable(false);
-            if (TextUtils.isEmpty(mTitle)) {
-                throw new IllegalArgumentException("Footer title cannot be empty!");
-            }
-            footerPreference.setTitle(mTitle);
-            if (!TextUtils.isEmpty(mKey)) {
-                footerPreference.setKey(mKey);
-            }
-            return footerPreference;
-        }
-    }
-}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
index 47d4beb..6f7f73a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
@@ -465,4 +465,12 @@
         assertThat(mInfoMediaDevice1.getState()).isEqualTo(
                 LocalMediaManager.MediaDeviceState.STATE_CONNECTING_FAILED);
     }
+
+    @Test
+    public void getFeatures_noRouteInfo_returnEmptyList() {
+        mBluetoothMediaDevice1 = new BluetoothMediaDevice(mContext, mCachedDevice1,
+                mMediaRouter2Manager, null /* MediaRoute2Info */, TEST_PACKAGE_NAME);
+
+        assertThat(mBluetoothMediaDevice1.getFeatures().size()).isEqualTo(0);
+    }
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/DiscreteValueValidator.java b/packages/SettingsProvider/src/android/provider/settings/validators/DiscreteValueValidator.java
index 183651f..e7d870e 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/DiscreteValueValidator.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/DiscreteValueValidator.java
@@ -34,6 +34,6 @@
 
     @Override
     public boolean validate(@Nullable String value) {
-        return ArrayUtils.contains(mValues, value);
+        return value == null || ArrayUtils.contains(mValues, value);
     }
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index a02d67f..668e267 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -34,10 +34,6 @@
  * Validators for Global settings
  */
 public class GlobalSettingsValidators {
-    /**
-     * All settings in {@link Global.SETTINGS_TO_BACKUP} array *must* have a non-null validator,
-     * otherwise they won't be restored.
-     */
     public static final Map<String, Validator> VALIDATORS = new ArrayMap<>();
 
     static {
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/InclusiveFloatRangeValidator.java b/packages/SettingsProvider/src/android/provider/settings/validators/InclusiveFloatRangeValidator.java
index 1a0b88c..58620b5 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/InclusiveFloatRangeValidator.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/InclusiveFloatRangeValidator.java
@@ -34,6 +34,9 @@
 
     @Override
     public boolean validate(@Nullable String value) {
+        if (value == null) {
+            return true;
+        }
         try {
             final float floatValue = Float.parseFloat(value);
             return floatValue >= mMin && floatValue <= mMax;
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/InclusiveIntegerRangeValidator.java b/packages/SettingsProvider/src/android/provider/settings/validators/InclusiveIntegerRangeValidator.java
index f9f8ce8..aa27c877 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/InclusiveIntegerRangeValidator.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/InclusiveIntegerRangeValidator.java
@@ -34,6 +34,9 @@
 
     @Override
     public boolean validate(@Nullable String value) {
+        if (value == null) {
+            return true;
+        }
         try {
             final int intValue = Integer.parseInt(value);
             return intValue >= mMin && intValue <= mMax;
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 9331b5e..517fa54 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -42,11 +42,6 @@
  * Validators for the Secure Settings.
  */
 public class SecureSettingsValidators {
-    /**
-     * All settings in {@link Secure.SETTINGS_TO_BACKUP} and {@link
-     * DeviceSpecificSettings.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP} array *must* have a non-null
-     * validator, otherwise they won't be restored.
-     */
     public static final Map<String, Validator> VALIDATORS = new ArrayMap<>();
 
     static {
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
index 8d5c6e6..97e1d68 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
@@ -16,6 +16,7 @@
 
 package android.provider.settings.validators;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.net.Uri;
@@ -48,6 +49,9 @@
     public static final Validator NON_NEGATIVE_INTEGER_VALIDATOR = new Validator() {
         @Override
         public boolean validate(@Nullable String value) {
+            if (value == null) {
+                return true;
+            }
             try {
                 return Integer.parseInt(value) >= 0;
             } catch (NumberFormatException e) {
@@ -59,6 +63,9 @@
     public static final Validator ANY_INTEGER_VALIDATOR = new Validator() {
         @Override
         public boolean validate(@Nullable String value) {
+            if (value == null) {
+                return true;
+            }
             try {
                 Integer.parseInt(value);
                 return true;
@@ -71,6 +78,9 @@
     public static final Validator URI_VALIDATOR = new Validator() {
         @Override
         public boolean validate(@Nullable String value) {
+            if (value == null) {
+                return true;
+            }
             try {
                 Uri.decode(value);
                 return true;
@@ -87,7 +97,7 @@
      */
     public static final Validator COMPONENT_NAME_VALIDATOR = new Validator() {
         @Override
-        public boolean validate(@Nullable String value) {
+        public boolean validate(@NonNull String value) {
             return value != null && ComponentName.unflattenFromString(value) != null;
         }
     };
@@ -104,18 +114,15 @@
 
     public static final Validator PACKAGE_NAME_VALIDATOR = new Validator() {
         @Override
-        public boolean validate(@Nullable String value) {
+        public boolean validate(@NonNull String value) {
             return value != null && isStringPackageName(value);
         }
 
-        private boolean isStringPackageName(String value) {
+        private boolean isStringPackageName(@NonNull String value) {
             // The name may contain uppercase or lowercase letters ('A' through 'Z'), numbers,
             // and underscores ('_'). However, individual package name parts may only
             // start with letters.
             // (https://developer.android.com/guide/topics/manifest/manifest-element.html#package)
-            if (value == null) {
-                return false;
-            }
             String[] subparts = value.split("\\.");
             boolean isValidPackageName = true;
             for (String subpart : subparts) {
@@ -143,7 +150,7 @@
         @Override
         public boolean validate(@Nullable String value) {
             if (value == null) {
-                return false;
+                return true;
             }
             return value.length() <= MAX_IPV6_LENGTH;
         }
@@ -153,7 +160,7 @@
         @Override
         public boolean validate(@Nullable String value) {
             if (value == null) {
-                return false;
+                return true;
             }
             Locale[] validLocales = Locale.getAvailableLocales();
             for (Locale locale : validLocales) {
@@ -167,6 +174,9 @@
 
     /** {@link Validator} that checks whether a value is a valid {@link JSONObject}. */
     public static final Validator JSON_OBJECT_VALIDATOR = (value) -> {
+        if (value == null) {
+            return true;
+        }
         if (TextUtils.isEmpty(value)) {
             return false;
         }
@@ -184,6 +194,9 @@
 
     static final Validator DATE_FORMAT_VALIDATOR = value -> {
         try {
+            if (value == null) {
+                return true;
+            }
             new SimpleDateFormat(value);
             return true;
         } catch (IllegalArgumentException | NullPointerException e) {
@@ -211,6 +224,9 @@
     static final Validator NONE_NEGATIVE_LONG_VALIDATOR = new Validator() {
         @Override
         public boolean validate(String value) {
+            if (value == null) {
+                return true;
+            }
             try {
                 return Long.parseLong(value) >= 0;
             } catch (NumberFormatException e) {
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index c5d4fa9..d278c59 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -38,12 +38,6 @@
  * Validators for System settings
  */
 public class SystemSettingsValidators {
-    /**
-     * These are all public system settings
-     *
-     * <p>All settings in {@link System.SETTINGS_TO_BACKUP} array *must* have a non-null validator,
-     * otherwise they won't be restored.
-     */
     @UnsupportedAppUsage
     public static final Map<String, Validator> VALIDATORS = new ArrayMap<>();
 
@@ -89,15 +83,7 @@
                         return value == null || value.length() < MAX_LENGTH;
                     }
                 });
-        VALIDATORS.put(
-                System.FONT_SCALE,
-                value -> {
-                    try {
-                        return Float.parseFloat(value) >= 0;
-                    } catch (NumberFormatException | NullPointerException e) {
-                        return false;
-                    }
-                });
+        VALIDATORS.put(System.FONT_SCALE, new InclusiveFloatRangeValidator(0.85f, 1.3f));
         VALIDATORS.put(System.DIM_SCREEN, BOOLEAN_VALIDATOR);
         VALIDATORS.put(
                 System.DISPLAY_COLOR_MODE,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index a61e3cd..c9e3b6f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3342,7 +3342,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 195;
+            private static final int SETTINGS_VERSION = 196;
 
             private final int mUserId;
 
@@ -4777,6 +4777,15 @@
                     currentVersion = 195;
                 }
 
+                if (currentVersion == 195) {
+                    // Version 195: delete obsolete manged services settings
+                    getSecureSettingsLocked(userId).deleteSettingLocked(
+                            Secure.ENABLED_NOTIFICATION_ASSISTANT);
+                    getSecureSettingsLocked(userId).deleteSettingLocked(
+                            Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES);
+                    currentVersion = 196;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 75eea8d..c740bac 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -146,7 +146,6 @@
                     Settings.Global.BROADCAST_OFFLOAD_CONSTANTS,
                     Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD,
                     Settings.Global.BATTERY_DISCHARGE_THRESHOLD,
-                    Settings.Global.BATTERY_SAVER_ADAPTIVE_DEVICE_SPECIFIC_CONSTANTS,
                     Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS,
                     Settings.Global.BATTERY_STATS_CONSTANTS,
                     Settings.Global.BINDER_CALLS_STATS,
@@ -232,7 +231,6 @@
                     Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_VR,
                     Settings.Global.DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH,
                     Settings.Global.DEVICE_DEMO_MODE,
-                    Settings.Global.BATTERY_SAVER_ADAPTIVE_CONSTANTS,
                     Settings.Global.BATTERY_SAVER_CONSTANTS,
                     Settings.Global.BATTERY_TIP_CONSTANTS,
                     Settings.Global.DEFAULT_SM_DP_PLUS,
diff --git a/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java b/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java
index 9134d87..e5d148c 100644
--- a/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java
@@ -56,8 +56,8 @@
     }
 
     @Test
-    public void testNonNegativeIntegerValidator_onNullValue_returnsFalse() {
-        assertFalse(SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR.validate(null));
+    public void testNonNegativeIntegerValidator_onNullValue_returnsTrue() {
+        assertTrue(SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR.validate(null));
     }
 
     @Test
@@ -69,8 +69,8 @@
     }
 
     @Test
-    public void testAnyIntegerValidator_onNullValue_returnsFalse() {
-        assertFalse(SettingsValidators.ANY_INTEGER_VALIDATOR.validate(null));
+    public void testAnyIntegerValidator_onNullValue_returnsTrue() {
+        assertTrue(SettingsValidators.ANY_INTEGER_VALIDATOR.validate(null));
     }
 
     @Test
@@ -91,8 +91,8 @@
     }
 
     @Test
-    public void testLenientIpAddressValidator_onNullValue_returnsFalse() {
-        assertFalse(SettingsValidators.LENIENT_IP_ADDRESS_VALIDATOR.validate(null));
+    public void testLenientIpAddressValidator_onNullValue_returnsTrue() {
+        assertTrue(SettingsValidators.LENIENT_IP_ADDRESS_VALIDATOR.validate(null));
     }
 
     @Test
@@ -120,8 +120,8 @@
     }
 
     @Test
-    public void testLocaleValidator_onNullValue_returnsFalse() {
-        assertFalse(SettingsValidators.LOCALE_VALIDATOR.validate(null));
+    public void testLocaleValidator_onNullValue_returnsTrue() {
+        assertTrue(SettingsValidators.LOCALE_VALIDATOR.validate(null));
     }
 
     @Test
@@ -149,11 +149,11 @@
     }
 
     @Test
-    public void testDiscreteValueValidator_onNullValue_returnsFalse() {
+    public void testDiscreteValueValidator_onNullValue_returnsTrue() {
         String[] discreteTypes = new String[]{"Type1", "Type2"};
         Validator v = new DiscreteValueValidator(discreteTypes);
 
-        assertFalse(v.validate(null));
+        assertTrue(v.validate(null));
     }
 
     @Test
@@ -167,10 +167,10 @@
     }
 
     @Test
-    public void testInclusiveIntegerRangeValidator_onNullValue_returnsFalse() {
+    public void testInclusiveIntegerRangeValidator_onNullValue_returnsTrue() {
         Validator v = new InclusiveIntegerRangeValidator(0, 5);
 
-        assertFalse(v.validate(null));
+        assertTrue(v.validate(null));
     }
 
     @Test
@@ -184,10 +184,10 @@
     }
 
     @Test
-    public void testInclusiveFloatRangeValidator_onNullValue_returnsFalse() {
+    public void testInclusiveFloatRangeValidator_onNullValue_returnsTrue() {
         Validator v = new InclusiveFloatRangeValidator(0.0f, 5.0f);
 
-        assertFalse(v.validate(null));
+        assertTrue(v.validate(null));
     }
 
     @Test
@@ -220,8 +220,8 @@
     }
 
     @Test
-    public void dateFormatValidator_onNullValue_returnsFalse() {
-        assertFalse(SettingsValidators.DATE_FORMAT_VALIDATOR.validate(null));
+    public void dateFormatValidator_onNullValue_returnsTrue() {
+        assertTrue(SettingsValidators.DATE_FORMAT_VALIDATOR.validate(null));
     }
 
     @Test
@@ -240,8 +240,8 @@
     }
 
     @Test
-    public void testJSONObjectValidator_onNullValue_returnsFalse() {
-        assertFalse(SettingsValidators.JSON_OBJECT_VALIDATOR.validate(null));
+    public void testJSONObjectValidator_onNullValue_returnsTrue() {
+        assertTrue(SettingsValidators.JSON_OBJECT_VALIDATOR.validate(null));
     }
 
     @Test
diff --git a/packages/SharedStorageBackup/OWNERS b/packages/SharedStorageBackup/OWNERS
new file mode 100644
index 0000000..d99779e
--- /dev/null
+++ b/packages/SharedStorageBackup/OWNERS
@@ -0,0 +1 @@
+include /services/backup/OWNERS
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 92b1ca7..7b1257b0 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -281,6 +281,9 @@
     <uses-permission android:name="android.permission.MANAGE_NOTIFICATIONS"/>
     <uses-permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS"/>
 
+    <!-- Permission needed for CTS test - MusicRecognitionManagerTest -->
+    <uses-permission android:name="android.permission.MANAGE_MUSIC_RECOGNITION" />
+
     <!-- Permissions required to test ambient display. -->
     <uses-permission android:name="android.permission.READ_DREAM_STATE"/>
     <uses-permission android:name="android.permission.WRITE_DREAM_STATE"/>
@@ -347,9 +350,18 @@
     <!-- Permissions required for CTS test - NotificationManagerTest -->
     <uses-permission android:name="android.permission.MANAGE_NOTIFICATION_LISTENERS" />
 
+    <!-- Permissions required for CTS test - CtsContactsProviderTestCases -->
+    <uses-permission android:name="android.contacts.permission.MANAGE_SIM_ACCOUNTS" />
+
+    <!-- Permissions required for CTS test - CarrierMessagingServiceWrapprTest -->
+    <uses-permission android:name="android.permission.BIND_CARRIER_SERVICES" />
+
     <!-- Allows overriding the system's device state from the shell -->
     <uses-permission android:name="android.permission.CONTROL_DEVICE_STATE"/>
 
+    <!-- Permissions required for CTS tests to close system dialogs -->
+    <uses-permission android:name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS" />
+
     <application android:label="@string/app_label"
                 android:theme="@android:style/Theme.DeviceDefault.DayNight"
                 android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/Shell/OWNERS b/packages/Shell/OWNERS
index 6ba1fcb..2d7a3e6 100644
--- a/packages/Shell/OWNERS
+++ b/packages/Shell/OWNERS
@@ -1,6 +1,6 @@
 set noparent
 
-jsharkey@android.com
+jsharkey@google.com
 felipeal@google.com
 nandana@google.com
 svetoslavganov@google.com
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 2da958f..285c4a1 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -576,6 +576,7 @@
             android:launchMode="singleInstance">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
+                <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index f884270..3bda710 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -1,6 +1,6 @@
 set noparent
 
-dsandler@android.com
+dsandler@google.com
 
 aaliomer@google.com
 adamcohen@google.com
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
index 6c6c927..3058d94 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
@@ -127,6 +127,13 @@
     default void onTimeZoneChanged(TimeZone timeZone) {}
 
     /**
+     * Notifies that the time format has changed.
+     *
+     * @param timeFormat "12" for 12-hour format, "24" for 24-hour format
+     */
+    default void onTimeFormatChanged(String timeFormat) {}
+
+    /**
      * Indicates whether the keyguard status area (date) should be shown below
      * the clock.
      */
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index c82bda6..19f8248 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -73,13 +73,15 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:gravity="right"
-            android:textSize="80dp"
+            android:textSize="100dp"
             android:letterSpacing="0.02"
             android:lineSpacingMultiplier=".8"
             android:includeFontPadding="false"
             android:fontFamily="@font/clock"
             android:typeface="monospace"
             android:elegantTextHeight="false"
+            dozeWeight="200"
+            lockScreenWeight="300"
         />
     </FrameLayout>
     <FrameLayout
@@ -95,13 +97,15 @@
             android:layout_height="wrap_content"
             android:layout_gravity="center_horizontal"
             android:gravity="center_horizontal"
-            android:textSize="180dp"
+            android:textSize="200dp"
             android:letterSpacing="0.02"
             android:lineSpacingMultiplier=".8"
             android:includeFontPadding="false"
             android:fontFamily="@font/clock"
             android:typeface="monospace"
             android:elegantTextHeight="false"
+            dozeWeight="100"
+            lockScreenWeight="400"
         />
     </FrameLayout>
     <include layout="@layout/keyguard_status_area"
diff --git a/packages/SystemUI/res-keyguard/values/attrs.xml b/packages/SystemUI/res-keyguard/values/attrs.xml
index 293b683..bfcc56c 100644
--- a/packages/SystemUI/res-keyguard/values/attrs.xml
+++ b/packages/SystemUI/res-keyguard/values/attrs.xml
@@ -39,4 +39,9 @@
     </declare-styleable>
 
     <attr name="passwordStyle" format="reference" />
+
+    <declare-styleable name="AnimatableClockView">
+        <attr name="dozeWeight" format="integer" />
+        <attr name="lockScreenWeight" format="integer" />
+    </declare-styleable>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index d95ab37..4b662137 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -79,8 +79,8 @@
          is not fully charged, and it's plugged into a slow charger, say that it's charging slowly.  -->
     <string name="keyguard_plugged_in_charging_slowly"><xliff:g id="percentage">%s</xliff:g> • Charging slowly</string>
 
-    <!-- When the lock screen is showing and the phone plugged in, and the defend mode is triggered, say that it's limited temporarily.  -->
-    <string name="keyguard_plugged_in_charging_limited"><xliff:g id="percentage">%s</xliff:g> • Battery limited temporarily</string>
+    <!-- When the lock screen is showing and the phone plugged in, and the defend mode is triggered, say that it's optimizing for battery health.  -->
+    <string name="keyguard_plugged_in_charging_limited"><xliff:g id="percentage">%s</xliff:g> • Optimizing for battery health</string>
 
     <!-- When the lock screen is showing and the battery is low, warn user to plug
          in the phone soon. -->
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index bc48e8f..71a1cc2 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -137,5 +137,4 @@
         <item name="android:shadowColor">@color/keyguard_shadow_color</item>
         <item name="android:shadowRadius">?attr/shadowRadius</item>
     </style>
-
 </resources>
diff --git a/packages/SystemUI/res/color/qs_background_dark.xml b/packages/SystemUI/res/color/qs_background_dark.xml
deleted file mode 100644
index c47959a..0000000
--- a/packages/SystemUI/res/color/qs_background_dark.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:alpha="1"
-          android:color="?android:attr/colorBackground"/>
-</selector>
diff --git a/packages/SystemUI/res/drawable/brightness_mirror_background.xml b/packages/SystemUI/res/drawable/brightness_mirror_background.xml
index 43c9b73..02261b2 100644
--- a/packages/SystemUI/res/drawable/brightness_mirror_background.xml
+++ b/packages/SystemUI/res/drawable/brightness_mirror_background.xml
@@ -15,6 +15,6 @@
   ~ limitations under the License
   -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="@color/qs_background_dark" />
+    <solid android:color="?android:attr/colorBackground" />
     <corners android:radius="8dp" />
 </shape>
diff --git a/packages/SystemUI/res/drawable/people_space_activity_card.xml b/packages/SystemUI/res/drawable/people_space_activity_card.xml
new file mode 100644
index 0000000..81162d2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/people_space_activity_card.xml
@@ -0,0 +1,19 @@
+<!--
+  ~ 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">
+    <solid android:color="?android:attr/colorAccent" />
+    <corners android:radius="@dimen/people_space_widget_radius" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_background_primary.xml b/packages/SystemUI/res/drawable/qs_background_primary.xml
deleted file mode 100644
index dd74cadd..0000000
--- a/packages/SystemUI/res/drawable/qs_background_primary.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 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.
--->
-<inset xmlns:android="http://schemas.android.com/apk/res/android">
-    <shape>
-        <solid android:color="@color/qs_background_dark"/>
-        <corners android:radius="?android:attr/dialogCornerRadius" />
-    </shape>
-</inset>
diff --git a/packages/SystemUI/res/drawable/qs_footer_drag_handle.xml b/packages/SystemUI/res/drawable/qs_footer_drag_handle.xml
index 509cd1f..59dad0e 100644
--- a/packages/SystemUI/res/drawable/qs_footer_drag_handle.xml
+++ b/packages/SystemUI/res/drawable/qs_footer_drag_handle.xml
@@ -17,6 +17,6 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle" >
     <solid
-        android:color="#e5e5e5" />
+        android:color="?android:attr/textColorPrimary" />
     <corners android:radius="2dp" />
 </shape>
diff --git a/packages/SystemUI/res/layout/people_space_activity.xml b/packages/SystemUI/res/layout/people_space_activity.xml
index 67ecdaa..07af01b 100644
--- a/packages/SystemUI/res/layout/people_space_activity.xml
+++ b/packages/SystemUI/res/layout/people_space_activity.xml
@@ -17,8 +17,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/scroll"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:background="@android:color/holo_blue_light">
+    android:layout_height="match_parent">
 
     <LinearLayout
         android:id="@+id/people_space_layout"
@@ -30,16 +29,15 @@
         android:clipChildren="false"
         android:clipToPadding="false">
 
-        <ImageView
-            android:id="@+id/people_space_cloud"
-            android:layout_width="67dp"
-            android:layout_height="67dp"
+        <TextView
+            android:id="@+id/select_conversation"
+            android:text="@string/select_conversation_text"
+            android:layout_width="match_parent"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+            android:textSize="24sp"
+            android:layout_height="wrap_content"
             android:layout_gravity="center_horizontal"
-            android:scaleType="fitCenter"
-            android:focusable="false"
-            android:paddingBottom="16dp"
-            android:tint="?android:attr/colorControlNormal"
-            android:src="@drawable/cloud" />
+            android:paddingBottom="16dp" />
 
     </LinearLayout>
 </androidx.core.widget.NestedScrollView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/people_space_tile_view.xml b/packages/SystemUI/res/layout/people_space_tile_view.xml
index 80bb070..c751e7d 100644
--- a/packages/SystemUI/res/layout/people_space_tile_view.xml
+++ b/packages/SystemUI/res/layout/people_space_tile_view.xml
@@ -20,46 +20,53 @@
     android:orientation="vertical">
 
     <LinearLayout
-        android:background="@drawable/people_space_tile_view_card"
         android:orientation="vertical"
-        android:padding="16dp"
-        android:layout_marginBottom="24dp"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
+        android:background="@drawable/people_space_activity_card"
+        android:padding="12dp"
         android:elevation="4dp"
-        android:gravity="start">
+        android:layout_marginBottom="12dp"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
 
-        <ImageView
-            android:id="@+id/tile_view_package_icon"
-            android:layout_width="32dp"
-            android:layout_height="32dp"
-            android:layout_gravity="end" />
-
-        <ImageView
-            android:id="@+id/tile_view_person_icon"
-            android:layout_width="32dp"
-            android:layout_height="32dp"
-            android:layout_gravity="start" />
-
-        <TextView
-            android:id="@+id/tile_view_name"
-            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
-            android:paddingVertical="4dp"
-            android:textSize="22sp"
-            android:textColor="?android:attr/textColorPrimary"
-            android:layout_width="wrap_content"
+        <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_gravity="start" />
+            android:gravity="start">
 
-        <TextView
-            android:id="@+id/tile_view_status"
-            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
-            android:paddingVertical="4dp"
-            android:textSize="16sp"
-            android:textColor="?android:attr/textColorSecondary"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:ellipsize="end"
-            android:layout_gravity="start" />
+            <ImageView
+                android:id="@+id/tile_view_person_icon"
+                android:layout_width="48dp"
+                android:layout_height="48dp" />
+
+            <ImageView
+                android:id="@+id/tile_view_package_icon"
+                android:layout_width="16dp"
+                android:layout_marginStart="-8dp"
+                android:layout_height="16dp" />
+
+            <LinearLayout
+                android:orientation="vertical"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content">
+
+                <TextView
+                    android:id="@+id/tile_view_name"
+                    android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+                    android:paddingHorizontal="16dp"
+                    android:textSize="22sp"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content" />
+
+                <TextView
+                    android:id="@+id/tile_view_status"
+                    android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+                    android:paddingVertical="4dp"
+                    android:textSize="12sp"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:ellipsize="end" />
+            </LinearLayout>
+        </LinearLayout>
     </LinearLayout>
 </LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/people_space_widget.xml b/packages/SystemUI/res/layout/people_space_widget.xml
index b417fcf..f4db321 100644
--- a/packages/SystemUI/res/layout/people_space_widget.xml
+++ b/packages/SystemUI/res/layout/people_space_widget.xml
@@ -22,6 +22,6 @@
     android:background="@drawable/people_space_widget_background"
     android:clipChildren="false"
     android:clipToPadding="false"
-    android:padding="5dp"
+    android:padding="2dp"
     android:divider="@null"
     android:dividerHeight="0dp"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/people_space_widget_item.xml b/packages/SystemUI/res/layout/people_space_widget_item.xml
index e4de6f9..95de6d6 100644
--- a/packages/SystemUI/res/layout/people_space_widget_item.xml
+++ b/packages/SystemUI/res/layout/people_space_widget_item.xml
@@ -22,38 +22,57 @@
         android:background="@drawable/people_space_tile_view_card"
         android:id="@+id/item"
         android:orientation="vertical"
-        android:padding="6dp"
-        android:layout_marginBottom="6dp"
+        android:padding="4dp"
+        android:layout_marginBottom="2dp"
         android:elevation="4dp"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="start">
-        <ImageView
-            android:id="@+id/package_icon"
-            android:layout_width="30dp"
-            android:layout_height="30dp"
-            android:layout_gravity="end" />
-        <ImageView
-            android:id="@+id/person_icon"
-            android:layout_width="30dp"
-            android:layout_height="30dp"
-            android:layout_gravity="start" />
-        <TextView
-            android:id="@+id/name"
-            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
-            android:textSize="18sp"
-            android:textColor="?android:attr/textColorPrimary"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="start" />
-        <TextView
-            android:id="@+id/status"
-            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
-            android:paddingVertical="2dp"
-            android:textSize="14sp"
-            android:textColor="?android:attr/textColorSecondary"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="start" />
+        android:layout_height="wrap_content">
+
+        <LinearLayout
+            android:orientation="horizontal"
+            android:gravity="center_vertical"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <ImageView
+                android:id="@+id/person_icon"
+                android:layout_width="42dp"
+                android:layout_height="42dp" />
+
+            <ImageView
+                android:id="@+id/package_icon"
+                android:gravity="bottom|end"
+                android:layout_width="14dp"
+                android:layout_marginStart="-8dp"
+                android:layout_height="14dp" />
+
+            <LinearLayout
+                android:orientation="vertical"
+                android:paddingStart="4dp"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content">
+
+                <TextView
+                    android:id="@+id/name"
+                    android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+                    android:textColor="?android:attr/textColorPrimary"
+                    android:textSize="16sp"
+                    android:maxLines="1"
+                    android:ellipsize="end"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content" />
+
+                <TextView
+                    android:id="@+id/status"
+                    android:textColor="?android:attr/textColorSecondary"
+                    android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+                    android:paddingVertical="2dp"
+                    android:textSize="12sp"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:maxLines="3"
+                    android:ellipsize="end" />
+            </LinearLayout>
+        </LinearLayout>
     </LinearLayout>
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 89bf12d..387f2f2 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -25,9 +25,7 @@
     <View
         android:id="@+id/quick_settings_background"
         android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:elevation="4dp"
-        android:background="@drawable/qs_background_primary" />
+        android:layout_height="0dp" />
 
     <com.android.systemui.qs.NonInterceptingScrollView
         android:id="@+id/expanded_qs_scroll_view"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_plugin_frame.xml b/packages/SystemUI/res/layout/status_bar_expanded_plugin_frame.xml
index 69beffe..6f9d745 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_plugin_frame.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_plugin_frame.xml
@@ -25,5 +25,4 @@
     android:layout_marginTop="@dimen/notification_side_paddings"
     android:layout_marginLeft="@dimen/notification_side_paddings"
     android:layout_marginRight="@dimen/notification_side_paddings"
-    android:visibility="gone"
-    android:background="@drawable/qs_background_primary"/>
+    android:visibility="gone"/>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 01b55b7..880dd378 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -357,6 +357,9 @@
          the notification is not swiped enough to dismiss it. -->
     <bool name="config_showNotificationGear">true</bool>
 
+    <!-- Whether or not a background should be drawn behind a notification. -->
+    <bool name="config_drawNotificationBackground">true</bool>
+
     <!-- Whether or the notifications can be shown and dismissed with a drag. -->
     <bool name="config_enableNotificationShadeDrag">true</bool>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 5b74687..7989b7a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2824,13 +2824,15 @@
     <string name="build_number_copy_toast">Build number copied to clipboard.</string>
 
     <!-- Status for last interaction with exact time [CHAR LIMIT=120] -->
-    <string name="last_interaction_status" translatable="false">You last chatted <xliff:g id="duration" example="5 hours">%1$s</xliff:g> ago</string>
+    <string name="last_interaction_status" translatable="false">Last chatted <xliff:g id="duration" example="5 hours">%1$s</xliff:g> ago</string>
     <!-- Status for last interaction when less than a certain time window [CHAR LIMIT=120] -->
-    <string name="last_interaction_status_less_than" translatable="false">You last chatted less than <xliff:g id="duration" example="5 hours">%1$s</xliff:g> ago</string>
+    <string name="last_interaction_status_less_than" translatable="false">Last chatted less than <xliff:g id="duration" example="5 hours">%1$s</xliff:g> ago</string>
     <!-- Status for last interaction when over a certain time window [CHAR LIMIT=120] -->
-    <string name="last_interaction_status_over" translatable="false">You last chatted over <xliff:g id="duration" example="1 week">%1$s</xliff:g> ago</string>
+    <string name="last_interaction_status_over" translatable="false">Last chatted over <xliff:g id="duration" example="1 week">%1$s</xliff:g> ago</string>
     <!-- Status for conversation without interaction data [CHAR LIMIT=120] -->
     <string name="basic_status" translatable="false">Open conversation</string>
+    <!-- Status for conversation without interaction data [CHAR LIMIT=120] -->
+    <string name="select_conversation_text" translatable="false">Select one conversation to show in your widget:</string>
 
     <!-- Title to display in a notification when ACTION_BATTERY_CHANGED.EXTRA_PRESENT field is false
     [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/res/xml/people_space_widget_info.xml b/packages/SystemUI/res/xml/people_space_widget_info.xml
index f08c8c8..10e28c4 100644
--- a/packages/SystemUI/res/xml/people_space_widget_info.xml
+++ b/packages/SystemUI/res/xml/people_space_widget_info.xml
@@ -15,10 +15,11 @@
   -->
 
 <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
-    android:minWidth="72dp"
-    android:minHeight="150dp"
+    android:minWidth="180dp"
+    android:minHeight="40dp"
     android:updatePeriodMillis="60000"
-    android:previewImage="@drawable/cloud"
+    android:previewImage="@drawable/ic_android"
     android:resizeMode="horizontal|vertical"
+    android:configure="com.android.systemui.people.PeopleSpaceActivity"
     android:initialLayout="@layout/people_space_widget">
 </appwidget-provider>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
index c8607df..ee7030a8 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
@@ -386,7 +386,10 @@
                     }
                     Intent i = new Intent(PluginManagerImpl.DISABLE_PLUGIN).setData(
                             Uri.parse("package://" + component.flattenToString()));
-                    PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, i, 0);
+                    // TODO(b/174161910) Please replace FLAG_MUTABLE_UNAUDITED below
+                    // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
+                    PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, i,
+                            PendingIntent.FLAG_MUTABLE_UNAUDITED);
                     nb.addAction(new Action.Builder(null, "Disable plugin", pi).build());
                     mContext.getSystemService(NotificationManager.class)
                             .notify(SystemMessage.NOTE_PLUGIN, nb.build());
diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
index 3157a5a..7c6a274 100644
--- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
@@ -24,6 +24,8 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.util.ViewController;
 
+import java.util.TimeZone;
+
 /**
  * Controls the color of a GradientTextClock.
  */
@@ -62,12 +64,26 @@
     }
 
     /**
-     * Updates the time for this view.
+     * Updates the time for the view.
      */
     public void refreshTime() {
         mView.refreshTime();
     }
 
+    /**
+     * Updates the timezone for the view.
+     */
+    public void onTimeZoneChanged(TimeZone timeZone) {
+        mView.onTimeZoneChanged(timeZone);
+    }
+
+    /**
+     * Trigger a time format update
+     */
+    public void refreshFormat() {
+        mView.refreshFormat();
+    }
+
     private void initColors() {
         mLockScreenColors[0] = Utils.getColorAttrDefaultColor(getContext(),
                 com.android.systemui.R.attr.wallpaperTextColor);
diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java b/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java
index 6d1d42e..ca99563 100644
--- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java
+++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockView.java
@@ -19,13 +19,17 @@
 import android.annotation.FloatRange;
 import android.annotation.IntRange;
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.icu.text.DateTimePatternGenerator;
 import android.text.format.DateFormat;
 import android.util.AttributeSet;
 import android.widget.TextView;
 
+import com.android.systemui.R;
+
 import java.util.Calendar;
+import java.util.TimeZone;
 
 import kotlin.Unit;
 
@@ -38,11 +42,14 @@
     private static final CharSequence FORMAT_24_HOUR = "HH\nmm";
     private static final long ANIM_DURATION = 300;
 
+    private final Calendar mTime = Calendar.getInstance();
+
     private CharSequence mFormat;
     private CharSequence mDescFormat;
-    private Calendar mTime = Calendar.getInstance();
     private int[] mDozingColors;
     private int[] mLockScreenColors;
+    private final int mDozingWeight;
+    private final int mLockScreenWeight;
 
     private TextAnimator mTextAnimator = null;
     private Runnable mOnTextAnimatorInitialized;
@@ -62,13 +69,21 @@
     public AnimatableClockView(Context context, AttributeSet attrs, int defStyleAttr,
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        updateTimeFormat();
+        TypedArray ta = context.obtainStyledAttributes(
+                attrs, R.styleable.AnimatableClockView, defStyleAttr, defStyleRes);
+        try {
+            mDozingWeight = ta.getInt(R.styleable.AnimatableClockView_dozeWeight, 100);
+            mLockScreenWeight = ta.getInt(R.styleable.AnimatableClockView_lockScreenWeight, 300);
+        } finally {
+            ta.recycle();
+        }
+        refreshFormat();
     }
 
     @Override
     public void onAttachedToWindow() {
         super.onAttachedToWindow();
-        updateTimeFormat();
+        refreshFormat();
     }
 
     @Override
@@ -82,6 +97,11 @@
         setContentDescription(DateFormat.format(mDescFormat, mTime));
     }
 
+    void onTimeZoneChanged(TimeZone timeZone) {
+        mTime.setTimeZone(timeZone);
+        refreshFormat();
+    }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -113,7 +133,7 @@
     }
 
     void animateDoze(boolean isDozing, boolean animate) {
-        setTextStyle(isDozing ? 100 : 300 /* weight */,
+        setTextStyle(isDozing ? mDozingWeight : mLockScreenWeight /* weight */,
                 -1,
                 isDozing ? mDozingColors : mLockScreenColors,
                 animate);
@@ -144,10 +164,11 @@
         }
     }
 
-    private void updateTimeFormat() {
+    void refreshFormat() {
         final boolean use24HourFormat = DateFormat.is24HourFormat(getContext());
         mFormat =  use24HourFormat ? FORMAT_24_HOUR : FORMAT_12_HOUR;
         mDescFormat = getBestDateTimePattern(getContext(), use24HourFormat ? "Hm" : "hm");
+        refreshTime();
     }
 
     private static String getBestDateTimePattern(Context context, String skeleton) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 68405a1..ab7ba8a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -156,13 +156,17 @@
 
             statusAreaLP.removeRule(RelativeLayout.BELOW);
             statusAreaLP.addRule(RelativeLayout.ALIGN_PARENT_START);
+            statusAreaLP.addRule(RelativeLayout.START_OF, R.id.new_lockscreen_clock_view);
+            statusAreaLP.width = 0;
         } else {
             setPaddingRelative(0, 0, 0, 0);
             mSmallClockFrame.setVisibility(VISIBLE);
             mNewLockscreenClockFrame.setVisibility(GONE);
 
             statusAreaLP.removeRule(RelativeLayout.ALIGN_PARENT_START);
+            statusAreaLP.removeRule(RelativeLayout.START_OF);
             statusAreaLP.addRule(RelativeLayout.BELOW, R.id.clock_view);
+            statusAreaLP.width = ViewGroup.LayoutParams.WRAP_CONTENT;
         }
 
         requestLayout();
@@ -401,6 +405,17 @@
         }
     }
 
+    /**
+     * Notifies that the time format has changed.
+     *
+     * @param timeFormat "12" for 12-hour format, "24" for 24-hour format
+     */
+    public void onTimeFormatChanged(String timeFormat) {
+        if (mClockPlugin != null) {
+            mClockPlugin.onTimeFormatChanged(timeFormat);
+        }
+    }
+
     void updateColors(ColorExtractor.GradientColors colors) {
         mSupportsDarkText = colors.supportsDarkText();
         mColorPalette = colors.getColorPalette();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 829ff97..4d6e8a9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -17,7 +17,9 @@
 package com.android.keyguard;
 
 import android.app.WallpaperManager;
+import android.content.ContentResolver;
 import android.content.res.Resources;
+import android.provider.Settings;
 import android.text.format.DateFormat;
 import android.util.TypedValue;
 import android.view.View;
@@ -90,6 +92,7 @@
     };
 
     private ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
+    private String mTimeFormat;
 
     @Inject
     public KeyguardClockSwitchController(
@@ -98,7 +101,8 @@
             StatusBarStateController statusBarStateController,
             SysuiColorExtractor colorExtractor, ClockManager clockManager,
             KeyguardSliceViewController keyguardSliceViewController,
-            NotificationIconAreaController notificationIconAreaController) {
+            NotificationIconAreaController notificationIconAreaController,
+            ContentResolver contentResolver) {
         super(keyguardClockSwitch);
         mResources = resources;
         mStatusBarStateController = statusBarStateController;
@@ -106,6 +110,7 @@
         mClockManager = clockManager;
         mKeyguardSliceViewController = keyguardSliceViewController;
         mNotificationIconAreaController = notificationIconAreaController;
+        mTimeFormat = Settings.System.getString(contentResolver, Settings.System.TIME_12_24);
     }
 
     /**
@@ -246,12 +251,26 @@
 
     void updateTimeZone(TimeZone timeZone) {
         mView.onTimeZoneChanged(timeZone);
+        if (mNewLockScreenClockViewController != null) {
+            mNewLockScreenClockViewController.onTimeZoneChanged(timeZone);
+            mNewLockScreenLargeClockViewController.onTimeZoneChanged(timeZone);
+        }
     }
 
-    void refreshFormat() {
+    void refreshFormat(String timeFormat) {
+        mTimeFormat = timeFormat;
         Patterns.update(mResources);
         mView.setFormat12Hour(Patterns.sClockView12);
         mView.setFormat24Hour(Patterns.sClockView24);
+        mView.onTimeFormatChanged(mTimeFormat);
+        if (mNewLockScreenClockViewController != null) {
+            mNewLockScreenClockViewController.refreshFormat();
+            mNewLockScreenLargeClockViewController.refreshFormat();
+        }
+    }
+
+    void refreshFormat() {
+        refreshFormat(mTimeFormat);
     }
 
     float getClockTextTopPadding() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index bc81a198..826020c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -329,6 +329,11 @@
         }
 
         @Override
+        public void onTimeFormatChanged(String timeFormat) {
+            mKeyguardClockSwitchController.refreshFormat(timeFormat);
+        }
+
+        @Override
         public void onKeyguardVisibilityChanged(boolean showing) {
             if (showing) {
                 if (DEBUG) Slog.v(TAG, "refresh statusview showing:" + showing);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index a7e5195..2071cfa 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -182,6 +182,7 @@
     private static final int MSG_USER_REMOVED = 341;
     private static final int MSG_KEYGUARD_GOING_AWAY = 342;
     private static final int MSG_LOCK_SCREEN_MODE = 343;
+    private static final int MSG_TIME_FORMAT_UPDATE = 344;
 
     public static final int LOCK_SCREEN_MODE_NORMAL = 0;
     public static final int LOCK_SCREEN_MODE_LAYOUT_1 = 1;
@@ -280,6 +281,7 @@
             mCallbacks = Lists.newArrayList();
     private ContentObserver mDeviceProvisionedObserver;
     private ContentObserver mLockScreenModeObserver;
+    private ContentObserver mTimeFormatChangeObserver;
 
     private boolean mSwitchingUser;
 
@@ -1721,6 +1723,9 @@
                     case MSG_LOCK_SCREEN_MODE:
                         handleLockScreenMode();
                         break;
+                    case MSG_TIME_FORMAT_UPDATE:
+                        handleTimeFormatUpdate((String) msg.obj);
+                        break;
                     default:
                         super.handleMessage(msg);
                         break;
@@ -1866,12 +1871,25 @@
         mContext.getContentResolver().registerContentObserver(
                 Settings.Global.getUriFor(Settings.Global.SHOW_NEW_LOCKSCREEN),
                 false, mLockScreenModeObserver);
+
+        mTimeFormatChangeObserver = new ContentObserver(mHandler) {
+            @Override
+            public void onChange(boolean selfChange) {
+                mHandler.sendMessage(mHandler.obtainMessage(
+                        MSG_TIME_FORMAT_UPDATE,
+                        Settings.System.getString(
+                                mContext.getContentResolver(),
+                                Settings.System.TIME_12_24)));
+            }
+        };
+        mContext.getContentResolver().registerContentObserver(
+                Settings.System.getUriFor(Settings.System.TIME_12_24),
+                false, mTimeFormatChangeObserver, UserHandle.USER_ALL);
     }
 
     private void updateLockScreenMode() {
         final int newMode = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.SHOW_NEW_LOCKSCREEN,
-                isUdfpsEnrolled() ? 1 : 0);
+                Settings.Global.SHOW_NEW_LOCKSCREEN, LOCK_SCREEN_MODE_LAYOUT_1);
         if (newMode != mLockScreenMode) {
             mLockScreenMode = newMode;
             mHandler.sendEmptyMessage(MSG_LOCK_SCREEN_MODE);
@@ -2451,6 +2469,22 @@
     }
 
     /**
+     * Handle (@line #MSG_TIME_FORMAT_UPDATE}
+     *
+     * @param timeFormat "12" for 12-hour format, "24" for 24-hour format
+     */
+    private void handleTimeFormatUpdate(String timeFormat) {
+        Assert.isMainThread();
+        if (DEBUG) Log.d(TAG, "handleTimeFormatUpdate timeFormat=" + timeFormat);
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onTimeFormatChanged(timeFormat);
+            }
+        }
+    }
+
+    /**
      * Handle {@link #MSG_BATTERY_UPDATE}
      */
     private void handleBatteryUpdate(BatteryStatus status) {
@@ -2687,6 +2721,11 @@
             return true;
         }
 
+        // change in battery overheat
+        if (current.health != old.health) {
+            return true;
+        }
+
         return false;
     }
 
@@ -3055,6 +3094,10 @@
             mContext.getContentResolver().unregisterContentObserver(mLockScreenModeObserver);
         }
 
+        if (mTimeFormatChangeObserver != null) {
+            mContext.getContentResolver().unregisterContentObserver(mTimeFormatChangeObserver);
+        }
+
         try {
             ActivityManager.getService().unregisterUserSwitchObserver(mUserSwitchObserver);
         } catch (RemoteException e) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index b722dea..36617c2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -58,6 +58,11 @@
     public void onTimeZoneChanged(TimeZone timeZone) { }
 
     /**
+     * Called when time format changes.
+     */
+    public void onTimeFormatChanged(String timeFormat) { }
+
+    /**
      * Called when the carrier PLMN or SPN changes.
      */
     public void onRefreshCarrierInfo() { }
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
index e49a5be..e6ad1cb 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
@@ -400,7 +400,10 @@
                 case INTENT_ACTION_ACCESSIBILITY_SHORTCUT: {
                     Intent intent = new Intent(intentAction);
                     intent.setPackage(context.getPackageName());
-                    return PendingIntent.getBroadcast(context, 0, intent, 0);
+                    // TODO(b/173157883) Please replace FLAG_MUTABLE_UNAUDITED below
+                    // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
+                    return PendingIntent.getBroadcast(context, 0, intent,
+                            PendingIntent.FLAG_MUTABLE_UNAUDITED);
                 }
                 default:
                     break;
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index a330be6..ce5795c 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -103,7 +103,7 @@
 
         d.setOnShowListener(dialog -> {
             if (mBlurUtils.supportsBlursOnWindows()) {
-                background.setAlpha((int) (ScrimController.BLUR_SCRIM_ALPHA * 255));
+                background.setAlpha((int) (ScrimController.BUSY_SCRIM_ALPHA * 255));
                 mBlurUtils.applyBlur(d.getWindow().getDecorView().getViewRootImpl(),
                         mBlurUtils.blurRadiusOfRatio(1));
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
index 5cd3b33..4a633c3 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
@@ -16,19 +16,30 @@
 
 package com.android.systemui.people;
 
+import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID;
+import static android.appwidget.AppWidgetManager.INVALID_APPWIDGET_ID;
+
 import android.app.Activity;
 import android.app.INotificationManager;
 import android.app.people.IPeopleManager;
 import android.app.people.PeopleSpaceTile;
+import android.appwidget.AppWidgetManager;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
 import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.os.ServiceManager;
+import android.provider.Settings;
 import android.util.Log;
 import android.view.ViewGroup;
 
+import androidx.preference.PreferenceManager;
+
 import com.android.systemui.R;
+import com.android.systemui.people.widget.PeopleSpaceWidgetProvider;
 
 import java.util.List;
 import java.util.Map;
@@ -46,6 +57,9 @@
     private PackageManager mPackageManager;
     private LauncherApps mLauncherApps;
     private Context mContext;
+    private AppWidgetManager mAppWidgetManager;
+    private int mAppWidgetId;
+    private boolean mShowSingleConversation;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -59,7 +73,18 @@
         mPeopleManager = IPeopleManager.Stub.asInterface(
                 ServiceManager.getService(Context.PEOPLE_SERVICE));
         mLauncherApps = mContext.getSystemService(LauncherApps.class);
+        mAppWidgetManager = AppWidgetManager.getInstance(mContext);
         setTileViewsWithPriorityConversations();
+        mAppWidgetId = getIntent().getIntExtra(EXTRA_APPWIDGET_ID,
+                INVALID_APPWIDGET_ID);
+        mShowSingleConversation = Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0;
+        // Finish the configuration activity immediately if a widget is added for multiple
+        // conversations. If the mAppWidgetId is INVALID, then the activity wasn't launched as a
+        // widget configuration activity.
+        if (!mShowSingleConversation && mAppWidgetId != INVALID_APPWIDGET_ID) {
+            finishActivity();
+        }
     }
 
     /**
@@ -93,12 +118,39 @@
             tileView.setName(tile.getUserName().toString());
             tileView.setPackageIcon(mPackageManager.getApplicationIcon(pkg));
             tileView.setPersonIcon(tile.getUserIcon());
-            tileView.setOnClickListener(mLauncherApps, tile);
+            tileView.setOnClickListener(v -> storeWidgetConfiguration(tile));
         } catch (Exception e) {
             Log.e(TAG, "Couldn't retrieve shortcut information", e);
         }
     }
 
+    /** Stores the user selected configuration for {@code mAppWidgetId}. */
+    private void storeWidgetConfiguration(PeopleSpaceTile tile) {
+        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
+        SharedPreferences.Editor editor = sp.edit();
+        if (PeopleSpaceUtils.DEBUG) {
+            Log.d(TAG, "Put " + tile.getUserName() + "'s shortcut ID: "
+                    + tile.getId() + " for widget ID: "
+                    + mAppWidgetId);
+        }
+        editor.putString(String.valueOf(mAppWidgetId), tile.getId());
+        editor.commit();
+        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
+        int[] widgetIds = appWidgetManager.getAppWidgetIds(
+                new ComponentName(mContext, PeopleSpaceWidgetProvider.class));
+        PeopleSpaceUtils.updateSingleConversationWidgets(mContext, widgetIds, mAppWidgetManager,
+                mNotificationManager);
+        finishActivity();
+    }
+
+    /** Finish activity with a successful widget configuration result. */
+    private void finishActivity() {
+        Intent resultValue = new Intent();
+        resultValue.putExtra(EXTRA_APPWIDGET_ID, mAppWidgetId);
+        setResult(RESULT_OK, resultValue);
+        finish();
+    }
+
     @Override
     protected void onResume() {
         super.onResume();
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java
index 4aea5b8..9ae7847 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java
@@ -84,4 +84,9 @@
                 launcherApps.startShortcut(tile.getPackageName(), tile.getId(), null, null,
                         UserHandle.getUserHandleForUid(tile.getUid())));
     }
+
+    /** Sets the click listener of the tile directly. */
+    public void setOnClickListener(OnClickListener onClickListener) {
+        mTileView.setOnClickListener(onClickListener);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
index fe262b4..5f3ceb1 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
@@ -17,11 +17,17 @@
 package com.android.systemui.people;
 
 import android.app.INotificationManager;
+import android.app.PendingIntent;
 import android.app.people.ConversationChannel;
 import android.app.people.IPeopleManager;
 import android.app.people.PeopleSpaceTile;
+import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetManager;
 import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
 import android.content.pm.LauncherApps;
+import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.drawable.BitmapDrawable;
@@ -29,17 +35,24 @@
 import android.icu.text.MeasureFormat;
 import android.icu.util.Measure;
 import android.icu.util.MeasureUnit;
+import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.notification.ConversationChannelWrapper;
 import android.util.Log;
+import android.widget.RemoteViews;
+
+import androidx.preference.PreferenceManager;
 
 import com.android.systemui.R;
+import com.android.systemui.people.widget.LaunchConversationActivity;
+import com.android.systemui.people.widget.PeopleSpaceWidgetProvider;
 
 import java.time.Duration;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Optional;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -57,14 +70,15 @@
             Context context, INotificationManager notificationManager, IPeopleManager peopleManager,
             LauncherApps launcherApps)
             throws Exception {
-        boolean showAllConversations = Settings.Global.getInt(context.getContentResolver(),
-                Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0;
+        boolean showOnlyPriority = Settings.Global.getInt(context.getContentResolver(),
+                Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 1;
         List<ConversationChannelWrapper> conversations = notificationManager.getConversations(
                 true).getList();
         List<Map.Entry<Long, PeopleSpaceTile>> tiles = getSortedTiles(peopleManager,
                 conversations.stream().map(c ->
                         new PeopleSpaceTile.Builder(c.getShortcutInfo(), launcherApps).build()));
-        if (showAllConversations) {
+        if (!showOnlyPriority) {
+            if (DEBUG) Log.d(TAG, "Add recent conversations");
             List<ConversationChannel> recentConversations =
                     peopleManager.getRecentConversations().getList();
             List<Map.Entry<Long, PeopleSpaceTile>> recentTiles =
@@ -77,6 +91,73 @@
         return tiles;
     }
 
+    /** Updates {@code appWidgetIds} with their associated conversation stored. */
+    public static void updateSingleConversationWidgets(Context context, int[] appWidgetIds,
+            AppWidgetManager appWidgetManager, INotificationManager notificationManager) {
+        PackageManager mPackageManager = context.getPackageManager();
+        IPeopleManager mPeopleManager = IPeopleManager.Stub.asInterface(
+                ServiceManager.getService(Context.PEOPLE_SERVICE));
+        LauncherApps mLauncherApps = context.getSystemService(LauncherApps.class);
+        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
+        Intent activityIntent = new Intent(context, LaunchConversationActivity.class);
+        activityIntent.addFlags(
+                Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_CLEAR_TASK
+                        | Intent.FLAG_ACTIVITY_NO_HISTORY
+                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+        try {
+            List<Map.Entry<Long, PeopleSpaceTile>> shortcutInfos =
+                    PeopleSpaceUtils.getTiles(
+                            context, notificationManager,
+                            mPeopleManager, mLauncherApps);
+            for (int appWidgetId : appWidgetIds) {
+                RemoteViews views = new RemoteViews(context.getPackageName(),
+                        R.layout.people_space_widget_item);
+                String shortcutId = sp.getString(String.valueOf(appWidgetId), null);
+                if (DEBUG) {
+                    Log.d(TAG, "Set widget: " + appWidgetId + " with shortcut ID: " + shortcutId);
+                }
+
+                Optional<Map.Entry<Long, PeopleSpaceTile>> entry = shortcutInfos.stream().filter(
+                        e -> e.getValue().getId().equals(shortcutId)).findFirst();
+                if (!entry.isPresent() || shortcutId == null) {
+                    if (DEBUG) Log.d(TAG, "Matching conversation not found for shortcut ID");
+                    AppWidgetHost host = new AppWidgetHost(context, 0);
+                    host.deleteAppWidgetId(appWidgetId);
+                    continue;
+                }
+                PeopleSpaceTile tile = entry.get().getValue();
+
+                String status = PeopleSpaceUtils.getLastInteractionString(context,
+                        entry.get().getKey());
+                views.setTextViewText(R.id.status, status);
+                views.setTextViewText(R.id.name, tile.getUserName().toString());
+
+                activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_TILE_ID, tile.getId());
+                activityIntent.putExtra(
+                        PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME, tile.getPackageName());
+                activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_UID, tile.getUid());
+                views.setOnClickPendingIntent(R.id.item, PendingIntent.getActivity(
+                        context,
+                        appWidgetId,
+                        activityIntent,
+                        PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE));
+
+                views.setImageViewBitmap(
+                        R.id.package_icon,
+                        PeopleSpaceUtils.convertDrawableToBitmap(
+                                mPackageManager.getApplicationIcon(tile.getPackageName())
+                        )
+                );
+                views.setImageViewIcon(R.id.person_icon, tile.getUserIcon());
+                // Tell the AppWidgetManager to perform an update on the current app widget.
+                appWidgetManager.updateAppWidget(appWidgetId, views);
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to retrieve conversations to set tiles");
+        }
+    }
+
     /** Returns a list sorted by ascending last interaction time from {@code stream}. */
     private static List<Map.Entry<Long, PeopleSpaceTile>> getSortedTiles(
             IPeopleManager peopleManager, Stream<PeopleSpaceTile> stream) {
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
index 9b7cf6e..ac32e19 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
@@ -16,11 +16,14 @@
 
 package com.android.systemui.people.widget;
 
+import android.app.INotificationManager;
 import android.app.NotificationChannel;
+import android.appwidget.AppWidgetManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
 import android.util.Log;
@@ -42,13 +45,18 @@
     private static final boolean DEBUG = PeopleSpaceUtils.DEBUG;
 
     private final Context mContext;
-    private IAppWidgetService mAppWidgetManager;
+    private IAppWidgetService mAppWidgetService;
+    private AppWidgetManager mAppWidgetManager;
+    private INotificationManager mNotificationManager;
 
     @Inject
     public PeopleSpaceWidgetManager(Context context, IAppWidgetService appWidgetService) {
         if (DEBUG) Log.d(TAG, "constructor");
         mContext = context;
-        mAppWidgetManager = appWidgetService;
+        mAppWidgetService = appWidgetService;
+        mAppWidgetManager = AppWidgetManager.getInstance(context);
+        mNotificationManager = INotificationManager.Stub.asInterface(
+                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
     }
 
     /** Constructor used for testing. */
@@ -56,21 +64,24 @@
     protected PeopleSpaceWidgetManager(Context context) {
         if (DEBUG) Log.d(TAG, "constructor");
         mContext = context;
-        mAppWidgetManager = IAppWidgetService.Stub.asInterface(
+        mAppWidgetService = IAppWidgetService.Stub.asInterface(
                 ServiceManager.getService(Context.APPWIDGET_SERVICE));
     }
 
     /** AppWidgetManager setter used for testing. */
     @VisibleForTesting
-    protected void setAppWidgetManager(IAppWidgetService appWidgetService) {
-        mAppWidgetManager = appWidgetService;
+    protected void setAppWidgetManager(IAppWidgetService appWidgetService,
+            AppWidgetManager appWidgetManager, INotificationManager notificationManager) {
+        mAppWidgetService = appWidgetService;
+        mAppWidgetManager = appWidgetManager;
+        mNotificationManager = notificationManager;
     }
 
     /** Updates People Space widgets. */
     public void updateWidgets() {
         try {
             if (DEBUG) Log.d(TAG, "updateWidgets called");
-            int[] widgetIds = mAppWidgetManager.getAppWidgetIds(
+            int[] widgetIds = mAppWidgetService.getAppWidgetIds(
                     new ComponentName(mContext, PeopleSpaceWidgetProvider.class)
             );
 
@@ -80,9 +91,16 @@
             }
 
             if (DEBUG) Log.d(TAG, "updating " + widgetIds.length + " widgets");
-            mAppWidgetManager
-                    .notifyAppWidgetViewDataChanged(mContext.getOpPackageName(), widgetIds,
-                            R.id.widget_list_view);
+            boolean showSingleConversation = Settings.Global.getInt(mContext.getContentResolver(),
+                    Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0;
+            if (showSingleConversation) {
+                PeopleSpaceUtils.updateSingleConversationWidgets(mContext, widgetIds,
+                        mAppWidgetManager, mNotificationManager);
+            } else {
+                mAppWidgetService
+                        .notifyAppWidgetViewDataChanged(mContext.getOpPackageName(), widgetIds,
+                                R.id.widget_list_view);
+            }
         } catch (Exception e) {
             Log.e(TAG, "Exception: " + e);
         }
@@ -125,7 +143,8 @@
 
         @Override
         public void onNotificationRankingUpdate(
-                NotificationListenerService.RankingMap rankingMap) { }
+                NotificationListenerService.RankingMap rankingMap) {
+        }
 
         @Override
         public void onNotificationsInitialized() {
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java
index 9f84514..1ee9e0e 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetProvider.java
@@ -16,11 +16,14 @@
 
 package com.android.systemui.people.widget;
 
+import android.app.INotificationManager;
 import android.app.PendingIntent;
 import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProvider;
 import android.content.Context;
 import android.content.Intent;
+import android.os.ServiceManager;
+import android.provider.Settings;
 import android.util.Log;
 import android.widget.RemoteViews;
 
@@ -41,6 +44,14 @@
         super.onUpdate(context, appWidgetManager, appWidgetIds);
 
         if (DEBUG) Log.d(TAG, "onUpdate called");
+        boolean showSingleConversation = Settings.Global.getInt(context.getContentResolver(),
+                Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0;
+        if (showSingleConversation) {
+            PeopleSpaceUtils.updateSingleConversationWidgets(context, appWidgetIds,
+                    appWidgetManager, INotificationManager.Stub.asInterface(
+                            ServiceManager.getService(Context.NOTIFICATION_SERVICE)));
+            return;
+        }
         // Perform this loop procedure for each App Widget that belongs to this provider
         for (int appWidgetId : appWidgetIds) {
             RemoteViews views =
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index 5afe526..3866382 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -143,8 +143,6 @@
     }
 
     public void showDeviceMonitoringDialog() {
-        mHost.collapsePanels();
-        // TODO: Delay dialog creation until after panels are collapsed.
         createDialog();
     }
 
@@ -291,6 +289,7 @@
         if (which == DialogInterface.BUTTON_NEGATIVE) {
             final Intent intent = new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS);
             mDialog.dismiss();
+            // This dismisses the shade on opening the activity
             mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
         }
     }
@@ -605,6 +604,7 @@
         public void onClick(View widget) {
             final Intent intent = new Intent(Settings.ACTION_VPN_SETTINGS);
             mDialog.dismiss();
+            // This dismisses the shade on opening the activity
             mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 3765e5a..5259aa9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -117,6 +117,8 @@
     private boolean mPowerPluggedIn;
     private boolean mPowerPluggedInWired;
     private boolean mPowerCharged;
+    private boolean mBatteryOverheated;
+    private boolean mEnableBatteryDefender;
     private int mChargingSpeed;
     private int mChargingWattage;
     private int mBatteryLevel;
@@ -410,7 +412,7 @@
             } else if (!TextUtils.isEmpty(mAlignmentIndication)) {
                 mTextView.switchIndication(mAlignmentIndication);
                 mTextView.setTextColor(mContext.getColor(R.color.misalignment_text_color));
-            } else if (mPowerPluggedIn) {
+            } else if (mPowerPluggedIn || mEnableBatteryDefender) {
                 String indication = computePowerIndication();
                 if (animate) {
                     animateText(mTextView, indication);
@@ -430,7 +432,7 @@
         String trustManagedIndication = getTrustManagedIndication();
 
         String powerIndication = null;
-        if (mPowerPluggedIn) {
+        if (mPowerPluggedIn || mEnableBatteryDefender) {
             powerIndication = computePowerIndication();
         }
 
@@ -465,7 +467,7 @@
             mTextView.switchIndication(mAlignmentIndication);
             isError = true;
             hideIndication = !mBatteryPresent;
-        } else if (mPowerPluggedIn) {
+        } else if (mPowerPluggedIn || mEnableBatteryDefender) {
             if (DEBUG_CHARGING_SPEED) {
                 powerIndication += ",  " + (mChargingWattage / 1000) + " mW";
             }
@@ -545,8 +547,14 @@
             return mContext.getResources().getString(R.string.keyguard_charged);
         }
 
-        final boolean hasChargingTime = mChargingTimeRemaining > 0;
         int chargingId;
+        String percentage = NumberFormat.getPercentInstance().format(mBatteryLevel / 100f);
+        if (mBatteryOverheated) {
+            chargingId = R.string.keyguard_plugged_in_charging_limited;
+            return mContext.getResources().getString(chargingId, percentage);
+        }
+
+        final boolean hasChargingTime = mChargingTimeRemaining > 0;
         if (mPowerPluggedInWired) {
             switch (mChargingSpeed) {
                 case BatteryStatus.CHARGING_FAST:
@@ -571,8 +579,6 @@
                     : R.string.keyguard_plugged_in_wireless;
         }
 
-        String percentage = NumberFormat.getPercentInstance()
-                .format(mBatteryLevel / 100f);
         if (hasChargingTime) {
             String chargingTimeFormatted = Formatter.formatShortElapsedTimeRoundingUpToMinutes(
                     mContext, mChargingTimeRemaining);
@@ -692,6 +698,8 @@
             mChargingSpeed = status.getChargingSpeed(mContext);
             mBatteryLevel = status.level;
             mBatteryPresent = status.present;
+            mBatteryOverheated = status.isOverheated();
+            mEnableBatteryDefender = mBatteryOverheated && status.isPluggedIn();
             try {
                 mChargingTimeRemaining = mPowerPluggedIn
                         ? mBatteryInfo.computeChargeTimeRemaining() : -1;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 3c48302..7eb921b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -335,7 +335,7 @@
         }
         NotificationEntry visibleEntry = getEntryManager().getActiveNotificationUnfiltered(key);
         return isLockscreenPublicMode(mCurrentUserId) && visibleEntry != null
-                && visibleEntry.getRanking().getVisibilityOverride() == VISIBILITY_SECRET;
+                && visibleEntry.getRanking().getLockscreenVisibilityOverride() == VISIBILITY_SECRET;
     }
 
     public boolean shouldShowOnKeyguard(NotificationEntry entry) {
@@ -513,7 +513,8 @@
         }
         NotificationEntry entry = getEntryManager().getActiveNotificationUnfiltered(key);
         return entry != null
-                && entry.getRanking().getVisibilityOverride() == Notification.VISIBILITY_PRIVATE;
+                && entry.getRanking().getLockscreenVisibilityOverride() 
+                == Notification.VISIBILITY_PRIVATE;
     }
 
     private void updateCurrentProfilesCache() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
index b1c6f53..23d5369 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -120,7 +120,7 @@
                 // notifications to show in public mode
                 if (mLockscreenUserManager.isLockscreenPublicMode(currUserId)
                         || mLockscreenUserManager.isLockscreenPublicMode(notifUserId)) {
-                    if (entry.getRanking().getVisibilityOverride() == VISIBILITY_SECRET) {
+                    if (entry.getRanking().getLockscreenVisibilityOverride() == VISIBILITY_SECRET) {
                         return true;
                     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
index 37d5da2..7c5d4a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
@@ -20,6 +20,7 @@
 
 import android.app.Notification;
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.util.ArraySet;
 import android.view.NotificationHeaderView;
 import android.view.NotificationTopLineView;
@@ -168,9 +169,11 @@
 
     public void applyConversationSkin() {
         if (mAppNameText != null) {
+            final ColorStateList colors = mAppNameText.getTextColors();
             mAppNameText.setTextAppearance(
                     com.android.internal.R.style
                             .TextAppearance_DeviceDefault_Notification_Conversation_AppName);
+            mAppNameText.setTextColor(colors);
             MarginLayoutParams layoutParams = (MarginLayoutParams) mAppNameText.getLayoutParams();
             layoutParams.setMarginStart(0);
         }
@@ -189,11 +192,13 @@
 
     public void clearConversationSkin() {
         if (mAppNameText != null) {
+            final ColorStateList colors = mAppNameText.getTextColors();
             final int textAppearance = Utils.getThemeAttr(
                     mAppNameText.getContext(),
                     com.android.internal.R.attr.notificationHeaderTextAppearance,
                     com.android.internal.R.style.TextAppearance_DeviceDefault_Notification_Info);
             mAppNameText.setTextAppearance(textAppearance);
+            mAppNameText.setTextColor(colors);
             MarginLayoutParams layoutParams = (MarginLayoutParams) mAppNameText.getLayoutParams();
             final int marginStart = mAppNameText.getResources().getDimensionPixelSize(
                     com.android.internal.R.dimen.notification_header_app_name_margin_start);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index ac3b6d2..885048d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -82,6 +82,9 @@
     private ExpandableNotificationRow mTrackedHeadsUpRow;
     private float mAppearFraction;
 
+    /** Tracks the state from AlertingNotificationManager#hasNotifications() */
+    private boolean mHasAlertEntries;
+
     public AmbientState(
             Context context,
             @NonNull SectionProvider sectionProvider) {
@@ -365,10 +368,21 @@
         mPanelTracking = panelTracking;
     }
 
+    public boolean hasPulsingNotifications() {
+        return mPulsing && mHasAlertEntries;
+    }
+
     public void setPulsing(boolean hasPulsing) {
         mPulsing = hasPulsing;
     }
 
+    /**
+     * @return if we're pulsing in general
+     */
+    public boolean isPulsing() {
+        return mPulsing;
+    }
+
     public boolean isPulsing(NotificationEntry entry) {
         return mPulsing && entry.isAlerting();
     }
@@ -527,4 +541,8 @@
     public float getAppearFraction() {
         return mAppearFraction;
     }
+
+    public void setHasAlertEntries(boolean hasAlertEntries) {
+        mHasAlertEntries = hasAlertEntries;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
index ba03a50..1131a65 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
@@ -31,22 +31,175 @@
 import com.android.systemui.statusbar.notification.row.ExpandableView;
 
 /**
- * Represents the priority of a notification section and tracks first and last visible children.
+ * Represents the bounds of a section of the notification shade and handles animation when the
+ * bounds change.
  */
 public class NotificationSection {
     private @PriorityBucket int mBucket;
+    private View mOwningView;
+    private Rect mBounds = new Rect();
+    private Rect mCurrentBounds = new Rect(-1, -1, -1, -1);
+    private Rect mStartAnimationRect = new Rect();
+    private Rect mEndAnimationRect = new Rect();
+    private ObjectAnimator mTopAnimator = null;
+    private ObjectAnimator mBottomAnimator = null;
     private ExpandableView mFirstVisibleChild;
     private ExpandableView mLastVisibleChild;
 
-    NotificationSection(@PriorityBucket int bucket) {
+    NotificationSection(View owningView, @PriorityBucket int bucket) {
+        mOwningView = owningView;
         mBucket = bucket;
     }
 
+    public void cancelAnimators() {
+        if (mBottomAnimator != null) {
+            mBottomAnimator.cancel();
+        }
+        if (mTopAnimator != null) {
+            mTopAnimator.cancel();
+        }
+    }
+
+    public Rect getCurrentBounds() {
+        return mCurrentBounds;
+    }
+
+    public Rect getBounds() {
+        return mBounds;
+    }
+
+    public boolean didBoundsChange() {
+        return !mCurrentBounds.equals(mBounds);
+    }
+
+    public boolean areBoundsAnimating() {
+        return mBottomAnimator != null || mTopAnimator != null;
+    }
+
     @PriorityBucket
     public int getBucket() {
         return mBucket;
     }
 
+    public void startBackgroundAnimation(boolean animateTop, boolean animateBottom) {
+        // Left and right bounds are always applied immediately.
+        mCurrentBounds.left = mBounds.left;
+        mCurrentBounds.right = mBounds.right;
+        startBottomAnimation(animateBottom);
+        startTopAnimation(animateTop);
+    }
+
+
+    @ShadeViewRefactor(ShadeViewRefactor.RefactorComponent.STATE_RESOLVER)
+    private void startTopAnimation(boolean animate) {
+        int previousEndValue = mEndAnimationRect.top;
+        int newEndValue = mBounds.top;
+        ObjectAnimator previousAnimator = mTopAnimator;
+        if (previousAnimator != null && previousEndValue == newEndValue) {
+            return;
+        }
+        if (!animate) {
+            // just a local update was performed
+            if (previousAnimator != null) {
+                // we need to increase all animation keyframes of the previous animator by the
+                // relative change to the end value
+                int previousStartValue = mStartAnimationRect.top;
+                PropertyValuesHolder[] values = previousAnimator.getValues();
+                values[0].setIntValues(previousStartValue, newEndValue);
+                mStartAnimationRect.top = previousStartValue;
+                mEndAnimationRect.top = newEndValue;
+                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+                return;
+            } else {
+                // no new animation needed, let's just apply the value
+                setBackgroundTop(newEndValue);
+                return;
+            }
+        }
+        if (previousAnimator != null) {
+            previousAnimator.cancel();
+        }
+        ObjectAnimator animator = ObjectAnimator.ofInt(this, "backgroundTop",
+                mCurrentBounds.top, newEndValue);
+        Interpolator interpolator = Interpolators.FAST_OUT_SLOW_IN;
+        animator.setInterpolator(interpolator);
+        animator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+        // remove the tag when the animation is finished
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mStartAnimationRect.top = -1;
+                mEndAnimationRect.top = -1;
+                mTopAnimator = null;
+            }
+        });
+        animator.start();
+        mStartAnimationRect.top = mCurrentBounds.top;
+        mEndAnimationRect.top = newEndValue;
+        mTopAnimator = animator;
+    }
+
+    @ShadeViewRefactor(ShadeViewRefactor.RefactorComponent.STATE_RESOLVER)
+    private void startBottomAnimation(boolean animate) {
+        int previousStartValue = mStartAnimationRect.bottom;
+        int previousEndValue = mEndAnimationRect.bottom;
+        int newEndValue = mBounds.bottom;
+        ObjectAnimator previousAnimator = mBottomAnimator;
+        if (previousAnimator != null && previousEndValue == newEndValue) {
+            return;
+        }
+        if (!animate) {
+            // just a local update was performed
+            if (previousAnimator != null) {
+                // we need to increase all animation keyframes of the previous animator by the
+                // relative change to the end value
+                PropertyValuesHolder[] values = previousAnimator.getValues();
+                values[0].setIntValues(previousStartValue, newEndValue);
+                mStartAnimationRect.bottom = previousStartValue;
+                mEndAnimationRect.bottom = newEndValue;
+                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+                return;
+            } else {
+                // no new animation needed, let's just apply the value
+                setBackgroundBottom(newEndValue);
+                return;
+            }
+        }
+        if (previousAnimator != null) {
+            previousAnimator.cancel();
+        }
+        ObjectAnimator animator = ObjectAnimator.ofInt(this, "backgroundBottom",
+                mCurrentBounds.bottom, newEndValue);
+        Interpolator interpolator = Interpolators.FAST_OUT_SLOW_IN;
+        animator.setInterpolator(interpolator);
+        animator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+        // remove the tag when the animation is finished
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mStartAnimationRect.bottom = -1;
+                mEndAnimationRect.bottom = -1;
+                mBottomAnimator = null;
+            }
+        });
+        animator.start();
+        mStartAnimationRect.bottom = mCurrentBounds.bottom;
+        mEndAnimationRect.bottom = newEndValue;
+        mBottomAnimator = animator;
+    }
+
+    @ShadeViewRefactor(ShadeViewRefactor.RefactorComponent.SHADE_VIEW)
+    private void setBackgroundTop(int top) {
+        mCurrentBounds.top = top;
+        mOwningView.invalidate();
+    }
+
+    @ShadeViewRefactor(ShadeViewRefactor.RefactorComponent.SHADE_VIEW)
+    private void setBackgroundBottom(int bottom) {
+        mCurrentBounds.bottom = bottom;
+        mOwningView.invalidate();
+    }
+
     public ExpandableView getFirstVisibleChild() {
         return mFirstVisibleChild;
     }
@@ -66,4 +219,93 @@
         mLastVisibleChild = child;
         return changed;
     }
+
+    public void resetCurrentBounds() {
+        mCurrentBounds.set(mBounds);
+    }
+
+    /**
+     * Returns true if {@code top} is equal to the top of this section (if not currently animating)
+     * or where the top of this section will be when animation completes.
+     */
+    public boolean isTargetTop(int top) {
+        return (mTopAnimator == null && mCurrentBounds.top == top)
+                || (mTopAnimator != null && mEndAnimationRect.top == top);
+    }
+
+    /**
+     * Returns true if {@code bottom} is equal to the bottom of this section (if not currently
+     * animating) or where the bottom of this section will be when animation completes.
+     */
+    public boolean isTargetBottom(int bottom) {
+        return (mBottomAnimator == null && mCurrentBounds.bottom == bottom)
+                || (mBottomAnimator != null && mEndAnimationRect.bottom == bottom);
+    }
+
+    /**
+     * Update the bounds of this section based on it's views
+     *
+     * @param minTopPosition the minimum position that the top needs to have
+     * @param minBottomPosition the minimum position that the bottom needs to have
+     * @return the position of the new bottom
+     */
+    public int updateBounds(int minTopPosition, int minBottomPosition,
+            boolean shiftBackgroundWithFirst) {
+        int top = minTopPosition;
+        int bottom = minTopPosition;
+        ExpandableView firstView = getFirstVisibleChild();
+        if (firstView != null) {
+            // Round Y up to avoid seeing the background during animation
+            int finalTranslationY = (int) Math.ceil(ViewState.getFinalTranslationY(firstView));
+            // TODO: look into the already animating part
+            int newTop;
+            if (isTargetTop(finalTranslationY)) {
+                // we're ending up at the same location as we are now, let's just skip the
+                // animation
+                newTop = finalTranslationY;
+            } else {
+                newTop = (int) Math.ceil(firstView.getTranslationY());
+            }
+            top = Math.max(newTop, top);
+            if (firstView.showingPulsing()) {
+                // If we're pulsing, the notification can actually go below!
+                bottom = Math.max(bottom, finalTranslationY
+                        + ExpandableViewState.getFinalActualHeight(firstView));
+                if (shiftBackgroundWithFirst) {
+                    mBounds.left += Math.max(firstView.getTranslation(), 0);
+                    mBounds.right += Math.min(firstView.getTranslation(), 0);
+                }
+            }
+        }
+        top = Math.max(minTopPosition, top);
+        ExpandableView lastView = getLastVisibleChild();
+        if (lastView != null) {
+            float finalTranslationY = ViewState.getFinalTranslationY(lastView);
+            int finalHeight = ExpandableViewState.getFinalActualHeight(lastView);
+            // Round Y down to avoid seeing the background during animation
+            int finalBottom = (int) Math.floor(
+                    finalTranslationY + finalHeight - lastView.getClipBottomAmount());
+            int newBottom;
+            if (isTargetBottom(finalBottom)) {
+                // we're ending up at the same location as we are now, lets just skip the animation
+                newBottom = finalBottom;
+            } else {
+                newBottom = (int) (lastView.getTranslationY() + lastView.getActualHeight()
+                        - lastView.getClipBottomAmount());
+                // The background can never be lower than the end of the last view
+                minBottomPosition = (int) Math.min(
+                        lastView.getTranslationY() + lastView.getActualHeight(),
+                        minBottomPosition);
+            }
+            bottom = Math.max(bottom, Math.max(newBottom, minBottomPosition));
+        }
+        bottom = Math.max(top, bottom);
+        mBounds.top = top;
+        mBounds.bottom = bottom;
+        return bottom;
+    }
+
+    public boolean needsBackground() {
+        return mFirstVisibleChild != null && mBucket != BUCKET_MEDIA_CONTROLS;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index 36c5419..4f7e14b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -126,7 +126,7 @@
 
     fun createSectionsForBuckets(): Array<NotificationSection> =
             sectionsFeatureManager.getNotificationBuckets()
-                    .map { NotificationSection(it) }
+                    .map { NotificationSection(parent, it) }
                     .toTypedArray()
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 5cc17a0..4487142 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -38,9 +38,12 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Outline;
 import android.graphics.Paint;
 import android.graphics.PointF;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.UserHandle;
@@ -69,6 +72,7 @@
 import android.widget.ScrollView;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.graphics.ColorUtils;
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.keyguard.KeyguardSliceView;
@@ -153,6 +157,8 @@
     private ExpandHelper mExpandHelper;
     private NotificationSwipeHelper mSwipeHelper;
     private int mCurrentStackHeight = Integer.MAX_VALUE;
+    private final Paint mBackgroundPaint = new Paint();
+    private final boolean mShouldDrawNotificationBackground;
     private boolean mHighPriorityBeforeSpeedBump;
     private boolean mDismissRtl;
 
@@ -251,6 +257,7 @@
     protected FooterView mFooterView;
     protected EmptyShadeView mEmptyShadeView;
     private boolean mDismissAllInProgress;
+    private boolean mFadeNotificationsOnDismiss;
     private FooterDismissListener mFooterDismissListener;
     private boolean mFlingAfterUpEvent;
 
@@ -320,6 +327,10 @@
         }
     };
     private NotificationSection[] mSections;
+    private boolean mAnimateNextBackgroundTop;
+    private boolean mAnimateNextBackgroundBottom;
+    private boolean mAnimateNextSectionBoundsChange;
+    private int mBgColor;
     private float mDimAmount;
     private ValueAnimator mDimAnimator;
     private ArrayList<ExpandableView> mTmpSortedChildren = new ArrayList<>();
@@ -330,14 +341,25 @@
         }
     };
     private ValueAnimator.AnimatorUpdateListener mDimUpdateListener
-            = animation -> setDimAmount((Float) animation.getAnimatedValue());
+            = new ValueAnimator.AnimatorUpdateListener() {
+
+        @Override
+        public void onAnimationUpdate(ValueAnimator animation) {
+            setDimAmount((Float) animation.getAnimatedValue());
+        }
+    };
     protected ViewGroup mQsContainer;
     private boolean mContinuousShadowUpdate;
+    private boolean mContinuousBackgroundUpdate;
     private ViewTreeObserver.OnPreDrawListener mShadowUpdater
             = () -> {
                 updateViewShadows();
                 return true;
             };
+    private ViewTreeObserver.OnPreDrawListener mBackgroundUpdater = () -> {
+                updateBackground();
+                return true;
+            };
     private Comparator<ExpandableView> mViewPositionComparator = (view, otherView) -> {
         float endY = view.getTranslationY() + view.getActualHeight();
         float otherEndY = otherView.getTranslationY() + otherView.getActualHeight();
@@ -356,7 +378,7 @@
             if (mAmbientState.isHiddenAtAll()) {
                 float xProgress = mHideXInterpolator.getInterpolation(
                         (1 - mLinearHideAmount) * mBackgroundXFactor);
-                outline.setRoundRect(mOutlineAnimationRect,
+                outline.setRoundRect(mBackgroundAnimationRect,
                         MathUtils.lerp(mCornerRadius / 2.0f, mCornerRadius,
                                 xProgress));
                 outline.setAlpha(1.0f - mAmbientState.getHideAmount());
@@ -365,6 +387,7 @@
             }
         }
     };
+    private PorterDuffXfermode mSrcMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
     private boolean mPulsing;
     private boolean mScrollable;
     private View mForcedScroll;
@@ -397,6 +420,7 @@
     private boolean mInHeadsUpPinnedMode;
     private boolean mHeadsUpAnimatingAway;
     private int mStatusBarState;
+    private int mCachedBackgroundColor;
     private boolean mHeadsUpGoingAwayAnimationsAllowed = true;
     private Runnable mReflingAndAnimateScroll = () -> {
         if (ANCHOR_SCROLLING) {
@@ -406,7 +430,7 @@
     };
     private int mCornerRadius;
     private int mSidePaddings;
-    private final Rect mOutlineAnimationRect = new Rect();
+    private final Rect mBackgroundAnimationRect = new Rect();
     private ArrayList<BiConsumer<Float, Float>> mExpandedHeightListeners = new ArrayList<>();
     private int mHeadsUpInset;
     private HeadsUpAppearanceController mHeadsUpAppearanceController;
@@ -426,6 +450,7 @@
 
     private final NotificationSectionsManager mSectionsManager;
     private ForegroundServiceDungeonView mFgsSectionView;
+    private boolean mAnimateBottomOnLayout;
     private float mLastSentAppear;
     private float mLastSentExpandedHeight;
     private boolean mWillExpand;
@@ -436,6 +461,7 @@
 
     private boolean mKeyguardMediaControllorVisible;
     private NotificationEntry mTopHeadsUpEntry;
+    private long mNumHeadsUp;
     private NotificationStackScrollLayoutController.TouchHandler mTouchHandler;
 
     private final ExpandableView.OnHeightChangedListener mOnChildHeightChangedListener =
@@ -502,6 +528,7 @@
         mSections = mSectionsManager.createSectionsForBuckets();
 
         mAmbientState = new AmbientState(context, mSectionsManager);
+        mBgColor = Utils.getColorAttr(mContext, android.R.attr.colorBackground).getDefaultColor();
         int minHeight = res.getDimensionPixelSize(R.dimen.notification_min_height);
         int maxHeight = res.getDimensionPixelSize(R.dimen.notification_max_height);
         mExpandHelper = new ExpandHelper(getContext(), mExpandHelperCallback,
@@ -510,9 +537,13 @@
         mExpandHelper.setScrollAdapter(mScrollAdapter);
 
         mStackScrollAlgorithm = createStackScrollAlgorithm(context);
+        mShouldDrawNotificationBackground =
+                res.getBoolean(R.bool.config_drawNotificationBackground);
         setOutlineProvider(mOutlineProvider);
 
-        setWillNotDraw(!DEBUG);
+        boolean willDraw = mShouldDrawNotificationBackground || DEBUG;
+        setWillNotDraw(!willDraw);
+        mBackgroundPaint.setAntiAlias(true);
         if (DEBUG) {
             mDebugPaint = new Paint();
             mDebugPaint.setColor(0xffff0000);
@@ -557,7 +588,7 @@
      * @return the height at which we will wake up when pulsing
      */
     public float getWakeUpHeight() {
-        ExpandableView firstChild = getFirstExpandableView();
+        ExpandableView firstChild = getFirstChildWithBackground();
         if (firstChild != null) {
             if (mKeyguardBypassEnabledProvider.getBypassEnabled()) {
                 return firstChild.getHeadsUpHeightWithoutHeader();
@@ -608,11 +639,22 @@
     }
 
     void updateBgColor() {
+        mBgColor = Utils.getColorAttr(mContext, android.R.attr.colorBackground).getDefaultColor();
+        updateBackgroundDimming();
         mShelf.onUiModeChanged();
     }
 
     @ShadeViewRefactor(RefactorComponent.DECORATOR)
     protected void onDraw(Canvas canvas) {
+        if (mShouldDrawNotificationBackground
+                && (mSections[0].getCurrentBounds().top
+                < mSections[mSections.length - 1].getCurrentBounds().bottom
+                || mAmbientState.isDozing())) {
+            drawBackground(canvas);
+        } else if (mInHeadsUpPinnedMode || mHeadsUpAnimatingAway) {
+            drawHeadsUpBackground(canvas);
+        }
+
         if (DEBUG) {
             int y = mTopPadding;
             canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
@@ -647,6 +689,160 @@
         }
     }
 
+    @ShadeViewRefactor(RefactorComponent.DECORATOR)
+    private void drawBackground(Canvas canvas) {
+        int lockScreenLeft = mSidePaddings;
+        int lockScreenRight = getWidth() - mSidePaddings;
+        int lockScreenTop = mSections[0].getCurrentBounds().top;
+        int lockScreenBottom = mSections[mSections.length - 1].getCurrentBounds().bottom;
+        int hiddenLeft = getWidth() / 2;
+        int hiddenTop = mTopPadding;
+
+        float yProgress = 1 - mInterpolatedHideAmount;
+        float xProgress = mHideXInterpolator.getInterpolation(
+                (1 - mLinearHideAmount) * mBackgroundXFactor);
+
+        int left = (int) MathUtils.lerp(hiddenLeft, lockScreenLeft, xProgress);
+        int right = (int) MathUtils.lerp(hiddenLeft, lockScreenRight, xProgress);
+        int top = (int) MathUtils.lerp(hiddenTop, lockScreenTop, yProgress);
+        int bottom = (int) MathUtils.lerp(hiddenTop, lockScreenBottom, yProgress);
+        mBackgroundAnimationRect.set(
+                left,
+                top,
+                right,
+                bottom);
+
+        int backgroundTopAnimationOffset = top - lockScreenTop;
+        // TODO(kprevas): this may not be necessary any more since we don't display the shelf in AOD
+        boolean anySectionHasVisibleChild = false;
+        for (NotificationSection section : mSections) {
+            if (section.needsBackground()) {
+                anySectionHasVisibleChild = true;
+                break;
+            }
+        }
+        boolean shouldDrawBackground;
+        if (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard()) {
+            shouldDrawBackground = isPulseExpanding();
+        } else {
+            shouldDrawBackground = !mAmbientState.isDozing() || anySectionHasVisibleChild;
+        }
+        if (shouldDrawBackground) {
+            drawBackgroundRects(canvas, left, right, top, backgroundTopAnimationOffset);
+        }
+
+        updateClipping();
+    }
+
+    /**
+     * Draws round rects for each background section.
+     *
+     * We want to draw a round rect for each background section as defined by {@link #mSections}.
+     * However, if two sections are directly adjacent with no gap between them (e.g. on the
+     * lockscreen where the shelf can appear directly below the high priority section, or while
+     * scrolling the shade so that the top of the shelf is right at the bottom of the high priority
+     * section), we don't want to round the adjacent corners.
+     *
+     * Since {@link Canvas} doesn't provide a way to draw a half-rounded rect, this means that we
+     * need to coalesce the backgrounds for adjacent sections and draw them as a single round rect.
+     * This method tracks the top of each rect we need to draw, then iterates through the visible
+     * sections.  If a section is not adjacent to the previous section, we draw the previous rect
+     * behind the sections we've accumulated up to that point, then start a new rect at the top of
+     * the current section.  When we're done iterating we will always have one rect left to draw.
+     */
+    private void drawBackgroundRects(Canvas canvas, int left, int right, int top,
+            int animationYOffset) {
+        int backgroundRectTop = top;
+        int lastSectionBottom =
+                mSections[0].getCurrentBounds().bottom + animationYOffset;
+        int currentLeft = left;
+        int currentRight = right;
+        boolean first = true;
+        for (NotificationSection section : mSections) {
+            if (!section.needsBackground()) {
+                continue;
+            }
+            int sectionTop = section.getCurrentBounds().top + animationYOffset;
+            int ownLeft = Math.min(Math.max(left, section.getCurrentBounds().left), right);
+            int ownRight = Math.max(Math.min(right, section.getCurrentBounds().right), ownLeft);
+            // If sections are directly adjacent to each other, we don't want to draw them
+            // as separate roundrects, as the rounded corners right next to each other look
+            // bad.
+            if (sectionTop - lastSectionBottom > DISTANCE_BETWEEN_ADJACENT_SECTIONS_PX
+                    || ((currentLeft != ownLeft || currentRight != ownRight) && !first)) {
+                canvas.drawRoundRect(currentLeft,
+                        backgroundRectTop,
+                        currentRight,
+                        lastSectionBottom,
+                        mCornerRadius, mCornerRadius, mBackgroundPaint);
+                backgroundRectTop = sectionTop;
+            }
+            currentLeft = ownLeft;
+            currentRight = ownRight;
+            lastSectionBottom =
+                    section.getCurrentBounds().bottom + animationYOffset;
+            first = false;
+        }
+        canvas.drawRoundRect(currentLeft,
+                backgroundRectTop,
+                currentRight,
+                lastSectionBottom,
+                mCornerRadius, mCornerRadius, mBackgroundPaint);
+    }
+
+    private void drawHeadsUpBackground(Canvas canvas) {
+        int left = mSidePaddings;
+        int right = getWidth() - mSidePaddings;
+
+        float top = getHeight();
+        float bottom = 0;
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View child = getChildAt(i);
+            if (child.getVisibility() != View.GONE
+                    && child instanceof ExpandableNotificationRow) {
+                ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+                if ((row.isPinned() || row.isHeadsUpAnimatingAway()) && row.getTranslation() < 0
+                        && row.getProvider().shouldShowGutsOnSnapOpen()) {
+                    top = Math.min(top, row.getTranslationY());
+                    bottom = Math.max(bottom, row.getTranslationY() + row.getActualHeight());
+                }
+            }
+        }
+
+        if (top < bottom) {
+            canvas.drawRoundRect(
+                    left, top, right, bottom,
+                    mCornerRadius, mCornerRadius, mBackgroundPaint);
+        }
+    }
+
+    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+    void updateBackgroundDimming() {
+        // No need to update the background color if it's not being drawn.
+        if (!mShouldDrawNotificationBackground) {
+            return;
+        }
+        final boolean newFlowHideShelf = Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.SHOW_NEW_NOTIF_DISMISS, 1 /* on by default */) == 1;
+        if (newFlowHideShelf) {
+            mBackgroundPaint.setColor(Color.TRANSPARENT);
+            invalidate();
+            return;
+        }
+        // Interpolate between semi-transparent notification panel background color
+        // and white AOD separator.
+        float colorInterpolation = MathUtils.smoothStep(0.4f /* start */, 1f /* end */,
+                mLinearHideAmount);
+        int color = ColorUtils.blendARGB(mBgColor, Color.WHITE, colorInterpolation);
+
+        if (mCachedBackgroundColor != color) {
+            mCachedBackgroundColor = color;
+            mBackgroundPaint.setColor(color);
+            invalidate();
+        }
+    }
+
     private void reinitView() {
         initView(getContext(), mKeyguardBypassEnabledProvider, mSwipeHelper);
     }
@@ -781,7 +977,7 @@
         updateContentHeight();
         clampScrollPosition();
         requestChildrenUpdate();
-        updateFirstAndLastExpandableView();
+        updateFirstAndLastBackgroundViews();
         updateAlgorithmLayoutMinHeight();
         updateOwnTranslationZ();
     }
@@ -852,6 +1048,9 @@
     private void onPreDrawDuringAnimation() {
         mShelf.updateAppearance();
         updateClippingToTopRoundedCorner();
+        if (!mNeedsAnimation && !mChildrenUpdateRequested) {
+            updateBackground();
+        }
     }
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -2168,6 +2367,131 @@
         }
     }
 
+    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+    private void updateBackground() {
+        // No need to update the background color if it's not being drawn.
+        if (!mShouldDrawNotificationBackground) {
+            return;
+        }
+
+        updateBackgroundBounds();
+        if (didSectionBoundsChange()) {
+            boolean animate = mAnimateNextSectionBoundsChange || mAnimateNextBackgroundTop
+                    || mAnimateNextBackgroundBottom || areSectionBoundsAnimating();
+            if (!isExpanded()) {
+                abortBackgroundAnimators();
+                animate = false;
+            }
+            if (animate) {
+                startBackgroundAnimation();
+            } else {
+                for (NotificationSection section : mSections) {
+                    section.resetCurrentBounds();
+                }
+                invalidate();
+            }
+        } else {
+            abortBackgroundAnimators();
+        }
+        mAnimateNextBackgroundTop = false;
+        mAnimateNextBackgroundBottom = false;
+        mAnimateNextSectionBoundsChange = false;
+    }
+
+    @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
+    private void abortBackgroundAnimators() {
+        for (NotificationSection section : mSections) {
+            section.cancelAnimators();
+        }
+    }
+
+    private boolean didSectionBoundsChange() {
+        for (NotificationSection section : mSections) {
+            if (section.didBoundsChange()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
+    private boolean areSectionBoundsAnimating() {
+        for (NotificationSection section : mSections) {
+            if (section.areBoundsAnimating()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
+    private void startBackgroundAnimation() {
+        // TODO(kprevas): do we still need separate fields for top/bottom?
+        // or can each section manage its own animation state?
+        NotificationSection firstVisibleSection = getFirstVisibleSection();
+        NotificationSection lastVisibleSection = getLastVisibleSection();
+        for (NotificationSection section : mSections) {
+            section.startBackgroundAnimation(
+                    section == firstVisibleSection
+                            ? mAnimateNextBackgroundTop
+                            : mAnimateNextSectionBoundsChange,
+                    section == lastVisibleSection
+                            ? mAnimateNextBackgroundBottom
+                            : mAnimateNextSectionBoundsChange);
+        }
+    }
+
+    /**
+     * Update the background bounds to the new desired bounds
+     */
+    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+    private void updateBackgroundBounds() {
+        int left = mSidePaddings;
+        int right = getWidth() - mSidePaddings;
+        for (NotificationSection section : mSections) {
+            section.getBounds().left = left;
+            section.getBounds().right = right;
+        }
+
+        if (!mIsExpanded) {
+            for (NotificationSection section : mSections) {
+                section.getBounds().top = 0;
+                section.getBounds().bottom = 0;
+            }
+            return;
+        }
+        int minTopPosition;
+        NotificationSection lastSection = getLastVisibleSection();
+        boolean onKeyguard = mStatusBarState == StatusBarState.KEYGUARD;
+        if (!onKeyguard) {
+            minTopPosition = (int) (mTopPadding + mStackTranslation);
+        } else if (lastSection == null) {
+            minTopPosition = mTopPadding;
+        } else {
+            // The first sections could be empty while there could still be elements in later
+            // sections. The position of these first few sections is determined by the position of
+            // the first visible section.
+            NotificationSection firstVisibleSection = getFirstVisibleSection();
+            firstVisibleSection.updateBounds(0 /* minTopPosition*/, 0 /* minBottomPosition */,
+                    false /* shiftPulsingWithFirst */);
+            minTopPosition = firstVisibleSection.getBounds().top;
+        }
+        boolean shiftPulsingWithFirst = mNumHeadsUp <= 1
+                && (mAmbientState.isDozing()
+                        || (mKeyguardBypassEnabledProvider.getBypassEnabled() && onKeyguard));
+        for (NotificationSection section : mSections) {
+            int minBottomPosition = minTopPosition;
+            if (section == lastSection) {
+                // We need to make sure the section goes all the way to the shelf
+                minBottomPosition = (int) (ViewState.getFinalTranslationY(mShelf)
+                        + mShelf.getIntrinsicHeight());
+            }
+            minTopPosition = section.updateBounds(minTopPosition, minBottomPosition,
+                    shiftPulsingWithFirst);
+            shiftPulsingWithFirst = false;
+        }
+    }
+
     private NotificationSection getFirstVisibleSection() {
         for (NotificationSection section : mSections) {
             if (section.getFirstVisibleChild() != null) {
@@ -2188,7 +2512,7 @@
     }
 
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
-    private ExpandableView getLastExpandableView() {
+    private ExpandableView getLastChildWithBackground() {
         int childCount = getChildCount();
         for (int i = childCount - 1; i >= 0; i--) {
             ExpandableView child = (ExpandableView) getChildAt(i);
@@ -2201,7 +2525,7 @@
     }
 
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
-    private ExpandableView getFirstExpandableView() {
+    private ExpandableView getFirstChildWithBackground() {
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             ExpandableView child = (ExpandableView) getChildAt(i);
@@ -2214,7 +2538,7 @@
     }
 
     //TODO: We shouldn't have to generate this list every time
-    private List<ExpandableView> getExpandableViewList() {
+    private List<ExpandableView> getChildrenWithBackground() {
         ArrayList<ExpandableView> children = new ArrayList<>();
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
@@ -2752,13 +3076,32 @@
     }
 
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
-    private void updateFirstAndLastExpandableView() {
-        ExpandableView lastChild = getLastExpandableView();
-        mSectionsManager.updateFirstAndLastViewsForAllSections(
-                mSections, getExpandableViewList());
+    private void updateFirstAndLastBackgroundViews() {
+        NotificationSection firstSection = getFirstVisibleSection();
+        NotificationSection lastSection = getLastVisibleSection();
+        ExpandableView previousFirstChild =
+                firstSection == null ? null : firstSection.getFirstVisibleChild();
+        ExpandableView previousLastChild =
+                lastSection == null ? null : lastSection.getLastVisibleChild();
+
+        ExpandableView firstChild = getFirstChildWithBackground();
+        ExpandableView lastChild = getLastChildWithBackground();
+        boolean sectionViewsChanged = mSectionsManager.updateFirstAndLastViewsForAllSections(
+                mSections, getChildrenWithBackground());
+
+        if (mAnimationsEnabled && mIsExpanded) {
+            mAnimateNextBackgroundTop = firstChild != previousFirstChild;
+            mAnimateNextBackgroundBottom = lastChild != previousLastChild || mAnimateBottomOnLayout;
+            mAnimateNextSectionBoundsChange = sectionViewsChanged;
+        } else {
+            mAnimateNextBackgroundTop = false;
+            mAnimateNextBackgroundBottom = false;
+            mAnimateNextSectionBoundsChange = false;
+        }
         mAmbientState.setLastVisibleBackgroundChild(lastChild);
         // TODO: Refactor SectionManager and put the RoundnessManager there.
         mController.getNoticationRoundessManager().updateRoundedChildren(mSections);
+        mAnimateBottomOnLayout = false;
         invalidate();
     }
 
@@ -2920,6 +3263,7 @@
             setAnimationRunning(true);
             mStateAnimator.startAnimationForEvents(mAnimationEvents, mGoToFullShadeDelay);
             mAnimationEvents.clear();
+            updateBackground();
             updateViewShadows();
             updateClippingToTopRoundedCorner();
         } else {
@@ -4004,6 +4348,7 @@
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     private void setDimAmount(float dimAmount) {
         mDimAmount = dimAmount;
+        updateBackgroundDimming();
     }
 
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@@ -4072,6 +4417,7 @@
         }
         runAnimationFinishedRunnables();
         setAnimationRunning(false);
+        updateBackground();
         updateViewShadows();
         updateClippingToTopRoundedCorner();
     }
@@ -4200,6 +4546,7 @@
             invalidateOutline();
         }
         updateAlgorithmHeightAndPadding();
+        updateBackgroundDimming();
         requestChildrenUpdate();
         updateOwnTranslationZ();
     }
@@ -5080,6 +5427,7 @@
      */
     public void setDozeAmount(float dozeAmount) {
         mAmbientState.setDozeAmount(dozeAmount);
+        updateContinuousBackgroundDrawing();
         requestChildrenUpdate();
     }
 
@@ -5117,6 +5465,7 @@
     }
 
     void setAnimateBottomOnLayout(boolean animateBottomOnLayout) {
+        mAnimateBottomOnLayout = animateBottomOnLayout;
     }
 
     public void setOnPulseHeightChangedListener(Runnable listener) {
@@ -5149,14 +5498,25 @@
 
     void onSwipeBegin() {
         requestDisallowInterceptTouchEvent(true);
+        updateFirstAndLastBackgroundViews();
         updateContinuousShadowDrawing();
+        updateContinuousBackgroundDrawing();
         requestChildrenUpdate();
     }
 
+    void onSwipeEnd() {
+        updateFirstAndLastBackgroundViews();
+    }
+
     void setTopHeadsUpEntry(NotificationEntry topEntry) {
         mTopHeadsUpEntry = topEntry;
     }
 
+    void setNumHeadsUp(long numHeadsUp) {
+        mNumHeadsUp = numHeadsUp;
+        mAmbientState.setHasAlertEntries(numHeadsUp > 0);
+    }
+
     public boolean getIsExpanded() {
         return mIsExpanded;
     }
@@ -5271,6 +5631,27 @@
         mSectionsManager.updateSectionBoundaries(reason);
     }
 
+    boolean isSilkDismissEnabled() {
+        return Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.SHOW_NEW_NOTIF_DISMISS, 1 /* enabled by default */) == 1;
+    }
+
+    void updateContinuousBackgroundDrawing() {
+        if (isSilkDismissEnabled()) {
+            return;
+        }
+        boolean continuousBackground = !mAmbientState.isFullyAwake()
+                && mSwipeHelper.isSwiping();
+        if (continuousBackground != mContinuousBackgroundUpdate) {
+            mContinuousBackgroundUpdate = continuousBackground;
+            if (continuousBackground) {
+                getViewTreeObserver().addOnPreDrawListener(mBackgroundUpdater);
+            } else {
+                getViewTreeObserver().removeOnPreDrawListener(mBackgroundUpdater);
+            }
+        }
+    }
+
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
     void updateContinuousShadowDrawing() {
         boolean continuousShadowUpdate = mAnimationRunning
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 8a03309..c2d030b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -395,6 +395,7 @@
                     if (mView.getDismissAllInProgress()) {
                         return;
                     }
+                    mView.onSwipeEnd();
                     if (view instanceof ExpandableNotificationRow) {
                         ExpandableNotificationRow row = (ExpandableNotificationRow) view;
                         if (row.isHeadsUp()) {
@@ -454,6 +455,7 @@
 
                 @Override
                 public void onChildSnappedBack(View animView, float targetLeft) {
+                    mView.onSwipeEnd();
                     if (animView instanceof ExpandableNotificationRow) {
                         ExpandableNotificationRow row = (ExpandableNotificationRow) animView;
                         if (row.isPinned() && !canChildBeDismissed(row)
@@ -517,7 +519,9 @@
 
                 @Override
                 public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
+                    long numEntries = mHeadsUpManager.getAllEntries().count();
                     NotificationEntry topEntry = mHeadsUpManager.getTopEntry();
+                    mView.setNumHeadsUp(numEntries);
                     mView.setTopHeadsUpEntry(topEntry);
                     mNotificationRoundnessManager.updateView(entry.getRow(), false /* animate */);
                 }
@@ -661,6 +665,8 @@
         mHeadsUpManager.setAnimationStateHandler(mView::setHeadsUpGoingAwayAnimationsAllowed);
         mDynamicPrivacyController.addListener(mDynamicPrivacyControllerListener);
 
+        mScrimController.setScrimBehindChangeRunnable(mView::updateBackgroundDimming);
+
         mLockscreenUserManager.addUserChangedListener(mLockscreenUserChangeListener);
 
         mFadeNotificationsOnDismiss =  // TODO: this should probably be injected directly
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 9854f54..4ca9c5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -289,6 +289,8 @@
                     SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__HIDDEN);
             mDismissCallbackRegistry.notifyDismissCancelled();
         }
+        mExpansion = EXPANSION_HIDDEN;
+        dispatchExpansionChanged();
         mIsScrimmed = false;
         mFalsingCollector.onBouncerHidden();
         mCallback.onBouncerVisiblityChanged(false /* shown */);
@@ -377,6 +379,7 @@
      */
     public void setExpansion(float fraction) {
         float oldExpansion = mExpansion;
+        boolean expansionChanged = mExpansion != fraction;
         mExpansion = fraction;
         if (mKeyguardViewController != null && !mIsAnimatingAway) {
             mKeyguardViewController.setExpansion(fraction);
@@ -394,6 +397,10 @@
                 mKeyguardViewController.onStartingToHide();
             }
         }
+
+        if (expansionChanged) {
+            dispatchExpansionChanged();
+        }
     }
 
     public boolean willDismissWithAction() {
@@ -518,6 +525,12 @@
         }
     }
 
+    private void dispatchExpansionChanged() {
+        for (BouncerExpansionCallback callback : mExpansionCallbacks) {
+            callback.onExpansionChanged(mExpansion);
+        }
+    }
+
     public void dump(PrintWriter pw) {
         pw.println("KeyguardBouncer");
         pw.println("  isShowing(): " + isShowing());
@@ -534,6 +547,12 @@
         void onStartingToHide();
         void onStartingToShow();
         void onFullyHidden();
+
+        /**
+         * From 0f {@link KeyguardBouncer#EXPANSION_VISIBLE} when fully visible
+         * to 1f {@link KeyguardBouncer#EXPANSION_HIDDEN} when fully hidden
+         */
+        default void onExpansionChanged(float bouncerHideAmount) {}
     }
 
     /** Create a {@link KeyguardBouncer} once a container and bouncer callback are available. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 1a2d1cf..b9e8d74 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -116,6 +116,11 @@
      */
     private float mDarkAmount;
 
+    /**
+     * How visible the quick settings panel is.
+     */
+    private float mQsExpansion;
+
     private float mEmptyDragAmount;
 
     /**
@@ -159,7 +164,8 @@
     public void setup(int statusBarMinHeight, int maxShadeBottom, int notificationStackHeight,
             float panelExpansion, int parentHeight, int keyguardStatusHeight, int clockPreferredY,
             boolean hasCustomClock, boolean hasVisibleNotifs, float dark, float emptyDragAmount,
-            boolean bypassEnabled, int unlockedStackScrollerPadding, boolean udfpsEnrolled) {
+            boolean bypassEnabled, int unlockedStackScrollerPadding, boolean udfpsEnrolled,
+            float qsExpansion) {
         mMinTopMargin = statusBarMinHeight + (udfpsEnrolled ? mContainerTopPaddingWithoutLockIcon :
                 mContainerTopPaddingWithLockIcon);
         mMaxShadeBottom = maxShadeBottom;
@@ -174,6 +180,7 @@
         mEmptyDragAmount = emptyDragAmount;
         mBypassEnabled = bypassEnabled;
         mUnlockedStackScrollerPadding = unlockedStackScrollerPadding;
+        mQsExpansion = qsExpansion;
     }
 
     public void run(Result result) {
@@ -274,6 +281,7 @@
      */
     private float getClockAlpha(int y) {
         float alphaKeyguard = Math.max(0, y / Math.max(1f, getClockY(1f)));
+        alphaKeyguard *= (1f - mQsExpansion);
         alphaKeyguard = Interpolators.ACCELERATE.getInterpolation(alphaKeyguard);
         return MathUtils.lerp(alphaKeyguard, 1f, mDarkAmount);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
index 0e7e2fd..547a370 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
@@ -23,6 +23,7 @@
 import static com.android.systemui.statusbar.phone.LockIcon.STATE_LOCK_OPEN;
 import static com.android.systemui.statusbar.phone.LockIcon.STATE_SCANNING_FACE;
 
+import android.animation.ArgbEvaluator;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -38,6 +39,7 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.settingslib.Utils;
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -84,7 +86,7 @@
     private boolean mDocked;
     private boolean mWakeAndUnlockRunning;
     private boolean mShowingLaunchAffordance;
-    private boolean mBouncerShowing;
+    private float mBouncerHiddenAmount = KeyguardBouncer.EXPANSION_HIDDEN;
     private boolean mBouncerShowingScrimmed;
     private boolean mFingerprintUnlock;
     private int mStatusBarState = StatusBarState.SHADE;
@@ -104,6 +106,8 @@
 
             mSimLocked = mKeyguardUpdateMonitor.isSimPinSecure();
             mConfigurationListener.onThemeChanged();
+
+            updateColor();
             update();
         }
 
@@ -348,7 +352,6 @@
      */
     public void attach(LockIcon lockIcon) {
         mLockIcon = lockIcon;
-        updateColor();
 
         mLockIcon.setOnClickListener(this::handleClick);
         mLockIcon.setOnLongClickListener(this::handleLongClick);
@@ -408,20 +411,44 @@
 
     /** Sets whether the bouncer is showing. */
     public void setBouncerShowingScrimmed(boolean showing, boolean scrimmed) {
-        mBouncerShowing = showing;
         mBouncerShowingScrimmed = scrimmed;
         update();
     }
 
+    /**
+     * Sets how hidden the bouncer is, where 0f is fully visible and 1f is fully hidden
+     * See {@link KeyguardBouncer#EXPANSION_VISIBLE} and {@link KeyguardBouncer#EXPANSION_HIDDEN}.
+     */
+    public void setBouncerHideAmount(float hideAmount) {
+        mBouncerHiddenAmount = hideAmount;
+        updateColor();
+    }
+
     private void updateColor() {
         if (mLockIcon == null) {
             return;
         }
 
-        TypedArray typedArray = mLockIcon.getContext().getTheme().obtainStyledAttributes(
-                null, new int[]{ android.R.attr.textColorPrimary }, 0, 0);
-        int iconColor = typedArray.getColor(0, Color.WHITE);
-        typedArray.recycle();
+        int iconColor = -1;
+        if (mBouncerHiddenAmount == KeyguardBouncer.EXPANSION_VISIBLE) {
+            TypedArray typedArray = mLockIcon.getContext().getTheme().obtainStyledAttributes(
+                    null, new int[]{ android.R.attr.textColorPrimary }, 0, 0);
+            iconColor = typedArray.getColor(0, Color.WHITE);
+            typedArray.recycle();
+        } else if (mBouncerHiddenAmount == KeyguardBouncer.EXPANSION_HIDDEN) {
+            iconColor = Utils.getColorAttrDefaultColor(
+                    mLockIcon.getContext(), com.android.systemui.R.attr.wallpaperTextColor);
+        } else {
+            // bouncer is transitioning
+            TypedArray typedArray = mLockIcon.getContext().getTheme().obtainStyledAttributes(
+                    null, new int[]{ android.R.attr.textColorPrimary }, 0, 0);
+            int bouncerIconColor = typedArray.getColor(0, Color.WHITE);
+            typedArray.recycle();
+            int keyguardIconColor = Utils.getColorAttrDefaultColor(
+                    mLockIcon.getContext(), com.android.systemui.R.attr.wallpaperTextColor);
+            iconColor = (int) new ArgbEvaluator().evaluate(
+                    mBouncerHiddenAmount, bouncerIconColor, keyguardIconColor);
+        }
         mLockIcon.updateColor(iconColor);
     }
 
@@ -520,10 +547,7 @@
             return changed;
         }
         boolean onAodOrDocked = mStatusBarStateController.isDozing() || mDocked;
-        boolean onKeyguardWithoutBouncer = mStatusBarState == StatusBarState.KEYGUARD
-                && !mBouncerShowing;
-        boolean invisible = onAodOrDocked || mWakeAndUnlockRunning || mShowingLaunchAffordance
-                || onKeyguardWithoutBouncer;
+        boolean invisible = onAodOrDocked || mWakeAndUnlockRunning || mShowingLaunchAffordance;
         boolean fingerprintOrBypass = mFingerprintUnlock
                 || mKeyguardBypassController.getBypassEnabled();
         if (fingerprintOrBypass && !mBouncerShowingScrimmed) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 84eacdc..01a7292 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -292,6 +292,7 @@
     private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
     private final QSDetailDisplayer mQSDetailDisplayer;
+    private final ScrimController mScrimController;
     // Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow card.
     // If there are exactly 1 + mMaxKeyguardNotifications, then still shows all notifications
     private final int mMaxKeyguardNotifications;
@@ -549,6 +550,7 @@
             NotificationIconAreaController notificationIconAreaController,
             AuthController authController,
             QSDetailDisplayer qsDetailDisplayer,
+            ScrimController scrimController,
             MediaDataManager mediaDataManager) {
         super(view, falsingManager, dozeLog, keyguardStateController,
                 (SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
@@ -579,6 +581,7 @@
         mPulseExpansionHandler = pulseExpansionHandler;
         mDozeParameters = dozeParameters;
         mBiometricUnlockController = biometricUnlockController;
+        mScrimController = scrimController;
         mMediaDataManager = mediaDataManager;
         pulseExpansionHandler.setPulseExpandAbortListener(() -> {
             if (mQs != null) {
@@ -909,7 +912,7 @@
                     clockPreferredY, hasCustomClock(),
                     hasVisibleNotifications, mInterpolatedDarkAmount, mEmptyDragAmount,
                     bypassEnabled, getUnlockedStackScrollerPadding(),
-                    mUpdateMonitor.isUdfpsEnrolled());
+                    mUpdateMonitor.isUdfpsEnrolled(), getQsExpansionFraction());
             mClockPositionAlgorithm.run(mClockPositionResult);
             mKeyguardStatusViewController.updatePosition(
                     mClockPositionResult.clockX, mClockPositionResult.clockY,
@@ -1756,6 +1759,7 @@
         updateHeaderKeyguardAlpha();
         if (mBarState == StatusBarState.SHADE_LOCKED || mBarState == KEYGUARD) {
             updateKeyguardBottomAreaAlpha();
+            positionClockAndNotifications();
             updateBigClockAlpha();
         }
 
@@ -1782,6 +1786,7 @@
         float qsExpansionFraction = getQsExpansionFraction();
         mQs.setQsExpansion(qsExpansionFraction, getHeaderTranslation());
         mMediaHierarchyManager.setQsExpansion(qsExpansionFraction);
+        mScrimController.setQsExpansion(qsExpansionFraction);
         mNotificationStackScrollLayoutController.setQsExpansionFraction(qsExpansionFraction);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 9e7efc1..f8e361f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -125,11 +125,6 @@
      */
     public static final float BUSY_SCRIM_ALPHA = 1f;
 
-    /**
-     * Same as above, but when blur is supported.
-     */
-    public static final float BLUR_SCRIM_ALPHA = 0.80f;
-
     static final int TAG_KEY_ANIM = R.id.scrim;
     private static final int TAG_START_ALPHA = R.id.scrim_alpha_start;
     private static final int TAG_END_ALPHA = R.id.scrim_alpha_end;
@@ -161,6 +156,7 @@
 
     // Assuming the shade is expanded during initialization
     private float mExpansionFraction = 1f;
+    private float mQsExpansion;
 
     private boolean mDarkenWhileDragging;
     private boolean mExpansionAffectsAlpha = true;
@@ -206,8 +202,7 @@
             BlurUtils blurUtils, ConfigurationController configurationController) {
 
         mScrimStateListener = lightBarController::setScrimState;
-        mDefaultScrimAlpha = blurUtils.supportsBlursOnWindows()
-                ? BLUR_SCRIM_ALPHA : BUSY_SCRIM_ALPHA;
+        mDefaultScrimAlpha = BUSY_SCRIM_ALPHA;
         mBlurUtils = blurUtils;
 
         mKeyguardStateController = keyguardStateController;
@@ -464,6 +459,31 @@
 
             boolean relevantState = (mState == ScrimState.UNLOCKED
                     || mState == ScrimState.KEYGUARD
+                    || mState == ScrimState.SHADE_LOCKED
+                    || mState == ScrimState.PULSING
+                    || mState == ScrimState.BUBBLE_EXPANDED);
+            if (!(relevantState && mExpansionAffectsAlpha)) {
+                return;
+            }
+            applyAndDispatchExpansion();
+        }
+    }
+
+    /**
+     * Current state of the QuickSettings expansion when pulling it from the top.
+     *
+     * @param fraction From 0 to 1 where 0 means collapsed and 1 expanded.
+     */
+    public void setQsExpansion(float fraction) {
+        if (isNaN(fraction)) {
+            return;
+        }
+        if (mQsExpansion != fraction) {
+            mQsExpansion = fraction;
+            Log.d(TAG, "set qs fraction");
+
+            boolean relevantState = (mState == ScrimState.SHADE_LOCKED
+                    || mState == ScrimState.KEYGUARD
                     || mState == ScrimState.PULSING
                     || mState == ScrimState.BUBBLE_EXPANDED);
             if (!(relevantState && mExpansionAffectsAlpha)) {
@@ -506,7 +526,8 @@
             behindFraction = (float) Math.pow(behindFraction, 0.8f);
             mBehindAlpha = behindFraction * mDefaultScrimAlpha;
             mInFrontAlpha = 0;
-        } else if (mState == ScrimState.KEYGUARD || mState == ScrimState.PULSING) {
+        } else if (mState == ScrimState.KEYGUARD || mState == ScrimState.SHADE_LOCKED
+                || mState == ScrimState.PULSING) {
             // Either darken of make the scrim transparent when you
             // pull down the shade
             float interpolatedFract = getInterpolatedFraction();
@@ -522,6 +543,11 @@
             }
             mBehindTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getBehindTint(),
                     mState.getBehindTint(), interpolatedFract);
+            if (mQsExpansion > 0) {
+                mBehindAlpha = MathUtils.lerp(mBehindAlpha, mDefaultScrimAlpha, mQsExpansion);
+                mBehindTint = ColorUtils.blendARGB(mBehindTint,
+                        ScrimState.SHADE_LOCKED.getBehindTint(), mQsExpansion);
+            }
         }
         if (isNaN(mBehindAlpha) || isNaN(mInFrontAlpha)) {
             throw new IllegalStateException("Scrim opacity is NaN for state: " + mState
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index fc91c16..994da79 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -112,6 +112,15 @@
         }
     },
 
+    SHADE_LOCKED {
+        @Override
+        public void prepare(ScrimState previousState) {
+            mBehindAlpha = mDefaultScrimAlpha;
+            mBubbleAlpha = 0f;
+            mFrontAlpha = 0f;
+        }
+    },
+
     /**
      * Changing screen brightness from quick settings.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 9e872ab..9ebde53 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3794,6 +3794,14 @@
     }
 
     /**
+     * Sets how hidden the bouncer is, where 0f is fully visible and 1f is fully hidden
+     * See {@link KeyguardBouncer#EXPANSION_VISIBLE} and {@link KeyguardBouncer#EXPANSION_HIDDEN}.
+     */
+    public void setBouncerHideAmount(float hideAmount) {
+        mLockscreenLockIconController.setBouncerHideAmount(hideAmount);
+    }
+
+    /**
      * Collapses the notification shade if it is tracking or expanded.
      */
     public void collapseShade() {
@@ -4091,6 +4099,8 @@
             mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
         } else if (mBrightnessMirrorVisible) {
             mScrimController.transitionTo(ScrimState.BRIGHTNESS_MIRROR);
+        } else if (mState == StatusBarState.SHADE_LOCKED) {
+            mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
         } else if (mDozeServiceHost.isPulsing()) {
             mScrimController.transitionTo(ScrimState.PULSING,
                     mDozeScrimController.getScrimCallback());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index b912614..055b78a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -130,6 +130,11 @@
             updateStates();
             updateLockIcon();
         }
+
+        @Override
+        public void onExpansionChanged(float hideAmount) {
+            mStatusBar.setBouncerHideAmount(hideAmount);
+        }
     };
     private final DockManager.DockEventListener mDockEventListener =
             new DockManager.DockEventListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index acca953..6a0ebf7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -378,8 +378,8 @@
                 // We have to post the removal to the UI thread for synchronization.
                 mMainThreadHandler.post(() -> {
                     final Runnable removeNotification = () -> {
-                        mOnUserInteractionCallback.onDismiss(entry, REASON_CLICK);
                         mClickNotifier.onNotificationClick(entry.getKey(), nv);
+                        mOnUserInteractionCallback.onDismiss(entry, REASON_CLICK);
                     };
                     if (mPresenter.isCollapsing()) {
                         // To avoid lags we're only performing the remove
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index adbc85b..6c5251b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -18,7 +18,6 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.Notification;
@@ -42,6 +41,7 @@
 import android.text.TextWatcher;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.Pair;
 import android.view.ContentInfo;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -74,8 +74,8 @@
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 import com.android.systemui.statusbar.phone.LightBarController;
 
+import java.util.Collection;
 import java.util.HashMap;
-import java.util.Map;
 import java.util.function.Consumer;
 
 /**
@@ -315,8 +315,7 @@
         mRemoteInputs = remoteInputs;
         mRemoteInput = remoteInput;
         mEditText.setHint(mRemoteInput.getLabel());
-        mEditText.mSupportedMimeTypes = (remoteInput.getAllowedDataTypes() == null) ? null
-                : remoteInput.getAllowedDataTypes().toArray(new String[0]);
+        mEditText.setSupportedMimeTypes(remoteInput.getAllowedDataTypes());
 
         mEntry.editedSuggestionInfo = editedSuggestionInfo;
         if (editedSuggestionInfo != null) {
@@ -570,12 +569,13 @@
      */
     public static class RemoteEditText extends EditText {
 
+        private final OnReceiveContentListener mOnReceiveContentListener = this::onReceiveContent;
+
         private final Drawable mBackground;
         private RemoteInputView mRemoteInputView;
         boolean mShowImeOnInputConnection;
         private LightBarController mLightBarController;
         UserHandle mUser;
-        private String[] mSupportedMimeTypes;
 
         public RemoteEditText(Context context, AttributeSet attrs) {
             super(context, attrs);
@@ -583,39 +583,14 @@
             mLightBarController = Dependency.get(LightBarController.class);
         }
 
-        @Override
-        protected void onFinishInflate() {
-            super.onFinishInflate();
-            if (mSupportedMimeTypes != null && mSupportedMimeTypes.length > 0) {
-                setOnReceiveContentListener(mSupportedMimeTypes,
-                        new OnReceiveContentListener() {
-                            @Override
-                            @Nullable
-                            public ContentInfo onReceiveContent(@NonNull View view,
-                                    @NonNull ContentInfo payload) {
-                                Map<Boolean, ContentInfo> split = payload.partition(
-                                        item -> item.getUri() != null);
-                                ContentInfo uriItems = split.get(true);
-                                ContentInfo remainingItems = split.get(false);
-                                if (uriItems != null) {
-                                    ClipData clip = uriItems.getClip();
-                                    ClipDescription description = clip.getDescription();
-                                    if (clip.getItemCount() > 1
-                                            || description.getMimeTypeCount() < 1
-                                            || remainingItems != null) {
-                                        // TODO(b/172363500): Update to loop over all the items
-                                        return payload;
-                                    }
-                                    Uri contentUri = clip.getItemAt(0).getUri();
-                                    String mimeType = description.getMimeType(0);
-                                    Intent dataIntent = mRemoteInputView
-                                            .prepareRemoteInputFromData(mimeType, contentUri);
-                                    mRemoteInputView.sendRemoteInput(dataIntent);
-                                }
-                                return remainingItems;
-                            }
-                        });
+        void setSupportedMimeTypes(@Nullable Collection<String> mimeTypes) {
+            String[] types = null;
+            OnReceiveContentListener listener = null;
+            if (mimeTypes != null && !mimeTypes.isEmpty()) {
+                types = mimeTypes.toArray(new String[0]);
+                listener = mOnReceiveContentListener;
             }
+            setOnReceiveContentListener(types, listener);
         }
 
         private void defocusIfNeeded(boolean animate) {
@@ -759,5 +734,28 @@
                 setBackground(null);
             }
         }
+
+        private ContentInfo onReceiveContent(View view, ContentInfo payload) {
+            Pair<ContentInfo, ContentInfo> split =
+                    payload.partition(item -> item.getUri() != null);
+            ContentInfo uriItems = split.first;
+            ContentInfo remainingItems = split.second;
+            if (uriItems != null) {
+                ClipData clip = uriItems.getClip();
+                ClipDescription description = clip.getDescription();
+                if (clip.getItemCount() > 1
+                        || description.getMimeTypeCount() < 1
+                        || remainingItems != null) {
+                    // TODO(b/172363500): Update to loop over all the items
+                    return payload;
+                }
+                Uri contentUri = clip.getItemAt(0).getUri();
+                String mimeType = description.getMimeType(0);
+                Intent dataIntent =
+                        mRemoteInputView.prepareRemoteInputFromData(mimeType, contentUri);
+                mRemoteInputView.sendRemoteInput(dataIntent);
+            }
+            return remainingItems;
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
index 286b7c0..21d700e 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
@@ -35,6 +35,8 @@
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
 import android.widget.CheckBox;
 import android.widget.CompoundButton;
 import android.widget.TextView;
@@ -58,6 +60,9 @@
 
     @Override
     public void onCreate(Bundle icicle) {
+        getWindow().addSystemFlags(
+                WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+
         super.onCreate(icicle);
 
         Intent intent = getIntent();
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index be5ed0c..71a883d 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -16,14 +16,19 @@
 
 package com.android.systemui.wmshell;
 
+import static android.os.Process.THREAD_PRIORITY_DISPLAY;
+
+import android.animation.AnimationHandler;
 import android.app.IActivityManager;
 import android.content.Context;
 import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager;
 import android.os.Handler;
+import android.os.HandlerThread;
 import android.view.IWindowManager;
 import android.view.WindowManager;
 
+import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.dagger.WMSingleton;
@@ -36,7 +41,6 @@
 import com.android.wm.shell.apppairs.AppPairs;
 import com.android.wm.shell.bubbles.BubbleController;
 import com.android.wm.shell.bubbles.Bubbles;
-import com.android.wm.shell.common.AnimationThread;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayImeController;
 import com.android.wm.shell.common.FloatingContentCoordinator;
@@ -46,6 +50,9 @@
 import com.android.wm.shell.common.SystemWindows;
 import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.common.annotations.ChoreographerSfVsync;
+import com.android.wm.shell.common.annotations.ShellAnimationThread;
+import com.android.wm.shell.common.annotations.ShellMainThread;
 import com.android.wm.shell.draganddrop.DragAndDropController;
 import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
 import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
@@ -62,6 +69,7 @@
 import com.android.wm.shell.splitscreen.SplitScreen;
 
 import java.util.Optional;
+import java.util.concurrent.TimeUnit;
 
 import dagger.BindsOptionalOf;
 import dagger.Module;
@@ -74,6 +82,89 @@
 @Module
 public abstract class WMShellBaseModule {
 
+    private static final boolean ENABLE_SHELL_MAIN_THREAD = false;
+
+    //
+    // Shell Concurrency - Components used for managing threading in the Shell and SysUI
+    //
+
+    /**
+     * Provide a SysUI main-thread Executor.
+     */
+    @WMSingleton
+    @Provides
+    @Main
+    public static ShellExecutor provideSysUIMainExecutor(@Main Handler sysuiMainHandler) {
+        return new HandlerExecutor(sysuiMainHandler);
+    }
+
+    /**
+     * Shell main-thread Handler, don't use this unless really necessary (ie. need to dedupe
+     * multiple types of messages, etc.)
+     */
+    @WMSingleton
+    @Provides
+    @ShellMainThread
+    public static Handler provideShellMainHandler(@Main Handler sysuiMainHandler) {
+        if (ENABLE_SHELL_MAIN_THREAD) {
+             HandlerThread shellMainThread = new HandlerThread("wmshell.main");
+             shellMainThread.start();
+             return shellMainThread.getThreadHandler();
+        }
+        return sysuiMainHandler;
+    }
+
+    /**
+     * Provide a Shell main-thread Executor.
+     */
+    @WMSingleton
+    @Provides
+    @ShellMainThread
+    public static ShellExecutor provideShellMainExecutor(@ShellMainThread Handler shellMainHandler,
+            @Main ShellExecutor sysuiMainExecutor) {
+        if (ENABLE_SHELL_MAIN_THREAD) {
+            return new HandlerExecutor(shellMainHandler);
+        }
+        return sysuiMainExecutor;
+    }
+
+    /**
+     * Provide a Shell animation-thread Executor.
+     */
+    @WMSingleton
+    @Provides
+    @ShellAnimationThread
+    public static ShellExecutor provideShellAnimationExecutor() {
+         HandlerThread shellAnimationThread = new HandlerThread("wmshell.anim",
+                 THREAD_PRIORITY_DISPLAY);
+         shellAnimationThread.start();
+         return new HandlerExecutor(shellAnimationThread.getThreadHandler());
+    }
+
+    /**
+     * Provide a Shell animation-thread AnimationHandler.  The AnimationHandler can be set on
+     * {@link android.animation.ValueAnimator}s and will ensure that the animation will run on
+     * the Shell animation-thread.
+     */
+    @WMSingleton
+    @Provides
+    @ChoreographerSfVsync
+    public static AnimationHandler provideShellAnimationExecutorSfVsyncAnimationHandler(
+            @ShellAnimationThread ShellExecutor shellAnimationExecutor) {
+        try {
+            AnimationHandler handler = new AnimationHandler();
+            shellAnimationExecutor.executeBlocking(() -> {
+                // This is called on the animation thread since it calls
+                // Choreographer.getSfInstance() which returns a thread-local Choreographer instance
+                // that uses the SF vsync
+                handler.setProvider(new SfVsyncFrameCallbackProvider());
+            }, 1, TimeUnit.SECONDS);
+            return handler;
+        } catch (InterruptedException e) {
+            throw new RuntimeException("Failed to initialize SfVsync animation handler in 1s", e);
+        }
+    }
+
     @WMSingleton
     @Provides
     static ShellInit provideShellInit(DisplayImeController displayImeController,
@@ -139,8 +230,9 @@
 
     @WMSingleton
     @Provides
-    static WindowManagerShellWrapper provideWindowManagerShellWrapper() {
-        return new WindowManagerShellWrapper();
+    static WindowManagerShellWrapper provideWindowManagerShellWrapper(
+            @ShellMainThread ShellExecutor shellMainExecutor) {
+        return new WindowManagerShellWrapper(shellMainExecutor);
     }
 
     @WMSingleton
@@ -187,9 +279,11 @@
     @WMSingleton
     @Provides
     static ShellTaskOrganizer provideShellTaskOrganizer(SyncTransactionQueue syncQueue,
-            ShellExecutor mainExecutor, TransactionPool transactionPool, Context context) {
-        return new ShellTaskOrganizer(syncQueue, transactionPool, mainExecutor,
-                AnimationThread.instance().getExecutor(), context);
+            @ShellMainThread ShellExecutor shellMainExecutor,
+            @ShellAnimationThread ShellExecutor shellAnimationExecutor,
+            TransactionPool transactionPool, Context context) {
+        return new ShellTaskOrganizer(syncQueue, transactionPool, shellMainExecutor,
+                shellAnimationExecutor, context);
     }
 
     @WMSingleton
@@ -230,12 +324,6 @@
 
     @WMSingleton
     @Provides
-    static ShellExecutor provideMainShellExecutor(@Main Handler handler) {
-        return new HandlerExecutor(handler);
-    }
-
-    @WMSingleton
-    @Provides
     static Optional<HideDisplayCutout> provideHideDisplayCutoutController(Context context,
             DisplayController displayController) {
         return Optional.ofNullable(HideDisplayCutoutController.create(context, displayController));
@@ -262,5 +350,4 @@
     static LetterboxConfigController provideLetterboxConfigController(Context context) {
         return new LetterboxConfigController(context);
     }
-
 }
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 5f48c42..281b1aa 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -34,6 +34,7 @@
 import com.android.wm.shell.common.SystemWindows;
 import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.common.annotations.ShellMainThread;
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.pip.PipBoundsState;
@@ -95,11 +96,12 @@
             PipBoundsState pipBoundsState, PipMediaController pipMediaController,
             PhonePipMenuController phonePipMenuController, PipTaskOrganizer pipTaskOrganizer,
             PipTouchHandler pipTouchHandler, WindowManagerShellWrapper windowManagerShellWrapper,
-            TaskStackListenerImpl taskStackListener, ShellExecutor mainExecutor) {
+            TaskStackListenerImpl taskStackListener,
+            @ShellMainThread ShellExecutor shellMainExecutor) {
         return Optional.ofNullable(PipController.create(context, displayController,
                 pipAppOpsListener, pipBoundsAlgorithm, pipBoundsState, pipMediaController,
                 phonePipMenuController, pipTaskOrganizer, pipTouchHandler,
-                windowManagerShellWrapper, taskStackListener, mainExecutor));
+                windowManagerShellWrapper, taskStackListener, shellMainExecutor));
     }
 
     @WMSingleton
@@ -129,9 +131,11 @@
             PipBoundsState pipBoundsState,
             PipTaskOrganizer pipTaskOrganizer,
             FloatingContentCoordinator floatingContentCoordinator,
-            PipUiEventLogger pipUiEventLogger) {
+            PipUiEventLogger pipUiEventLogger,
+            @ShellMainThread ShellExecutor shellMainExecutor) {
         return new PipTouchHandler(context, menuPhoneController, pipBoundsAlgorithm,
-                pipBoundsState, pipTaskOrganizer, floatingContentCoordinator, pipUiEventLogger);
+                pipBoundsState, pipTaskOrganizer, floatingContentCoordinator, pipUiEventLogger,
+                shellMainExecutor);
     }
 
     @WMSingleton
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index 4559113..a2eaea1 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -23,6 +23,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.content.ContentResolver;
 import android.content.res.Resources;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
@@ -72,6 +73,8 @@
     Resources mResources;
     @Mock
     NotificationIconAreaController mNotificationIconAreaController;
+    @Mock
+    ContentResolver mContentResolver;
 
     private KeyguardClockSwitchController mController;
 
@@ -90,7 +93,8 @@
                 mColorExtractor,
                 mClockManager,
                 mKeyguardSliceViewController,
-                mNotificationIconAreaController);
+                mNotificationIconAreaController,
+                mContentResolver);
 
         when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
         when(mColorExtractor.getColors(anyInt())).thenReturn(mGradientColors);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
index a0ae35f..1115043 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
@@ -29,20 +29,23 @@
 import static com.android.systemui.accessibility.MagnificationModeSwitch.getIconResId;
 
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
 
 import static org.hamcrest.CoreMatchers.hasItems;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.content.pm.ActivityInfo;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.testing.AndroidTestingRunner;
@@ -60,15 +63,18 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 public class MagnificationModeSwitchTest extends SysuiTestCase {
@@ -81,11 +87,10 @@
     private AccessibilityManager mAccessibilityManager;
     @Mock
     private WindowManager mWindowManager;
-    @Mock
     private ViewPropertyAnimator mViewPropertyAnimator;
     private MagnificationModeSwitch mMagnificationModeSwitch;
-    @Captor
-    private ArgumentCaptor<View.OnTouchListener> mTouchListenerCaptor;
+    private View.OnTouchListener mTouchListener;
+    private List<MotionEvent> mMotionEvents = new ArrayList<>();
 
     @Before
     public void setUp() throws Exception {
@@ -97,9 +102,23 @@
         mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);
         mContext.addMockSystemService(Context.ACCESSIBILITY_SERVICE, mAccessibilityManager);
         mSpyImageView = Mockito.spy(new ImageView(mContext));
-        resetMockImageViewAndAnimator();
-
+        mViewPropertyAnimator = Mockito.spy(mSpyImageView.animate());
+        resetAndStubMockImageViewAndAnimator();
+        doAnswer((invocation) -> {
+            mTouchListener = invocation.getArgument(0);
+            return null;
+        }).when(mSpyImageView).setOnTouchListener(
+                any(View.OnTouchListener.class));
         mMagnificationModeSwitch = new MagnificationModeSwitch(mContext, mSpyImageView);
+        assertNotNull(mTouchListener);
+    }
+
+    @After
+    public void tearDown() {
+        for (MotionEvent event:mMotionEvents) {
+            event.recycle();
+        }
+        mMotionEvents.clear();
     }
 
     @Test
@@ -124,7 +143,7 @@
     }
 
     @Test
-    public void showMagnificationButton_a11yTimeout_autoFadeOut() {
+    public void showMagnificationButton_setA11yTimeout_postDelayedAnimationWithA11yTimeout() {
         final int a11yTimeout = 12345;
         when(mAccessibilityManager.getRecommendedTimeoutMillis(anyInt(), anyInt())).thenReturn(
                 a11yTimeout);
@@ -134,14 +153,21 @@
         verify(mAccessibilityManager).getRecommendedTimeoutMillis(
                 DEFAULT_FADE_OUT_ANIMATION_DELAY_MS, AccessibilityManager.FLAG_CONTENT_ICONS
                         | AccessibilityManager.FLAG_CONTENT_CONTROLS);
-        final ArgumentCaptor<Runnable> fadeOutCaptor = ArgumentCaptor.forClass(Runnable.class);
-        final ArgumentCaptor<Long> fadeOutDelay = ArgumentCaptor.forClass(Long.class);
-        verify(mSpyImageView).postOnAnimationDelayed(fadeOutCaptor.capture(),
-                fadeOutDelay.capture());
-        assertEquals(a11yTimeout, (long) fadeOutDelay.getValue());
+        verify(mSpyImageView).postOnAnimationDelayed(any(Runnable.class), eq((long) a11yTimeout));
+    }
+
+    @Test
+    public void showMagnificationButton_windowMode_verifyAnimationEndAction() {
+        // Execute the runnable immediately to run the animation.
+        doAnswer((invocation) -> {
+            final Runnable action = invocation.getArgument(0);
+            action.run();
+            return null;
+        }).when(mSpyImageView).postOnAnimationDelayed(any(Runnable.class), anyLong());
+
+        mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
 
         // Verify the end action after fade-out.
-        fadeOutCaptor.getValue().run();
         final ArgumentCaptor<Runnable> endActionCaptor = ArgumentCaptor.forClass(Runnable.class);
         verify(mViewPropertyAnimator).withEndAction(endActionCaptor.capture());
 
@@ -154,7 +180,7 @@
     @Test
     public void onConfigurationChanged_buttonIsShowing_setImageResource() {
         mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
-        resetMockImageViewAndAnimator();
+        resetAndStubMockImageViewAndAnimator();
 
         mMagnificationModeSwitch.onConfigurationChanged(ActivityInfo.CONFIG_DENSITY);
 
@@ -165,42 +191,46 @@
     @Test
     public void performSingleTap_fullscreenMode_removeViewAndChangeSettingsValue() {
         mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
-        resetMockImageViewAndAnimator();
+        resetAndStubMockImageViewAndAnimator();
 
         // Perform a single-tap
-        final View.OnTouchListener listener = mTouchListenerCaptor.getValue();
-        listener.onTouch(mSpyImageView, MotionEvent.obtain(
-                0, 0, ACTION_DOWN, 100, 100, 0));
+        final long downTime = SystemClock.uptimeMillis();
+        mTouchListener.onTouch(mSpyImageView,
+                obtainMotionEvent(downTime, 0, ACTION_DOWN, 100, 100));
+
         verify(mViewPropertyAnimator).cancel();
 
-        resetMockImageViewAndAnimator();
-        listener.onTouch(mSpyImageView, MotionEvent.obtain(
-                0, ViewConfiguration.getTapTimeout(), ACTION_UP, 100, 100, 0));
+        resetAndStubMockImageViewAndAnimator();
+        mTouchListener.onTouch(mSpyImageView,
+                obtainMotionEvent(downTime, downTime, ACTION_UP, 100, 100));
+
         verifyTapAction(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
     }
 
     @Test
-    public void showMagnificationButton_performDragging_updateViewLayout() {
+    public void performDragging_showMagnificationButton_updateViewLayout() {
         mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
-        resetMockImageViewAndAnimator();
-
-        // Perform dragging
-        final View.OnTouchListener listener = mTouchListenerCaptor.getValue();
-        final int offset = ViewConfiguration.get(mContext).getScaledTouchSlop();
+        resetAndStubMockImageViewAndAnimator();
         final int previousMode = Settings.Secure.getIntForUser(mContext.getContentResolver(),
                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0, UserHandle.USER_CURRENT);
-        listener.onTouch(mSpyImageView, MotionEvent.obtain(
-                0, 0, ACTION_DOWN, 100, 100, 0));
+
+        // Perform dragging
+        final int offset = ViewConfiguration.get(mContext).getScaledTouchSlop() + 10;
+        final long downTime = SystemClock.uptimeMillis();
+        mTouchListener.onTouch(mSpyImageView, obtainMotionEvent(
+                downTime, 0, ACTION_DOWN, 100, 100));
         verify(mViewPropertyAnimator).cancel();
 
-        listener.onTouch(mSpyImageView, MotionEvent.obtain(
-                0, ViewConfiguration.getTapTimeout(), ACTION_MOVE, 100 + offset, 100, 0));
+        mTouchListener.onTouch(mSpyImageView,
+                obtainMotionEvent(downTime, downTime, ACTION_MOVE, 100 + offset,
+                        100));
         verify(mWindowManager).updateViewLayout(eq(mSpyImageView),
                 any(WindowManager.LayoutParams.class));
 
-        resetMockImageViewAndAnimator();
-        listener.onTouch(mSpyImageView, MotionEvent.obtain(
-                0, ViewConfiguration.getTapTimeout() + 10, ACTION_UP, 100 + offset, 100, 0));
+        resetAndStubMockImageViewAndAnimator();
+        mTouchListener.onTouch(mSpyImageView, obtainMotionEvent(
+                downTime, downTime, ACTION_UP, 100 + offset, 100));
+
         assertModeUnchanged(previousMode);
         assertShowFadingAnimation(FADE_OUT_ALPHA);
     }
@@ -208,18 +238,17 @@
     @Test
     public void performSingleTapActionCanceled_showButtonAnimation() {
         mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
-        resetMockImageViewAndAnimator();
-
-        // Perform single tap
-        final View.OnTouchListener listener = mTouchListenerCaptor.getValue();
+        resetAndStubMockImageViewAndAnimator();
         final int previousMode = Settings.Secure.getInt(mContext.getContentResolver(),
                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0);
-        listener.onTouch(mSpyImageView, MotionEvent.obtain(
-                0, 0, ACTION_DOWN, 100, 100, 0));
 
-        resetMockImageViewAndAnimator();
-        listener.onTouch(mSpyImageView, MotionEvent.obtain(
-                0, ViewConfiguration.getTapTimeout(), ACTION_CANCEL, 100, 100, 0));
+        final long downTime = SystemClock.uptimeMillis();
+        mTouchListener.onTouch(mSpyImageView, obtainMotionEvent(
+                downTime, downTime, ACTION_DOWN, 100, 100));
+        resetAndStubMockImageViewAndAnimator();
+        mTouchListener.onTouch(mSpyImageView, obtainMotionEvent(
+                downTime, downTime, ACTION_CANCEL, 100, 100));
+
         assertModeUnchanged(previousMode);
         assertShowFadingAnimation(FADE_OUT_ALPHA);
     }
@@ -227,21 +256,21 @@
     @Test
     public void performDraggingActionCanceled_showButtonAnimation() {
         mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
-        resetMockImageViewAndAnimator();
-
-        // Perform dragging
-        final View.OnTouchListener listener = mTouchListenerCaptor.getValue();
-        final int offset = ViewConfiguration.get(mContext).getScaledTouchSlop();
+        resetAndStubMockImageViewAndAnimator();
         final int previousMode = Settings.Secure.getInt(mContext.getContentResolver(),
                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0);
-        listener.onTouch(mSpyImageView, MotionEvent.obtain(
-                0, 0, ACTION_DOWN, 100, 100, 0));
-        listener.onTouch(mSpyImageView, MotionEvent.obtain(
-                0, ViewConfiguration.getTapTimeout(), ACTION_MOVE, 100 + offset, 100, 0));
 
-        resetMockImageViewAndAnimator();
-        listener.onTouch(mSpyImageView, MotionEvent.obtain(
-                0, ViewConfiguration.getTapTimeout(), ACTION_CANCEL, 100 + offset, 100, 0));
+        // Perform dragging
+        final long downTime = SystemClock.uptimeMillis();
+        final int offset = ViewConfiguration.get(mContext).getScaledTouchSlop() + 10;
+        mTouchListener.onTouch(mSpyImageView, obtainMotionEvent(
+                0, 0, ACTION_DOWN, 100, 100));
+        mTouchListener.onTouch(mSpyImageView, obtainMotionEvent(
+                downTime, downTime, ACTION_MOVE, 100 + offset, 100));
+        resetAndStubMockImageViewAndAnimator();
+        mTouchListener.onTouch(mSpyImageView, obtainMotionEvent(
+                downTime, downTime, ACTION_CANCEL, 100 + offset, 100));
+
         assertModeUnchanged(previousMode);
         assertShowFadingAnimation(FADE_OUT_ALPHA);
     }
@@ -266,7 +295,7 @@
     @Test
     public void performA11yActions_showWindowModeButton_verifyTapAction() {
         mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
-        resetMockImageViewAndAnimator();
+        resetAndStubMockImageViewAndAnimator();
 
         mSpyImageView.performAccessibilityAction(
                 ACTION_CLICK.getId(), null);
@@ -278,7 +307,7 @@
     public void showButton_showFadeOutAnimation_fadeOutAnimationCanceled() {
         mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
         assertShowFadingAnimation(FADE_OUT_ALPHA);
-        resetMockImageViewAndAnimator();
+        resetAndStubMockImageViewAndAnimator();
 
         mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
 
@@ -327,7 +356,7 @@
         } else { // Fade-out
             verify(mSpyImageView).postOnAnimationDelayed(runnableCaptor.capture(), anyLong());
         }
-        resetMockAnimator();
+        resetAndStubMockAnimator();
 
         runnableCaptor.getValue().run();
 
@@ -336,20 +365,15 @@
         verify(mViewPropertyAnimator).start();
     }
 
-    private void resetMockImageViewAndAnimator() {
+    private void resetAndStubMockImageViewAndAnimator() {
+        resetAndStubMockAnimator();
         Mockito.reset(mSpyImageView);
-        doAnswer(invocation -> null).when(mSpyImageView).setOnTouchListener(
-                mTouchListenerCaptor.capture());
-        resetMockAnimator();
+        doReturn(mViewPropertyAnimator).when(mSpyImageView).animate();
     }
 
-    private void resetMockAnimator() {
+    private void resetAndStubMockAnimator() {
         Mockito.reset(mViewPropertyAnimator);
-        when(mViewPropertyAnimator.setDuration(anyLong())).thenReturn(mViewPropertyAnimator);
-        when(mViewPropertyAnimator.alpha(anyFloat())).thenReturn(mViewPropertyAnimator);
-        when(mViewPropertyAnimator.withEndAction(any(Runnable.class))).thenReturn(
-                mViewPropertyAnimator);
-        when(mSpyImageView.animate()).thenReturn(mViewPropertyAnimator);
+        doNothing().when(mViewPropertyAnimator).start();
     }
 
     /**
@@ -366,4 +390,11 @@
                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0, UserHandle.USER_CURRENT);
         assertEquals(expectedMode, actualMode);
     }
+
+    private MotionEvent obtainMotionEvent(long downTime, long eventTime, int action, float x,
+            float y) {
+        MotionEvent event = MotionEvent.obtain(downTime, eventTime, action, x, y, 0);
+        mMotionEvents.add(event);
+        return event;
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
index 477fe63..019424c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
@@ -29,12 +29,20 @@
 
 import static java.util.Objects.requireNonNull;
 
+import android.app.INotificationManager;
 import android.app.NotificationChannel;
-import android.content.Context;
+import android.appwidget.AppWidgetManager;
+import android.content.SharedPreferences;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.ShortcutInfo;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.provider.Settings;
+import android.service.notification.ConversationChannelWrapper;
 import android.testing.AndroidTestingRunner;
+import android.widget.RemoteViews;
 
+import androidx.preference.PreferenceManager;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.appwidget.IAppWidgetService;
@@ -54,6 +62,9 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
@@ -65,14 +76,23 @@
     private static final String TEST_CHANNEL_NAME = "channel_name";
     private static final String TEST_PARENT_CHANNEL_ID = "parent_channel_id";
     private static final String TEST_CONVERSATION_ID = "conversation_id";
+    private static final int WIDGET_ID_WITH_SHORTCUT = 1;
+    private static final int WIDGET_ID_WITHOUT_SHORTCUT = 2;
+    private static final String SHORTCUT_ID = "101";
 
     private PeopleSpaceWidgetManager mManager;
 
-    @Mock private NotificationListener mListenerService;
-    @Mock private IAppWidgetService mIAppWidgetService;
-    @Mock private Context mContext;
+    @Mock
+    private NotificationListener mListenerService;
+    @Mock
+    private IAppWidgetService mIAppWidgetService;
+    @Mock
+    private AppWidgetManager mAppWidgetManager;
+    @Mock
+    private INotificationManager mINotificationManager;
 
-    @Captor private ArgumentCaptor<NotificationHandler> mListenerCaptor;
+    @Captor
+    private ArgumentCaptor<NotificationHandler> mListenerCaptor;
 
     private final NoManSimulator mNoMan = new NoManSimulator();
     private final FakeSystemClock mClock = new FakeSystemClock();
@@ -80,18 +100,18 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-
         mManager =
                 new PeopleSpaceWidgetManager(mContext);
-        mManager.setAppWidgetManager(mIAppWidgetService);
+        mManager.setAppWidgetManager(mIAppWidgetService, mAppWidgetManager, mINotificationManager);
         mManager.attach(mListenerService);
 
         verify(mListenerService).addNotificationHandler(mListenerCaptor.capture());
         NotificationHandler serviceListener = requireNonNull(mListenerCaptor.getValue());
         mNoMan.addListener(serviceListener);
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 2);
     }
 
-
     @Test
     public void testDoNotNotifyAppWidgetIfNoWidgets() throws RemoteException {
         int[] widgetIdsArray = {};
@@ -105,7 +125,24 @@
 
         verify(mIAppWidgetService, times(1)).getAppWidgetIds(any());
         verify(mIAppWidgetService, never()).notifyAppWidgetViewDataChanged(any(), any(), anyInt());
+    }
 
+    @Test
+    public void testDoNotNotifySingleConversationAppWidgetIfNoWidgets() throws RemoteException {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0);
+        int[] widgetIdsArray = {};
+        when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+
+        NotifEvent notif1 = mNoMan.postNotif(
+                new NotificationEntryBuilder()
+                        .setId(0)
+                        .setPkg(TEST_PACKAGE_A));
+        mClock.advanceTime(MIN_LINGER_DURATION);
+
+        verify(mIAppWidgetService, times(1)).getAppWidgetIds(any());
+        verify(mAppWidgetManager, never()).updateAppWidget(anyInt(), any(RemoteViews.class));
+        verify(mIAppWidgetService, never()).notifyAppWidgetViewDataChanged(any(), any(), anyInt());
     }
 
     @Test
@@ -122,7 +159,66 @@
         verify(mIAppWidgetService, times(1)).getAppWidgetIds(any());
         verify(mIAppWidgetService, times(1))
                 .notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
+        verify(mIAppWidgetService, never()).updateAppWidgetIds(any(), any(),
+                any(RemoteViews.class));
+    }
 
+    @Test
+    public void testNotifySingleConversationAppWidgetOnceIfNotificationPosted()
+            throws RemoteException {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0);
+        when(mINotificationManager.getConversations(true)).thenReturn(
+                new ParceledListSlice(getConversationWithShortcutId()));
+        int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
+        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
+        SharedPreferences.Editor editor = sp.edit();
+        editor.putString(String.valueOf(WIDGET_ID_WITH_SHORTCUT), SHORTCUT_ID);
+        editor.commit();
+        when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+
+        NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_A)
+                .setId(1));
+
+        verify(mIAppWidgetService, times(1)).getAppWidgetIds(any());
+        verify(mIAppWidgetService, never())
+                .notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
+        verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
+                any(RemoteViews.class));
+        verify(mAppWidgetManager, never()).updateAppWidget(eq(WIDGET_ID_WITHOUT_SHORTCUT),
+                any(RemoteViews.class));
+    }
+
+    @Test
+    public void testNotifySingleConversationAppWidgetTwiceIfTwoNotificationsPosted()
+            throws RemoteException {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0);
+        when(mINotificationManager.getConversations(true)).thenReturn(
+                new ParceledListSlice(getConversationWithShortcutId()));
+        int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
+        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
+        SharedPreferences.Editor editor = sp.edit();
+        editor.putString(String.valueOf(WIDGET_ID_WITH_SHORTCUT), SHORTCUT_ID);
+        editor.commit();
+        when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+
+        NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_A)
+                .setId(1));
+        mClock.advanceTime(4);
+        NotifEvent notif2 = mNoMan.postNotif(new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_B)
+                .setId(2));
+
+        verify(mIAppWidgetService, times(2)).getAppWidgetIds(any());
+        verify(mIAppWidgetService, never())
+                .notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
+        verify(mAppWidgetManager, times(2)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
+                any(RemoteViews.class));
+        verify(mAppWidgetManager, never()).updateAppWidget(eq(WIDGET_ID_WITHOUT_SHORTCUT),
+                any(RemoteViews.class));
     }
 
     @Test
@@ -141,6 +237,8 @@
         verify(mIAppWidgetService, times(2)).getAppWidgetIds(any());
         verify(mIAppWidgetService, times(2))
                 .notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
+        verify(mAppWidgetManager, never()).updateAppWidget(anyInt(),
+                any(RemoteViews.class));
     }
 
     @Test
@@ -157,6 +255,8 @@
         verify(mIAppWidgetService, times(2)).getAppWidgetIds(any());
         verify(mIAppWidgetService, times(2))
                 .notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
+        verify(mAppWidgetManager, never()).updateAppWidget(anyInt(),
+                any(RemoteViews.class));
     }
 
     @Test
@@ -173,7 +273,8 @@
 
         verify(mIAppWidgetService, never()).getAppWidgetIds(any());
         verify(mIAppWidgetService, never()).notifyAppWidgetViewDataChanged(any(), any(), anyInt());
-
+        verify(mAppWidgetManager, never()).updateAppWidget(anyInt(),
+                any(RemoteViews.class));
     }
 
     @Test
@@ -192,6 +293,17 @@
         verify(mIAppWidgetService, times(1)).getAppWidgetIds(any());
         verify(mIAppWidgetService, times(1))
                 .notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
+        verify(mAppWidgetManager, never()).updateAppWidget(anyInt(),
+                any(RemoteViews.class));
+    }
 
+    /** Returns a list of a single conversation associated with {@code SHORTCUT_ID}. */
+    private List<ConversationChannelWrapper> getConversationWithShortcutId() {
+        List<ConversationChannelWrapper> convos = new ArrayList<>();
+        ConversationChannelWrapper convo1 = new ConversationChannelWrapper();
+        convo1.setShortcutInfo(new ShortcutInfo.Builder(mContext, SHORTCUT_ID).setLongLabel(
+                "name").build());
+        convos.add(convo1);
+        return convos;
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index f9b14ba..91144be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -82,6 +82,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.text.NumberFormat;
 import java.util.Collections;
 
 @SmallTest
@@ -546,4 +547,68 @@
                 pluggedIndication, powerIndication);
         assertThat(mTextView.getText()).isEqualTo(pluggedIndication);
     }
+
+    @Test
+    public void onRefreshBatteryInfo_chargingWithOverheat_presentChargingLimited() {
+        createController();
+        BatteryStatus status = new BatteryStatus(BatteryManager.BATTERY_STATUS_CHARGING,
+                80 /* level */, BatteryManager.BATTERY_PLUGGED_AC,
+                BatteryManager.BATTERY_HEALTH_OVERHEAT, 0 /* maxChargingWattage */,
+                true /* present */);
+
+        mController.getKeyguardCallback().onRefreshBatteryInfo(status);
+        mController.setVisible(true);
+
+        String percentage = NumberFormat.getPercentInstance().format(80 / 100f);
+        String pluggedIndication = mContext.getString(
+                R.string.keyguard_plugged_in_charging_limited, percentage);
+        assertThat(mTextView.getText()).isEqualTo(pluggedIndication);
+    }
+
+    @Test
+    public void onRefreshBatteryInfo_pluggedWithOverheat_presentChargingLimited() {
+        createController();
+        BatteryStatus status = new BatteryStatus(BatteryManager.BATTERY_STATUS_DISCHARGING,
+                80 /* level */, BatteryManager.BATTERY_PLUGGED_AC,
+                BatteryManager.BATTERY_HEALTH_OVERHEAT, 0 /* maxChargingWattage */,
+                true /* present */);
+
+        mController.getKeyguardCallback().onRefreshBatteryInfo(status);
+        mController.setVisible(true);
+
+        String percentage = NumberFormat.getPercentInstance().format(80 / 100f);
+        String pluggedIndication = mContext.getString(
+                R.string.keyguard_plugged_in_charging_limited, percentage);
+        assertThat(mTextView.getText()).isEqualTo(pluggedIndication);
+    }
+
+    @Test
+    public void onRefreshBatteryInfo_fullChargedWithOverheat_presentCharged() {
+        createController();
+        BatteryStatus status = new BatteryStatus(BatteryManager.BATTERY_STATUS_CHARGING,
+                100 /* level */, BatteryManager.BATTERY_PLUGGED_AC,
+                BatteryManager.BATTERY_HEALTH_OVERHEAT, 0 /* maxChargingWattage */,
+                true /* present */);
+
+        mController.getKeyguardCallback().onRefreshBatteryInfo(status);
+        mController.setVisible(true);
+
+        String chargedIndication = mContext.getString(R.string.keyguard_charged);
+        assertThat(mTextView.getText()).isEqualTo(chargedIndication);
+    }
+
+    @Test
+    public void onRefreshBatteryInfo_dischargingWithOverheat_presentBatteryPercentage() {
+        createController();
+        BatteryStatus status = new BatteryStatus(BatteryManager.BATTERY_STATUS_DISCHARGING,
+                90 /* level */, 0 /* plugged */, BatteryManager.BATTERY_HEALTH_OVERHEAT,
+                0 /* maxChargingWattage */, true /* present */);
+
+        mController.getKeyguardCallback().onRefreshBatteryInfo(status);
+        mController.setDozing(true);
+        mController.setVisible(true);
+
+        String percentage = NumberFormat.getPercentInstance().format(90 / 100f);
+        assertThat(mTextView.getText()).isEqualTo(percentage);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java
index 3c9c9cc..353647b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationUiAdjustmentTest.java
@@ -39,8 +39,11 @@
 
     @Test
     public void needReinflate_differentLength() {
+        // TODO(b/174258598) Please replace FLAG_MUTABLE_UNAUDITED below
+        // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
         PendingIntent pendingIntent =
-                PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+                PendingIntent.getActivity(mContext, 0, new Intent(),
+                        PendingIntent.FLAG_MUTABLE_UNAUDITED);
         Notification.Action action =
                 createActionBuilder("first", R.drawable.ic_corp_icon, pendingIntent).build();
         assertThat(NotificationUiAdjustment.needReinflate(
@@ -51,8 +54,11 @@
 
     @Test
     public void needReinflate_differentLabels() {
+        // TODO(b/174258598) Please replace FLAG_MUTABLE_UNAUDITED below
+        // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
         PendingIntent pendingIntent =
-                PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+                PendingIntent.getActivity(mContext, 0, new Intent(),
+                        PendingIntent.FLAG_MUTABLE_UNAUDITED);
         Notification.Action firstAction =
                 createActionBuilder("first", R.drawable.ic_corp_icon, pendingIntent).build();
         Notification.Action secondAction =
@@ -66,8 +72,11 @@
 
     @Test
     public void needReinflate_differentIcons() {
+        // TODO(b/174258598) Please replace FLAG_MUTABLE_UNAUDITED below
+        // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
         PendingIntent pendingIntent =
-                PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+                PendingIntent.getActivity(mContext, 0, new Intent(),
+                        PendingIntent.FLAG_MUTABLE_UNAUDITED);
         Notification.Action firstAction =
                 createActionBuilder("same", R.drawable.ic_corp_icon, pendingIntent).build();
         Notification.Action secondAction =
@@ -82,10 +91,14 @@
 
     @Test
     public void needReinflate_differentPendingIntent() {
+        // TODO(b/174258598) Please replace FLAG_MUTABLE_UNAUDITED below
+        // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
         PendingIntent firstPendingIntent =
-                PendingIntent.getActivity(mContext, 0, new Intent(Intent.ACTION_VIEW), 0);
+                PendingIntent.getActivity(mContext, 0, new Intent(Intent.ACTION_VIEW),
+                        PendingIntent.FLAG_MUTABLE_UNAUDITED);
         PendingIntent secondPendingIntent =
-                PendingIntent.getActivity(mContext, 0, new Intent(Intent.ACTION_PROCESS_TEXT), 0);
+                PendingIntent.getActivity(mContext, 0, new Intent(Intent.ACTION_PROCESS_TEXT),
+                        PendingIntent.FLAG_MUTABLE_UNAUDITED);
         Notification.Action firstAction =
                 createActionBuilder("same", R.drawable.ic_corp_icon, firstPendingIntent)
                         .build();
@@ -101,8 +114,11 @@
 
     @Test
     public void needReinflate_differentChoices() {
+        // TODO(b/174258598) Please replace FLAG_MUTABLE_UNAUDITED below
+        // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
         PendingIntent pendingIntent =
-                PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+                PendingIntent.getActivity(mContext, 0, new Intent(),
+                        PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
         RemoteInput firstRemoteInput =
                 createRemoteInput("same", "same", new CharSequence[] {"first"});
@@ -126,8 +142,11 @@
 
     @Test
     public void needReinflate_differentRemoteInputLabel() {
+        // TODO(b/174258598) Please replace FLAG_MUTABLE_UNAUDITED below
+        // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
         PendingIntent pendingIntent =
-                PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+                PendingIntent.getActivity(mContext, 0, new Intent(),
+                        PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
         RemoteInput firstRemoteInput =
                 createRemoteInput("same", "first", new CharSequence[] {"same"});
@@ -151,8 +170,11 @@
 
     @Test
     public void needReinflate_negative() {
+        // TODO(b/174258598) Please replace FLAG_MUTABLE_UNAUDITED below
+        // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
         PendingIntent pendingIntent =
-                PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+                PendingIntent.getActivity(mContext, 0, new Intent(),
+                        PendingIntent.FLAG_MUTABLE_UNAUDITED);
         RemoteInput firstRemoteInput =
                 createRemoteInput("same", "same", new CharSequence[] {"same"});
         RemoteInput secondRemoteInput =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java
index 152c51e..ac699f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java
@@ -65,7 +65,7 @@
         mKey = ranking.getKey();
         mRank = ranking.getRank();
         mMatchesInterruptionFilter = ranking.matchesInterruptionFilter();
-        mVisibilityOverride = ranking.getVisibilityOverride();
+        mVisibilityOverride = ranking.getLockscreenVisibilityOverride();
         mSuppressedVisualEffects = ranking.getSuppressedVisualEffects();
         mImportance = ranking.getImportance();
         mExplanation = ranking.getImportanceExplanation();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index 0be9f7d..b0e17cd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -629,7 +629,10 @@
         return new Notification.Action.Builder(
                 Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
                 "action",
-                PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0)).build();
+                // TODO(b/174935104) Please replace FLAG_MUTABLE_UNAUDITED below
+                // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
+                PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"),
+                    PendingIntent.FLAG_MUTABLE_UNAUDITED)).build();
     }
 
     private static class FakeNotificationLifetimeExtender implements NotificationLifetimeExtender {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
index 1a022ec..01b3d8e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
@@ -233,7 +233,10 @@
         return new Notification.Action.Builder(
                 Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
                 title,
-                PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0))
+                // TODO(b/174965424) Please replace FLAG_MUTABLE_UNAUDITED below
+                // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
+                PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"),
+                    PendingIntent.FLAG_MUTABLE_UNAUDITED))
                 .setContextual(true)
                 .build();
     }
@@ -242,7 +245,10 @@
         return new Notification.Action.Builder(
                 Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
                 title,
-                PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0)).build();
+                // TODO(b/174965424) Please replace FLAG_MUTABLE_UNAUDITED below
+                // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
+                PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"),
+                    PendingIntent.FLAG_MUTABLE_UNAUDITED)).build();
     }
 
     private ArrayList<Notification.Action> createActions(String... titles) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index e254cd2..d606316 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
@@ -476,7 +476,10 @@
 
     private NotificationEntry createBubble() {
         Notification.BubbleMetadata data = new Notification.BubbleMetadata.Builder(
-                PendingIntent.getActivity(mContext, 0, new Intent(), 0),
+                // TODO(b/174970399) Please replace FLAG_MUTABLE_UNAUDITED below
+                // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
+                PendingIntent.getActivity(mContext, 0, new Intent(),
+                    PendingIntent.FLAG_MUTABLE_UNAUDITED),
                         Icon.createWithResource(mContext.getResources(), R.drawable.android))
                 .build();
         Notification n = new Notification.Builder(getContext(), "a")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index f7dfe0b..1387a63 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -213,8 +213,11 @@
                 notification, UserHandle.CURRENT, null, 0);
         mEntry = new NotificationEntryBuilder().setSbn(mSbn).setShortcutInfo(mShortcutInfo).build();
 
+        // TODO(b/175005650) Please replace FLAG_MUTABLE_UNAUDITED below
+        // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
         PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0,
-                new Intent(mContext, BubblesTestActivity.class), 0);
+                new Intent(mContext, BubblesTestActivity.class),
+                PendingIntent.FLAG_MUTABLE_UNAUDITED);
         mBubbleSbn = new SbnBuilder(mSbn).setBubbleMetadata(
                 new Notification.BubbleMetadata.Builder(bubbleIntent,
                         Icon.createWithResource(mContext, R.drawable.android)).build())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 7470a13..43ba844 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -455,7 +455,10 @@
 
     private BubbleMetadata makeBubbleMetadata(PendingIntent deleteIntent) {
         Intent target = new Intent(mContext, BubblesTestActivity.class);
-        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, target, 0);
+        // TODO(b/175014468) Please replace FLAG_MUTABLE_UNAUDITED below
+        // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
+        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, target,
+                PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
         return new BubbleMetadata.Builder(bubbleIntent,
                         Icon.createWithResource(mContext, R.drawable.android))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
index 83ef87a..c7c1823 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
@@ -19,7 +19,6 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
 
 import androidx.test.filters.SmallTest;
 
@@ -31,7 +30,6 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
 public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
 
     private static final int SCREEN_HEIGHT = 2000;
@@ -53,6 +51,7 @@
     private int mPreferredClockY;
     private boolean mHasCustomClock;
     private boolean mHasVisibleNotifs;
+    private float mQsExpansion;
 
     @Before
     public void setUp() {
@@ -355,6 +354,17 @@
     }
 
     @Test
+    public void clockHiddenWhenQsIsExpanded() {
+        // GIVEN on the lock screen with a custom clock and visible notifications
+        givenLockScreen();
+        mQsExpansion = 1;
+        // WHEN the clock position algorithm is run
+        positionClock();
+        // THEN the clock Y position is the middle of the screen (SCREEN_HEIGHT / 2).
+        assertThat(mClockPosition.clockAlpha).isEqualTo(TRANSPARENT);
+    }
+
+    @Test
     public void preferredCustomClockPositionWithVisibleNotificationsOnAod() {
         // GIVEN on the lock screen with a custom clock and visible notifications
         givenAOD();
@@ -384,7 +394,7 @@
         mClockPositionAlgorithm.setup(EMPTY_MARGIN, SCREEN_HEIGHT, mNotificationStackHeight,
                 mPanelExpansion, SCREEN_HEIGHT, mKeyguardStatusHeight, mPreferredClockY,
                 mHasCustomClock, mHasVisibleNotifs, mDark, ZERO_DRAG, false /* bypassEnabled */,
-                0 /* unlockedStackScrollerPadding */, false /* udfpsEnrolled */);
+                0 /* unlockedStackScrollerPadding */, false /* udfpsEnrolled */, mQsExpansion);
         mClockPositionAlgorithm.run(mClockPosition);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index d4a94a1..d452861 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -199,6 +199,8 @@
     @Mock
     private AuthController mAuthController;
     @Mock
+    private ScrimController mScrimController;
+    @Mock
     private MediaDataManager mMediaDataManager;
 
     private NotificationPanelViewController mNotificationPanelViewController;
@@ -279,6 +281,7 @@
                 mNotificationAreaController,
                 mAuthController,
                 new QSDetailDisplayer(),
+                mScrimController,
                 mMediaDataManager);
         mNotificationPanelViewController.initDependencies(
                 mStatusBar,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index eaf31ed..342b2f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -249,6 +249,20 @@
     }
 
     @Test
+    public void transitionToShadeLocked() {
+        mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
+        finishAnimationsImmediately();
+
+        assertScrimAlpha(TRANSPARENT /* front */,
+                OPAQUE /* back */,
+                TRANSPARENT /* bubble */);
+
+        assertScrimTint(false /* front */,
+                false /* behind */,
+                false /* bubble */);
+    }
+
+    @Test
     public void transitionToOff() {
         mScrimController.transitionTo(ScrimState.OFF);
         finishAnimationsImmediately();
@@ -464,7 +478,7 @@
         // Front scrim should be transparent
         // Back scrim should be visible without tint
         assertScrimAlpha(TRANSPARENT /* front */,
-                SEMI_TRANSPARENT /* back */,
+                OPAQUE /* back */,
                 TRANSPARENT /* bubble */);
 
         assertScrimTint(false /* front */,
@@ -478,7 +492,7 @@
         finishAnimationsImmediately();
         // Front scrim should be transparent
         // Back scrim should be visible without tint
-        assertScrimAlpha(SEMI_TRANSPARENT /* front */,
+        assertScrimAlpha(OPAQUE /* front */,
                 TRANSPARENT /* back */,
                 TRANSPARENT /* bubble */);
         assertScrimTint(false /* front */,
@@ -519,11 +533,11 @@
         Assert.assertEquals(ScrimController.TRANSPARENT,
                 mScrimInFront.getViewAlpha(), 0.0f);
         // Back scrim should be visible
-        Assert.assertEquals(ScrimController.BLUR_SCRIM_ALPHA,
+        Assert.assertEquals(ScrimController.BUSY_SCRIM_ALPHA,
                 mScrimBehind.getViewAlpha(), 0.0f);
         // Bubble scrim should be visible
-        Assert.assertEquals(ScrimController.BLUR_SCRIM_ALPHA,
-                mScrimBehind.getViewAlpha(), 0.0f);
+        Assert.assertEquals(ScrimController.BUBBLE_SCRIM_ALPHA,
+                mScrimForBubble.getViewAlpha(), 0.0f);
     }
 
     @Test
@@ -564,6 +578,15 @@
     }
 
     @Test
+    public void qsExpansion() {
+        reset(mScrimBehind);
+        mScrimController.setQsExpansion(1f);
+        finishAnimationsImmediately();
+
+        assertScrimAlpha(TRANSPARENT, OPAQUE, TRANSPARENT);
+    }
+
+    @Test
     public void panelExpansionAffectsAlpha() {
         mScrimController.setPanelExpansion(0f);
         mScrimController.setPanelExpansion(0.5f);
@@ -888,7 +911,7 @@
         HashSet<ScrimState> regularStates = new HashSet<>(Arrays.asList(
                 ScrimState.UNINITIALIZED, ScrimState.KEYGUARD, ScrimState.BOUNCER,
                 ScrimState.BOUNCER_SCRIMMED, ScrimState.BRIGHTNESS_MIRROR, ScrimState.UNLOCKED,
-                ScrimState.BUBBLE_EXPANDED));
+                ScrimState.BUBBLE_EXPANDED, ScrimState.SHADE_LOCKED));
 
         for (ScrimState state : ScrimState.values()) {
             if (!lowPowerModeStates.contains(state) && !regularStates.contains(state)) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 1f31fcd..52b7b02 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -81,7 +81,9 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.InOrder;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.mockito.stubbing.Answer;
 
@@ -261,11 +263,12 @@
 
         verify(mAssistManager).hideAssist();
 
-        verify(mClickNotifier).onNotificationClick(
+        InOrder orderVerifier = Mockito.inOrder(mClickNotifier, mOnUserInteractionCallback);
+        orderVerifier.verify(mClickNotifier).onNotificationClick(
                 eq(sbn.getKey()), any(NotificationVisibility.class));
-
         // Notification calls dismiss callback to remove notification due to FLAG_AUTO_CANCEL
-        verify(mOnUserInteractionCallback).onDismiss(mNotificationRow.getEntry(), REASON_CLICK);
+        orderVerifier.verify(mOnUserInteractionCallback).onDismiss(mNotificationRow.getEntry(),
+                REASON_CLICK);
     }
 
     @Test
diff --git a/packages/Tethering/OWNERS b/packages/Tethering/OWNERS
new file mode 100644
index 0000000..aa87958
--- /dev/null
+++ b/packages/Tethering/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/net/OWNERS
diff --git a/packages/VpnDialogs/OWNERS b/packages/VpnDialogs/OWNERS
new file mode 100644
index 0000000..aa87958
--- /dev/null
+++ b/packages/VpnDialogs/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/net/OWNERS
diff --git a/packages/WAPPushManager/OWNERS b/packages/WAPPushManager/OWNERS
new file mode 100644
index 0000000..640baf2
--- /dev/null
+++ b/packages/WAPPushManager/OWNERS
@@ -0,0 +1 @@
+include /telephony/OWNERS
diff --git a/packages/WallpaperBackup/OWNERS b/packages/WallpaperBackup/OWNERS
new file mode 100644
index 0000000..d99779e
--- /dev/null
+++ b/packages/WallpaperBackup/OWNERS
@@ -0,0 +1 @@
+include /services/backup/OWNERS
diff --git a/packages/WallpaperCropper/OWNERS b/packages/WallpaperCropper/OWNERS
new file mode 100644
index 0000000..8ff0f74
--- /dev/null
+++ b/packages/WallpaperCropper/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/wallpaper/OWNERS
diff --git a/packages/WindowManager/OWNERS b/packages/WindowManager/OWNERS
new file mode 100644
index 0000000..0862c05
--- /dev/null
+++ b/packages/WindowManager/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/packages/overlays/OWNERS b/packages/overlays/OWNERS
new file mode 100644
index 0000000..afb98d4
--- /dev/null
+++ b/packages/overlays/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/content/om/OWNERS
diff --git a/packages/services/PacProcessor/OWNERS b/packages/services/PacProcessor/OWNERS
new file mode 100644
index 0000000..aa87958
--- /dev/null
+++ b/packages/services/PacProcessor/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/net/OWNERS
diff --git a/packages/services/Proxy/OWNERS b/packages/services/Proxy/OWNERS
new file mode 100644
index 0000000..aa87958
--- /dev/null
+++ b/packages/services/Proxy/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/net/OWNERS
diff --git a/proto/src/OWNERS b/proto/src/OWNERS
new file mode 100644
index 0000000..e7ddf86
--- /dev/null
+++ b/proto/src/OWNERS
@@ -0,0 +1,2 @@
+per-file gnss.proto = file:/services/core/java/com/android/server/location/OWNERS
+per-file wifi.proto = file:/wifi/OWNERS
diff --git a/proto/src/metrics_constants/OWNERS b/proto/src/metrics_constants/OWNERS
index 7009282..ab4d808 100644
--- a/proto/src/metrics_constants/OWNERS
+++ b/proto/src/metrics_constants/OWNERS
@@ -1,4 +1,4 @@
-cwren@android.com
+cwren@google.com
 yanglu@google.com
 yaochen@google.com
 yro@google.com
diff --git a/samples/training/network-usage/OWNERS b/samples/training/network-usage/OWNERS
new file mode 100644
index 0000000..aa87958
--- /dev/null
+++ b/samples/training/network-usage/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/net/OWNERS
diff --git a/services/OWNERS b/services/OWNERS
new file mode 100644
index 0000000..88d0b61
--- /dev/null
+++ b/services/OWNERS
@@ -0,0 +1 @@
+per-file Android.bp = file:platform/build/soong:/OWNERS
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index d6d4e4f..8f093c7 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -1797,4 +1797,7 @@
     public void setTouchExplorationPassthroughRegion(int displayId, Region region) {
         mSystemSupport.setTouchExplorationPassthroughRegion(displayId, region);
     }
+
+    @Override
+    public void setFocusAppearance(int strokeWidth, int color) { }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index be2f8f1..c6919ad 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1968,6 +1968,7 @@
         // Update the capabilities before the mode.
         updateMagnificationCapabilitiesSettingsChangeLocked(userState);
         updateMagnificationModeChangeSettingsLocked(userState);
+        updateFocusAppearanceDataLocked(userState);
     }
 
     private void updateWindowsForAccessibilityCallbackLocked(AccessibilityUserState userState) {
@@ -3012,6 +3013,30 @@
         }
     }
 
+    /**
+     * Gets the stroke width of the focus rectangle.
+     * @return The stroke width.
+     */
+    public int getFocusStrokeWidth() {
+        synchronized (mLock) {
+            final AccessibilityUserState userState = getCurrentUserStateLocked();
+
+            return userState.getFocusStrokeWidthLocked();
+        }
+    }
+
+    /**
+     * Gets the color of the focus rectangle.
+     * @return The color.
+     */
+    public int getFocusColor() {
+        synchronized (mLock) {
+            final AccessibilityUserState userState = getCurrentUserStateLocked();
+
+            return userState.getFocusColorLocked();
+        }
+    }
+
     @Override
     public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
@@ -3623,4 +3648,18 @@
             }
         }
     }
+
+    private void updateFocusAppearanceDataLocked(AccessibilityUserState userState) {
+        if (userState.mUserId != mCurrentUserId) {
+            return;
+        }
+
+        mMainHandler.post(() -> {
+            broadcastToClients(userState, ignoreRemoteException(client -> {
+                client.mCallback.setFocusAppearance(userState.getFocusStrokeWidthLocked(),
+                        userState.getFocusColorLocked());
+            }));
+        });
+
+    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index e48d11d..5d67992 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -120,6 +120,8 @@
         AccessibilityUserState userState = mUserStateWeakReference.get();
         if (userState == null) return;
         userState.removeServiceLocked(this);
+        userState.resetFocusAppearanceLocked();
+        mSystemSupport.onClientChangeLocked(false);
         mSystemSupport.getFullScreenMagnificationController().resetAllIfNeeded(mId);
         mActivityTaskManagerService.setAllowAppSwitches(mComponentName.flattenToString(), -1,
                 userState.mUserId);
@@ -144,6 +146,7 @@
                 } finally {
                     Binder.restoreCallingIdentity(identity);
                 }
+                userState.resetFocusAppearanceLocked();
                 mSystemSupport.onClientChangeLocked(false);
             }
         }
@@ -310,6 +313,7 @@
             AccessibilityUserState userState = mUserStateWeakReference.get();
             if (userState != null) {
                 userState.serviceDisconnectedLocked(this);
+                userState.resetFocusAppearanceLocked();
             }
             resetLocked();
             mSystemSupport.getFullScreenMagnificationController().resetAllIfNeeded(mId);
@@ -391,4 +395,32 @@
             }
         }
     }
+
+    @Override
+    public void setFocusAppearance(int strokeWidth, int color) {
+        AccessibilityUserState userState = mUserStateWeakReference.get();
+        if (userState == null) {
+            return;
+        }
+
+        synchronized (mLock) {
+            if (!hasRightsToCurrentUserLocked()) {
+                return;
+            }
+
+            if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
+                return;
+            }
+
+            if (userState.getFocusStrokeWidthLocked() == strokeWidth
+                    && userState.getFocusColorLocked() == color) {
+                return;
+            }
+
+            // Sets the appearance data in the A11yUserState.
+            userState.setFocusAppearanceLocked(strokeWidth, color);
+            // Updates the appearance data in the A11yManager.
+            mSystemSupport.onClientChangeLocked(false);
+        }
+    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
index 240c7ff..90e2fdf 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
@@ -45,6 +45,7 @@
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.IAccessibilityManagerClient;
 
+import com.android.internal.R;
 import com.android.internal.accessibility.AccessibilityShortcutController;
 
 import java.io.FileDescriptor;
@@ -122,6 +123,15 @@
     // The magnification capabilities used to know magnification mode could be switched.
     private int mMagnificationCapabilities = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
 
+    /** The stroke width of the focus rectangle in pixels */
+    private int mFocusStrokeWidth;
+    /** The color of the focus rectangle */
+    private int mFocusColor;
+    // The default value of the focus stroke width.
+    private final int mFocusStrokeWidthDefaultValue;
+    // The default value of the focus color.
+    private final int mFocusColorDefaultValue;
+
     private Context mContext;
 
     @SoftKeyboardShowMode
@@ -140,6 +150,12 @@
         mUserId = userId;
         mContext = context;
         mServiceInfoChangeListener = serviceInfoChangeListener;
+        mFocusStrokeWidthDefaultValue = mContext.getResources().getDimensionPixelSize(
+                R.dimen.accessibility_focus_highlight_stroke_width);
+        mFocusColorDefaultValue = mContext.getResources().getColor(
+                R.color.accessibility_focus_highlight_color);
+        mFocusStrokeWidth = mFocusStrokeWidthDefaultValue;
+        mFocusColor = mFocusColorDefaultValue;
     }
 
     boolean isHandlingAccessibilityEventsLocked() {
@@ -178,6 +194,7 @@
         mUserNonInteractiveUiTimeout = 0;
         mUserInteractiveUiTimeout = 0;
         mMagnificationMode = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
+        resetFocusAppearanceLocked();
     }
 
     void addServiceLocked(AccessibilityServiceConnection serviceConnection) {
@@ -880,4 +897,40 @@
         }
         return false;
     }
+
+    /**
+     * Gets the stroke width of the focus rectangle.
+     * @return The stroke width.
+     */
+    public int getFocusStrokeWidthLocked() {
+        return mFocusStrokeWidth;
+    }
+
+    /**
+     * Gets the color of the focus rectangle.
+     * @return The color.
+     */
+    public int getFocusColorLocked() {
+        return mFocusColor;
+    }
+
+    /**
+     * Sets the stroke width and color of the focus rectangle.
+     *
+     * @param strokeWidth The strokeWidth of the focus rectangle.
+     * @param color The color of the focus rectangle.
+     */
+    public void setFocusAppearanceLocked(int strokeWidth, int color) {
+        mFocusStrokeWidth = strokeWidth;
+        mFocusColor = color;
+    }
+
+    /**
+     * Resets the stroke width and color of the focus rectangle to the default value.
+     *
+     */
+    public void resetFocusAppearanceLocked() {
+        mFocusStrokeWidth = mFocusStrokeWidthDefaultValue;
+        mFocusColor = mFocusColorDefaultValue;
+    }
 }
diff --git a/services/api/OWNERS b/services/api/OWNERS
new file mode 100644
index 0000000..a609390
--- /dev/null
+++ b/services/api/OWNERS
@@ -0,0 +1,4 @@
+per-file Android.bp = file:platform/build/soong:/OWNERS
+
+# API changes are managed via Prolog rules, not OWNERS
+*
diff --git a/services/appprediction/OWNERS b/services/appprediction/OWNERS
new file mode 100644
index 0000000..3a5d23d
--- /dev/null
+++ b/services/appprediction/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/appprediction/OWNERS
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index f1988e9..449063d 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -19,6 +19,7 @@
 import static android.content.Context.KEYGUARD_SERVICE;
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 
 import android.annotation.UserIdInt;
@@ -102,6 +103,7 @@
 import android.view.Display;
 import android.view.View;
 import android.widget.RemoteViews;
+
 import com.android.internal.R;
 import com.android.internal.app.SuspendedAppActivity;
 import com.android.internal.app.UnlaunchableAppActivity;
@@ -111,11 +113,14 @@
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
-import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.widget.IRemoteViewsFactory;
 import com.android.server.LocalServices;
 import com.android.server.WidgetBackupProvider;
 import com.android.server.policy.IconUtilities;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -137,9 +142,6 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicLong;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBackupProvider,
         OnCrossProfileWidgetProvidersChangeListener {
@@ -2497,85 +2499,80 @@
         }
     }
 
-    private static void serializeProvider(XmlSerializer out, Provider p) throws IOException {
+    private static void serializeProvider(TypedXmlSerializer out, Provider p) throws IOException {
         out.startTag(null, "p");
         out.attribute(null, "pkg", p.info.provider.getPackageName());
         out.attribute(null, "cl", p.info.provider.getClassName());
-        out.attribute(null, "tag", Integer.toHexString(p.tag));
+        out.attributeIntHex(null, "tag", p.tag);
         if (!TextUtils.isEmpty(p.infoTag)) {
             out.attribute(null, "info_tag", p.infoTag);
         }
         out.endTag(null, "p");
     }
 
-    private static void serializeHost(XmlSerializer out, Host host) throws IOException {
+    private static void serializeHost(TypedXmlSerializer out, Host host) throws IOException {
         out.startTag(null, "h");
         out.attribute(null, "pkg", host.id.packageName);
-        out.attribute(null, "id", Integer.toHexString(host.id.hostId));
-        out.attribute(null, "tag", Integer.toHexString(host.tag));
+        out.attributeIntHex(null, "id", host.id.hostId);
+        out.attributeIntHex(null, "tag", host.tag);
         out.endTag(null, "h");
     }
 
-    private static void serializeAppWidget(XmlSerializer out, Widget widget,
+    private static void serializeAppWidget(TypedXmlSerializer out, Widget widget,
             boolean saveRestoreCompleted) throws IOException {
         out.startTag(null, "g");
-        out.attribute(null, "id", Integer.toHexString(widget.appWidgetId));
-        out.attribute(null, "rid", Integer.toHexString(widget.restoredId));
-        out.attribute(null, "h", Integer.toHexString(widget.host.tag));
+        out.attributeIntHex(null, "id", widget.appWidgetId);
+        out.attributeIntHex(null, "rid", widget.restoredId);
+        out.attributeIntHex(null, "h", widget.host.tag);
         if (widget.provider != null) {
-            out.attribute(null, "p", Integer.toHexString(widget.provider.tag));
+            out.attributeIntHex(null, "p", widget.provider.tag);
         }
         if (widget.options != null) {
             int minWidth = widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
             int minHeight = widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);
             int maxWidth = widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH);
             int maxHeight = widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT);
-            out.attribute(null, "min_width", Integer.toHexString((minWidth > 0) ? minWidth : 0));
-            out.attribute(null, "min_height", Integer.toHexString((minHeight > 0) ? minHeight : 0));
-            out.attribute(null, "max_width", Integer.toHexString((maxWidth > 0) ? maxWidth : 0));
-            out.attribute(null, "max_height", Integer.toHexString((maxHeight > 0) ? maxHeight : 0));
-            out.attribute(null, "host_category", Integer.toHexString(widget.options.getInt(
-                    AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY)));
+            out.attributeIntHex(null, "min_width", (minWidth > 0) ? minWidth : 0);
+            out.attributeIntHex(null, "min_height", (minHeight > 0) ? minHeight : 0);
+            out.attributeIntHex(null, "max_width", (maxWidth > 0) ? maxWidth : 0);
+            out.attributeIntHex(null, "max_height", (maxHeight > 0) ? maxHeight : 0);
+            out.attributeIntHex(null, "host_category", widget.options.getInt(
+                    AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY));
             if (saveRestoreCompleted) {
                 boolean restoreCompleted = widget.options.getBoolean(
                         AppWidgetManager.OPTION_APPWIDGET_RESTORE_COMPLETED);
-                out.attribute(null, "restore_completed", Boolean.toString(restoreCompleted));
+                out.attributeBoolean(null, "restore_completed", restoreCompleted);
             }
         }
         out.endTag(null, "g");
     }
 
-    private static Bundle parseWidgetIdOptions(XmlPullParser parser) {
+    private static Bundle parseWidgetIdOptions(TypedXmlPullParser parser) {
         Bundle options = new Bundle();
-        String restoreCompleted = parser.getAttributeValue(null, "restore_completed");
-        if (restoreCompleted != null) {
-            options.putBoolean(AppWidgetManager.OPTION_APPWIDGET_RESTORE_COMPLETED,
-                    Boolean.valueOf(restoreCompleted));
+        boolean restoreCompleted = parser.getAttributeBoolean(null, "restore_completed", false);
+        if (restoreCompleted) {
+            options.putBoolean(AppWidgetManager.OPTION_APPWIDGET_RESTORE_COMPLETED, true);
         }
-        String minWidthString = parser.getAttributeValue(null, "min_width");
-        if (minWidthString != null) {
-            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
-                    Integer.parseInt(minWidthString, 16));
+        int minWidth = parser.getAttributeIntHex(null, "min_width", -1);
+        if (minWidth != -1) {
+            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, minWidth);
         }
-        String minHeightString = parser.getAttributeValue(null, "min_height");
-        if (minHeightString != null) {
-            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
-                    Integer.parseInt(minHeightString, 16));
+        int minHeight = parser.getAttributeIntHex(null, "min_height", -1);
+        if (minHeight != -1) {
+            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, minHeight);
         }
-        String maxWidthString = parser.getAttributeValue(null, "max_width");
-        if (maxWidthString != null) {
-            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
-                    Integer.parseInt(maxWidthString, 16));
+        int maxWidth = parser.getAttributeIntHex(null, "max_width", -1);
+        if (maxWidth != -1) {
+            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, maxWidth);
         }
-        String maxHeightString = parser.getAttributeValue(null, "max_height");
-        if (maxHeightString != null) {
-            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
-                    Integer.parseInt(maxHeightString, 16));
+        int maxHeight = parser.getAttributeIntHex(null, "max_height", -1);
+        if (maxHeight != -1) {
+            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, maxHeight);
         }
-        String categoryString = parser.getAttributeValue(null, "host_category");
-        if (categoryString != null) {
-            options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
-                    Integer.parseInt(categoryString, 16));
+        int category = parser.getAttributeIntHex(null, "host_category",
+                AppWidgetProviderInfo.WIDGET_CATEGORY_UNKNOWN);
+        if (category != AppWidgetProviderInfo.WIDGET_CATEGORY_UNKNOWN) {
+            options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, category);
         }
         return options;
     }
@@ -3080,7 +3077,7 @@
             TypedXmlSerializer out = Xml.resolveSerializer(stream);
             out.startDocument(null, true);
             out.startTag(null, "gs");
-            out.attribute(null, "version", String.valueOf(CURRENT_VERSION));
+            out.attributeInt(null, "version", CURRENT_VERSION);
 
             N = mProviders.size();
             for (int i = 0; i < N; i++) {
@@ -3149,12 +3146,7 @@
                 if (type == XmlPullParser.START_TAG) {
                     String tag = parser.getName();
                     if ("gs".equals(tag)) {
-                        String attributeValue = parser.getAttributeValue(null, "version");
-                        try {
-                            version = Integer.parseInt(attributeValue);
-                        } catch (NumberFormatException e) {
-                            version = 0;
-                        }
+                        version = parser.getAttributeInt(null, "version", 0);
                     } else if ("p".equals(tag)) {
                         legacyProviderIndex++;
                         // TODO: do we need to check that this package has the same signature
@@ -3193,9 +3185,8 @@
                             mProviders.add(provider);
                         }
 
-                        String tagAttribute = parser.getAttributeValue(null, "tag");
-                        final int providerTag = !TextUtils.isEmpty(tagAttribute)
-                                ? Integer.parseInt(tagAttribute, 16) : legacyProviderIndex;
+                        final int providerTag = parser.getAttributeIntHex(null, "tag",
+                                legacyProviderIndex);
                         provider.tag = providerTag;
 
                         provider.infoTag = parser.getAttributeValue(null, "info_tag");
@@ -3221,12 +3212,9 @@
                         if (!host.zombie || mSafeMode) {
                             // In safe mode, we don't discard the hosts we don't recognize
                             // so that they're not pruned from our list. Otherwise, we do.
-                            final int hostId = Integer.parseInt(parser.getAttributeValue(
-                                    null, "id"), 16);
-
-                            String tagAttribute = parser.getAttributeValue(null, "tag");
-                            final int hostTag = !TextUtils.isEmpty(tagAttribute)
-                                    ? Integer.parseInt(tagAttribute, 16) : legacyHostIndex;
+                            final int hostId = parser.getAttributeIntHex(null, "id");
+                            final int hostTag = parser.getAttributeIntHex(null, "tag",
+                                    legacyHostIndex);
 
                             host.tag = hostTag;
                             host.id = new HostId(uid, hostId, pkg);
@@ -3241,21 +3229,17 @@
                         }
                     } else if ("g".equals(tag)) {
                         Widget widget = new Widget();
-                        widget.appWidgetId = Integer.parseInt(parser.getAttributeValue(
-                                null, "id"), 16);
+                        widget.appWidgetId = parser.getAttributeIntHex(null, "id");
                         setMinAppWidgetIdLocked(userId, widget.appWidgetId + 1);
 
                         // restored ID is allowed to be absent
-                        String restoredIdString = parser.getAttributeValue(null, "rid");
-                        widget.restoredId = (restoredIdString == null) ? 0
-                                : Integer.parseInt(restoredIdString, 16);
+                        widget.restoredId = parser.getAttributeIntHex(null, "rid", 0);
                         widget.options = parseWidgetIdOptions(parser);
 
-                        final int hostTag = Integer.parseInt(parser.getAttributeValue(
-                                null, "h"), 16);
+                        final int hostTag = parser.getAttributeIntHex(null, "h");
                         String providerString = parser.getAttributeValue(null, "p");
-                        final int providerTag = (providerString != null) ? Integer.parseInt(
-                                parser.getAttributeValue(null, "p"), 16) : TAG_UNDEFINED;
+                        final int providerTag = (providerString != null)
+                                ? parser.getAttributeIntHex(null, "p") : TAG_UNDEFINED;
 
                         // We can match widgets with hosts and providers only after hosts
                         // and providers for all users have been loaded since the widget
@@ -4372,11 +4356,11 @@
                 }
 
                 try {
-                    XmlSerializer out = new FastXmlSerializer();
+                    TypedXmlSerializer out = Xml.newFastSerializer();
                     out.setOutput(stream, StandardCharsets.UTF_8.name());
                     out.startDocument(null, true);
                     out.startTag(null, "ws");      // widget state
-                    out.attribute(null, "version", String.valueOf(WIDGET_STATE_VERSION));
+                    out.attributeInt(null, "version", WIDGET_STATE_VERSION);
                     out.attribute(null, "pkg", backedupPackage);
 
                     // Remember all the providers that are currently hosted or published
@@ -4464,7 +4448,7 @@
                 // Hosts mentioned in the widget dataset by ordinal
                 ArrayList<Host> restoredHosts = new ArrayList<>();
 
-                XmlPullParser parser = Xml.newPullParser();
+                TypedXmlPullParser parser = Xml.newFastPullParser();
                 parser.setInput(stream, StandardCharsets.UTF_8.name());
 
                 synchronized (mLock) {
@@ -4474,11 +4458,9 @@
                         if (type == XmlPullParser.START_TAG) {
                             final String tag = parser.getName();
                             if ("ws".equals(tag)) {
-                                String version = parser.getAttributeValue(null, "version");
-
-                                final int versionNumber = Integer.parseInt(version);
+                                final int versionNumber = parser.getAttributeInt(null, "version");
                                 if (versionNumber > WIDGET_STATE_VERSION) {
-                                    Slog.w(TAG, "Unable to process state version " + version);
+                                    Slog.w(TAG, "Unable to process state version " + versionNumber);
                                     return;
                                 }
 
@@ -4520,8 +4502,7 @@
                                 String pkg = parser.getAttributeValue(null, "pkg");
 
                                 final int uid = getUidForPackage(pkg, userId);
-                                final int hostId = Integer.parseInt(
-                                        parser.getAttributeValue(null, "id"), 16);
+                                final int hostId = parser.getAttributeIntHex(null, "id");
 
                                 HostId id = new HostId(uid, hostId, pkg);
                                 Host h = lookupOrAddHostLocked(id);
@@ -4532,17 +4513,14 @@
                                             + "]: {" + h.id + "}");
                                 }
                             } else if ("g".equals(tag)) {
-                                int restoredId = Integer.parseInt(
-                                        parser.getAttributeValue(null, "id"), 16);
-                                int hostIndex = Integer.parseInt(
-                                        parser.getAttributeValue(null, "h"), 16);
+                                int restoredId = parser.getAttributeIntHex(null, "id");
+                                int hostIndex = parser.getAttributeIntHex(null, "h");
                                 Host host = restoredHosts.get(hostIndex);
                                 Provider p = null;
-                                String prov = parser.getAttributeValue(null, "p");
-                                if (prov != null) {
+                                int which = parser.getAttributeIntHex(null, "p", -1);
+                                if (which != -1) {
                                     // could have been null if the app had allocated an id
                                     // but not yet established a binding under that id
-                                    int which = Integer.parseInt(prov, 16);
                                     p = restoredProviders.get(which);
                                 }
 
diff --git a/services/art-profile b/services/art-profile
index 23a2e16..287e6094b 100644
--- a/services/art-profile
+++ b/services/art-profile
@@ -32073,6 +32073,32 @@
 PLcom/android/server/wm/AccessibilityController;->setMagnificationCallbacksLocked(ILcom/android/server/wm/WindowManagerInternal$MagnificationCallbacks;)Z
 PLcom/android/server/wm/AccessibilityController;->setMagnificationSpecLocked(ILandroid/view/MagnificationSpec;)V
 PLcom/android/server/wm/AccessibilityController;->setWindowsForAccessibilityCallbackLocked(ILcom/android/server/wm/WindowManagerInternal$WindowsForAccessibilityCallback;)Z
+HPLcom/android/server/wm/ActivityClientController;->activityDestroyed(Landroid/os/IBinder;)V
+HPLcom/android/server/wm/ActivityClientController;->activityIdle(Landroid/os/IBinder;Landroid/content/res/Configuration;Z)V
+HPLcom/android/server/wm/ActivityClientController;->activityPaused(Landroid/os/IBinder;)V
+PLcom/android/server/wm/ActivityClientController;->activityRelaunched(Landroid/os/IBinder;)V
+HPLcom/android/server/wm/ActivityClientController;->activityResumed(Landroid/os/IBinder;)V
+HPLcom/android/server/wm/ActivityClientController;->activityStopped(Landroid/os/IBinder;Landroid/os/Bundle;Landroid/os/PersistableBundle;Ljava/lang/CharSequence;)V
+HPLcom/android/server/wm/ActivityClientController;->activityTopResumedStateLost()V
+PLcom/android/server/wm/ActivityClientController;->ensureValidPictureInPictureActivityParamsLocked(Ljava/lang/String;Landroid/os/IBinder;Landroid/app/PictureInPictureParams;)Lcom/android/server/wm/ActivityRecord;
+PLcom/android/server/wm/ActivityClientController;->enterPictureInPictureMode(Landroid/os/IBinder;Landroid/app/PictureInPictureParams;)Z
+HPLcom/android/server/wm/ActivityClientController;->getActivityOptions(Landroid/os/IBinder;)Landroid/os/Bundle;
+PLcom/android/server/wm/ActivityClientController;->getCallingRecord(Landroid/os/IBinder;)Lcom/android/server/wm/ActivityRecord;
+PLcom/android/server/wm/ActivityClientController;->isTopOfTask(Landroid/os/IBinder;)Z
+PLcom/android/server/wm/ActivityClientController;->moveActivityTaskToBack(Landroid/os/IBinder;Z)Z
+PLcom/android/server/wm/ActivityClientController;->navigateUpTo(Landroid/os/IBinder;Landroid/content/Intent;ILandroid/content/Intent;)Z
+HPLcom/android/server/wm/ActivityClientController;->notifyActivityDrawn(Landroid/os/IBinder;)V
+HPLcom/android/server/wm/ActivityClientController;->onBackPressedOnTaskRoot(Landroid/os/IBinder;)V
+PLcom/android/server/wm/ActivityClientController;->overridePendingTransition(Landroid/os/IBinder;Ljava/lang/String;II)V
+PLcom/android/server/wm/ActivityClientController;->registerRemoteAnimations(Landroid/os/IBinder;Landroid/view/RemoteAnimationDefinition;)V
+PLcom/android/server/wm/ActivityClientController;->releaseActivityInstance(Landroid/os/IBinder;)Z
+PLcom/android/server/wm/ActivityClientController;->reportActivityFullyDrawn(Landroid/os/IBinder;Z)V
+HPLcom/android/server/wm/ActivityClientController;->reportSizeConfigurations(Landroid/os/IBinder;[I[I[I)V
+PLcom/android/server/wm/ActivityClientController;->setDisablePreviewScreenshots(Landroid/os/IBinder;Z)V
+PLcom/android/server/wm/ActivityClientController;->setShowWhenLocked(Landroid/os/IBinder;Z)V
+HPLcom/android/server/wm/ActivityClientController;->setTaskDescription(Landroid/os/IBinder;Landroid/app/ActivityManager$TaskDescription;)V
+PLcom/android/server/wm/ActivityClientController;->setTurnScreenOn(Landroid/os/IBinder;Z)V
+PLcom/android/server/wm/ActivityClientController;->unregisterRemoteAnimations(Landroid/os/IBinder;)V
 HSPLcom/android/server/wm/ActivityMetricsLogger$LaunchingState;-><init>()V
 HSPLcom/android/server/wm/ActivityMetricsLogger$LaunchingState;->access$000(Lcom/android/server/wm/ActivityMetricsLogger$LaunchingState;)J
 HSPLcom/android/server/wm/ActivityMetricsLogger$LaunchingState;->access$002(Lcom/android/server/wm/ActivityMetricsLogger$LaunchingState;J)J
@@ -32859,13 +32885,6 @@
 HSPLcom/android/server/wm/ActivityTaskManagerService;->access$602(Lcom/android/server/wm/ActivityTaskManagerService;Lcom/android/server/wm/BackgroundActivityStartCallback;)Lcom/android/server/wm/BackgroundActivityStartCallback;
 PLcom/android/server/wm/ActivityTaskManagerService;->access$802(Lcom/android/server/wm/ActivityTaskManagerService;Z)Z
 HSPLcom/android/server/wm/ActivityTaskManagerService;->access$900(Lcom/android/server/wm/ActivityTaskManagerService;)Z
-HPLcom/android/server/wm/ActivityTaskManagerService;->activityDestroyed(Landroid/os/IBinder;)V
-HPLcom/android/server/wm/ActivityTaskManagerService;->activityIdle(Landroid/os/IBinder;Landroid/content/res/Configuration;Z)V
-HPLcom/android/server/wm/ActivityTaskManagerService;->activityPaused(Landroid/os/IBinder;)V
-PLcom/android/server/wm/ActivityTaskManagerService;->activityRelaunched(Landroid/os/IBinder;)V
-HPLcom/android/server/wm/ActivityTaskManagerService;->activityResumed(Landroid/os/IBinder;)V
-HPLcom/android/server/wm/ActivityTaskManagerService;->activityStopped(Landroid/os/IBinder;Landroid/os/Bundle;Landroid/os/PersistableBundle;Ljava/lang/CharSequence;)V
-HPLcom/android/server/wm/ActivityTaskManagerService;->activityTopResumedStateLost()V
 HSPLcom/android/server/wm/ActivityTaskManagerService;->addWindowLayoutReasons(I)V
 HPLcom/android/server/wm/ActivityTaskManagerService;->applyUpdateLockStateLocked(Lcom/android/server/wm/ActivityRecord;)V
 HPLcom/android/server/wm/ActivityTaskManagerService;->applyUpdateVrModeLocked(Lcom/android/server/wm/ActivityRecord;)V
@@ -32898,8 +32917,6 @@
 HPLcom/android/server/wm/ActivityTaskManagerService;->enforceTaskPermission(Ljava/lang/String;)V
 PLcom/android/server/wm/ActivityTaskManagerService;->enqueueAssistContext(ILandroid/content/Intent;Ljava/lang/String;Landroid/app/IAssistDataReceiver;Landroid/os/Bundle;Landroid/os/IBinder;ZZILandroid/os/Bundle;JI)Lcom/android/server/wm/ActivityTaskManagerService$PendingAssistExtras;
 HSPLcom/android/server/wm/ActivityTaskManagerService;->ensureConfigAndVisibilityAfterUpdate(Lcom/android/server/wm/ActivityRecord;I)Z
-PLcom/android/server/wm/ActivityTaskManagerService;->ensureValidPictureInPictureActivityParamsLocked(Ljava/lang/String;Landroid/os/IBinder;Landroid/app/PictureInPictureParams;)Lcom/android/server/wm/ActivityRecord;
-PLcom/android/server/wm/ActivityTaskManagerService;->enterPictureInPictureMode(Landroid/os/IBinder;Landroid/app/PictureInPictureParams;)Z
 PLcom/android/server/wm/ActivityTaskManagerService;->enterPictureInPictureMode(Lcom/android/server/wm/ActivityRecord;Landroid/app/PictureInPictureParams;)Z
 PLcom/android/server/wm/ActivityTaskManagerService;->expireStartAsCallerTokenMsg(Landroid/os/IBinder;)V
 HPLcom/android/server/wm/ActivityTaskManagerService;->finishActivity(Landroid/os/IBinder;ILandroid/content/Intent;I)Z
@@ -32909,7 +32926,6 @@
 PLcom/android/server/wm/ActivityTaskManagerService;->finishVoiceTask(Landroid/service/voice/IVoiceInteractionSession;)V
 PLcom/android/server/wm/ActivityTaskManagerService;->forgetStartAsCallerTokenMsg(Landroid/os/IBinder;)V
 PLcom/android/server/wm/ActivityTaskManagerService;->getActivityClassForToken(Landroid/os/IBinder;)Landroid/content/ComponentName;
-HPLcom/android/server/wm/ActivityTaskManagerService;->getActivityOptions(Landroid/os/IBinder;)Landroid/os/Bundle;
 HSPLcom/android/server/wm/ActivityTaskManagerService;->getActivityStartController()Lcom/android/server/wm/ActivityStartController;
 PLcom/android/server/wm/ActivityTaskManagerService;->getAllRootTaskInfosOnDisplay(I)Ljava/util/List;
 HSPLcom/android/server/wm/ActivityTaskManagerService;->getAppInfoForUser(Landroid/content/pm/ApplicationInfo;I)Landroid/content/pm/ApplicationInfo;
@@ -32919,7 +32935,6 @@
 HSPLcom/android/server/wm/ActivityTaskManagerService;->getBackgroundActivityStartCallback()Lcom/android/server/wm/BackgroundActivityStartCallback;
 PLcom/android/server/wm/ActivityTaskManagerService;->getCallingActivity(Landroid/os/IBinder;)Landroid/content/ComponentName;
 PLcom/android/server/wm/ActivityTaskManagerService;->getCallingPackage(Landroid/os/IBinder;)Ljava/lang/String;
-PLcom/android/server/wm/ActivityTaskManagerService;->getCallingRecordLocked(Landroid/os/IBinder;)Lcom/android/server/wm/ActivityRecord;
 PLcom/android/server/wm/ActivityTaskManagerService;->getConfiguration()Landroid/content/res/Configuration;
 PLcom/android/server/wm/ActivityTaskManagerService;->getCurrentUserId()I
 HPLcom/android/server/wm/ActivityTaskManagerService;->getDeviceConfigurationInfo()Landroid/content/pm/ConfigurationInfo;
@@ -32984,7 +32999,6 @@
 HPLcom/android/server/wm/ActivityTaskManagerService;->isSameApp(ILjava/lang/String;)Z
 HSPLcom/android/server/wm/ActivityTaskManagerService;->isSleepingLocked()Z
 HPLcom/android/server/wm/ActivityTaskManagerService;->isSleepingOrShuttingDownLocked()Z
-PLcom/android/server/wm/ActivityTaskManagerService;->isTopOfTask(Landroid/os/IBinder;)Z
 HPLcom/android/server/wm/ActivityTaskManagerService;->isUidForeground(I)Z
 HPLcom/android/server/wm/ActivityTaskManagerService;->keyguardGoingAway(I)V
 PLcom/android/server/wm/ActivityTaskManagerService;->lambda$4YLTqMi21jZ51BFcKX_h_gIoeGg(Lcom/android/server/wm/ActivityTaskManagerService;Ljava/util/Locale;)V
@@ -33000,33 +33014,22 @@
 PLcom/android/server/wm/ActivityTaskManagerService;->lambda$tPFRgtovnZu_2Zm4sCcLa9-oBto(Lcom/android/server/wm/ActivityTaskManagerService;Landroid/os/IBinder;)V
 PLcom/android/server/wm/ActivityTaskManagerService;->lambda$uDPnzqVuuoVSFA7RJcXFWsrCwrY(Lcom/android/server/wm/ActivityTaskManagerService;ILandroid/content/res/Configuration;)V
 PLcom/android/server/wm/ActivityTaskManagerService;->logAppTooSlow(Lcom/android/server/wm/WindowProcessController;JLjava/lang/String;)V
-PLcom/android/server/wm/ActivityTaskManagerService;->moveActivityTaskToBack(Landroid/os/IBinder;Z)Z
 PLcom/android/server/wm/ActivityTaskManagerService;->moveTaskToFrontLocked(Landroid/app/IApplicationThread;Ljava/lang/String;IILcom/android/server/wm/SafeActivityOptions;)V
-PLcom/android/server/wm/ActivityTaskManagerService;->navigateUpTo(Landroid/os/IBinder;Landroid/content/Intent;ILandroid/content/Intent;)Z
-HPLcom/android/server/wm/ActivityTaskManagerService;->notifyActivityDrawn(Landroid/os/IBinder;)V
-HSPLcom/android/server/wm/ActivityTaskManagerService;->notifyEnterAnimationComplete(Landroid/os/IBinder;)V
-PLcom/android/server/wm/ActivityTaskManagerService;->notifyLaunchTaskBehindComplete(Landroid/os/IBinder;)V
 PLcom/android/server/wm/ActivityTaskManagerService;->notifyTaskPersisterLocked(Lcom/android/server/wm/Task;Z)V
 HSPLcom/android/server/wm/ActivityTaskManagerService;->onActivityManagerInternalAdded()V
-HPLcom/android/server/wm/ActivityTaskManagerService;->onBackPressedOnTaskRoot(Landroid/os/IBinder;)V
 HSPLcom/android/server/wm/ActivityTaskManagerService;->onInitPowerManagement()V
 HPLcom/android/server/wm/ActivityTaskManagerService;->onScreenAwakeChanged(Z)V
 HSPLcom/android/server/wm/ActivityTaskManagerService;->onStartActivitySetDidAppSwitch()V
 HSPLcom/android/server/wm/ActivityTaskManagerService;->onSystemReady()V
-PLcom/android/server/wm/ActivityTaskManagerService;->overridePendingTransition(Landroid/os/IBinder;Ljava/lang/String;II)V
 PLcom/android/server/wm/ActivityTaskManagerService;->pendingAssistExtrasTimedOut(Lcom/android/server/wm/ActivityTaskManagerService$PendingAssistExtras;)V
 PLcom/android/server/wm/ActivityTaskManagerService;->postFinishBooting(ZZ)V
 PLcom/android/server/wm/ActivityTaskManagerService;->registerRemoteAnimationForNextActivityStart(Ljava/lang/String;Landroid/view/RemoteAnimationAdapter;)V
-PLcom/android/server/wm/ActivityTaskManagerService;->registerRemoteAnimations(Landroid/os/IBinder;Landroid/view/RemoteAnimationDefinition;)V
 HPLcom/android/server/wm/ActivityTaskManagerService;->registerTaskStackListener(Landroid/app/ITaskStackListener;)V
 PLcom/android/server/wm/ActivityTaskManagerService;->relaunchReasonToString(I)Ljava/lang/String;
-PLcom/android/server/wm/ActivityTaskManagerService;->releaseActivityInstance(Landroid/os/IBinder;)Z
 PLcom/android/server/wm/ActivityTaskManagerService;->releaseSomeActivities(Landroid/app/IApplicationThread;)V
 PLcom/android/server/wm/ActivityTaskManagerService;->removeRootTasksInWindowingModes([I)V
 PLcom/android/server/wm/ActivityTaskManagerService;->removeTask(I)Z
-PLcom/android/server/wm/ActivityTaskManagerService;->reportActivityFullyDrawn(Landroid/os/IBinder;Z)V
 PLcom/android/server/wm/ActivityTaskManagerService;->reportAssistContextExtras(Landroid/os/IBinder;Landroid/os/Bundle;Landroid/app/assist/AssistStructure;Landroid/app/assist/AssistContent;Landroid/net/Uri;)V
-HPLcom/android/server/wm/ActivityTaskManagerService;->reportSizeConfigurations(Landroid/os/IBinder;[I[I[I)V
 PLcom/android/server/wm/ActivityTaskManagerService;->requestAssistContextExtras(ILandroid/app/IAssistDataReceiver;Landroid/os/Bundle;Landroid/os/IBinder;ZZ)Z
 PLcom/android/server/wm/ActivityTaskManagerService;->requestAutofillData(Landroid/app/IAssistDataReceiver;Landroid/os/Bundle;Landroid/os/IBinder;I)Z
 PLcom/android/server/wm/ActivityTaskManagerService;->requestStartActivityPermissionToken(Landroid/os/IBinder;)Landroid/os/IBinder;
@@ -33039,7 +33042,6 @@
 PLcom/android/server/wm/ActivityTaskManagerService;->setBooted(Z)V
 PLcom/android/server/wm/ActivityTaskManagerService;->setBooting(Z)V
 HSPLcom/android/server/wm/ActivityTaskManagerService;->setDeviceOwnerUid(I)V
-PLcom/android/server/wm/ActivityTaskManagerService;->setDisablePreviewScreenshots(Landroid/os/IBinder;Z)V
 PLcom/android/server/wm/ActivityTaskManagerService;->setFocusedTask(I)V
 PLcom/android/server/wm/ActivityTaskManagerService;->setImmersive(Landroid/os/IBinder;Z)V
 HPLcom/android/server/wm/ActivityTaskManagerService;->setLockScreenShown(ZZ)V
@@ -33047,10 +33049,7 @@
 HSPLcom/android/server/wm/ActivityTaskManagerService;->setRecentTasks(Lcom/android/server/wm/RecentTasks;)V
 PLcom/android/server/wm/ActivityTaskManagerService;->setRequestedOrientation(Landroid/os/IBinder;I)V
 HPLcom/android/server/wm/ActivityTaskManagerService;->setResumedActivityUncheckLocked(Lcom/android/server/wm/ActivityRecord;Ljava/lang/String;)V
-PLcom/android/server/wm/ActivityTaskManagerService;->setShowWhenLocked(Landroid/os/IBinder;Z)V
 PLcom/android/server/wm/ActivityTaskManagerService;->setSplitScreenResizing(Z)V
-HPLcom/android/server/wm/ActivityTaskManagerService;->setTaskDescription(Landroid/os/IBinder;Landroid/app/ActivityManager$TaskDescription;)V
-PLcom/android/server/wm/ActivityTaskManagerService;->setTurnScreenOn(Landroid/os/IBinder;Z)V
 HSPLcom/android/server/wm/ActivityTaskManagerService;->setUsageStatsManager(Landroid/app/usage/UsageStatsManagerInternal;)V
 HSPLcom/android/server/wm/ActivityTaskManagerService;->setWindowManager(Lcom/android/server/wm/WindowManagerService;)V
 PLcom/android/server/wm/ActivityTaskManagerService;->shouldDisableNonVrUiLocked()Z
@@ -33070,7 +33069,6 @@
 PLcom/android/server/wm/ActivityTaskManagerService;->stopAppSwitches()V
 PLcom/android/server/wm/ActivityTaskManagerService;->stopLockTaskModeInternal(Landroid/os/IBinder;Z)V
 PLcom/android/server/wm/ActivityTaskManagerService;->stopSystemLockTaskMode()V
-PLcom/android/server/wm/ActivityTaskManagerService;->unregisterRemoteAnimations(Landroid/os/IBinder;)V
 HPLcom/android/server/wm/ActivityTaskManagerService;->unregisterTaskStackListener(Landroid/app/ITaskStackListener;)V
 HPLcom/android/server/wm/ActivityTaskManagerService;->updateActivityUsageStats(Lcom/android/server/wm/ActivityRecord;I)V
 HPLcom/android/server/wm/ActivityTaskManagerService;->updateBatteryStats(Lcom/android/server/wm/ActivityRecord;Z)V
diff --git a/services/autofill/OWNERS b/services/autofill/OWNERS
new file mode 100644
index 0000000..c52751d
--- /dev/null
+++ b/services/autofill/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/autofill/OWNERS
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 3212698..33d13de 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -1138,7 +1138,7 @@
         final int sessionCount = mSessions.size();
         for (int i = sessionCount - 1; i >= 0; i--) {
             final Session session = mSessions.valueAt(i);
-            if (session.isSavingLocked()) {
+            if (session.isSaveUiShowingLocked()) {
                 if (sDebug) Slog.d(TAG, "destroyFinishedSessionsLocked(): " + session.id);
                 session.forceRemoveFromServiceLocked();
             } else {
@@ -1660,7 +1660,7 @@
 
                     if (sessionToRemove != null && sessionsToRemove.valueAt(i)
                             == sessionToRemove.getActivityTokenLocked()) {
-                        if (sessionToRemove.isSavingLocked()) {
+                        if (sessionToRemove.isSaveUiShowingLocked()) {
                             if (sVerbose) {
                                 Slog.v(TAG, "Session " + sessionToRemove.id + " is saving");
                             }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index b48d71a..9d8901a 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -39,6 +39,7 @@
 import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
 import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Activity;
@@ -113,6 +114,8 @@
 import com.android.server.inputmethod.InputMethodManagerInternal;
 
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -153,6 +156,33 @@
 
     private static AtomicInteger sIdCounter = new AtomicInteger(2);
 
+    @GuardedBy("mLock")
+    private @SessionState int mSessionState = STATE_UNKNOWN;
+
+    /** Session state uninitiated. */
+    public static final int STATE_UNKNOWN = 0;
+
+    /** Session is active for filling. */
+    public static final int STATE_ACTIVE = 1;
+
+    /** Session finished for filling, staying alive for saving. */
+    public static final int STATE_FINISHED = 2;
+
+    /** Session is destroyed and removed from the manager service. */
+    public static final int STATE_REMOVED = 3;
+
+    @IntDef(prefix = { "STATE_" }, value = {
+            STATE_UNKNOWN,
+            STATE_ACTIVE,
+            STATE_FINISHED,
+            STATE_REMOVED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface SessionState{}
+
+    @GuardedBy("mLock")
+    private final SessionFlags mSessionFlags;
+
     /**
      * ID of the session.
      *
@@ -236,10 +266,6 @@
     @GuardedBy("mLock")
     private boolean mDestroyed;
 
-    /** Whether the session is currently saving. */
-    @GuardedBy("mLock")
-    private boolean mIsSaving;
-
     /**
      * Helper used to handle state of Save UI when it must be hiding to show a custom description
      * link and later recovered.
@@ -270,9 +296,6 @@
     @GuardedBy("mLock")
     private final LocalLog mWtfHistory;
 
-    @GuardedBy("mLock")
-    private boolean mExpiredResponse;
-
     /**
      * Map of {@link MetricsEvent#AUTOFILL_REQUEST} metrics, keyed by fill request id.
      */
@@ -307,13 +330,6 @@
     @GuardedBy("mLock")
     private ArrayList<AutofillId> mAugmentedAutofillableIds;
 
-    /**
-     * When {@code true}, the session was created only to handle Augmented Autofill requests (i.e.,
-     * the session would not have existed otherwsie).
-     */
-    @GuardedBy("mLock")
-    private boolean mForAugmentedAutofillOnly;
-
     @Nullable
     private final AutofillInlineSessionController mInlineSessionController;
 
@@ -327,18 +343,18 @@
         // returns null, and augmented autofill is triggered,  and then the user switches the input
         // method. Tapping on the field again will not trigger a new augmented autofill request.
         // This may be fixed by adding more checks such as whether mCurrentViewId is null.
-        if (mExpiredResponse) {
+        if (mSessionFlags.mExpiredResponse) {
             return;
         }
         if (shouldResetSessionStateOnInputMethodSwitch()) {
             // Set the old response expired, so the next action (ACTION_VIEW_ENTERED) can trigger
             // a new fill request.
-            mExpiredResponse = true;
+            mSessionFlags.mExpiredResponse = true;
             // Clear the augmented autofillable ids so augmented autofill will trigger again.
             mAugmentedAutofillableIds = null;
             // In case the field is augmented autofill only, we clear the current view id, so that
             // we won't skip view entered due to same view entered, for the augmented autofill.
-            if (mForAugmentedAutofillOnly) {
+            if (mSessionFlags.mAugmentedAutofillOnly) {
                 mCurrentViewId = null;
             }
         }
@@ -356,7 +372,7 @@
             return false;
         }
 
-        if (isInlineSuggestionsEnabledByAutofillProviderLocked()) {
+        if (mSessionFlags.mInlineSupportedByService) {
             return true;
         }
 
@@ -370,6 +386,31 @@
     }
 
     /**
+     * Collection of flags/booleans that helps determine Session behaviors.
+     */
+    private final class SessionFlags {
+        /** Whether autofill is disabled by the service */
+        @GuardedBy("mLock")
+        private boolean mAutofillDisabled;
+
+        /** Whether the autofill service supports inline suggestions */
+        @GuardedBy("mLock")
+        private boolean mInlineSupportedByService;
+
+        /** True if session is for augmented only */
+        @GuardedBy("mLock")
+        private boolean mAugmentedAutofillOnly;
+
+        /** Whether the session is currently showing the SaveUi. */
+        @GuardedBy("mLock")
+        private boolean mShowingSaveUi;
+
+        /** Whether the current {@link FillResponse} is expired. */
+        @GuardedBy("mLock")
+        private boolean mExpiredResponse;
+    }
+
+    /**
      * TODO(b/151867668): improve how asynchronous data dependencies are handled, without using
      * CountDownLatch.
      */
@@ -423,7 +464,7 @@
         public void onHandleAssistData(Bundle resultData) throws RemoteException {
             if (mRemoteFillService == null) {
                 wtf(null, "onHandleAssistData() called without a remote service. "
-                        + "mForAugmentedAutofillOnly: %s", mForAugmentedAutofillOnly);
+                        + "mForAugmentedAutofillOnly: %s", mSessionFlags.mAugmentedAutofillOnly);
                 return;
             }
             // Keeps to prevent it is cleared on multiple threads.
@@ -685,7 +726,7 @@
     private void cancelCurrentRequestLocked() {
         if (mRemoteFillService == null) {
             wtf(null, "cancelCurrentRequestLocked() called without a remote service. "
-                    + "mForAugmentedAutofillOnly: %s", mForAugmentedAutofillOnly);
+                    + "mForAugmentedAutofillOnly: %s", mSessionFlags.mAugmentedAutofillOnly);
             return;
         }
         final int canceledRequest = mRemoteFillService.cancelCurrentRequest();
@@ -705,14 +746,6 @@
         }
     }
 
-    /**
-     * Returns whether inline suggestions are supported by Autofill provider (not augmented
-     * Autofill provider).
-     */
-    private boolean isInlineSuggestionsEnabledByAutofillProviderLocked() {
-        return mService.isInlineSuggestionsEnabledLocked();
-    }
-
     private boolean isViewFocusedLocked(int flags) {
         return (flags & FLAG_VIEW_NOT_FOCUSED) == 0;
     }
@@ -733,14 +766,15 @@
                     ViewState.STATE_INITIAL,
                     /* clearResponse= */ true);
         }
-        mExpiredResponse = false;
-        if (mForAugmentedAutofillOnly || mRemoteFillService == null) {
+        mSessionFlags.mExpiredResponse = false;
+        mSessionState = STATE_ACTIVE;
+        if (mSessionFlags.mAugmentedAutofillOnly || mRemoteFillService == null) {
             if (sVerbose) {
                 Slog.v(TAG, "requestNewFillResponse(): triggering augmented autofill instead "
-                        + "(mForAugmentedAutofillOnly=" + mForAugmentedAutofillOnly
+                        + "(mForAugmentedAutofillOnly=" + mSessionFlags.mAugmentedAutofillOnly
                         + ", flags=" + flags + ")");
             }
-            mForAugmentedAutofillOnly = true;
+            mSessionFlags.mAugmentedAutofillOnly = true;
             triggerAugmentedAutofillLocked(flags);
             return;
         }
@@ -779,7 +813,7 @@
         // is also not focused.
         final RemoteInlineSuggestionRenderService remoteRenderService =
                 mService.getRemoteInlineSuggestionRenderServiceLocked();
-        if (isInlineSuggestionsEnabledByAutofillProviderLocked()
+        if (mSessionFlags.mInlineSupportedByService
                 && remoteRenderService != null
                 && isViewFocusedLocked(flags)) {
             Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer =
@@ -849,8 +883,13 @@
         mWtfHistory = wtfHistory;
         mComponentName = componentName;
         mCompatMode = compatMode;
-        mForAugmentedAutofillOnly = forAugmentedAutofillOnly;
-        setClientLocked(client);
+        mSessionState = STATE_ACTIVE;
+        synchronized (mLock) {
+            mSessionFlags = new SessionFlags();
+            mSessionFlags.mAugmentedAutofillOnly = forAugmentedAutofillOnly;
+            mSessionFlags.mInlineSupportedByService = mService.isInlineSuggestionsEnabledLocked();
+            setClientLocked(client);
+        }
 
         mInlineSessionController = new AutofillInlineSessionController(inputMethodManagerInternal,
                 userId, componentName, handler, mLock,
@@ -906,9 +945,10 @@
         unlinkClientVultureLocked();
         mClient = IAutoFillManagerClient.Stub.asInterface(client);
         mClientVulture = () -> {
-            Slog.d(TAG, "handling death of " + mActivityToken + " when saving=" + mIsSaving);
             synchronized (mLock) {
-                if (mIsSaving) {
+                Slog.d(TAG, "handling death of " + mActivityToken + " when saving="
+                        + mSessionFlags.mShowingSaveUi);
+                if (mSessionFlags.mShowingSaveUi) {
                     mUi.hideFillUi(this);
                 } else {
                     mUi.destroyAll(mPendingSaveUi, this, false);
@@ -973,9 +1013,9 @@
 
         mService.setLastResponse(id, response);
 
-        int sessionFinishedState = 0;
         final long disableDuration = response.getDisableDuration();
-        if (disableDuration > 0) {
+        final boolean autofillDisabled = disableDuration > 0;
+        if (autofillDisabled) {
             final int flags = response.getFlags();
             final boolean disableActivityOnly =
                     (flags & FillResponse.FLAG_DISABLE_ACTIVITY_ONLY) != 0;
@@ -990,15 +1030,21 @@
                         id, mCompatMode);
             }
 
-            // Although "standard" autofill is disabled, it might still trigger augmented autofill
-            if (triggerAugmentedAutofillLocked(requestFlags) != null) {
-                mForAugmentedAutofillOnly = true;
-                if (sDebug) {
-                    Slog.d(TAG, "Service disabled autofill for " + mComponentName
-                            + ", but session is kept for augmented autofill only");
+            synchronized (mLock) {
+                mSessionFlags.mAutofillDisabled = true;
+
+                // Although "standard" autofill is disabled, it might still trigger augmented
+                // autofill
+                if (triggerAugmentedAutofillLocked(requestFlags) != null) {
+                    mSessionFlags.mAugmentedAutofillOnly = true;
+                    if (sDebug) {
+                        Slog.d(TAG, "Service disabled autofill for " + mComponentName
+                                + ", but session is kept for augmented autofill only");
+                    }
+                    return;
                 }
-                return;
             }
+
             if (sDebug) {
                 final StringBuilder message = new StringBuilder("Service disabled autofill for ")
                                 .append(mComponentName)
@@ -1007,14 +1053,15 @@
                 TimeUtils.formatDuration(disableDuration, message);
                 Slog.d(TAG, message.toString());
             }
-            sessionFinishedState = AutofillManager.STATE_DISABLED_BY_SERVICE;
         }
 
         if (((response.getDatasets() == null || response.getDatasets().isEmpty())
                         && response.getAuthentication() == null)
-                || disableDuration > 0) {
+                || autofillDisabled) {
             // Response is "empty" from an UI point of view, need to notify client.
-            notifyUnavailableToClient(sessionFinishedState, /* autofillableIds= */ null);
+            notifyUnavailableToClient(
+                    autofillDisabled ? AutofillManager.STATE_DISABLED_BY_SERVICE : 0,
+                    /* autofillableIds= */ null);
             synchronized (mLock) {
                 mInlineSessionController.setInlineFillUiLocked(
                         InlineFillUi.emptyUi(mCurrentViewId));
@@ -1094,7 +1141,7 @@
     public void onSaveRequestSuccess(@NonNull String servicePackageName,
             @Nullable IntentSender intentSender) {
         synchronized (mLock) {
-            mIsSaving = false;
+            mSessionFlags.mShowingSaveUi = false;
 
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#onSaveRequestSuccess() rejected - session: "
@@ -1120,7 +1167,7 @@
             @NonNull String servicePackageName) {
         boolean showMessage = !TextUtils.isEmpty(message);
         synchronized (mLock) {
-            mIsSaving = false;
+            mSessionFlags.mShowingSaveUi = false;
 
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#onSaveRequestFailure() rejected - session: "
@@ -1246,7 +1293,7 @@
     @Override
     public void cancelSave() {
         synchronized (mLock) {
-            mIsSaving = false;
+            mSessionFlags.mShowingSaveUi = false;
 
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#cancelSave() rejected - session: "
@@ -1424,7 +1471,7 @@
         }
 
         // The client becomes invisible for the authentication, the response is effective.
-        mExpiredResponse = false;
+        mSessionFlags.mExpiredResponse = false;
 
         final Parcelable result = data.getParcelable(AutofillManager.EXTRA_AUTHENTICATION_RESULT);
         final Bundle newClientState = data.getBundle(AutofillManager.EXTRA_CLIENT_STATE);
@@ -1996,6 +2043,7 @@
             return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ false,
                     Event.NO_SAVE_REASON_NONE);
         }
+        mSessionState = STATE_FINISHED;
         final FillResponse response = getLastResponseLocked("showSaveLocked(%s)");
         final SaveInfo saveInfo = response == null ? null : response.getSaveInfo();
 
@@ -2267,7 +2315,7 @@
                         Slog.e(TAG, "Error notifying client to set save UI state to shown: " + e);
                     }
                 }
-                mIsSaving = true;
+                mSessionFlags.mShowingSaveUi = true;
                 return new SaveResult(/* logSaveShown= */ true, /* removeSession= */ false,
                         Event.NO_SAVE_REASON_NONE);
             }
@@ -2316,8 +2364,8 @@
      * Returns whether the session is currently showing the save UI
      */
     @GuardedBy("mLock")
-    boolean isSavingLocked() {
-        return mIsSaving;
+    boolean isSaveUiShowingLocked() {
+        return mSessionFlags.mShowingSaveUi;
     }
 
     /**
@@ -2435,7 +2483,7 @@
         }
         if (mRemoteFillService == null) {
             wtf(null, "callSaveLocked() called without a remote service. "
-                    + "mForAugmentedAutofillOnly: %s", mForAugmentedAutofillOnly);
+                    + "mForAugmentedAutofillOnly: %s", mSessionFlags.mAugmentedAutofillOnly);
             return;
         }
 
@@ -2540,7 +2588,7 @@
     private boolean requestNewFillResponseOnViewEnteredIfNecessaryLocked(@NonNull AutofillId id,
             @NonNull ViewState viewState, int flags) {
         if ((flags & FLAG_MANUAL_REQUEST) != 0) {
-            mForAugmentedAutofillOnly = false;
+            mSessionFlags.mAugmentedAutofillOnly = false;
             if (sDebug) Slog.d(TAG, "Re-starting session on view " + id + " and flags " + flags);
             requestNewFillResponseLocked(viewState, ViewState.STATE_RESTARTED_SESSION, flags);
             return true;
@@ -2578,7 +2626,7 @@
                     & ViewState.STATE_PENDING_CREATE_INLINE_REQUEST) == 0;
         }
 
-        if (mExpiredResponse) {
+        if (mSessionFlags.mExpiredResponse) {
             if (sDebug) {
                 Slog.d(TAG, "Starting a new partition because the response has expired.");
             }
@@ -2637,7 +2685,7 @@
             return;
         }
         if (action == ACTION_RESPONSE_EXPIRED) {
-            mExpiredResponse = true;
+            mSessionFlags.mExpiredResponse = true;
             if (sDebug) {
                 Slog.d(TAG, "Set the response has expired.");
             }
@@ -2652,7 +2700,8 @@
         ViewState viewState = mViewStates.get(id);
         if (sVerbose) {
             Slog.v(TAG, "updateLocked(" + this.id + "): mCurrentViewId=" + mCurrentViewId
-                    + ", mExpiredResponse=" + mExpiredResponse + ", viewState=" + viewState);
+                    + ", mExpiredResponse=" + mSessionFlags.mExpiredResponse
+                    + ", viewState=" + viewState);
         }
 
         if (viewState == null) {
@@ -2753,7 +2802,7 @@
                             if (sDebug) Slog.d(TAG, "skip augmented autofill for same view.");
                         }
                         return;
-                    } else if (mForAugmentedAutofillOnly && isSameViewEntered) {
+                    } else if (mSessionFlags.mAugmentedAutofillOnly && isSameViewEntered) {
                         // Regular autofill is disabled.
                         if (sDebug) Slog.d(TAG, "skip augmented autofill for same view.");
                         return;
@@ -3369,9 +3418,9 @@
         final RemoteInlineSuggestionRenderService remoteRenderService =
                 mService.getRemoteInlineSuggestionRenderServiceLocked();
         if (remoteRenderService != null
-                && (mForAugmentedAutofillOnly
-                || !isInlineSuggestionsEnabledByAutofillProviderLocked()
-                || mExpiredResponse)
+                && (mSessionFlags.mAugmentedAutofillOnly
+                || !mSessionFlags.mInlineSupportedByService
+                || mSessionFlags.mExpiredResponse)
                 && isViewFocusedLocked(flags)) {
             if (sDebug) Slog.d(TAG, "Create inline request for augmented autofill");
             remoteRenderService.getInlineSuggestionsRendererInfo(new RemoteCallback(
@@ -3694,7 +3743,8 @@
 
     @Override
     public String toString() {
-        return "Session: [id=" + id + ", component=" + mComponentName + "]";
+        return "Session: [id=" + id + ", component=" + mComponentName
+                + ", state=" + sessionStateAsString(mSessionState) + "]";
     }
 
     @GuardedBy("mLock")
@@ -3704,6 +3754,7 @@
         pw.print(prefix); pw.print("uid: "); pw.println(uid);
         pw.print(prefix); pw.print("taskId: "); pw.println(taskId);
         pw.print(prefix); pw.print("flags: "); pw.println(mFlags);
+        pw.print(prefix); pw.print("state: "); pw.println(sessionStateAsString(mSessionState));
         pw.print(prefix); pw.print("mComponentName: "); pw.println(mComponentName);
         pw.print(prefix); pw.print("mActivityToken: "); pw.println(mActivityToken);
         pw.print(prefix); pw.print("mStartTime: "); pw.println(mStartTime);
@@ -3734,7 +3785,7 @@
         }
         pw.print(prefix); pw.print("mCurrentViewId: "); pw.println(mCurrentViewId);
         pw.print(prefix); pw.print("mDestroyed: "); pw.println(mDestroyed);
-        pw.print(prefix); pw.print("mIsSaving: "); pw.println(mIsSaving);
+        pw.print(prefix); pw.print("mShowingSaveUi: "); pw.println(mSessionFlags.mShowingSaveUi);
         pw.print(prefix); pw.print("mPendingSaveUi: "); pw.println(mPendingSaveUi);
         final int numberViews = mViewStates.size();
         pw.print(prefix); pw.print("mViewStates size: "); pw.println(mViewStates.size());
@@ -3778,7 +3829,7 @@
         pw.print(prefix); pw.print("mSaveOnAllViewsInvisible: "); pw.println(
                 mSaveOnAllViewsInvisible);
         pw.print(prefix); pw.print("mSelectedDatasetIds: "); pw.println(mSelectedDatasetIds);
-        if (mForAugmentedAutofillOnly) {
+        if (mSessionFlags.mAugmentedAutofillOnly) {
             pw.print(prefix); pw.println("For Augmented Autofill Only");
         }
         if (mAugmentedAutofillDestroyer != null) {
@@ -3967,7 +4018,7 @@
             log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUMBER_AUGMENTED_REQUESTS,
                     totalAugmentedRequests);
         }
-        if (mForAugmentedAutofillOnly) {
+        if (mSessionFlags.mAugmentedAutofillOnly) {
             log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_AUGMENTED_ONLY, 1);
         }
         mMetricsLogger.write(log);
@@ -3988,9 +4039,9 @@
     void forceRemoveFromServiceIfForAugmentedOnlyLocked() {
         if (sVerbose) {
             Slog.v(TAG, "forceRemoveFromServiceIfForAugmentedOnlyLocked(" + this.id + "): "
-                    + mForAugmentedAutofillOnly);
+                    + mSessionFlags.mAugmentedAutofillOnly);
         }
-        if (!mForAugmentedAutofillOnly) return;
+        if (!mSessionFlags.mAugmentedAutofillOnly) return;
 
         forceRemoveFromServiceLocked();
     }
@@ -4052,6 +4103,7 @@
         if (remoteFillService != null) {
             remoteFillService.destroy();
         }
+        mSessionState = STATE_REMOVED;
     }
 
     void onPendingSaveUi(int operation, @NonNull IBinder token) {
@@ -4168,4 +4220,19 @@
                 return "UNKNOWN_" + action;
         }
     }
+
+    private static String sessionStateAsString(@SessionState int sessionState) {
+        switch (sessionState) {
+            case STATE_UNKNOWN:
+                return "STATE_UNKNOWN";
+            case STATE_ACTIVE:
+                return "STATE_ACTIVE";
+            case STATE_FINISHED:
+                return "STATE_FINISHED";
+            case STATE_REMOVED:
+                return "STATE_REMOVED";
+            default:
+                return "UNKNOWN_SESSION_STATE_" + sessionState;
+        }
+    }
 }
diff --git a/services/backup/Android.bp b/services/backup/Android.bp
index b5444f4..68376c5 100644
--- a/services/backup/Android.bp
+++ b/services/backup/Android.bp
@@ -10,5 +10,5 @@
     defaults: ["platform_service_defaults"],
     srcs: [":services.backup-sources"],
     libs: ["services.core"],
-    static_libs: ["backuplib"],
+    static_libs: ["backuplib", "app-compat-annotations"],
 }
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 2ff66b5..136cd22f 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -3030,9 +3030,11 @@
             }
             Slog.i(TAG, addUserIdToLogMessage(mUserId, "Beginning adb backup..."));
 
+            BackupEligibilityRules eligibilityRules = getEligibilityRulesForOperation(
+                    OperationType.ADB_BACKUP);
             AdbBackupParams params = new AdbBackupParams(fd, includeApks, includeObbs,
                     includeShared, doWidgets, doAllApps, includeSystem, compress, doKeyValue,
-                    pkgList, mScheduledBackupEligibility);
+                    pkgList, eligibilityRules);
             final int token = generateRandomIntegerToken();
             synchronized (mAdbBackupRestoreConfirmations) {
                 mAdbBackupRestoreConfirmations.put(token, params);
diff --git a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
index c94286f..e03150e 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
@@ -24,6 +24,7 @@
 import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_HEADER_MAGIC;
 import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_VERSION;
 
+import android.app.backup.BackupManager;
 import android.app.backup.IFullBackupRestoreObserver;
 import android.content.pm.PackageManagerInternal;
 import android.os.ParcelFileDescriptor;
@@ -104,11 +105,13 @@
                 return;
             }
 
+            BackupEligibilityRules eligibilityRules = new BackupEligibilityRules(
+                    mBackupManagerService.getPackageManager(),
+                    LocalServices.getService(PackageManagerInternal.class),
+                    mBackupManagerService.getUserId(), BackupManager.OperationType.ADB_BACKUP);
             FullRestoreEngine mEngine = new FullRestoreEngine(mBackupManagerService, null,
                     mObserver, null, null, true, 0 /*unused*/, true,
-                    BackupEligibilityRules.forBackup(mBackupManagerService.getPackageManager(),
-                                    LocalServices.getService(PackageManagerInternal.class),
-                                    mBackupManagerService.getUserId()));
+                    eligibilityRules);
             FullRestoreEngineThread mEngineThread = new FullRestoreEngineThread(mEngine,
                     tarInputStream);
             mEngineThread.run();
diff --git a/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
index 73ba1f1..2078492 100644
--- a/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
+++ b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
@@ -25,12 +25,16 @@
 import android.annotation.Nullable;
 import android.app.backup.BackupManager.OperationType;
 import android.app.backup.BackupTransport;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
+import android.app.compat.CompatChanges;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.Signature;
 import android.content.pm.SigningInfo;
+import android.os.Build;
 import android.os.UserHandle;
 import android.util.Slog;
 
@@ -41,6 +45,7 @@
 
 import com.google.android.collect.Sets;
 
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -57,6 +62,15 @@
     private final int mUserId;
     @OperationType  private final int mOperationType;
 
+    /**
+     * When  this change is enabled, {@code adb backup}  is automatically turned on for apps
+     * running as debuggable ({@code android:debuggable} set to {@code true}) and unavailable to
+     * any other apps.
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
+    static final long RESTRICT_ADB_BACKUP = 171032338L;
+
     public static BackupEligibilityRules forBackup(PackageManager packageManager,
             PackageManagerInternal packageManagerInternal,
             int userId) {
@@ -134,12 +148,53 @@
     * @return boolean indicating whether backup is allowed.
     */
     public boolean isAppBackupAllowed(ApplicationInfo app) {
-        if (mOperationType == OperationType.MIGRATION && !UserHandle.isCore(app.uid)) {
-            // Backup / restore of all apps is force allowed during device-to-device migration.
-            return true;
-        }
+        boolean isSystemApp = UserHandle.isCore(app.uid);
+        boolean allowBackup = (app.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0;
+        switch (mOperationType) {
+            case OperationType.MIGRATION:
+                // Backup / restore of all non-system apps is force allowed during
+                // device-to-device migration.
+                return !isSystemApp || allowBackup;
+            case OperationType.ADB_BACKUP:
+                String packageName = app.packageName;
+                if (packageName == null) {
+                    Slog.w(TAG, "Invalid ApplicationInfo object");
+                    return false;
+                }
 
-        return (app.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0;
+                if (!CompatChanges.isChangeEnabled(RESTRICT_ADB_BACKUP, packageName,
+                        UserHandle.of(mUserId))) {
+                    return allowBackup;
+                }
+
+                if (PLATFORM_PACKAGE_NAME.equals(packageName)) {
+                    // Always enable adb backup for SystemBackupAgent in "android" package (this is
+                    // done to avoid breaking existing integration tests and might change in the
+                    // future).
+                    return true;
+                }
+
+                boolean isPrivileged = (app.flags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
+                boolean isDebuggable = (app.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+                if (isSystemApp || isPrivileged) {
+                    try {
+                        return mPackageManager.getProperty(PackageManager.PROPERTY_ALLOW_ADB_BACKUP,
+                                packageName).getBoolean();
+                    } catch (PackageManager.NameNotFoundException e) {
+                        Slog.w(TAG, "Failed to read allowAdbBackup property for + "
+                                + packageName);
+                        return false;
+                    }
+                } else {
+                    // All other apps can use adb backup only when running in debuggable mode.
+                    return isDebuggable;
+                }
+            case OperationType.BACKUP:
+                return allowBackup;
+            default:
+                Slog.w(TAG, "Unknown operation type:" + mOperationType);
+                return false;
+        }
     }
 
     /**
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 5fedf9f..0a80b02 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -31,8 +31,12 @@
 import android.annotation.CheckResult;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
+import android.app.role.RoleManager;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
 import android.companion.Association;
 import android.companion.AssociationRequest;
 import android.companion.CompanionDeviceManager;
@@ -47,6 +51,7 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageItemInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
 import android.net.NetworkPolicyManager;
 import android.os.Binder;
 import android.os.Environment;
@@ -62,6 +67,7 @@
 import android.os.ShellCallback;
 import android.os.ShellCommand;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.provider.SettingsStringUtil.ComponentNameSet;
 import android.text.BidiFormatter;
@@ -70,6 +76,7 @@
 import android.util.ExceptionUtils;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
@@ -116,12 +123,16 @@
 //TODO on associate called again after configuration change -> replace old callback with new
 //TODO avoid leaking calling activity in IFindDeviceCallback (see PrintManager#print for example)
 /** @hide */
+@SuppressLint("LongLogTag")
 public class CompanionDeviceManagerService extends SystemService implements Binder.DeathRecipient {
 
     private static final ComponentName SERVICE_TO_BIND_TO = ComponentName.createRelative(
             CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME,
             ".DeviceDiscoveryService");
 
+    // 10 min
+    public static final int DEVICE_DISCONNECT_PROFILE_REVOKE_DELAY_MS = 10 * 60 * 1000;
+
     private static final boolean DEBUG = false;
     private static final String LOG_TAG = "CompanionDeviceManagerService";
 
@@ -132,6 +143,8 @@
     private static final String XML_TAG_ASSOCIATION = "association";
     private static final String XML_ATTR_PACKAGE = "package";
     private static final String XML_ATTR_DEVICE = "device";
+    private static final String XML_ATTR_PROFILE = "profile";
+    private static final String XML_ATTR_PERSISTENT_PROFILE_GRANTS = "persistent_profile_grants";
     private static final String XML_FILE_NAME = "companion_device_manager_associations.xml";
 
     private final CompanionDeviceManagerImpl mImpl;
@@ -139,21 +152,29 @@
     private PowerWhitelistManager mPowerWhitelistManager;
     private PerUser<ServiceConnector<ICompanionDeviceDiscoveryService>> mServiceConnectors;
     private IAppOpsService mAppOpsManager;
+    private RoleManager mRoleManager;
+    private BluetoothAdapter mBluetoothAdapter;
 
     private IFindDeviceCallback mFindDeviceCallback;
     private AssociationRequest mRequest;
     private String mCallingPackage;
     private AndroidFuture<Association> mOngoingDeviceDiscovery;
 
+    private BluetoothDeviceConnectedListener mBluetoothDeviceConnectedListener =
+            new BluetoothDeviceConnectedListener();
+    private List<String> mCurrentlyConnectedDevices = new ArrayList<>();
+
     private final Object mLock = new Object();
 
+    /** userId -> [association] */
     @GuardedBy("mLock")
-    private @Nullable Set<Association> mCachedAssociations = null;
+    private @Nullable SparseArray<Set<Association>> mCachedAssociations = new SparseArray<>();
 
     public CompanionDeviceManagerService(Context context) {
         super(context);
         mImpl = new CompanionDeviceManagerImpl();
         mPowerWhitelistManager = context.getSystemService(PowerWhitelistManager.class);
+        mRoleManager = context.getSystemService(RoleManager.class);
         mAppOpsManager = IAppOpsService.Stub.asInterface(
                 ServiceManager.getService(Context.APP_OPS_SERVICE));
 
@@ -184,9 +205,9 @@
             @Override
             public void onPackageModified(String packageName) {
                 int userId = getChangingUserId();
-                if (!ArrayUtils.isEmpty(getAllAssociations(userId, packageName))) {
-                    updateSpecialAccessPermissionForAssociatedPackage(packageName, userId);
-                }
+                forEach(getAllAssociations(userId, packageName), association -> {
+                    updateSpecialAccessPermissionForAssociatedPackage(association);
+                });
             }
 
         }.register(getContext(), FgThread.get().getLooper(), UserHandle.ALL, true);
@@ -198,6 +219,18 @@
     }
 
     @Override
+    public void onBootPhase(int phase) {
+        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+            mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+            if (mBluetoothAdapter != null) {
+                mBluetoothAdapter.registerBluetoothConnectionCallback(
+                        getContext().getMainExecutor(),
+                        mBluetoothDeviceConnectedListener);
+            }
+        }
+    }
+
+    @Override
     public void onUserUnlocking(@NonNull TargetUser user) {
         int userHandle = user.getUserIdentifier();
         Set<Association> associations = getAllAssociations(userHandle);
@@ -495,12 +528,14 @@
 
             fout.append("Companion Device Associations:").append('\n');
             synchronized (mLock) {
-                forEach(mCachedAssociations, a -> {
-                    fout.append("  ")
-                            .append("u").append("" + a.getUserId()).append(": ")
-                            .append(a.getPackageName()).append(" - ")
-                            .append(a.getDeviceMacAddress()).append('\n');
-                });
+                for (UserInfo user : getAllUsers()) {
+                    forEach(mCachedAssociations.get(user.id), a -> {
+                        fout.append("  ")
+                                .append("u").append("" + a.getUserId()).append(": ")
+                                .append(a.getPackageName()).append(" - ")
+                                .append(a.getDeviceMacAddress()).append('\n');
+                    });
+                }
             }
         }
     }
@@ -513,32 +548,34 @@
         return Binder.getCallingUid() == Process.SYSTEM_UID;
     }
 
-    void addAssociation(int userId, String packageName, String deviceAddress) {
-        addAssociation(new Association(userId, deviceAddress, packageName));
-    }
-
     void addAssociation(Association association) {
-        updateSpecialAccessPermissionForAssociatedPackage(
-                association.getPackageName(), association.getUserId());
+        updateSpecialAccessPermissionForAssociatedPackage(association);
         recordAssociation(association);
     }
 
     void removeAssociation(int userId, String pkg, String deviceMacAddress) {
-        updateAssociations(associations -> CollectionUtils.remove(associations,
-                new Association(userId, deviceMacAddress, pkg)));
+        updateAssociations(associations -> CollectionUtils.filter(associations, association -> {
+            return association.getUserId() != userId
+                    || !Objects.equals(association.getDeviceMacAddress(), deviceMacAddress)
+                    || !Objects.equals(association.getPackageName(), pkg);
+        }));
     }
 
-    private void updateSpecialAccessPermissionForAssociatedPackage(String packageName, int userId) {
-        PackageInfo packageInfo = getPackageInfo(packageName, userId);
+    private void updateSpecialAccessPermissionForAssociatedPackage(Association association) {
+        PackageInfo packageInfo = getPackageInfo(
+                association.getPackageName(),
+                association.getUserId());
         if (packageInfo == null) {
             return;
         }
 
         Binder.withCleanCallingIdentity(obtainRunnable(CompanionDeviceManagerService::
-                updateSpecialAccessPermissionAsSystem, this, packageInfo).recycleOnUse());
+                updateSpecialAccessPermissionAsSystem, this, association, packageInfo)
+                .recycleOnUse());
     }
 
-    private void updateSpecialAccessPermissionAsSystem(PackageInfo packageInfo) {
+    private void updateSpecialAccessPermissionAsSystem(
+            Association association, PackageInfo packageInfo) {
         if (containsEither(packageInfo.requestedPermissions,
                 android.Manifest.permission.RUN_IN_BACKGROUND,
                 android.Manifest.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND)) {
@@ -602,10 +639,6 @@
         updateAssociations(associations -> CollectionUtils.add(associations, association));
     }
 
-    private void recordAssociation(String privilegedPackage, String deviceAddress) {
-        recordAssociation(new Association(getCallingUserId(), deviceAddress, privilegedPackage));
-    }
-
     private void updateAssociations(Function<Set<Association>, Set<Association>> update) {
         updateAssociations(update, getCallingUserId());
     }
@@ -625,7 +658,7 @@
             if (DEBUG) {
                 Slog.i(LOG_TAG, "Updating associations: " + old + "  -->  " + associations);
             }
-            mCachedAssociations = Collections.unmodifiableSet(associations);
+            mCachedAssociations.put(userId, Collections.unmodifiableSet(associations));
             BackgroundThread.getHandler().sendMessage(PooledLambda.obtainMessage(
                     CompanionDeviceManagerService::persistAssociations,
                     this, associations, userId));
@@ -651,10 +684,17 @@
                     xml.startTag(null, XML_TAG_ASSOCIATIONS);
 
                     forEach(associations, association -> {
-                        xml.startTag(null, XML_TAG_ASSOCIATION)
+                        XmlSerializer tag = xml.startTag(null, XML_TAG_ASSOCIATION)
                                 .attribute(null, XML_ATTR_PACKAGE, association.getPackageName())
-                                .attribute(null, XML_ATTR_DEVICE, association.getDeviceMacAddress())
-                                .endTag(null, XML_TAG_ASSOCIATION);
+                                .attribute(null, XML_ATTR_DEVICE,
+                                        association.getDeviceMacAddress());
+                        if (association.getDeviceProfile() != null) {
+                            tag.attribute(null, XML_ATTR_PROFILE, association.getDeviceProfile());
+                            tag.attribute(null, XML_ATTR_PERSISTENT_PROFILE_GRANTS,
+                                    Boolean.toString(
+                                            association.isKeepProfilePrivilegesWhenDeviceAway()));
+                        }
+                        tag.endTag(null, XML_TAG_ASSOCIATION);
                     });
 
                     xml.endTag(null, XML_TAG_ASSOCIATIONS);
@@ -678,17 +718,21 @@
     @Nullable
     private Set<Association> getAllAssociations(int userId) {
         synchronized (mLock) {
-            if (mCachedAssociations == null) {
-                mCachedAssociations = Collections.unmodifiableSet(
-                        emptyIfNull(readAllAssociations(userId)));
+            if (mCachedAssociations.get(userId) == null) {
+                mCachedAssociations.put(userId, Collections.unmodifiableSet(
+                        emptyIfNull(readAllAssociations(userId))));
                 if (DEBUG) {
                     Slog.i(LOG_TAG, "Read associations from disk: " + mCachedAssociations);
                 }
             }
-            return mCachedAssociations;
+            return mCachedAssociations.get(userId);
         }
     }
 
+    private List<UserInfo> getAllUsers() {
+        return getContext().getSystemService(UserManager.class).getUsers();
+    }
+
     @Nullable
     private Set<Association> getAllAssociations(int userId, @Nullable String packageFilter) {
         return CollectionUtils.filter(
@@ -714,10 +758,15 @@
                     final String appPackage = parser.getAttributeValue(null, XML_ATTR_PACKAGE);
                     final String deviceAddress = parser.getAttributeValue(null, XML_ATTR_DEVICE);
 
+                    final String profile = parser.getAttributeValue(null, XML_ATTR_PROFILE);
+                    final boolean persistentGrants = Boolean.valueOf(
+                            parser.getAttributeValue(null, XML_ATTR_PERSISTENT_PROFILE_GRANTS));
+
                     if (appPackage == null || deviceAddress == null) continue;
 
                     result = ArrayUtils.add(result,
-                            new Association(userId, deviceAddress, appPackage));
+                            new Association(userId, deviceAddress, appPackage,
+                                    profile, persistentGrants));
                 }
                 return result;
             } catch (XmlPullParserException | IOException e) {
@@ -727,6 +776,77 @@
         }
     }
 
+    void onDeviceConnected(String address) {
+        mCurrentlyConnectedDevices.add(address);
+
+        Handler.getMain().removeCallbacksAndMessages(getDisconnectJobHandlerId(address));
+
+        for (UserInfo user : getAllUsers()) {
+            for (Association association : getAllAssociations(user.id)) {
+                if (Objects.equals(address, association.getDeviceMacAddress())) {
+                    if (association.getDeviceProfile() != null) {
+                        Log.i(LOG_TAG, "Granting role " + association.getDeviceProfile()
+                                + " to " + association.getPackageName()
+                                + " due to device connected: " + address);
+                        mRoleManager.addRoleHolderAsUser(
+                                association.getDeviceProfile(),
+                                association.getPackageName(),
+                                RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP,
+                                UserHandle.of(association.getUserId()),
+                                getContext().getMainExecutor(),
+                                success -> {
+                                    if (!success) {
+                                        Log.e(LOG_TAG, "Failed to grant device profile role "
+                                                + association.getDeviceProfile()
+                                                + " to " + association.getPackageName()
+                                                + " for user " + association.getUserId());
+                                    }
+                                });
+                    }
+                }
+            }
+        }
+    }
+
+    void onDeviceDisconnected(String address) {
+        mCurrentlyConnectedDevices.remove(address);
+
+        Handler.getMain().postDelayed(() -> {
+            if (!mCurrentlyConnectedDevices.contains(address)) {
+                for (UserInfo user : getAllUsers()) {
+                    for (Association association : getAllAssociations(user.id)) {
+                        if (association.getDeviceProfile() != null
+                                && Objects.equals(address, association.getDeviceMacAddress())
+                                && !association.isKeepProfilePrivilegesWhenDeviceAway()) {
+                            Log.i(LOG_TAG, "Revoking role " + association.getDeviceProfile()
+                                    + " to " + association.getPackageName()
+                                    + " due to device disconnected: " + address);
+                            mRoleManager.removeRoleHolderAsUser(
+                                    association.getDeviceProfile(),
+                                    association.getPackageName(),
+                                    RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP,
+                                    UserHandle.of(association.getUserId()),
+                                    getContext().getMainExecutor(),
+                                    success -> {
+                                        if (!success) {
+                                            Log.e(LOG_TAG, "Failed to revoke device profile role "
+                                                    + association.getDeviceProfile()
+                                                    + " to " + association.getPackageName()
+                                                    + " for user " + association.getUserId());
+                                        }
+                                    });
+                        }
+                    }
+                }
+            }
+        }, getDisconnectJobHandlerId(address), DEVICE_DISCONNECT_PROFILE_REVOKE_DELAY_MS);
+    }
+
+    @NonNull
+    private String getDisconnectJobHandlerId(String address) {
+        return "CDM_onDisconnected_" + address;
+    }
+
     private class ShellCmd extends ShellCommand {
         public static final String USAGE = "help\n"
                 + "list USER_ID\n"
@@ -749,13 +869,22 @@
                 } break;
 
                 case "associate": {
-                    addAssociation(getNextArgInt(), getNextArgRequired(), getNextArgRequired());
+                    addAssociation(new Association(getNextArgInt(), getNextArgRequired(),
+                            getNextArgRequired(), null, false));
                 } break;
 
                 case "disassociate": {
                     removeAssociation(getNextArgInt(), getNextArgRequired(), getNextArgRequired());
                 } break;
 
+                case "simulate_connect": {
+                    onDeviceConnected(getNextArgRequired());
+                } break;
+
+                case "simulate_disconnect": {
+                    onDeviceDisconnected(getNextArgRequired());
+                } break;
+
                 default: return handleDefaultCommands(cmd);
             }
             return 0;
@@ -771,4 +900,17 @@
         }
     }
 
+
+    private class BluetoothDeviceConnectedListener
+            extends BluetoothAdapter.BluetoothConnectionCallback {
+        @Override
+        public void onDeviceConnected(BluetoothDevice device) {
+            CompanionDeviceManagerService.this.onDeviceConnected(device.getAddress());
+        }
+
+        @Override
+        public void onDeviceDisconnected(BluetoothDevice device) {
+            CompanionDeviceManagerService.this.onDeviceDisconnected(device.getAddress());
+        }
+    }
 }
diff --git a/services/contentcapture/OWNERS b/services/contentcapture/OWNERS
new file mode 100644
index 0000000..a28e00a
--- /dev/null
+++ b/services/contentcapture/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/contentcapture/OWNERS
diff --git a/services/contentsuggestions/OWNERS b/services/contentsuggestions/OWNERS
new file mode 100644
index 0000000..449db3a
--- /dev/null
+++ b/services/contentsuggestions/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/contentsuggestions/OWNERS
diff --git a/services/core/OWNERS b/services/core/OWNERS
new file mode 100644
index 0000000..88d0b61
--- /dev/null
+++ b/services/core/OWNERS
@@ -0,0 +1 @@
+per-file Android.bp = file:platform/build/soong:/OWNERS
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 6989e32..53bfcec 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -949,9 +949,6 @@
     /** Returns whether or not permissions need to be upgraded for the given user */
     public abstract boolean isPermissionUpgradeNeeded(@UserIdInt int userId);
 
-    /** Sets the enforcement of reading external storage */
-    public abstract void setReadExternalStorageEnforced(boolean enforced);
-
     /**
      * Allows the integrity component to respond to the
      * {@link Intent#ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION package verification
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index f0677a2..0d0f0dd 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -169,7 +169,6 @@
 import android.util.LocalLog;
 import android.util.Log;
 import android.util.Pair;
-import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.util.Xml;
@@ -1973,7 +1972,7 @@
     private void registerNetdEventCallback() {
         final IIpConnectivityMetrics ipConnectivityMetrics = mDeps.getIpConnectivityMetrics();
         if (ipConnectivityMetrics == null) {
-            Slog.wtf(TAG, "Missing IIpConnectivityMetrics");
+            Log.wtf(TAG, "Missing IIpConnectivityMetrics");
             return;
         }
 
@@ -2439,7 +2438,7 @@
             if (VDBG || DDBG) log("Setting MTU size: " + iface + ", " + mtu);
             mNetd.interfaceSetMtu(iface, mtu);
         } catch (RemoteException | ServiceSpecificException e) {
-            Slog.e(TAG, "exception in interfaceSetMtu()" + e);
+            loge("exception in interfaceSetMtu()" + e);
         }
     }
 
@@ -2461,7 +2460,7 @@
         if (tcpBufferSizes.equals(mCurrentTcpBufferSizes)) return;
 
         try {
-            if (VDBG || DDBG) Slog.d(TAG, "Setting tx/rx TCP buffers to " + tcpBufferSizes);
+            if (VDBG || DDBG) log("Setting tx/rx TCP buffers to " + tcpBufferSizes);
 
             String rmemValues = String.join(" ", values[0], values[1], values[2]);
             String wmemValues = String.join(" ", values[3], values[4], values[5]);
@@ -2762,7 +2761,7 @@
                 case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: {
                     NetworkCapabilities networkCapabilities = (NetworkCapabilities) msg.obj;
                     if (networkCapabilities.hasConnectivityManagedCapability()) {
-                        Slog.wtf(TAG, "BUG: " + nai + " has CS-managed capability.");
+                        Log.wtf(TAG, "BUG: " + nai + " has CS-managed capability.");
                     }
                     if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
                         // Make sure the original object is not mutated. NetworkAgent normally
@@ -3067,7 +3066,7 @@
             // Legacy version of notifyNetworkTestedWithExtras.
             // Would only be called if the system has a NetworkStack module older than the
             // framework, which does not happen in practice.
-            Slog.wtf(TAG, "Deprecated notifyNetworkTested called: no action taken");
+            Log.wtf(TAG, "Deprecated notifyNetworkTested called: no action taken");
         }
 
         @Override
@@ -3544,7 +3543,7 @@
                 numRequests = nai.numForegroundNetworkRequests();
                 break;
             default:
-                Slog.wtf(TAG, "Invalid reason. Cannot happen.");
+                Log.wtf(TAG, "Invalid reason. Cannot happen.");
                 return true;
         }
 
@@ -3706,7 +3705,7 @@
         synchronized (mUidToNetworkRequestCount) {
             final int requests = mUidToNetworkRequestCount.get(nri.mUid, 0);
             if (requests < 1) {
-                Slog.wtf(TAG, "BUG: too small request count " + requests + " for UID " + nri.mUid);
+                Log.wtf(TAG, "BUG: too small request count " + requests + " for UID " + nri.mUid);
             } else if (requests == 1) {
                 mUidToNetworkRequestCount.removeAt(mUidToNetworkRequestCount.indexOfKey(nri.mUid));
             } else {
@@ -3751,7 +3750,7 @@
         }
 
         if (!nai.networkAgentConfig.explicitlySelected) {
-            Slog.wtf(TAG, "BUG: setAcceptUnvalidated non non-explicitly selected network");
+            Log.wtf(TAG, "BUG: setAcceptUnvalidated non non-explicitly selected network");
         }
 
         if (accept != nai.networkAgentConfig.acceptUnvalidated) {
@@ -4021,7 +4020,7 @@
                 highPriority = nai.networkAgentConfig.explicitlySelected;
                 break;
             default:
-                Slog.wtf(TAG, "Unknown notification type " + type);
+                Log.wtf(TAG, "Unknown notification type " + type);
                 return;
         }
 
@@ -4343,7 +4342,7 @@
         synchronized (this) {
             if (!mNetTransitionWakeLock.isHeld()) {
                 mWakelockLogs.log(String.format("RELEASE: already released (%s)", event));
-                Slog.w(TAG, "expected Net Transition WakeLock to be held");
+                Log.w(TAG, "expected Net Transition WakeLock to be held");
                 return;
             }
             mNetTransitionWakeLock.release();
@@ -4515,7 +4514,7 @@
 
         @Override
         public void onChange(boolean selfChange) {
-            Slog.wtf(TAG, "Should never be reached.");
+            Log.wtf(TAG, "Should never be reached.");
         }
 
         @Override
@@ -4530,15 +4529,19 @@
     }
 
     private static void log(String s) {
-        Slog.d(TAG, s);
+        Log.d(TAG, s);
+    }
+
+    private static void logw(String s) {
+        Log.w(TAG, s);
     }
 
     private static void loge(String s) {
-        Slog.e(TAG, s);
+        Log.e(TAG, s);
     }
 
     private static void loge(String s, Throwable t) {
-        Slog.e(TAG, s, t);
+        Log.e(TAG, s, t);
     }
 
     /**
@@ -4825,7 +4828,7 @@
     @Override
     public boolean updateLockdownVpn() {
         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
-            Slog.w(TAG, "Lockdown VPN only available to AID_SYSTEM");
+            logw("Lockdown VPN only available to AID_SYSTEM");
             return false;
         }
 
@@ -4835,21 +4838,21 @@
             if (mLockdownEnabled) {
                 byte[] profileTag = mKeyStore.get(Credentials.LOCKDOWN_VPN);
                 if (profileTag == null) {
-                    Slog.e(TAG, "Lockdown VPN configured but cannot be read from keystore");
+                    loge("Lockdown VPN configured but cannot be read from keystore");
                     return false;
                 }
                 String profileName = new String(profileTag);
                 final VpnProfile profile = VpnProfile.decode(
                         profileName, mKeyStore.get(Credentials.VPN + profileName));
                 if (profile == null) {
-                    Slog.e(TAG, "Lockdown VPN configured invalid profile " + profileName);
+                    loge("Lockdown VPN configured invalid profile " + profileName);
                     setLockdownTracker(null);
                     return true;
                 }
                 int user = UserHandle.getUserId(Binder.getCallingUid());
                 Vpn vpn = mVpns.get(user);
                 if (vpn == null) {
-                    Slog.w(TAG, "VPN for user " + user + " not ready yet. Skipping lockdown");
+                    logw("VPN for user " + user + " not ready yet. Skipping lockdown");
                     return false;
                 }
                 setLockdownTracker(new LockdownVpnTracker(mContext, this, mHandler, vpn, profile));
@@ -4909,7 +4912,7 @@
             if (vpn == null) {
                 // Shouldn't happen as all code paths that point here should have checked the Vpn
                 // exists already.
-                Slog.wtf(TAG, "User " + userId + " has no Vpn configuration");
+                Log.wtf(TAG, "User " + userId + " has no Vpn configuration");
                 return false;
             }
 
@@ -4925,7 +4928,7 @@
         synchronized (mVpns) {
             Vpn vpn = mVpns.get(userId);
             if (vpn == null) {
-                Slog.w(TAG, "User " + userId + " has no Vpn configuration");
+                logw("User " + userId + " has no Vpn configuration");
                 return false;
             }
             return vpn.isAlwaysOnPackageSupported(packageName, mKeyStore);
@@ -4946,7 +4949,7 @@
 
             Vpn vpn = mVpns.get(userId);
             if (vpn == null) {
-                Slog.w(TAG, "User " + userId + " has no Vpn configuration");
+                logw("User " + userId + " has no Vpn configuration");
                 return false;
             }
             if (!vpn.setAlwaysOnPackage(packageName, lockdown, lockdownWhitelist, mKeyStore)) {
@@ -4968,7 +4971,7 @@
         synchronized (mVpns) {
             Vpn vpn = mVpns.get(userId);
             if (vpn == null) {
-                Slog.w(TAG, "User " + userId + " has no Vpn configuration");
+                logw("User " + userId + " has no Vpn configuration");
                 return null;
             }
             return vpn.getAlwaysOnPackage();
@@ -4983,7 +4986,7 @@
         synchronized (mVpns) {
             Vpn vpn = mVpns.get(userId);
             if (vpn == null) {
-                Slog.w(TAG, "User " + userId + " has no Vpn configuration");
+                logw("User " + userId + " has no Vpn configuration");
                 return false;
             }
             return vpn.getLockdown();
@@ -4998,7 +5001,7 @@
         synchronized (mVpns) {
             Vpn vpn = mVpns.get(userId);
             if (vpn == null) {
-                Slog.w(TAG, "User " + userId + " has no Vpn configuration");
+                logw("User " + userId + " has no Vpn configuration");
                 return null;
             }
             return vpn.getLockdownAllowlist();
@@ -5183,7 +5186,7 @@
 
     private void onPackageReplaced(String packageName, int uid) {
         if (TextUtils.isEmpty(packageName) || uid < 0) {
-            Slog.wtf(TAG, "Invalid package in onPackageReplaced: " + packageName + " | " + uid);
+            Log.wtf(TAG, "Invalid package in onPackageReplaced: " + packageName + " | " + uid);
             return;
         }
         final int userId = UserHandle.getUserId(uid);
@@ -5194,7 +5197,7 @@
             }
             // Legacy always-on VPN won't be affected since the package name is not set.
             if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName)) {
-                Slog.d(TAG, "Restarting always-on VPN package " + packageName + " for user "
+                log("Restarting always-on VPN package " + packageName + " for user "
                         + userId);
                 vpn.startAlwaysOnVpn(mKeyStore);
             }
@@ -5203,7 +5206,7 @@
 
     private void onPackageRemoved(String packageName, int uid, boolean isReplacing) {
         if (TextUtils.isEmpty(packageName) || uid < 0) {
-            Slog.wtf(TAG, "Invalid package in onPackageRemoved: " + packageName + " | " + uid);
+            Log.wtf(TAG, "Invalid package in onPackageRemoved: " + packageName + " | " + uid);
             return;
         }
 
@@ -5215,7 +5218,7 @@
             }
             // Legacy always-on VPN won't be affected since the package name is not set.
             if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName) && !isReplacing) {
-                Slog.d(TAG, "Removing always-on VPN package " + packageName + " for user "
+                log("Removing always-on VPN package " + packageName + " for user "
                         + userId);
                 vpn.setAlwaysOnPackage(null, false, null, mKeyStore);
             }
@@ -5831,7 +5834,7 @@
             // Avoid creating duplicates. even if an app makes a direct AIDL call.
             // This will never happen if an app calls ConnectivityManager#registerNetworkProvider,
             // as that will throw if a duplicate provider is registered.
-            Slog.e(TAG, "Attempt to register existing NetworkProviderInfo "
+            loge("Attempt to register existing NetworkProviderInfo "
                     + mNetworkProviderInfos.get(npi.messenger).name);
             return;
         }
@@ -6049,6 +6052,7 @@
      * Stores into |nai| any data coming from the agent that might also be written to the network's
      * LinkProperties by ConnectivityService itself. This ensures that the data provided by the
      * agent is not lost when updateLinkProperties is called.
+     * This method should never alter the agent's LinkProperties, only store data in |nai|.
      */
     private void processLinkPropertiesFromAgent(NetworkAgentInfo nai, LinkProperties lp) {
         lp.ensureDirectlyConnectedRoutes();
@@ -6350,6 +6354,7 @@
      * Stores into |nai| any data coming from the agent that might also be written to the network's
      * NetworkCapabilities by ConnectivityService itself. This ensures that the data provided by the
      * agent is not lost when updateCapabilities is called.
+     * This method should never alter the agent's NetworkCapabilities, only store data in |nai|.
      */
     private void processCapabilitiesFromAgent(NetworkAgentInfo nai, NetworkCapabilities nc) {
         nai.declaredMetered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED);
@@ -6441,7 +6446,7 @@
             // stop being matched by the updated agent.
             String diff = nai.networkCapabilities.describeImmutableDifferences(nc);
             if (!TextUtils.isEmpty(diff)) {
-                Slog.wtf(TAG, "BUG: " + nai + " lost immutable capabilities:" + diff);
+                Log.wtf(TAG, "BUG: " + nai + " lost immutable capabilities:" + diff);
             }
         }
 
@@ -7001,7 +7006,7 @@
             }
             newSatisfier.unlingerRequest(nri.request);
             if (!newSatisfier.addRequest(nri.request)) {
-                Slog.wtf(TAG, "BUG: " + newSatisfier.toShortString() + " already has "
+                Log.wtf(TAG, "BUG: " + newSatisfier.toShortString() + " already has "
                         + nri.request);
             }
         } else {
@@ -7349,7 +7354,7 @@
             networkAgent.everConnected = true;
 
             if (networkAgent.linkProperties == null) {
-                Slog.wtf(TAG, networkAgent.toShortString() + " connected with null LinkProperties");
+                Log.wtf(TAG, networkAgent.toShortString() + " connected with null LinkProperties");
             }
 
             // NetworkCapabilities need to be set before sending the private DNS config to
@@ -8197,8 +8202,10 @@
 
         final NetworkRequestInfo nri = cbInfo.mRequestInfo;
 
-        if (uid != nri.mUid) {
-            if (VDBG) loge("Different uid than registrant attempting to unregister cb");
+        // Caller's UID must either be the registrants (if they are unregistering) or the System's
+        // (if the Binder died)
+        if (uid != nri.mUid && uid != Process.SYSTEM_UID) {
+            if (DBG) loge("Uid(" + uid + ") not registrant's (" + nri.mUid + ") or System's");
             return;
         }
 
diff --git a/services/core/java/com/android/server/MasterClearReceiver.java b/services/core/java/com/android/server/MasterClearReceiver.java
index 793e342..e248b21 100644
--- a/services/core/java/com/android/server/MasterClearReceiver.java
+++ b/services/core/java/com/android/server/MasterClearReceiver.java
@@ -25,7 +25,6 @@
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
 import android.text.TextUtils;
-import android.util.Log;
 import android.util.Slog;
 import android.view.WindowManager;
 
@@ -59,6 +58,7 @@
                 .getString(com.android.internal.R.string.config_factoryResetPackage);
         if (Intent.ACTION_FACTORY_RESET.equals(intent.getAction())
                 && !TextUtils.isEmpty(factoryResetPackage)) {
+            Slog.i(TAG, "Re-directing intent to " + factoryResetPackage);
             intent.setPackage(factoryResetPackage).setComponent(null);
             context.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
             return;
@@ -77,9 +77,12 @@
             @Override
             public void run() {
                 try {
+                    Slog.i(TAG, "Calling RecoverySystem.rebootWipeUserData(context, "
+                            + "shutdown=" + shutdown + ", reason=" + reason
+                            + ", forceWipe=" + forceWipe + ", wipeEsims=" + mWipeEsims + ")");
                     RecoverySystem
                             .rebootWipeUserData(context, shutdown, reason, forceWipe, mWipeEsims);
-                    Log.wtf(TAG, "Still running after master clear?!");
+                    Slog.wtf(TAG, "Still running after master clear?!");
                 } catch (IOException e) {
                     Slog.e(TAG, "Can't perform master clear/factory reset", e);
                 } catch (SecurityException e) {
@@ -90,8 +93,10 @@
 
         if (mWipeExternalStorage) {
             // thr will be started at the end of this task.
+            Slog.i(TAG, "Wiping external storage on async task");
             new WipeDataTask(context, thr).execute();
         } else {
+            Slog.i(TAG, "NOT wiping external storage; starting thread " + thr.getName());
             thr.start();
         }
     }
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 1c99465..821a967 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -24,12 +24,14 @@
 import static android.net.INetd.FIREWALL_CHAIN_DOZABLE;
 import static android.net.INetd.FIREWALL_CHAIN_NONE;
 import static android.net.INetd.FIREWALL_CHAIN_POWERSAVE;
+import static android.net.INetd.FIREWALL_CHAIN_RESTRICTED;
 import static android.net.INetd.FIREWALL_CHAIN_STANDBY;
 import static android.net.INetd.FIREWALL_DENYLIST;
 import static android.net.INetd.FIREWALL_RULE_ALLOW;
 import static android.net.INetd.FIREWALL_RULE_DENY;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_RESTRICTED;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
 import static android.net.NetworkStats.SET_DEFAULT;
@@ -88,7 +90,6 @@
 import android.util.SparseIntArray;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FrameworkStatsLog;
@@ -122,7 +123,7 @@
      * Helper class that encapsulates NetworkManagementService dependencies and makes them
      * easier to mock in unit tests.
      */
-    static class SystemServices {
+    static class Dependencies {
         public IBinder getService(String name) {
             return ServiceManager.getService(name);
         }
@@ -132,6 +133,10 @@
         public INetd getNetd() {
             return NetdService.get();
         }
+
+        public int getCallingUid() {
+            return Binder.getCallingUid();
+        }
     }
 
     private static final String TAG = "NetworkManagement";
@@ -157,7 +162,7 @@
 
     private final Handler mDaemonHandler;
 
-    private final SystemServices mServices;
+    private final Dependencies mDeps;
 
     private INetd mNetdService;
 
@@ -215,6 +220,11 @@
      */
     @GuardedBy("mRulesLock")
     private SparseIntArray mUidFirewallPowerSaveRules = new SparseIntArray();
+    /**
+     * Contains the per-UID firewall rules that are used when Restricted Networking Mode is enabled.
+     */
+    @GuardedBy("mRulesLock")
+    private SparseIntArray mUidFirewallRestrictedRules = new SparseIntArray();
     /** Set of states for the child firewall chains. True if the chain is active. */
     @GuardedBy("mRulesLock")
     final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
@@ -254,33 +264,32 @@
      * @param context  Binder context for this service
      */
     private NetworkManagementService(
-            Context context, SystemServices services) {
+            Context context, Dependencies deps) {
         mContext = context;
-        mServices = services;
+        mDeps = deps;
 
         mDaemonHandler = new Handler(FgThread.get().getLooper());
 
         mNetdUnsolicitedEventListener = new NetdUnsolicitedEventListener();
 
-        mServices.registerLocalService(new LocalService());
+        mDeps.registerLocalService(new LocalService());
 
         synchronized (mTetheringStatsProviders) {
             mTetheringStatsProviders.put(new NetdTetheringStatsProvider(), "netd");
         }
     }
 
-    @VisibleForTesting
-    NetworkManagementService() {
+    private NetworkManagementService() {
         mContext = null;
         mDaemonHandler = null;
-        mServices = null;
+        mDeps = null;
         mNetdUnsolicitedEventListener = null;
     }
 
-    static NetworkManagementService create(Context context, SystemServices services)
+    static NetworkManagementService create(Context context, Dependencies deps)
             throws InterruptedException {
         final NetworkManagementService service =
-                new NetworkManagementService(context, services);
+                new NetworkManagementService(context, deps);
         if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
         if (DBG) Slog.d(TAG, "Connecting native netd service");
         service.connectNativeNetdService();
@@ -289,7 +298,7 @@
     }
 
     public static NetworkManagementService create(Context context) throws InterruptedException {
-        return create(context, new SystemServices());
+        return create(context, new Dependencies());
     }
 
     public void systemReady() {
@@ -310,7 +319,7 @@
                 return mBatteryStats;
             }
             mBatteryStats =
-                    IBatteryStats.Stub.asInterface(mServices.getService(BatteryStats.SERVICE_NAME));
+                    IBatteryStats.Stub.asInterface(mDeps.getService(BatteryStats.SERVICE_NAME));
             return mBatteryStats;
         }
     }
@@ -511,7 +520,7 @@
     }
 
     private void connectNativeNetdService() {
-        mNetdService = mServices.getNetd();
+        mNetdService = mDeps.getNetd();
         try {
             mNetdService.registerUnsolicitedEventListener(mNetdUnsolicitedEventListener);
             if (DBG) Slog.d(TAG, "Register unsolicited event listener");
@@ -602,9 +611,15 @@
             syncFirewallChainLocked(FIREWALL_CHAIN_STANDBY, "standby ");
             syncFirewallChainLocked(FIREWALL_CHAIN_DOZABLE, "dozable ");
             syncFirewallChainLocked(FIREWALL_CHAIN_POWERSAVE, "powersave ");
+            syncFirewallChainLocked(FIREWALL_CHAIN_RESTRICTED, "restricted ");
 
-            final int[] chains =
-                    {FIREWALL_CHAIN_STANDBY, FIREWALL_CHAIN_DOZABLE, FIREWALL_CHAIN_POWERSAVE};
+            final int[] chains = {
+                    FIREWALL_CHAIN_STANDBY,
+                    FIREWALL_CHAIN_DOZABLE,
+                    FIREWALL_CHAIN_POWERSAVE,
+                    FIREWALL_CHAIN_RESTRICTED
+            };
+
             for (int chain : chains) {
                 if (getFirewallChainState(chain)) {
                     setFirewallChainEnabled(chain, true);
@@ -1437,7 +1452,7 @@
 
     @Override
     public void setUidCleartextNetworkPolicy(int uid, int policy) {
-        if (Binder.getCallingUid() != uid) {
+        if (mDeps.getCallingUid() != uid) {
             NetworkStack.checkNetworkStackPermission(mContext);
         }
 
@@ -1695,6 +1710,8 @@
                 return FIREWALL_CHAIN_NAME_DOZABLE;
             case FIREWALL_CHAIN_POWERSAVE:
                 return FIREWALL_CHAIN_NAME_POWERSAVE;
+            case FIREWALL_CHAIN_RESTRICTED:
+                return FIREWALL_CHAIN_NAME_RESTRICTED;
             default:
                 throw new IllegalArgumentException("Bad child chain: " + chain);
         }
@@ -1708,6 +1725,8 @@
                 return FIREWALL_ALLOWLIST;
             case FIREWALL_CHAIN_POWERSAVE:
                 return FIREWALL_ALLOWLIST;
+            case FIREWALL_CHAIN_RESTRICTED:
+                return FIREWALL_ALLOWLIST;
             default:
                 return isFirewallEnabled() ? FIREWALL_ALLOWLIST : FIREWALL_DENYLIST;
         }
@@ -1752,6 +1771,9 @@
                     case FIREWALL_CHAIN_POWERSAVE:
                         mNetdService.firewallReplaceUidChain("fw_powersave", true, uids);
                         break;
+                    case FIREWALL_CHAIN_RESTRICTED:
+                        mNetdService.firewallReplaceUidChain("fw_restricted", true, uids);
+                        break;
                     case FIREWALL_CHAIN_NONE:
                     default:
                         Slog.d(TAG, "setFirewallUidRules() called on invalid chain: " + chain);
@@ -1836,6 +1858,8 @@
                 return mUidFirewallDozableRules;
             case FIREWALL_CHAIN_POWERSAVE:
                 return mUidFirewallPowerSaveRules;
+            case FIREWALL_CHAIN_RESTRICTED:
+                return mUidFirewallRestrictedRules;
             case FIREWALL_CHAIN_NONE:
                 return mUidFirewallRules;
             default:
@@ -1851,8 +1875,8 @@
         return rule;
     }
 
-    private static void enforceSystemUid() {
-        final int uid = Binder.getCallingUid();
+    private void enforceSystemUid() {
+        final int uid = mDeps.getCallingUid();
         if (uid != Process.SYSTEM_UID) {
             throw new SecurityException("Only available to AID_SYSTEM");
         }
@@ -1910,17 +1934,22 @@
         synchronized (mRulesLock) {
             dumpUidFirewallRule(pw, "", mUidFirewallRules);
 
-            pw.print("UID firewall standby chain enabled: "); pw.println(
-                    getFirewallChainState(FIREWALL_CHAIN_STANDBY));
+            pw.print("UID firewall standby chain enabled: ");
+            pw.println(getFirewallChainState(FIREWALL_CHAIN_STANDBY));
             dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_STANDBY, mUidFirewallStandbyRules);
 
-            pw.print("UID firewall dozable chain enabled: "); pw.println(
-                    getFirewallChainState(FIREWALL_CHAIN_DOZABLE));
+            pw.print("UID firewall dozable chain enabled: ");
+            pw.println(getFirewallChainState(FIREWALL_CHAIN_DOZABLE));
             dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_DOZABLE, mUidFirewallDozableRules);
 
-            pw.println("UID firewall powersave chain enabled: " +
-                    getFirewallChainState(FIREWALL_CHAIN_POWERSAVE));
+            pw.print("UID firewall powersave chain enabled: ");
+            pw.println(getFirewallChainState(FIREWALL_CHAIN_POWERSAVE));
             dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_POWERSAVE, mUidFirewallPowerSaveRules);
+
+            pw.print("UID firewall restricted mode chain enabled: ");
+            pw.println(getFirewallChainState(FIREWALL_CHAIN_RESTRICTED));
+            dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_RESTRICTED,
+                    mUidFirewallRestrictedRules);
         }
 
         synchronized (mIdleTimerLock) {
@@ -2071,6 +2100,11 @@
                 if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of power saver mode");
                 return true;
             }
+            if (getFirewallChainState(FIREWALL_CHAIN_RESTRICTED)
+                    && mUidFirewallRestrictedRules.get(uid) != FIREWALL_RULE_ALLOW) {
+                if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of restricted mode");
+                return true;
+            }
             if (mUidRejectOnMetered.get(uid)) {
                 if (DBG) Slog.d(TAG, "Uid " + uid + " restricted because of no metered data"
                         + " in the background");
@@ -2096,60 +2130,10 @@
         }
     }
 
-    @VisibleForTesting
-    class LocalService extends NetworkManagementInternal {
+    private class LocalService extends NetworkManagementInternal {
         @Override
         public boolean isNetworkRestrictedForUid(int uid) {
             return isNetworkRestrictedInternal(uid);
         }
     }
-
-    @VisibleForTesting
-    Injector getInjector() {
-        return new Injector();
-    }
-
-    @VisibleForTesting
-    class Injector {
-        void setDataSaverMode(boolean dataSaverMode) {
-            mDataSaverMode = dataSaverMode;
-        }
-
-        void setFirewallChainState(int chain, boolean state) {
-            NetworkManagementService.this.setFirewallChainState(chain, state);
-        }
-
-        void setFirewallRule(int chain, int uid, int rule) {
-            synchronized (mRulesLock) {
-                getUidFirewallRulesLR(chain).put(uid, rule);
-            }
-        }
-
-        void setUidOnMeteredNetworkList(boolean denylist, int uid, boolean enable) {
-            synchronized (mRulesLock) {
-                if (denylist) {
-                    mUidRejectOnMetered.put(uid, enable);
-                } else {
-                    mUidAllowOnMetered.put(uid, enable);
-                }
-            }
-        }
-
-        void reset() {
-            synchronized (mRulesLock) {
-                setDataSaverMode(false);
-                final int[] chains = {
-                        FIREWALL_CHAIN_DOZABLE,
-                        FIREWALL_CHAIN_STANDBY,
-                        FIREWALL_CHAIN_POWERSAVE
-                };
-                for (int chain : chains) {
-                    setFirewallChainState(chain, false);
-                    getUidFirewallRulesLR(chain).clear();
-                }
-                mUidAllowOnMetered.clear();
-                mUidRejectOnMetered.clear();
-            }
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 3443918..fc3a7c8 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -59,7 +59,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.util.DumpUtils;
-import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.permission.LegacyPermissionManagerInternal;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -290,7 +290,7 @@
                     String useOpenWifiPackage = Global.getString(mContext.getContentResolver(),
                             Global.USE_OPEN_WIFI_PACKAGE);
                     if (!TextUtils.isEmpty(useOpenWifiPackage)) {
-                        LocalServices.getService(PermissionManagerServiceInternal.class)
+                        LocalServices.getService(LegacyPermissionManagerInternal.class)
                                 .grantDefaultPermissionsToDefaultUseOpenWifiApp(useOpenWifiPackage,
                                         userId);
                     }
@@ -302,7 +302,7 @@
                 false /*notifyForDescendants*/,
                 mUseOpenWifiPackageObserver);
         // Set a callback for the package manager to query the use open wifi app.
-        LocalServices.getService(PermissionManagerServiceInternal.class)
+        LocalServices.getService(LegacyPermissionManagerInternal.class)
                 .setUseOpenWifiAppPackagesProvider((userId) -> {
                     String useOpenWifiPackage = Global.getString(mContext.getContentResolver(),
                             Global.USE_OPEN_WIFI_PACKAGE);
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index 8706cdf..48cbd54 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -9,3 +9,19 @@
 
 # Userspace reboot
 per-file UserspaceRebootLogger.java = ioffe@google.com, tomcherry@google.com
+
+per-file *Alarm* = file:/apex/jobscheduler/OWNERS
+per-file *AppOps* = file:/core/java/android/permission/OWNERS
+per-file *Bluetooth* = file:/core/java/android/bluetooth/OWNERS
+per-file *Gnss* = file:/services/core/java/com/android/server/location/OWNERS
+per-file *Location* = file:/services/core/java/com/android/server/location/OWNERS
+per-file *Network* = file:/services/core/java/com/android/server/net/OWNERS
+per-file *Storage* = file:/core/java/android/os/storage/OWNERS
+per-file *TimeUpdate* = file:/core/java/android/app/timezone/OWNERS
+per-file ConnectivityService.java = file:/services/core/java/com/android/server/net/OWNERS
+per-file IpSecService.java = file:/services/core/java/com/android/server/net/OWNERS
+per-file MmsServiceBroker.java = file:/telephony/OWNERS
+per-file NetIdManager.java = file:/services/core/java/com/android/server/net/OWNERS
+per-file PackageWatchdog.java = file:/services/core/java/com/android/server/rollback/OWNERS
+per-file TelephonyRegistry.java = file:/telephony/OWNERS
+per-file UiModeManagerService.java = file:/packages/SystemUI/OWNERS
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index 9bf63cb..99a1d86 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -52,9 +52,7 @@
 
 import libcore.io.IoUtils;
 
-import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -149,6 +147,7 @@
     private static final String ATTR_DURATION = "duration";
     private static final String ATTR_EXPLICIT_HEALTH_CHECK_DURATION = "health-check-duration";
     private static final String ATTR_PASSED_HEALTH_CHECK = "passed-health-check";
+    private static final String ATTR_MITIGATION_CALLS = "mitigation-calls";
 
     @GuardedBy("PackageWatchdog.class")
     private static PackageWatchdog sPackageWatchdog;
@@ -779,7 +778,6 @@
 
     @GuardedBy("mLock")
     private Set<String> getPackagesPendingHealthChecksLocked() {
-        Slog.d(TAG, "Getting all observed packages pending health checks");
         Set<String> packages = new ArraySet<>();
         Iterator<ObserverInternal> oit = mAllObservers.values().iterator();
         while (oit.hasNext()) {
@@ -828,7 +826,6 @@
             Slog.i(TAG, "Cancelling state sync, nothing to sync");
             mUptimeAtLastStateSync = 0;
         } else {
-            Slog.i(TAG, "Scheduling next state sync in " + durationMs + "ms");
             mUptimeAtLastStateSync = mSystemClock.uptimeMillis();
             mShortTaskHandler.postDelayed(mSyncStateWithScheduledReason, durationMs);
         }
@@ -869,7 +866,6 @@
             return;
         }
 
-        Slog.i(TAG, "Removing " + elapsedMs + "ms from all packages on all observers");
         Iterator<ObserverInternal> it = mAllObservers.values().iterator();
         while (it.hasNext()) {
             ObserverInternal observer = it.next();
@@ -1067,6 +1063,33 @@
         }
     }
 
+    /** Convert a {@code LongArrayQueue} to a String of comma-separated values. */
+    public static String longArrayQueueToString(LongArrayQueue queue) {
+        if (queue.size() > 0) {
+            StringBuilder sb = new StringBuilder();
+            sb.append(queue.get(0));
+            for (int i = 1; i < queue.size(); i++) {
+                sb.append(",");
+                sb.append(queue.get(i));
+            }
+            return sb.toString();
+        }
+        return "";
+    }
+
+    /** Parse a comma-separated String of longs into a LongArrayQueue. */
+    public static LongArrayQueue parseLongArrayQueue(String commaSeparatedValues) {
+        LongArrayQueue result = new LongArrayQueue();
+        if (!TextUtils.isEmpty(commaSeparatedValues)) {
+            String[] values = commaSeparatedValues.split(",");
+            for (String value : values) {
+                result.addLast(Long.parseLong(value));
+            }
+        }
+        return result;
+    }
+
+
     /** Dump status of every observer in mAllObservers. */
     public void dump(IndentingPrintWriter pw) {
         pw.println("Package Watchdog status");
@@ -1240,16 +1263,7 @@
                 while (XmlUtils.nextElementWithin(parser, innerDepth)) {
                     if (TAG_PACKAGE.equals(parser.getName())) {
                         try {
-                            String packageName = parser.getAttributeValue(
-                                    null, ATTR_NAME);
-                            long duration = parser.getAttributeLong(
-                                    null, ATTR_DURATION);
-                            long healthCheckDuration = parser.getAttributeLong(
-                                    null, ATTR_EXPLICIT_HEALTH_CHECK_DURATION);
-                            boolean hasPassedHealthCheck = parser.getAttributeBoolean(
-                                    null, ATTR_PASSED_HEALTH_CHECK, false);
-                            MonitoredPackage pkg = watchdog.newMonitoredPackage(packageName,
-                                    duration, healthCheckDuration, hasPassedHealthCheck);
+                            MonitoredPackage pkg = watchdog.parseMonitoredPackage(parser);
                             if (pkg != null) {
                                 packages.add(pkg);
                             }
@@ -1305,16 +1319,31 @@
 
     MonitoredPackage newMonitoredPackage(
             String name, long durationMs, boolean hasPassedHealthCheck) {
-        return newMonitoredPackage(name, durationMs, Long.MAX_VALUE, hasPassedHealthCheck);
+        return newMonitoredPackage(name, durationMs, Long.MAX_VALUE, hasPassedHealthCheck,
+                new LongArrayQueue());
     }
 
     MonitoredPackage newMonitoredPackage(String name, long durationMs, long healthCheckDurationMs,
-            boolean hasPassedHealthCheck) {
+            boolean hasPassedHealthCheck, LongArrayQueue mitigationCalls) {
         VersionedPackage pkg = getVersionedPackage(name);
         if (pkg == null) {
             return null;
         }
-        return new MonitoredPackage(pkg, durationMs, healthCheckDurationMs, hasPassedHealthCheck);
+        return new MonitoredPackage(pkg, durationMs, healthCheckDurationMs,
+                hasPassedHealthCheck, mitigationCalls);
+    }
+
+    MonitoredPackage parseMonitoredPackage(TypedXmlPullParser parser)
+            throws XmlPullParserException {
+        String packageName = parser.getAttributeValue(null, ATTR_NAME);
+        long duration = parser.getAttributeLong(null, ATTR_DURATION);
+        long healthCheckDuration = parser.getAttributeLong(null,
+                        ATTR_EXPLICIT_HEALTH_CHECK_DURATION);
+        boolean hasPassedHealthCheck = parser.getAttributeBoolean(null, ATTR_PASSED_HEALTH_CHECK);
+        LongArrayQueue mitigationCalls = parseLongArrayQueue(
+                parser.getAttributeValue(null, ATTR_MITIGATION_CALLS));
+        return newMonitoredPackage(packageName,
+                duration, healthCheckDuration, hasPassedHealthCheck, mitigationCalls);
     }
 
     /**
@@ -1332,7 +1361,7 @@
         // Times when an observer was called to mitigate this package's failure. Sorted in
         // ascending order.
         @GuardedBy("mLock")
-        private final LongArrayQueue mMitigationCalls = new LongArrayQueue();
+        private final LongArrayQueue mMitigationCalls;
         // One of STATE_[ACTIVE|INACTIVE|PASSED|FAILED]. Updated on construction and after
         // methods that could change the health check state: handleElapsedTimeLocked and
         // tryPassHealthCheckLocked
@@ -1353,12 +1382,14 @@
         @GuardedBy("mLock")
         private long mHealthCheckDurationMs = Long.MAX_VALUE;
 
-        private MonitoredPackage(VersionedPackage pkg, long durationMs,
-                long healthCheckDurationMs, boolean hasPassedHealthCheck) {
+        MonitoredPackage(VersionedPackage pkg, long durationMs,
+                long healthCheckDurationMs, boolean hasPassedHealthCheck,
+                LongArrayQueue mitigationCalls) {
             mPackage = pkg;
             mDurationMs = durationMs;
             mHealthCheckDurationMs = healthCheckDurationMs;
             mHasPassedHealthCheck = hasPassedHealthCheck;
+            mMitigationCalls = mitigationCalls;
             updateHealthCheckStateLocked();
         }
 
@@ -1370,6 +1401,8 @@
             out.attributeLong(null, ATTR_DURATION, mDurationMs);
             out.attributeLong(null, ATTR_EXPLICIT_HEALTH_CHECK_DURATION, mHealthCheckDurationMs);
             out.attributeBoolean(null, ATTR_PASSED_HEALTH_CHECK, mHasPassedHealthCheck);
+            LongArrayQueue normalizedCalls = normalizeMitigationCalls();
+            out.attribute(null, ATTR_MITIGATION_CALLS, longArrayQueueToString(normalizedCalls));
             out.endTag(null, TAG_PACKAGE);
         }
 
@@ -1423,6 +1456,23 @@
         }
 
         /**
+         * Before writing to disk, make the mitigation call timestamps relative to the current
+         * system uptime. This is because they need to be relative to the uptime which will reset
+         * at the next boot.
+         *
+         * @return a LongArrayQueue of the mitigation calls relative to the current system uptime.
+         */
+        @GuardedBy("mLock")
+        public LongArrayQueue normalizeMitigationCalls() {
+            LongArrayQueue normalized = new LongArrayQueue();
+            final long now = mSystemClock.uptimeMillis();
+            for (int i = 0; i < mMitigationCalls.size(); i++) {
+                normalized.addLast(mMitigationCalls.get(i) - now);
+            }
+            return normalized;
+        }
+
+        /**
          * Sets the initial health check duration.
          *
          * @return the new health check state
@@ -1582,6 +1632,16 @@
         private long toPositive(long value) {
             return value > 0 ? value : Long.MAX_VALUE;
         }
+
+        /** Compares the equality of this object with another {@link MonitoredPackage}. */
+        @VisibleForTesting
+        boolean isEqualTo(MonitoredPackage pkg) {
+            return (getName().equals(pkg.getName()))
+                    && mDurationMs == pkg.mDurationMs
+                    && mHasPassedHealthCheck == pkg.mHasPassedHealthCheck
+                    && mHealthCheckDurationMs == pkg.mHealthCheckDurationMs
+                    && (mMitigationCalls.toString()).equals(pkg.mMitigationCalls.toString());
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index d30e9fb..51e2b12 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -158,7 +158,7 @@
                 XmlUtils.beginDocument(parser, XML_TAG_SENSOR_PRIVACY);
                 parser.next();
                 String tagName = parser.getName();
-                enabled = Boolean.valueOf(parser.getAttributeValue(null, XML_ATTRIBUTE_ENABLED));
+                enabled = parser.getAttributeBoolean(null, XML_ATTRIBUTE_ENABLED, false);
             } catch (IOException | XmlPullParserException e) {
                 Log.e(TAG, "Caught an exception reading the state from storage: ", e);
                 // Delete the file to prevent the same error on subsequent calls and assume sensor
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index eb55512..52eb77d 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -80,6 +80,7 @@
 import android.telephony.ims.ImsReasonInfo;
 import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.LocalLog;
 import android.util.Pair;
 
@@ -101,10 +102,13 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * Since phone process can be restarted, this class provides a centralized place
@@ -144,14 +148,14 @@
         int callerUid;
         int callerPid;
 
-        long events;
+        Set<Integer> eventList;
 
         int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
         int phoneId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
 
-        boolean matchPhoneStateListenerEvent(long events) {
-            return (callback != null) && ((events & this.events) != 0);
+        boolean matchPhoneStateListenerEvent(int event) {
+            return (callback != null) && (this.eventList.contains(event));
         }
 
         boolean matchOnSubscriptionsChangedListener() {
@@ -179,7 +183,7 @@
                     + onSubscriptionsChangedListenerCallback
                     + " onOpportunisticSubscriptionsChangedListenererCallback="
                     + onOpportunisticSubscriptionsChangedListenerCallback + " subId=" + subId
-                    + " phoneId=" + phoneId + " events=" + Long.toHexString(events) + "}";
+                    + " phoneId=" + phoneId + " events=" + eventList + "}";
         }
     }
 
@@ -310,6 +314,10 @@
 
     private List<PhysicalChannelConfig> mPhysicalChannelConfigs;
 
+    private boolean mIsDataEnabled = false;
+
+    private int mDataEnabledReason;
+
     /**
      * Per-phone map of precise data connection state. The key of the map is the pair of transport
      * type and APN setting. This is the cache to prevent redundant callbacks to the listeners.
@@ -319,40 +327,62 @@
     private List<Map<Pair<Integer, ApnSetting>, PreciseDataConnectionState>>
             mPreciseDataConnectionStates;
 
-    // Starting in Q, almost all cellular location requires FINE location enforcement.
-    // Prior to Q, cellular was available with COARSE location enforcement. Bits in this
-    // list will be checked for COARSE on apps targeting P or earlier and FINE on Q or later.
-    static final long ENFORCE_LOCATION_PERMISSION_MASK =
-            PhoneStateListener.LISTEN_CELL_LOCATION
-                    | PhoneStateListener.LISTEN_CELL_INFO
-                    | PhoneStateListener.LISTEN_REGISTRATION_FAILURE
-                    | PhoneStateListener.LISTEN_BARRING_INFO;
+    private static final Set<Integer> REQUIRE_PRECISE_PHONE_STATE_PERMISSION;
+    static {
+        REQUIRE_PRECISE_PHONE_STATE_PERMISSION = new HashSet<Integer>();
+        REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+                PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED);
+        REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+                PhoneStateListener.EVENT_DATA_CONNECTION_REAL_TIME_INFO_CHANGED);
+        REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+                PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED);
+        REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+                PhoneStateListener.EVENT_CALL_DISCONNECT_CAUSE_CHANGED);
+        REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+                PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED);
+        REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+                PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED);
+        REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(PhoneStateListener.EVENT_REGISTRATION_FAILURE);
+        REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(PhoneStateListener.EVENT_BARRING_INFO_CHANGED);
+        REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+                PhoneStateListener.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED);
+        REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
+                PhoneStateListener.EVENT_DATA_ENABLED_CHANGED);
+    }
 
-    static final long ENFORCE_PHONE_STATE_PERMISSION_MASK =
-            PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
-                    | PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
-                    | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST
-                    | PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED;
+    private boolean isLocationPermissionRequired(Set<Integer> events) {
+        return events.contains(PhoneStateListener.EVENT_CELL_LOCATION_CHANGED)
+                || events.contains(PhoneStateListener.EVENT_CELL_INFO_CHANGED)
+                || events.contains(PhoneStateListener.EVENT_REGISTRATION_FAILURE)
+                || events.contains(PhoneStateListener.EVENT_BARRING_INFO_CHANGED);
+    }
 
-    static final long ENFORCE_PRECISE_PHONE_STATE_PERMISSION_MASK =
-            PhoneStateListener.LISTEN_PRECISE_CALL_STATE
-                    | PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE
-                    | PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES
-                    | PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED
-                    | PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES
-                    | PhoneStateListener.LISTEN_REGISTRATION_FAILURE
-                    | PhoneStateListener.LISTEN_BARRING_INFO
-                    | PhoneStateListener.LISTEN_PHYSICAL_CHANNEL_CONFIGURATION;
+    private boolean isPhoneStatePermissionRequired(Set<Integer> events) {
+        return events.contains(PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)
+                || events.contains(PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)
+                || events.contains(PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED)
+                || events.contains(PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED);
+    }
 
-    static final long READ_ACTIVE_EMERGENCY_SESSION_PERMISSION_MASK =
-            PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL
-                    | PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_SMS;
+    private boolean isPrecisePhoneStatePermissionRequired(Set<Integer> events) {
+        for (Integer requireEvent : REQUIRE_PRECISE_PHONE_STATE_PERMISSION) {
+            if (events.contains(requireEvent)) {
+                return true;
+            }
+        }
+        return false;
+    }
 
-    static final long READ_PRIVILEGED_PHONE_STATE_PERMISSION_MASK =
-            PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT
-                    | PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED
-                    | PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED
-                    | PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE;
+    private boolean isActiveEmergencySessionPermissionRequired(Set<Integer> events) {
+        return events.contains(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_CALL)
+                || events.contains(PhoneStateListener.EVENT_OUTGOING_EMERGENCY_SMS);
+    }
+
+    private boolean isPrivilegedPhoneStatePermissionRequired(Set<Integer> events) {
+        return events.contains(PhoneStateListener.EVENT_SRVCC_STATE_CHANGED)
+                || events.contains(PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED)
+                || events.contains(PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED);
+    }
 
     private static final int MSG_USER_SWITCHED = 1;
     private static final int MSG_UPDATE_DEFAULT_SUB = 2;
@@ -670,7 +700,7 @@
             r.callingFeatureId = callingFeatureId;
             r.callerUid = Binder.getCallingUid();
             r.callerPid = Binder.getCallingPid();
-            r.events = 0;
+            r.eventList = new ArraySet<>();
             if (DBG) {
                 log("listen oscl:  Register r=" + r);
             }
@@ -724,7 +754,7 @@
             r.callingFeatureId = callingFeatureId;
             r.callerUid = Binder.getCallingUid();
             r.callerPid = Binder.getCallingPid();
-            r.events = 0;
+            r.eventList = new ArraySet<>();
             if (DBG) {
                 log("listen ooscl:  Register r=" + r);
             }
@@ -797,331 +827,337 @@
         }
     }
 
-    @Deprecated
     @Override
-    public void listen(String callingPackage, IPhoneStateListener callback, int events,
-            boolean notifyNow) {
-        listenWithFeature(callingPackage, null, callback, events, notifyNow);
-    }
-
-    @Override
-    public void listenWithFeature(String callingPackage, String callingFeatureId,
-            IPhoneStateListener callback, long events, boolean notifyNow) {
-        listenForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, callingPackage,
-                callingFeatureId, callback, events, notifyNow);
-    }
-
-    @Override
-    public void listenForSubscriber(int subId, String callingPackage, String callingFeatureId,
-            IPhoneStateListener callback, long events, boolean notifyNow) {
-        listen(callingPackage, callingFeatureId, callback, events, notifyNow, subId);
+    public void listenWithEventList(int subId, String callingPackage, String callingFeatureId,
+            IPhoneStateListener callback, int[] events, boolean notifyNow) {
+        Set<Integer> eventList = Arrays.stream(events).boxed().collect(Collectors.toSet());
+        listen(callingPackage, callingFeatureId, callback, eventList, notifyNow, subId);
     }
 
     private void listen(String callingPackage, @Nullable String callingFeatureId,
-            IPhoneStateListener callback, long events, boolean notifyNow, int subId) {
+            IPhoneStateListener callback, Set<Integer> events, boolean notifyNow, int subId) {
         int callerUserId = UserHandle.getCallingUserId();
         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
         String str = "listen: E pkg=" + pii(callingPackage) + " uid=" + Binder.getCallingUid()
-                + " events=0x" + Long.toHexString(events) + " notifyNow=" + notifyNow + " subId="
-                + subId + " myUserId=" + UserHandle.myUserId() + " callerUserId=" + callerUserId;
+                + " events=" + events + " notifyNow=" + notifyNow
+                + " subId=" + subId + " myUserId=" + UserHandle.myUserId()
+                + " callerUserId=" + callerUserId;
         mListenLog.log(str);
         if (VDBG) {
             log(str);
         }
 
-        if (events != PhoneStateListener.LISTEN_NONE) {
-            // Checks permission and throws SecurityException for disallowed operations. For pre-M
-            // apps whose runtime permission has been revoked, we return immediately to skip sending
-            // events to the app without crashing it.
-            if (!checkListenerPermission(events, subId, callingPackage, callingFeatureId,
-                    "listen")) {
+        if (events.isEmpty()) {
+            if (DBG) {
+                log("listen: Unregister");
+            }
+            events.clear();
+            remove(callback.asBinder());
+            return;
+        }
+
+        // Checks permission and throws SecurityException for disallowed operations. For pre-M
+        // apps whose runtime permission has been revoked, we return immediately to skip sending
+        // events to the app without crashing it.
+        if (!checkListenerPermission(events, subId, callingPackage, callingFeatureId,
+                "listen")) {
+            return;
+        }
+
+        int phoneId = getPhoneIdFromSubId(subId);
+        synchronized (mRecords) {
+            // register
+            IBinder b = callback.asBinder();
+            boolean doesLimitApply =
+                    Binder.getCallingUid() != Process.SYSTEM_UID
+                            && Binder.getCallingUid() != Process.PHONE_UID
+                            && Binder.getCallingUid() != Process.myUid();
+            Record r = add(b, Binder.getCallingUid(), Binder.getCallingPid(), doesLimitApply);
+
+            if (r == null) {
                 return;
             }
 
-            int phoneId = getPhoneIdFromSubId(subId);
-            synchronized (mRecords) {
-                // register
-                IBinder b = callback.asBinder();
-                boolean doesLimitApply =
-                        Binder.getCallingUid() != Process.SYSTEM_UID
-                        && Binder.getCallingUid() != Process.PHONE_UID
-                        && Binder.getCallingUid() != Process.myUid();
-                Record r = add(b, Binder.getCallingUid(), Binder.getCallingPid(), doesLimitApply);
-
-                if (r == null) {
-                    return;
+            r.context = mContext;
+            r.callback = callback;
+            r.callingPackage = callingPackage;
+            r.callingFeatureId = callingFeatureId;
+            r.callerUid = Binder.getCallingUid();
+            r.callerPid = Binder.getCallingPid();
+            // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID,
+            // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID
+            if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+                r.subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
+            } else {//APP specify subID
+                r.subId = subId;
+            }
+            r.phoneId = phoneId;
+            r.eventList = events;
+            if (DBG) {
+                log("listen:  Register r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId);
+            }
+            if (notifyNow && validatePhoneId(phoneId)) {
+                if (events.contains(PhoneStateListener.EVENT_SERVICE_STATE_CHANGED)) {
+                    try {
+                        if (VDBG) log("listen: call onSSC state=" + mServiceState[phoneId]);
+                        ServiceState rawSs = new ServiceState(mServiceState[phoneId]);
+                        if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+                            r.callback.onServiceStateChanged(rawSs);
+                        } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) {
+                            r.callback.onServiceStateChanged(
+                                    rawSs.createLocationInfoSanitizedCopy(false));
+                        } else {
+                            r.callback.onServiceStateChanged(
+                                    rawSs.createLocationInfoSanitizedCopy(true));
+                        }
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
+                    }
                 }
-
-                r.context = mContext;
-                r.callback = callback;
-                r.callingPackage = callingPackage;
-                r.callingFeatureId = callingFeatureId;
-                r.callerUid = Binder.getCallingUid();
-                r.callerPid = Binder.getCallingPid();
-                // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID,
-                // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID
-                if (!SubscriptionManager.isValidSubscriptionId(subId)) {
-                    r.subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
-                 } else {//APP specify subID
-                    r.subId = subId;
+                if (events.contains(PhoneStateListener.EVENT_SIGNAL_STRENGTH_CHANGED)) {
+                    try {
+                        if (mSignalStrength[phoneId] != null) {
+                            int gsmSignalStrength = mSignalStrength[phoneId]
+                                    .getGsmSignalStrength();
+                            r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
+                                    : gsmSignalStrength));
+                        }
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
+                    }
                 }
-                r.phoneId = phoneId;
-                r.events = events;
-                if (DBG) {
-                    log("listen:  Register r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId);
+                if (events.contains(
+                        PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)) {
+                    try {
+                        r.callback.onMessageWaitingIndicatorChanged(
+                                mMessageWaiting[phoneId]);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
+                    }
                 }
-                if (notifyNow && validatePhoneId(phoneId)) {
-                    if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
-                        try {
-                            if (VDBG) log("listen: call onSSC state=" + mServiceState[phoneId]);
-                            ServiceState rawSs = new ServiceState(mServiceState[phoneId]);
-                            if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
-                                r.callback.onServiceStateChanged(rawSs);
-                            } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) {
-                                r.callback.onServiceStateChanged(
-                                        rawSs.createLocationInfoSanitizedCopy(false));
-                            } else {
-                                r.callback.onServiceStateChanged(
-                                        rawSs.createLocationInfoSanitizedCopy(true));
-                            }
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                if (events.contains(
+                        PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)) {
+                    try {
+                        r.callback.onCallForwardingIndicatorChanged(
+                                mCallForwarding[phoneId]);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
-                        try {
-                            if (mSignalStrength[phoneId] != null) {
-                                int gsmSignalStrength = mSignalStrength[phoneId]
-                                        .getGsmSignalStrength();
-                                r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
-                                        : gsmSignalStrength));
-                            }
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
+                }
+                if (validateEventAndUserLocked(
+                        r, PhoneStateListener.EVENT_CELL_LOCATION_CHANGED)) {
+                    try {
+                        if (DBG_LOC) log("listen: mCellIdentity = " + mCellIdentity[phoneId]);
+                        if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+                                && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+                            // null will be translated to empty CellLocation object in client.
+                            r.callback.onCellLocationChanged(mCellIdentity[phoneId]);
                         }
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
-                        try {
-                            r.callback.onMessageWaitingIndicatorChanged(
-                                    mMessageWaiting[phoneId]);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_CALL_STATE_CHANGED)) {
+                    try {
+                        r.callback.onCallStateChanged(mCallState[phoneId],
+                                getCallIncomingNumber(r, phoneId));
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
-                        try {
-                            r.callback.onCallForwardingIndicatorChanged(
-                                    mCallForwarding[phoneId]);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
-                    }
-                    if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
-                        try {
-                            if (DBG_LOC) log("listen: mCellIdentity = " + mCellIdentity[phoneId]);
-                            if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
-                                    && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
-                                // null will be translated to empty CellLocation object in client.
-                                r.callback.onCellLocationChanged(mCellIdentity[phoneId]);
-                            }
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
-                    }
-                    if ((events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
-                        try {
-                            r.callback.onCallStateChanged(mCallState[phoneId],
-                                     getCallIncomingNumber(r, phoneId));
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
-                    }
-                    if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
-                        try {
-                            r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
+                }
+                if (events.contains(PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED)) {
+                    try {
+                        r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
                                 mDataConnectionNetworkType[phoneId]);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
-                        try {
-                            r.callback.onDataActivity(mDataActivity[phoneId]);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_DATA_ACTIVITY_CHANGED)) {
+                    try {
+                        r.callback.onDataActivity(mDataActivity[phoneId]);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
-                        try {
-                            if (mSignalStrength[phoneId] != null) {
-                                r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
-                            }
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
+                }
+                if (events.contains(PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED)) {
+                    try {
+                        if (mSignalStrength[phoneId] != null) {
+                            r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
                         }
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
-                            != 0) {
-                        updateReportSignalStrengthDecision(r.subId);
-                        try {
-                            if (mSignalStrength[phoneId] != null) {
-                                r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
-                            }
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
+                }
+                if (events.contains(
+                        PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
+                    updateReportSignalStrengthDecision(r.subId);
+                    try {
+                        if (mSignalStrength[phoneId] != null) {
+                            r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
                         }
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
-                        try {
-                            if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = "
-                                    + mCellInfo.get(phoneId));
-                            if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
-                                    && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
-                                r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
-                            }
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
+                }
+                if (validateEventAndUserLocked(
+                        r, PhoneStateListener.EVENT_CELL_INFO_CHANGED)) {
+                    try {
+                        if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = "
+                                + mCellInfo.get(phoneId));
+                        if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+                                && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+                            r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
                         }
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
-                        try {
-                            r.callback.onPreciseCallStateChanged(mPreciseCallState[phoneId]);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED)) {
+                    try {
+                        r.callback.onPreciseCallStateChanged(mPreciseCallState[phoneId]);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES) != 0) {
-                        try {
-                            r.callback.onCallDisconnectCauseChanged(mCallDisconnectCause[phoneId],
-                                    mCallPreciseDisconnectCause[phoneId]);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_CALL_DISCONNECT_CAUSE_CHANGED)) {
+                    try {
+                        r.callback.onCallDisconnectCauseChanged(mCallDisconnectCause[phoneId],
+                                mCallPreciseDisconnectCause[phoneId]);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES) != 0) {
-                        try {
-                            r.callback.onImsCallDisconnectCauseChanged(mImsReasonInfo.get(phoneId));
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED)) {
+                    try {
+                        r.callback.onImsCallDisconnectCauseChanged(mImsReasonInfo.get(phoneId));
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
-                        try {
-                            for (PreciseDataConnectionState pdcs
-                                    : mPreciseDataConnectionStates.get(phoneId).values()) {
-                                r.callback.onPreciseDataConnectionStateChanged(pdcs);
-                            }
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
+                }
+                if (events.contains(
+                        PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED)) {
+                    try {
+                        for (PreciseDataConnectionState pdcs
+                                : mPreciseDataConnectionStates.get(phoneId).values()) {
+                            r.callback.onPreciseDataConnectionStateChanged(pdcs);
                         }
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE) != 0) {
-                        try {
-                            r.callback.onCarrierNetworkChange(mCarrierNetworkChangeState);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_CARRIER_NETWORK_CHANGED)) {
+                    try {
+                        r.callback.onCarrierNetworkChange(mCarrierNetworkChangeState);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE) !=0) {
-                        try {
-                            r.callback.onVoiceActivationStateChanged(
-                                    mVoiceActivationState[phoneId]);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED)) {
+                    try {
+                        r.callback.onVoiceActivationStateChanged(
+                                mVoiceActivationState[phoneId]);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE) !=0) {
-                        try {
-                            r.callback.onDataActivationStateChanged(mDataActivationState[phoneId]);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_DATA_ACTIVATION_STATE_CHANGED)) {
+                    try {
+                        r.callback.onDataActivationStateChanged(mDataActivationState[phoneId]);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) != 0) {
-                        try {
-                            r.callback.onUserMobileDataStateChanged(mUserMobileDataState[phoneId]);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED)) {
+                    try {
+                        r.callback.onUserMobileDataStateChanged(mUserMobileDataState[phoneId]);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED) != 0) {
-                        try {
-                            if (mTelephonyDisplayInfos[phoneId] != null) {
-                                r.callback.onDisplayInfoChanged(mTelephonyDisplayInfos[phoneId]);
-                            }
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
+                }
+                if (events.contains(PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED)) {
+                    try {
+                        if (mTelephonyDisplayInfos[phoneId] != null) {
+                            r.callback.onDisplayInfoChanged(mTelephonyDisplayInfos[phoneId]);
                         }
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST) != 0) {
-                        try {
-                            r.callback.onEmergencyNumberListChanged(mEmergencyNumberList);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED)) {
+                    try {
+                        r.callback.onEmergencyNumberListChanged(mEmergencyNumberList);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_PHONE_CAPABILITY_CHANGE) != 0) {
-                        try {
-                            r.callback.onPhoneCapabilityChanged(mPhoneCapability);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_PHONE_CAPABILITY_CHANGED)) {
+                    try {
+                        r.callback.onPhoneCapabilityChanged(mPhoneCapability);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener
-                            .LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE) != 0) {
-                        try {
-                            r.callback.onActiveDataSubIdChanged(mActiveDataSubId);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(
+                        PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED)) {
+                    try {
+                        r.callback.onActiveDataSubIdChanged(mActiveDataSubId);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED) != 0) {
-                        try {
-                            r.callback.onRadioPowerStateChanged(mRadioPowerState);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED)) {
+                    try {
+                        r.callback.onRadioPowerStateChanged(mRadioPowerState);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED) != 0) {
-                        try {
-                            r.callback.onSrvccStateChanged(mSrvccState[phoneId]);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_SRVCC_STATE_CHANGED)) {
+                    try {
+                        r.callback.onSrvccStateChanged(mSrvccState[phoneId]);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED) != 0) {
-                        try {
-                            r.callback.onCallAttributesChanged(mCallAttributes[phoneId]);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED)) {
+                    try {
+                        r.callback.onCallAttributesChanged(mCallAttributes[phoneId]);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_BARRING_INFO) != 0) {
-                        BarringInfo barringInfo = mBarringInfo.get(phoneId);
-                        BarringInfo biNoLocation = barringInfo != null
-                                ? barringInfo.createLocationInfoSanitizedCopy() : null;
-                        if (VDBG) log("listen: call onBarringInfoChanged=" + barringInfo);
-                        try {
-                            r.callback.onBarringInfoChanged(
-                                    checkFineLocationAccess(r, Build.VERSION_CODES.BASE)
-                                            ? barringInfo : biNoLocation);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(PhoneStateListener.EVENT_BARRING_INFO_CHANGED)) {
+                    BarringInfo barringInfo = mBarringInfo.get(phoneId);
+                    BarringInfo biNoLocation = barringInfo != null
+                            ? barringInfo.createLocationInfoSanitizedCopy() : null;
+                    if (VDBG) log("listen: call onBarringInfoChanged=" + barringInfo);
+                    try {
+                        r.callback.onBarringInfoChanged(
+                                checkFineLocationAccess(r, Build.VERSION_CODES.BASE)
+                                        ? barringInfo : biNoLocation);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
-                    if ((events & PhoneStateListener.LISTEN_PHYSICAL_CHANNEL_CONFIGURATION) != 0) {
-                        try {
-                            r.callback.onPhysicalChannelConfigurationChanged(
-                                    mPhysicalChannelConfigs);
-                        } catch (RemoteException ex) {
-                            remove(r.binder);
-                        }
+                }
+                if (events.contains(
+                        PhoneStateListener.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED)) {
+                    try {
+                        r.callback.onPhysicalChannelConfigChanged(
+                                mPhysicalChannelConfigs);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
+                    }
+                }
+                if (events.contains(
+                        PhoneStateListener.EVENT_DATA_ENABLED_CHANGED)) {
+                    try {
+                        r.callback.onDataEnabledChanged(mIsDataEnabled, mDataEnabledReason);
+                    } catch (RemoteException ex) {
+                        remove(r.binder);
                     }
                 }
             }
-        } else {
-            if(DBG) log("listen: Unregister");
-            remove(callback.asBinder());
         }
     }
 
@@ -1133,7 +1169,7 @@
                 // If any of the system clients wants to always listen to signal strength,
                 // we need to set it on.
                 if (r.matchPhoneStateListenerEvent(
-                        PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)) {
+                        PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
                     telephonyManager.createForSubscriptionId(subscriptionId)
                             .setAlwaysReportSignalStrength(true);
                     return;
@@ -1234,7 +1270,7 @@
                     // strength is removed from registry records, we need to check if
                     // the signal strength decision needs to update on its slot.
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)) {
+                            PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
                         updateReportSignalStrengthDecision(r.subId);
                     }
                     return;
@@ -1254,8 +1290,8 @@
 
         synchronized (mRecords) {
             for (Record r : mRecords) {
-                if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_CALL_STATE) &&
-                        (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) {
+                if (r.matchPhoneStateListenerEvent(PhoneStateListener.EVENT_CALL_STATE_CHANGED)
+                        && (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) {
                     try {
                         // Ensure the listener has read call log permission; if they do not return
                         // an empty phone number.
@@ -1289,9 +1325,9 @@
                 mCallState[phoneId] = state;
                 mCallIncomingNumber[phoneId] = incomingNumber;
                 for (Record r : mRecords) {
-                    if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_CALL_STATE) &&
-                            (r.subId == subId) &&
-                            (r.subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) {
+                    if (r.matchPhoneStateListenerEvent(PhoneStateListener.EVENT_CALL_STATE_CHANGED)
+                            && (r.subId == subId)
+                            && (r.subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) {
                         try {
                             String incomingNumberOrEmpty = getCallIncomingNumber(r, phoneId);
                             r.callback.onCallStateChanged(state, incomingNumberOrEmpty);
@@ -1331,8 +1367,9 @@
                         log("notifyServiceStateForSubscriber: r=" + r + " subId=" + subId
                                 + " phoneId=" + phoneId + " state=" + state);
                     }
-                    if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SERVICE_STATE) &&
-                            idMatch(r.subId, subId, phoneId)) {
+                    if (r.matchPhoneStateListenerEvent(
+                            PhoneStateListener.EVENT_SERVICE_STATE_CHANGED)
+                            && idMatch(r.subId, subId, phoneId)) {
 
                         try {
                             ServiceState stateToSend;
@@ -1393,7 +1430,7 @@
                     try {
                         if ((activationType == SIM_ACTIVATION_TYPE_VOICE)
                                 && r.matchPhoneStateListenerEvent(
-                                        PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE)
+                                        PhoneStateListener.EVENT_VOICE_ACTIVATION_STATE_CHANGED)
                                 && idMatch(r.subId, subId, phoneId)) {
                             if (DBG) {
                                 log("notifyVoiceActivationStateForPhoneId: callback.onVASC r=" + r
@@ -1404,7 +1441,7 @@
                         }
                         if ((activationType == SIM_ACTIVATION_TYPE_DATA)
                                 && r.matchPhoneStateListenerEvent(
-                                        PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE)
+                                        PhoneStateListener.EVENT_DATA_ACTIVATION_STATE_CHANGED)
                                 && idMatch(r.subId, subId, phoneId)) {
                             if (DBG) {
                                 log("notifyDataActivationStateForPhoneId: callback.onDASC r=" + r
@@ -1443,9 +1480,11 @@
                         log("notifySignalStrengthForPhoneId: r=" + r + " subId=" + subId
                                 + " phoneId=" + phoneId + " ss=" + signalStrength);
                     }
-                    if ((r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SIGNAL_STRENGTHS)
+                    if ((r.matchPhoneStateListenerEvent(
+                            PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED)
                             || r.matchPhoneStateListenerEvent(
-                                    PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH))
+                                    PhoneStateListener.
+                                            EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED))
                             && idMatch(r.subId, subId, phoneId)) {
                         try {
                             if (DBG) {
@@ -1458,8 +1497,9 @@
                             mRemoveList.add(r.binder);
                         }
                     }
-                    if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SIGNAL_STRENGTH) &&
-                            idMatch(r.subId, subId, phoneId)) {
+                    if (r.matchPhoneStateListenerEvent(
+                            PhoneStateListener.EVENT_SIGNAL_STRENGTH_CHANGED)
+                            && idMatch(r.subId, subId, phoneId)) {
                         try {
                             int gsmSignalStrength = signalStrength.getGsmSignalStrength();
                             int ss = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength);
@@ -1505,8 +1545,8 @@
                 }
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE) &&
-                            idMatch(r.subId, subId, phoneId)) {
+                            PhoneStateListener.EVENT_CARRIER_NETWORK_CHANGED)
+                            && idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onCarrierNetworkChange(active);
                         } catch (RemoteException ex) {
@@ -1536,9 +1576,10 @@
             if (validatePhoneId(phoneId)) {
                 mCellInfo.set(phoneId, cellInfo);
                 for (Record r : mRecords) {
-                    if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO) &&
-                            idMatch(r.subId, subId, phoneId) &&
-                            (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+                    if (validateEventAndUserLocked(
+                            r, PhoneStateListener.EVENT_CELL_INFO_CHANGED)
+                            && idMatch(r.subId, subId, phoneId)
+                            && (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
                                     && checkFineLocationAccess(r, Build.VERSION_CODES.Q))) {
                         try {
                             if (DBG_LOC) {
@@ -1570,8 +1611,8 @@
                 mMessageWaiting[phoneId] = mwi;
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) &&
-                            idMatch(r.subId, subId, phoneId)) {
+                            PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)
+                            && idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onMessageWaitingIndicatorChanged(mwi);
                         } catch (RemoteException ex) {
@@ -1597,8 +1638,8 @@
                 mUserMobileDataState[phoneId] = state;
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) &&
-                            idMatch(r.subId, subId, phoneId)) {
+                            PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED)
+                            && idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onUserMobileDataStateChanged(state);
                         } catch (RemoteException ex) {
@@ -1636,7 +1677,7 @@
                 mTelephonyDisplayInfos[phoneId] = telephonyDisplayInfo;
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED)
+                            PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED)
                             && idMatchWithoutDefaultPhoneCheck(r.subId, subId)) {
                         try {
                             r.callback.onDisplayInfoChanged(telephonyDisplayInfo);
@@ -1668,8 +1709,8 @@
                 mCallForwarding[phoneId] = cfi;
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) &&
-                            idMatch(r.subId, subId, phoneId)) {
+                            PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)
+                            && idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onCallForwardingIndicatorChanged(cfi);
                         } catch (RemoteException ex) {
@@ -1696,8 +1737,9 @@
                 mDataActivity[phoneId] = state;
                 for (Record r : mRecords) {
                     // Notify by correct subId.
-                    if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_DATA_ACTIVITY) &&
-                            idMatch(r.subId, subId, phoneId)) {
+                    if (r.matchPhoneStateListenerEvent(
+                            PhoneStateListener.EVENT_DATA_ACTIVITY_CHANGED)
+                            && idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onDataActivity(state);
                         } catch (RemoteException ex) {
@@ -1744,7 +1786,7 @@
                     mLocalLog.log(str);
                     for (Record r : mRecords) {
                         if (r.matchPhoneStateListenerEvent(
-                                PhoneStateListener.LISTEN_DATA_CONNECTION_STATE)
+                                PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED)
                                 && idMatch(r.subId, subId, phoneId)) {
                             try {
                                 if (DBG) {
@@ -1769,7 +1811,7 @@
                 if (!Objects.equals(oldState, preciseState)) {
                     for (Record r : mRecords) {
                         if (r.matchPhoneStateListenerEvent(
-                                PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)
+                                PhoneStateListener.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED)
                                 && idMatch(r.subId, subId, phoneId)) {
                             try {
                                 r.callback.onPreciseDataConnectionStateChanged(preciseState);
@@ -1814,9 +1856,10 @@
             if (validatePhoneId(phoneId) && !Objects.equals(cellIdentity, mCellIdentity[phoneId])) {
                 mCellIdentity[phoneId] = cellIdentity;
                 for (Record r : mRecords) {
-                    if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) &&
-                            idMatch(r.subId, subId, phoneId) &&
-                            (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
+                    if (validateEventAndUserLocked(
+                            r, PhoneStateListener.EVENT_CELL_LOCATION_CHANGED)
+                            && idMatch(r.subId, subId, phoneId)
+                            && (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE)
                                     && checkFineLocationAccess(r, Build.VERSION_CODES.Q))) {
                         try {
                             if (DBG_LOC) {
@@ -1867,7 +1910,8 @@
                 }
 
                 for (Record r : mRecords) {
-                    if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_PRECISE_CALL_STATE)
+                    if (r.matchPhoneStateListenerEvent(
+                            PhoneStateListener.EVENT_PRECISE_CALL_STATE_CHANGED)
                             && idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onPreciseCallStateChanged(mPreciseCallState[phoneId]);
@@ -1876,7 +1920,7 @@
                         }
                     }
                     if (notifyCallAttributes && r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED)
+                            PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED)
                             && idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onCallAttributesChanged(mCallAttributes[phoneId]);
@@ -1925,7 +1969,7 @@
                 mImsReasonInfo.set(phoneId, imsReasonInfo);
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES)
+                            PhoneStateListener.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED)
                             && idMatch(r.subId, subId, phoneId)) {
                         try {
                             if (DBG_LOC) {
@@ -1957,8 +2001,8 @@
                 mSrvccState[phoneId] = state;
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED) &&
-                            idMatch(r.subId, subId, phoneId)) {
+                            PhoneStateListener.EVENT_SRVCC_STATE_CHANGED)
+                            && idMatch(r.subId, subId, phoneId)) {
                         try {
                             if (DBG_LOC) {
                                 log("notifySrvccStateChanged: mSrvccState=" + state + " r=" + r);
@@ -1986,7 +2030,7 @@
                         log("notifyOemHookRawEventForSubscriber:  r=" + r + " subId=" + subId);
                     }
                     if ((r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT))
+                            PhoneStateListener.EVENT_OEM_HOOK_RAW))
                             && idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onOemHookRawEvent(rawData);
@@ -2014,7 +2058,7 @@
 
             for (Record r : mRecords) {
                 if (r.matchPhoneStateListenerEvent(
-                        PhoneStateListener.LISTEN_PHONE_CAPABILITY_CHANGE)) {
+                        PhoneStateListener.EVENT_PHONE_CAPABILITY_CHANGED)) {
                     try {
                         r.callback.onPhoneCapabilityChanged(capability);
                     } catch (RemoteException ex) {
@@ -2039,7 +2083,7 @@
         synchronized (mRecords) {
             for (Record r : mRecords) {
                 if (r.matchPhoneStateListenerEvent(
-                        PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE)) {
+                        PhoneStateListener.EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED)) {
                     try {
                         r.callback.onActiveDataSubIdChanged(activeDataSubId);
                     } catch (RemoteException ex) {
@@ -2066,7 +2110,7 @@
 
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED)
+                            PhoneStateListener.EVENT_RADIO_POWER_STATE_CHANGED)
                             && idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onRadioPowerStateChanged(state);
@@ -2095,7 +2139,7 @@
 
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST)
+                            PhoneStateListener.EVENT_EMERGENCY_NUMBER_LIST_CHANGED)
                             && idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onEmergencyNumberListChanged(mEmergencyNumberList);
@@ -2127,7 +2171,7 @@
             for (Record r : mRecords) {
                 // Send to all listeners regardless of subscription
                 if (r.matchPhoneStateListenerEvent(
-                        PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL)) {
+                        PhoneStateListener.EVENT_OUTGOING_EMERGENCY_CALL)) {
                     try {
                         r.callback.onOutgoingEmergencyCall(emergencyNumber, subId);
                     } catch (RemoteException ex) {
@@ -2151,7 +2195,7 @@
                 for (Record r : mRecords) {
                     // Send to all listeners regardless of subscription
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_SMS)) {
+                            PhoneStateListener.EVENT_OUTGOING_EMERGENCY_SMS)) {
                         try {
                             r.callback.onOutgoingEmergencySms(emergencyNumber, subId);
                         } catch (RemoteException ex) {
@@ -2181,7 +2225,7 @@
 
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED)
+                            PhoneStateListener.EVENT_CALL_ATTRIBUTES_CHANGED)
                             && idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onCallAttributesChanged(mCallAttributes[phoneId]);
@@ -2212,7 +2256,7 @@
             if (validatePhoneId(phoneId)) {
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_REGISTRATION_FAILURE)
+                            PhoneStateListener.EVENT_REGISTRATION_FAILURE)
                             && idMatch(r.subId, subId, phoneId)) {
                         try {
                             r.callback.onRegistrationFailed(
@@ -2255,7 +2299,7 @@
                 if (VDBG) log("listen: call onBarringInfoChanged=" + barringInfo);
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_BARRING_INFO)
+                            PhoneStateListener.EVENT_BARRING_INFO_CHANGED)
                             && idMatch(r.subId, subId, phoneId)) {
                         try {
                             if (DBG_LOC) {
@@ -2282,14 +2326,14 @@
      * @param subId the subId
      * @param configs a list of {@link PhysicalChannelConfig}, the configs of physical channel.
      */
-    public void notifyPhysicalChannelConfigurationForSubscriber(
+    public void notifyPhysicalChannelConfigForSubscriber(
             int subId, List<PhysicalChannelConfig> configs) {
-        if (!checkNotifyPermission("notifyPhysicalChannelConfiguration()")) {
+        if (!checkNotifyPermission("notifyPhysicalChannelConfig()")) {
             return;
         }
 
         if (VDBG) {
-            log("notifyPhysicalChannelConfiguration: subId=" + subId + " configs=" + configs);
+            log("notifyPhysicalChannelConfig: subId=" + subId + " configs=" + configs);
         }
 
         synchronized (mRecords) {
@@ -2298,15 +2342,15 @@
                 mPhysicalChannelConfigs.set(phoneId, configs.get(phoneId));
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
-                            PhoneStateListener.LISTEN_PHYSICAL_CHANNEL_CONFIGURATION)
+                            PhoneStateListener.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED)
                             && idMatch(r.subId, subId, phoneId)) {
                         try {
                             if (DBG_LOC) {
-                                log("notifyPhysicalChannelConfiguration: "
+                                log("notifyPhysicalChannelConfig: "
                                         + "mPhysicalChannelConfigs="
                                         + configs + " r=" + r);
                             }
-                            r.callback.onPhysicalChannelConfigurationChanged(configs);
+                            r.callback.onPhysicalChannelConfigChanged(configs);
                         } catch (RemoteException ex) {
                             mRemoveList.add(r.binder);
                         }
@@ -2616,18 +2660,18 @@
                 == PackageManager.PERMISSION_GRANTED;
     }
 
-    private boolean checkListenerPermission(long events, int subId, String callingPackage,
-            @Nullable String callingFeatureId, String message) {
+    private boolean checkListenerPermission(Set<Integer> events, int subId, String callingPackage,
+                                            @Nullable String callingFeatureId, String message) {
         LocationAccessPolicy.LocationPermissionQuery.Builder locationQueryBuilder =
                 new LocationAccessPolicy.LocationPermissionQuery.Builder()
-                .setCallingPackage(callingPackage)
-                .setMethod(message + " events: " + events)
-                .setCallingPid(Binder.getCallingPid())
-                .setCallingUid(Binder.getCallingUid());
+                        .setCallingPackage(callingPackage)
+                        .setMethod(message + " events: " + events)
+                        .setCallingPid(Binder.getCallingPid())
+                        .setCallingUid(Binder.getCallingUid());
 
         boolean shouldCheckLocationPermissions = false;
 
-        if ((events & ENFORCE_LOCATION_PERMISSION_MASK) != 0) {
+        if (isLocationPermissionRequired(events)) {
             // Everything that requires fine location started in Q. So far...
             locationQueryBuilder.setMinSdkVersionForFine(Build.VERSION_CODES.Q);
             // If we're enforcing fine starting in Q, we also want to enforce coarse even for
@@ -2652,14 +2696,14 @@
             }
         }
 
-        if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) {
+        if (isPhoneStatePermissionRequired(events)) {
             if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
                     mContext, subId, callingPackage, callingFeatureId, message)) {
                 isPermissionCheckSuccessful = false;
             }
         }
 
-        if ((events & ENFORCE_PRECISE_PHONE_STATE_PERMISSION_MASK) != 0) {
+        if (isPrecisePhoneStatePermissionRequired(events)) {
             // check if calling app has either permission READ_PRECISE_PHONE_STATE
             // or with carrier privileges
             try {
@@ -2670,21 +2714,20 @@
             }
         }
 
-        if ((events & READ_ACTIVE_EMERGENCY_SESSION_PERMISSION_MASK) != 0) {
+        if (isActiveEmergencySessionPermissionRequired(events)) {
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION, null);
         }
 
-        if ((events & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) != 0) {
+        if ((events.contains(PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED))) {
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH, null);
         }
 
-        if ((events & READ_PRIVILEGED_PHONE_STATE_PERMISSION_MASK) != 0) {
+        if (isPrivilegedPhoneStatePermissionRequired(events)) {
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
         }
-
         return isPermissionCheckSuccessful;
     }
 
@@ -2692,25 +2735,25 @@
         int size = mRemoveList.size();
         if (VDBG) log("handleRemoveListLocked: mRemoveList.size()=" + size);
         if (size > 0) {
-            for (IBinder b: mRemoveList) {
+            for (IBinder b : mRemoveList) {
                 remove(b);
             }
             mRemoveList.clear();
         }
     }
 
-    private boolean validateEventsAndUserLocked(Record r, int events) {
+    private boolean validateEventAndUserLocked(Record r, int event) {
         int foregroundUser;
         final long callingIdentity = Binder.clearCallingIdentity();
         boolean valid = false;
         try {
             foregroundUser = ActivityManager.getCurrentUser();
             valid = UserHandle.getUserId(r.callerUid) == foregroundUser
-                    && r.matchPhoneStateListenerEvent(events);
+                    && r.matchPhoneStateListenerEvent(event);
             if (DBG | DBG_LOC) {
-                log("validateEventsAndUserLocked: valid=" + valid
+                log("validateEventAndUserLocked: valid=" + valid
                         + " r.callerUid=" + r.callerUid + " foregroundUser=" + foregroundUser
-                        + " r.events=" + r.events + " events=" + events);
+                        + " r.eventList=" + r.eventList + " event=" + event);
             }
         } finally {
             Binder.restoreCallingIdentity(callingIdentity);
@@ -2822,9 +2865,14 @@
     }
 
     private void checkPossibleMissNotify(Record r, int phoneId) {
-        long events = r.events;
+        Set<Integer> events = r.eventList;
 
-        if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
+        if (events == null || events.isEmpty()) {
+            log("checkPossibleMissNotify: events = null.");
+            return;
+        }
+
+        if ((events.contains(PhoneStateListener.EVENT_SERVICE_STATE_CHANGED))) {
             try {
                 if (VDBG) log("checkPossibleMissNotify: onServiceStateChanged state=" +
                         mServiceState[phoneId]);
@@ -2843,8 +2891,9 @@
             }
         }
 
-        if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0
-                || (events & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) != 0) {
+        if (events.contains(PhoneStateListener.EVENT_SIGNAL_STRENGTHS_CHANGED)
+                || events.contains(
+                PhoneStateListener.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) {
             try {
                 if (mSignalStrength[phoneId] != null) {
                     SignalStrength signalStrength = mSignalStrength[phoneId];
@@ -2859,7 +2908,7 @@
             }
         }
 
-        if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
+        if (events.contains(PhoneStateListener.EVENT_SIGNAL_STRENGTH_CHANGED)) {
             try {
                 if (mSignalStrength[phoneId] != null) {
                     int gsmSignalStrength = mSignalStrength[phoneId]
@@ -2876,7 +2925,7 @@
             }
         }
 
-        if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
+        if (validateEventAndUserLocked(r, PhoneStateListener.EVENT_CELL_INFO_CHANGED)) {
             try {
                 if (DBG_LOC) {
                     log("checkPossibleMissNotify: onCellInfoChanged[" + phoneId + "] = "
@@ -2891,7 +2940,7 @@
             }
         }
 
-        if ((events & PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) != 0) {
+        if (events.contains(PhoneStateListener.EVENT_USER_MOBILE_DATA_STATE_CHANGED)) {
             try {
                 if (VDBG) {
                     log("checkPossibleMissNotify: onUserMobileDataStateChanged phoneId="
@@ -2903,7 +2952,7 @@
             }
         }
 
-        if ((events & PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED) != 0) {
+        if (events.contains(PhoneStateListener.EVENT_DISPLAY_INFO_CHANGED)) {
             try {
                 if (VDBG) {
                     log("checkPossibleMissNotify: onDisplayInfoChanged phoneId="
@@ -2917,7 +2966,7 @@
             }
         }
 
-        if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
+        if (events.contains(PhoneStateListener.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)) {
             try {
                 if (VDBG) {
                     log("checkPossibleMissNotify: onMessageWaitingIndicatorChanged phoneId="
@@ -2930,7 +2979,7 @@
             }
         }
 
-        if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
+        if (events.contains(PhoneStateListener.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)) {
             try {
                 if (VDBG) {
                     log("checkPossibleMissNotify: onCallForwardingIndicatorChanged phoneId="
@@ -2943,7 +2992,7 @@
             }
         }
 
-        if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
+        if (validateEventAndUserLocked(r, PhoneStateListener.EVENT_CELL_LOCATION_CHANGED)) {
             try {
                 if (DBG_LOC) {
                     log("checkPossibleMissNotify: onCellLocationChanged mCellIdentity = "
@@ -2959,7 +3008,7 @@
             }
         }
 
-        if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
+        if (events.contains(PhoneStateListener.EVENT_DATA_CONNECTION_STATE_CHANGED)) {
             try {
                 if (DBG) {
                     log("checkPossibleMissNotify: onDataConnectionStateChanged(mDataConnectionState"
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index f49f1b1..7f638b9 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -1737,9 +1737,12 @@
                                 context.getString(R.string.car_mode_disable_notification_title))
                         .setContentText(
                                 context.getString(R.string.car_mode_disable_notification_message))
+
                         .setContentIntent(
+                                // TODO(b/173744200) Please replace FLAG_MUTABLE_UNAUDITED below
+                                // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
                                 PendingIntent.getActivityAsUser(context, 0,
-                                        carModeOffIntent, 0,
+                                        carModeOffIntent, PendingIntent.FLAG_MUTABLE_UNAUDITED,
                                         null, UserHandle.CURRENT));
                 mNotificationManager.notifyAsUser(null,
                         SystemMessage.NOTE_CAR_MODE_DISABLE, n.build(), UserHandle.ALL);
diff --git a/services/core/java/com/android/server/accounts/AccountAuthenticatorCache.java b/services/core/java/com/android/server/accounts/AccountAuthenticatorCache.java
index b9453db..725bccf 100644
--- a/services/core/java/com/android/server/accounts/AccountAuthenticatorCache.java
+++ b/services/core/java/com/android/server/accounts/AccountAuthenticatorCache.java
@@ -27,10 +27,10 @@
 import android.content.res.TypedArray;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 
-import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
 
@@ -83,13 +83,13 @@
 
     private static class MySerializer implements XmlSerializerAndParser<AuthenticatorDescription> {
         @Override
-        public void writeAsXml(AuthenticatorDescription item, XmlSerializer out)
+        public void writeAsXml(AuthenticatorDescription item, TypedXmlSerializer out)
                 throws IOException {
             out.attribute(null, "type", item.type);
         }
 
         @Override
-        public AuthenticatorDescription createFromXml(XmlPullParser parser)
+        public AuthenticatorDescription createFromXml(TypedXmlPullParser parser)
                 throws IOException, XmlPullParserException {
             return AuthenticatorDescription.newKey(parser.getAttributeValue(null, "type"));
         }
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index d99b195..1f35b88 100644
--- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
@@ -71,7 +71,6 @@
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.XmlUtils;
 import com.android.internal.util.dump.DualDumpOutputStream;
@@ -79,7 +78,6 @@
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -89,7 +87,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
 import java.security.SecureRandom;
 import java.util.AbstractMap;
@@ -1757,21 +1754,21 @@
             dump.write("user_keys", AdbDebuggingManagerProto.USER_KEYS,
                     FileUtils.readTextFile(new File("/data/misc/adb/adb_keys"), 0, null));
         } catch (IOException e) {
-            Slog.e(TAG, "Cannot read user keys", e);
+            Slog.i(TAG, "Cannot read user keys", e);
         }
 
         try {
             dump.write("system_keys", AdbDebuggingManagerProto.SYSTEM_KEYS,
                     FileUtils.readTextFile(new File("/adb_keys"), 0, null));
         } catch (IOException e) {
-            Slog.e(TAG, "Cannot read system keys", e);
+            Slog.i(TAG, "Cannot read system keys", e);
         }
 
         try {
             dump.write("keystore", AdbDebuggingManagerProto.KEYSTORE,
                     FileUtils.readTextFile(getAdbTempKeysFile(), 0, null));
         } catch (IOException e) {
-            Slog.e(TAG, "Cannot read keystore: ", e);
+            Slog.i(TAG, "Cannot read keystore: ", e);
         }
 
         dump.end(token);
@@ -1966,9 +1963,9 @@
                     String key = parser.getAttributeValue(null, XML_ATTRIBUTE_KEY);
                     long connectionTime;
                     try {
-                        connectionTime = Long.valueOf(
-                                parser.getAttributeValue(null, XML_ATTRIBUTE_LAST_CONNECTION));
-                    } catch (NumberFormatException e) {
+                        connectionTime = parser.getAttributeLong(null,
+                                XML_ATTRIBUTE_LAST_CONNECTION);
+                    } catch (XmlPullParserException e) {
                         Slog.e(TAG,
                                 "Caught a NumberFormatException parsing the last connection time: "
                                         + e);
@@ -2020,9 +2017,9 @@
                     String key = parser.getAttributeValue(null, XML_ATTRIBUTE_KEY);
                     long connectionTime;
                     try {
-                        connectionTime = Long.valueOf(
-                                parser.getAttributeValue(null, XML_ATTRIBUTE_LAST_CONNECTION));
-                    } catch (NumberFormatException e) {
+                        connectionTime = parser.getAttributeLong(null,
+                                XML_ATTRIBUTE_LAST_CONNECTION);
+                    } catch (XmlPullParserException e) {
                         Slog.e(TAG,
                                 "Caught a NumberFormatException parsing the last connection time: "
                                         + e);
@@ -2150,8 +2147,8 @@
                 for (Map.Entry<String, Long> keyEntry : mKeyMap.entrySet()) {
                     serializer.startTag(null, XML_TAG_ADB_KEY);
                     serializer.attribute(null, XML_ATTRIBUTE_KEY, keyEntry.getKey());
-                    serializer.attribute(null, XML_ATTRIBUTE_LAST_CONNECTION,
-                            String.valueOf(keyEntry.getValue()));
+                    serializer.attributeLong(null, XML_ATTRIBUTE_LAST_CONNECTION,
+                            keyEntry.getValue());
                     serializer.endTag(null, XML_TAG_ADB_KEY);
                 }
                 for (String bssid : mTrustedNetworks) {
diff --git a/services/core/java/com/android/server/adb/OWNERS b/services/core/java/com/android/server/adb/OWNERS
new file mode 100644
index 0000000..b97f795
--- /dev/null
+++ b/services/core/java/com/android/server/adb/OWNERS
@@ -0,0 +1 @@
+include platform/packages/modules/adb:/OWNERS
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index c7e3b23..dffe0ba 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -50,6 +50,7 @@
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
 import android.app.ApplicationExitInfo;
+import android.app.BroadcastOptions;
 import android.app.IApplicationThread;
 import android.app.IServiceConnection;
 import android.app.Notification;
@@ -3201,7 +3202,8 @@
                         + " for fg-service launch");
             }
             mAm.tempWhitelistUidLocked(r.appInfo.uid,
-                    SERVICE_START_FOREGROUND_TIMEOUT, "fg-service-launch");
+                    SERVICE_START_FOREGROUND_TIMEOUT, "fg-service-launch",
+                    BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED);
         }
 
         if (!mPendingServices.contains(r)) {
@@ -5284,8 +5286,9 @@
 
         if (ret == FGS_FEATURE_DENIED) {
             if (mAm.mConstants.mFlagFgsStartTempAllowListEnabled
-                    && mAm.isOnDeviceIdleWhitelistLocked(r.appInfo.uid, false)) {
-                // uid is on DeviceIdleController's allowlist.
+                    && mAm.isWhitelistedForFgsStartLocked(r.appInfo.uid)) {
+                // uid is on DeviceIdleController's user/system allowlist
+                // or AMS's FgsStartTempAllowList.
                 ret = FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST;
             }
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index da6e7ff..0f9e9ee 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -139,6 +139,7 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.Activity;
+import android.app.ActivityClient;
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManagerInternal;
@@ -264,7 +265,6 @@
 import android.os.WorkSource;
 import android.os.storage.IStorageManager;
 import android.os.storage.StorageManager;
-import android.permission.PermissionManagerInternal.CheckPermissionDelegate;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.server.ServerProtoEnums;
@@ -288,7 +288,6 @@
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 import android.util.proto.ProtoUtils;
-import android.view.Display;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -326,7 +325,6 @@
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.function.HeptFunction;
 import com.android.internal.util.function.QuadFunction;
-import com.android.internal.util.function.TriFunction;
 import com.android.server.AlarmManagerInternal;
 import com.android.server.AttributeCache;
 import com.android.server.DeviceIdleInternal;
@@ -394,7 +392,6 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.Executor;
-import java.util.function.BiFunction;
 
 public class ActivityManagerService extends IActivityManager.Stub
         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
@@ -1097,6 +1094,11 @@
     final PendingTempWhitelists mPendingTempWhitelist = new PendingTempWhitelists(this);
 
     /**
+     * The temp-allowlist that is allowed to start FGS from background.
+     */
+    final FgsStartTempAllowList mFgsStartTempAllowList = new FgsStartTempAllowList();
+
+    /**
      * Information about and control over application operations
      */
     final AppOpsService mAppOpsService;
@@ -2859,12 +2861,13 @@
     @Override
     public final boolean finishActivity(IBinder token, int resultCode, Intent resultData,
             int finishTask) {
-        return mActivityTaskManager.finishActivity(token, resultCode, resultData, finishTask);
+        return ActivityClient.getInstance().finishActivity(token, resultCode, resultData,
+                finishTask);
     }
 
     @Override
     public void setRequestedOrientation(IBinder token, int requestedOrientation) {
-        mActivityTaskManager.setRequestedOrientation(token, requestedOrientation);
+        ActivityClient.getInstance().setRequestedOrientation(token, requestedOrientation);
     }
 
     @Override
@@ -5512,6 +5515,12 @@
                 || mPendingTempWhitelist.indexOfKey(uid) >= 0;
     }
 
+    boolean isWhitelistedForFgsStartLocked(int uid) {
+        final int appId = UserHandle.getAppId(uid);
+        return Arrays.binarySearch(mDeviceIdleExceptIdleWhitelist, appId) >= 0
+                || mFgsStartTempAllowList.isAllowed(uid);
+    }
+
     /**
      * @return whitelist tag for a uid from mPendingTempWhitelist, null if not currently on
      * the whitelist
@@ -5711,7 +5720,7 @@
      */
     @Override
     public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
-        return mActivityTaskManager.moveActivityTaskToBack(token, nonRoot);
+        return ActivityClient.getInstance().moveActivityTaskToBack(token, nonRoot);
     }
 
     @Override
@@ -5746,7 +5755,7 @@
 
     @Override
     public int getTaskForActivity(IBinder token, boolean onlyRoot) {
-        return mActivityTaskManager.getTaskForActivity(token, onlyRoot);
+        return ActivityClient.getInstance().getTaskForActivity(token, onlyRoot);
     }
 
     @Override
@@ -6719,7 +6728,7 @@
 
     @Override
     public boolean isTopOfTask(IBinder token) {
-        return mActivityTaskManager.isTopOfTask(token);
+        return ActivityClient.getInstance().isTopOfTask(token);
     }
 
     @Override
@@ -14485,7 +14494,7 @@
                 mAppOpsService.setMode(AppOpsManager.OP_NO_ISOLATED_STORAGE, app.uid,
                         app.info.packageName, AppOpsManager.MODE_ERRORED);
                 mAppOpsService.setAppOpsServiceDelegate(null);
-                getPermissionManagerInternalLocked().setCheckPermissionDelegate(null);
+                getPermissionManagerInternalLocked().stopShellPermissionIdentityDelegation();
                 mHandler.obtainMessage(SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG,
                         instr.mUiAutomationConnection).sendToTarget();
             }
@@ -15326,17 +15335,22 @@
             }
         }
 
-        tempWhitelistUidLocked(targetUid, duration, tag);
+        tempWhitelistUidLocked(targetUid, duration, tag,
+                BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED);
     }
 
     /**
      * Whitelists {@code targetUid} to temporarily bypass Power Save mode.
      */
     @GuardedBy("this")
-    void tempWhitelistUidLocked(int targetUid, long duration, String tag) {
+    void tempWhitelistUidLocked(int targetUid, long duration, String tag, int type) {
         mPendingTempWhitelist.put(targetUid, new PendingTempWhitelist(targetUid, duration, tag));
         setUidTempWhitelistStateLocked(targetUid, true);
         mUiHandler.obtainMessage(PUSH_TEMP_WHITELIST_UI_MSG).sendToTarget();
+
+        if (type == BroadcastOptions.TEMPORARY_WHITELIST_TYPE_FOREGROUND_SERVICE_ALLOWED) {
+            mFgsStartTempAllowList.add(targetUid, duration);
+        }
     }
 
     void pushTempWhitelist() {
@@ -16305,14 +16319,9 @@
 
         @Override
         public ActivityPresentationInfo getActivityPresentationInfo(IBinder token) {
-            int displayId = Display.INVALID_DISPLAY;
-            try {
-                displayId = mActivityTaskManager.getDisplayId(token);
-            } catch (RemoteException e) {
-            }
-
-            return new ActivityPresentationInfo(mActivityTaskManager.getTaskForActivity(token,
-                    /*onlyRoot=*/ false), displayId,
+            final ActivityClient ac = ActivityClient.getInstance();
+            return new ActivityPresentationInfo(ac.getTaskForActivity(token,
+                    /*onlyRoot=*/ false), ac.getDisplayId(token),
                     mActivityTaskManager.getActivityClassForToken(token));
         }
 
@@ -17205,12 +17214,6 @@
 
         // We allow delegation only to one instrumentation started from the shell
         synchronized (ActivityManagerService.this) {
-            // If there is a delegate it should be the same instance for app ops and permissions.
-            if (mAppOpsService.getAppOpsServiceDelegate()
-                    != getPermissionManagerInternalLocked().getCheckPermissionDelegate()) {
-                throw new IllegalStateException("Bad shell delegate state");
-            }
-
             // If the delegate is already set up for the target UID, nothing to do.
             if (mAppOpsService.getAppOpsServiceDelegate() != null) {
                 if (!(mAppOpsService.getAppOpsServiceDelegate() instanceof ShellDelegate)) {
@@ -17239,10 +17242,14 @@
                 }
 
                 // Hook them up...
-                final ShellDelegate shellDelegate = new ShellDelegate(
-                        instr.mTargetInfo.packageName, delegateUid, permissions);
+                final ShellDelegate shellDelegate = new ShellDelegate(delegateUid,
+                        permissions);
                 mAppOpsService.setAppOpsServiceDelegate(shellDelegate);
-                getPermissionManagerInternalLocked().setCheckPermissionDelegate(shellDelegate);
+                final String packageName = instr.mTargetInfo.packageName;
+                final List<String> permissionNames = permissions != null ?
+                        Arrays.asList(permissions) : null;
+                getPermissionManagerInternalLocked().startShellPermissionIdentityDelegation(
+                        delegateUid, packageName, permissionNames);
                 return;
             }
         }
@@ -17256,17 +17263,15 @@
         }
         synchronized (ActivityManagerService.this) {
             mAppOpsService.setAppOpsServiceDelegate(null);
-            getPermissionManagerInternalLocked().setCheckPermissionDelegate(null);
+            getPermissionManagerInternalLocked().stopShellPermissionIdentityDelegation();
         }
     }
 
-    private class ShellDelegate implements CheckOpsDelegate, CheckPermissionDelegate {
-        private final String mTargetPackageName;
+    private class ShellDelegate implements CheckOpsDelegate {
         private final int mTargetUid;
         private @Nullable String[] mPermissions;
 
-        ShellDelegate(String targetPackageName, int targetUid, @Nullable String[] permissions) {
-            mTargetPackageName = targetPackageName;
+        ShellDelegate(int targetUid, @Nullable String[] permissions) {
             mTargetUid = targetUid;
             mPermissions = permissions;
         }
@@ -17284,10 +17289,11 @@
         public int checkOperation(int code, int uid, String packageName, boolean raw,
                 QuadFunction<Integer, Integer, String, Boolean, Integer> superImpl) {
             if (uid == mTargetUid && isTargetOp(code)) {
+                final int shellUid = UserHandle.getUid(UserHandle.getUserId(uid),
+                        Process.SHELL_UID);
                 final long identity = Binder.clearCallingIdentity();
                 try {
-                    return superImpl.apply(code, Process.SHELL_UID,
-                            "com.android.shell", raw);
+                    return superImpl.apply(code, shellUid, "com.android.shell", raw);
                 } finally {
                     Binder.restoreCallingIdentity(identity);
                 }
@@ -17299,10 +17305,11 @@
         public int checkAudioOperation(int code, int usage, int uid, String packageName,
                 QuadFunction<Integer, Integer, Integer, String, Integer> superImpl) {
             if (uid == mTargetUid && isTargetOp(code)) {
+                final int shellUid = UserHandle.getUid(UserHandle.getUserId(uid),
+                        Process.SHELL_UID);
                 final long identity = Binder.clearCallingIdentity();
                 try {
-                    return superImpl.apply(code, usage, Process.SHELL_UID,
-                            "com.android.shell");
+                    return superImpl.apply(code, usage, shellUid, "com.android.shell");
                 } finally {
                     Binder.restoreCallingIdentity(identity);
                 }
@@ -17317,9 +17324,11 @@
                 @NonNull HeptFunction<Integer, Integer, String, String, Boolean, String, Boolean,
                         Integer> superImpl) {
             if (uid == mTargetUid && isTargetOp(code)) {
+                final int shellUid = UserHandle.getUid(UserHandle.getUserId(uid),
+                        Process.SHELL_UID);
                 final long identity = Binder.clearCallingIdentity();
                 try {
-                    return superImpl.apply(code, Process.SHELL_UID, "com.android.shell", featureId,
+                    return superImpl.apply(code, shellUid, "com.android.shell", featureId,
                             shouldCollectAsyncNotedOp, message, shouldCollectMessage);
                 } finally {
                     Binder.restoreCallingIdentity(identity);
@@ -17329,34 +17338,6 @@
                     message, shouldCollectMessage);
         }
 
-        @Override
-        public int checkPermission(String permName, String pkgName, int userId,
-                TriFunction<String, String, Integer, Integer> superImpl) {
-            if (mTargetPackageName.equals(pkgName) && isTargetPermission(permName)) {
-                final long identity = Binder.clearCallingIdentity();
-                try {
-                    return superImpl.apply(permName, "com.android.shell", userId);
-                } finally {
-                    Binder.restoreCallingIdentity(identity);
-                }
-            }
-            return superImpl.apply(permName, pkgName, userId);
-        }
-
-        @Override
-        public int checkUidPermission(String permName, int uid,
-                BiFunction<String, Integer, Integer> superImpl) {
-            if (uid == mTargetUid  && isTargetPermission(permName)) {
-                final long identity = Binder.clearCallingIdentity();
-                try {
-                    return superImpl.apply(permName, Process.SHELL_UID);
-                } finally {
-                    Binder.restoreCallingIdentity(identity);
-                }
-            }
-            return superImpl.apply(permName, uid);
-        }
-
         private boolean isTargetOp(int code) {
             // null permissions means all ops are targeted
             if (mPermissions == null) {
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index fdc0f59..ca20224 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -353,7 +353,7 @@
                 mUidsToRemove.clear();
                 mCurrentFuture = null;
                 mUseLatestStates = true;
-                if ((updateFlags & UPDATE_ALL) != 0) {
+                if (updateFlags == UPDATE_ALL) {
                     cancelSyncDueToBatteryLevelChangeLocked();
                 }
                 if ((updateFlags & UPDATE_CPU) != 0) {
@@ -533,7 +533,7 @@
                 mStats.updateCpuTimeLocked(onBattery, onBatteryScreenOff);
             }
 
-            if ((updateFlags & UPDATE_ALL) != 0) {
+            if (updateFlags == UPDATE_ALL) {
                 mStats.updateKernelWakelocksLocked(elapsedRealtimeUs);
                 mStats.updateKernelMemoryBandwidthLocked(elapsedRealtimeUs);
             }
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 46e16bc..3b6f0ac 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -25,6 +25,7 @@
 import android.hardware.power.stats.EnergyConsumerResult;
 import android.os.BatteryStats;
 import android.os.BatteryStatsInternal;
+import android.os.BatteryUsageStats;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -57,6 +58,7 @@
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.os.BatteryStatsHelper;
 import com.android.internal.os.BatteryStatsImpl;
+import com.android.internal.os.BatteryUsageStatsProvider;
 import com.android.internal.os.BinderCallsStats;
 import com.android.internal.os.PowerProfile;
 import com.android.internal.os.RailStats;
@@ -105,6 +107,7 @@
     private final BatteryStatsImpl.UserInfoProvider mUserManagerUserInfoProvider;
     private final Context mContext;
     private final BatteryExternalStatsWorker mWorker;
+    private final BatteryUsageStatsProvider mBatteryUsageStatsProvider;
 
     private native void getLowPowerStats(RpmStats rpmStats);
     private native int getPlatformLowPowerStats(ByteBuffer outBuffer);
@@ -258,6 +261,7 @@
         mStats.setRadioScanningTimeoutLocked(mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_radioScanningTimeout) * 1000L);
         mStats.setPowerProfileLocked(new PowerProfile(context));
+        mBatteryUsageStatsProvider = new BatteryUsageStatsProvider(context, mStats);
     }
 
     public void publish() {
@@ -550,6 +554,16 @@
 
     // Public interface...
 
+    /**
+     * Returns BatteryUsageStats, which contains power attribution data on a per-subsystem
+     * and per-UID basis.
+     */
+    public BatteryUsageStats getBatteryUsageStats() {
+        mContext.enforceCallingPermission(
+                android.Manifest.permission.BATTERY_STATS, null);
+        return mBatteryUsageStatsProvider.getBatteryUsageStats();
+    }
+
     public byte[] getStatistics() {
         mContext.enforceCallingPermission(
                 android.Manifest.permission.BATTERY_STATS, null);
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 0877dd9..d2ee69e 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -896,7 +896,8 @@
         return false;
     }
 
-    final void scheduleTempWhitelistLocked(int uid, long duration, BroadcastRecord r) {
+    final void scheduleTempWhitelistLocked(int uid, long duration, BroadcastRecord r,
+            @BroadcastOptions.TempAllowListType int type) {
         if (duration > Integer.MAX_VALUE) {
             duration = Integer.MAX_VALUE;
         }
@@ -919,9 +920,9 @@
         }
         if (DEBUG_BROADCAST) {
             Slog.v(TAG, "Broadcast temp whitelist uid=" + uid + " duration=" + duration
-                    + " : " + b.toString());
+                    + " type=" + type + " : " + b.toString());
         }
-        mService.tempWhitelistUidLocked(uid, duration, b.toString());
+        mService.tempWhitelistUidLocked(uid, duration, b.toString(), type);
     }
 
     /**
@@ -1318,7 +1319,8 @@
                 }
                 if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
                     scheduleTempWhitelistLocked(filter.owningUid,
-                            brOptions.getTemporaryAppWhitelistDuration(), r);
+                            brOptions.getTemporaryAppWhitelistDuration(), r,
+                            brOptions.getTemporaryAppWhitelistType());
                 }
             }
             return;
@@ -1610,7 +1612,8 @@
                 (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0);
         if (isActivityCapable) {
             scheduleTempWhitelistLocked(receiverUid,
-                    brOptions.getTemporaryAppWhitelistDuration(), r);
+                    brOptions.getTemporaryAppWhitelistDuration(), r,
+                    brOptions.getTemporaryAppWhitelistType());
         }
 
         // Broadcast is being executed, its package can't be stopped.
diff --git a/services/core/java/com/android/server/am/FgsStartTempAllowList.java b/services/core/java/com/android/server/am/FgsStartTempAllowList.java
new file mode 100644
index 0000000..1f90393
--- /dev/null
+++ b/services/core/java/com/android/server/am/FgsStartTempAllowList.java
@@ -0,0 +1,72 @@
+/*
+ * 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.am;
+
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+
+import android.os.SystemClock;
+import android.util.Slog;
+import android.util.SparseLongArray;
+
+/**
+ * List of uids that are temporarily allowed to start FGS from background.
+ */
+final class FgsStartTempAllowList {
+    private static final int MAX_SIZE = 100;
+    /**
+     * The key is the UID, the value is expiration elapse time in ms of this temp-allowed UID.
+     */
+    private final SparseLongArray mTempAllowListFgs = new SparseLongArray();
+
+    FgsStartTempAllowList() {
+    }
+
+    void add(int uid, long duration) {
+        if (duration <= 0) {
+            Slog.e(TAG_AM, "FgsStartTempAllowList bad duration:" + duration + " uid: " + uid);
+            return;
+        }
+        // The temp allowlist should be a short list with only a few entries in it.
+        final int size = mTempAllowListFgs.size();
+        if (size > MAX_SIZE) {
+            Slog.w(TAG_AM, "FgsStartTempAllowList length:" + size + " exceeds " + MAX_SIZE);
+        }
+        final long now = SystemClock.elapsedRealtime();
+        for (int index = mTempAllowListFgs.size() - 1; index >= 0; index--) {
+            if (mTempAllowListFgs.valueAt(index) < now) {
+                mTempAllowListFgs.removeAt(index);
+            }
+        }
+        final long existingExpirationTime = mTempAllowListFgs.get(uid, -1);
+        final long expirationTime = now + duration;
+        if (existingExpirationTime == -1 || existingExpirationTime < expirationTime) {
+            mTempAllowListFgs.put(uid, expirationTime);
+        }
+    }
+
+    boolean isAllowed(int uid) {
+        final int index = mTempAllowListFgs.indexOfKey(uid);
+        if (index < 0) {
+            return false;
+        } else if (mTempAllowListFgs.valueAt(index) < SystemClock.elapsedRealtime()) {
+            mTempAllowListFgs.removeAt(index);
+            return false;
+        } else {
+            return true;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/appop/OWNERS b/services/core/java/com/android/server/appop/OWNERS
new file mode 100644
index 0000000..999ea0e
--- /dev/null
+++ b/services/core/java/com/android/server/appop/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/permission/OWNERS
diff --git a/services/core/java/com/android/server/attention/OWNERS b/services/core/java/com/android/server/attention/OWNERS
new file mode 100644
index 0000000..51fc9bd
--- /dev/null
+++ b/services/core/java/com/android/server/attention/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/attention/OWNERS
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 89150ae..af00731 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -545,7 +545,6 @@
             AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET,
             AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET,
             AudioSystem.DEVICE_OUT_HDMI_ARC,
-            AudioSystem.DEVICE_OUT_SPDIF,
             AudioSystem.DEVICE_OUT_AUX_LINE));
     // Devices for which the volume is always max, no volume panel
     Set<Integer> mFullVolumeDevices = new HashSet<>();
@@ -7445,8 +7444,8 @@
     private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
     private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000;  // 1 minute polling interval
     private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000;  // 30s after boot completed
-    // check playback or record activity every 3 seconds for UIDs owning mode IN_COMMUNICATION
-    private static final int CHECK_MODE_FOR_UID_PERIOD_MS = 3000;
+    // check playback or record activity every 6 seconds for UIDs owning mode IN_COMMUNICATION
+    private static final int CHECK_MODE_FOR_UID_PERIOD_MS = 6000;
 
     private int safeMediaVolumeIndex(int device) {
         if (!mSafeMediaVolumeDevices.contains(device)) {
diff --git a/services/core/java/com/android/server/backup/OWNERS b/services/core/java/com/android/server/backup/OWNERS
new file mode 100644
index 0000000..d99779e
--- /dev/null
+++ b/services/core/java/com/android/server/backup/OWNERS
@@ -0,0 +1 @@
+include /services/backup/OWNERS
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 0194259..75e1938 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -30,6 +30,7 @@
 import android.app.trust.ITrustManager;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.database.ContentObserver;
 import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricConstants;
@@ -809,12 +810,13 @@
 
         public List<FingerprintSensorPropertiesInternal> getFingerprintSensorProperties(
                 Context context) {
-            final FingerprintManager fpm = context.getSystemService(FingerprintManager.class);
-            if (fpm != null) {
-                return fpm.getSensorPropertiesInternal();
-            } else {
-                return new ArrayList<>();
+            if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+                final FingerprintManager fpm = context.getSystemService(FingerprintManager.class);
+                if (fpm != null) {
+                    return fpm.getSensorPropertiesInternal();
+                }
             }
+            return new ArrayList<>();
         }
     }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
index 62c9295..f07bf1e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
@@ -53,7 +53,7 @@
 
     @Override
     public byte[] dumpSensorServiceStateProto() throws RemoteException {
-        return mFaceService.dumpSensorServiceStateProto();
+        return mFaceService.dumpSensorServiceStateProto(mSensorId);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index 47897a1..cb56e8c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -127,17 +127,6 @@
         return properties;
     }
 
-    @NonNull
-    private List<Face> getEnrolledFaces(int userId, String opPackageName) {
-        final Pair<Integer, ServiceProvider> provider = getSingleProvider();
-        if (provider == null) {
-            Slog.w(TAG, "Null provider for getEnrolledFaces, caller: " + opPackageName);
-            return Collections.emptyList();
-        }
-
-        return provider.second.getEnrolledFaces(provider.first, userId);
-    }
-
     /**
      * Receives the incoming binder calls from FaceManager.
      */
@@ -157,14 +146,13 @@
         }
 
         @Override
-        public byte[] dumpSensorServiceStateProto() {
+        public byte[] dumpSensorServiceStateProto(int sensorId) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
 
             final ProtoOutputStream proto = new ProtoOutputStream();
-            for (ServiceProvider provider : mServiceProviders) {
-                for (FaceSensorPropertiesInternal props : provider.getSensorProperties()) {
-                    provider.dumpProtoState(props.sensorId, proto);
-                }
+            final ServiceProvider provider = getProviderForSensor(sensorId);
+            if (provider != null) {
+                provider.dumpProtoState(sensorId, proto);
             }
             proto.flush();
             return proto.getBytes();
@@ -439,6 +427,7 @@
                             pw.println("Dumping for sensorId: " + props.sensorId
                                     + ", provider: " + provider.getClass().getSimpleName());
                             provider.dumpInternal(props.sensorId, pw);
+                            pw.println();
                         }
                     }
                 }
@@ -472,7 +461,13 @@
                 Utils.checkPermission(getContext(), INTERACT_ACROSS_USERS);
             }
 
-            return FaceService.this.getEnrolledFaces(userId, opPackageName);
+            final ServiceProvider provider = getProviderForSensor(sensorId);
+            if (provider == null) {
+                Slog.w(TAG, "Null provider for getEnrolledFaces, caller: " + opPackageName);
+                return Collections.emptyList();
+            }
+
+            return provider.getEnrolledFaces(sensorId, userId);
         }
 
         @Override // Binder call
@@ -483,7 +478,16 @@
                 Utils.checkPermission(getContext(), INTERACT_ACROSS_USERS);
             }
 
-            return !FaceService.this.getEnrolledFaces(userId, opPackageName).isEmpty();
+            final ServiceProvider provider = getProviderForSensor(sensorId);
+            if (provider == null) {
+                Slog.w(TAG, "Null provider for hasEnrolledFaces, caller: " + opPackageName);
+                return false;
+            }
+
+            final boolean enrolled = provider.getEnrolledFaces(sensorId, userId).size() > 0;
+            Slog.d(TAG, "hasEnrolledFaces, sensor: " + sensorId + ", enrolled: " + enrolled);
+
+            return provider.getEnrolledFaces(sensorId, userId).size() > 0;
         }
 
         @Override // Binder call
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceUtils.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceUtils.java
index a0ffe58..a0cd4a5 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceUtils.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceUtils.java
@@ -72,13 +72,13 @@
     }
 
     /**
-     * Legacy getter for {@link android.hardware.biometrics.face.V1_0} and its extended subclasses,
-     * which do not support a well defined sensorId from the HAL.
+     * Legacy getter for {@link android.hardware.biometrics.face.V1_0} and its extended subclasses.
+     * Framework-side cache is always stored in the same file, regardless of sensorId.
      */
-    public static FaceUtils getInstance() {
+    public static FaceUtils getLegacyInstance(int sensorId) {
         // Note that sensorId for legacy services can be hard-coded to 0 since it's only used
         // to index into the sensor states map.
-        return getInstance(0 /* sensorId */, LEGACY_FACE_FILE);
+        return getInstance(sensorId, LEGACY_FACE_FILE);
     }
 
     private FaceUtils(String fileName) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
index 4c983fb..9ed8f78 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/BiometricTestSessionImpl.java
@@ -153,7 +153,8 @@
         Utils.checkPermission(mContext, TEST_BIOMETRIC);
 
         // Fake authentication with any of the existing fingers
-        List<Face> faces = FaceUtils.getInstance().getBiometricsForUser(mContext, userId);
+        List<Face> faces = FaceUtils.getLegacyInstance(mSensorId)
+                .getBiometricsForUser(mContext, userId);
         if (faces.isEmpty()) {
             Slog.w(TAG, "No faces, returning");
             return;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index d384bc6..c4e4d1f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -166,7 +166,7 @@
         @Override
         public void onEnrollResult(long deviceId, int faceId, int userId, int remaining) {
             mHandler.post(() -> {
-                final CharSequence name = FaceUtils.getInstance()
+                final CharSequence name = FaceUtils.getLegacyInstance(mSensorId)
                         .getUniqueName(mContext, userId);
                 final Face face = new Face(name, faceId, deviceId);
 
@@ -471,7 +471,7 @@
     @Override
     @NonNull
     public List<Face> getEnrolledFaces(int sensorId, int userId) {
-        return FaceUtils.getInstance().getBiometricsForUser(mContext, userId);
+        return FaceUtils.getLegacyInstance(mSensorId).getBiometricsForUser(mContext, userId);
     }
 
     @Override
@@ -610,8 +610,8 @@
 
             final FaceEnrollClient client = new FaceEnrollClient(mContext, mLazyDaemon, token,
                     new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
-                    opPackageName, FaceUtils.getInstance(), disabledFeatures, ENROLL_TIMEOUT_SEC,
-                    surfaceHandle, mSensorId);
+                    opPackageName, FaceUtils.getLegacyInstance(mSensorId), disabledFeatures,
+                    ENROLL_TIMEOUT_SEC, surfaceHandle, mSensorId);
 
             mScheduler.scheduleClientMonitor(client, new ClientMonitor.Callback() {
                 @Override
@@ -665,7 +665,7 @@
 
             final FaceRemovalClient client = new FaceRemovalClient(mContext, mLazyDaemon, token,
                     new ClientMonitorCallbackConverter(receiver), faceId, userId, opPackageName,
-                    FaceUtils.getInstance(), mSensorId, mAuthenticatorIds);
+                    FaceUtils.getLegacyInstance(mSensorId), mSensorId, mAuthenticatorIds);
             mScheduler.scheduleClientMonitor(client);
         });
     }
@@ -748,7 +748,7 @@
             final List<Face> enrolledList = getEnrolledFaces(mSensorId, userId);
             final FaceInternalCleanupClient client = new FaceInternalCleanupClient(mContext,
                     mLazyDaemon, userId, mContext.getOpPackageName(), mSensorId, enrolledList,
-                    FaceUtils.getInstance(), mAuthenticatorIds);
+                    FaceUtils.getLegacyInstance(mSensorId), mAuthenticatorIds);
             mScheduler.scheduleClientMonitor(client);
         });
     }
@@ -777,7 +777,7 @@
 
             final long userToken = proto.start(SensorStateProto.USER_STATES);
             proto.write(UserStateProto.USER_ID, userId);
-            proto.write(UserStateProto.NUM_ENROLLED, FaceUtils.getInstance()
+            proto.write(UserStateProto.NUM_ENROLLED, FaceUtils.getLegacyInstance(mSensorId)
                     .getBiometricsForUser(mContext, userId).size());
             proto.end(userToken);
         }
@@ -801,7 +801,8 @@
             JSONArray sets = new JSONArray();
             for (UserInfo user : UserManager.get(mContext).getUsers()) {
                 final int userId = user.getUserHandle().getIdentifier();
-                final int c = FaceUtils.getInstance().getBiometricsForUser(mContext, userId).size();
+                final int c = FaceUtils.getLegacyInstance(mSensorId)
+                        .getBiometricsForUser(mContext, userId).size();
                 JSONObject set = new JSONObject();
                 set.put("id", userId);
                 set.put("count", c);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
index ce880aa..cbffdd3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
@@ -198,9 +198,11 @@
             final Intent intent = new Intent("android.settings.FACE_SETTINGS");
             intent.setPackage("com.android.settings");
 
+            // TODO(b/174187097) Please replace FLAG_MUTABLE_UNAUDITED below
+            // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
             final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(getContext(),
-                    0 /* requestCode */, intent, 0 /* flags */, null /* options */,
-                    UserHandle.CURRENT);
+                    0 /* requestCode */, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED /* flags */,
+                    null /* options */, UserHandle.CURRENT);
 
             final String channelName = "FaceEnrollNotificationChannel";
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
index 1616457..d4cdc8b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
@@ -54,7 +54,7 @@
 
     @Override
     public byte[] dumpSensorServiceStateProto() throws RemoteException {
-        return mFingerprintService.dumpSensorServiceStateProto();
+        return mFingerprintService.dumpSensorServiceStateProto(mSensorId);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 6e91c9a..61f9cc4 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -115,15 +115,13 @@
         }
 
         @Override
-        public byte[] dumpSensorServiceStateProto() {
+        public byte[] dumpSensorServiceStateProto(int sensorId) {
             Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
 
             final ProtoOutputStream proto = new ProtoOutputStream();
-            for (ServiceProvider provider : mServiceProviders) {
-                for (FingerprintSensorPropertiesInternal props
-                        : provider.getSensorProperties()) {
-                    provider.dumpProtoState(props.sensorId, proto);
-                }
+            final ServiceProvider provider = getProviderForSensor(sensorId);
+            if (provider != null) {
+                provider.dumpProtoState(sensorId, proto);
             }
             proto.flush();
             return proto.getBytes();
@@ -437,6 +435,7 @@
                             pw.println("Dumping for sensorId: " + props.sensorId
                                     + ", provider: " + provider.getClass().getSimpleName());
                             provider.dumpInternal(props.sensorId, pw);
+                            pw.println();
                         }
                     }
                 }
@@ -588,13 +587,13 @@
                 @Nullable byte [] hardwareAuthToken, String opPackageName) {
             Utils.checkPermission(getContext(), RESET_FINGERPRINT_LOCKOUT);
 
-            final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+            final ServiceProvider provider = getProviderForSensor(sensorId);
             if (provider == null) {
                 Slog.w(TAG, "Null provider for resetLockout, caller: " + opPackageName);
                 return;
             }
 
-            provider.second.scheduleResetLockout(sensorId, userId, hardwareAuthToken);
+            provider.scheduleResetLockout(sensorId, userId, hardwareAuthToken);
         }
 
         @Override
@@ -747,14 +746,14 @@
     }
 
     /**
-     * For devices with only a single provider, returns that provider. If no providers, or multiple
-     * providers exist, returns null.
+     * For devices with only a single provider, returns that provider. If multiple providers,
+     * returns the first one. If no providers, returns null.
      */
     @Nullable
     private Pair<Integer, ServiceProvider> getSingleProvider() {
         final List<FingerprintSensorPropertiesInternal> properties = getSensorProperties();
-        if (properties.size() != 1) {
-            Slog.e(TAG, "Multiple sensors found: " + properties.size());
+        if (properties.isEmpty()) {
+            Slog.e(TAG, "No providers found");
             return null;
         }
 
@@ -767,7 +766,7 @@
             }
         }
 
-        Slog.e(TAG, "Single sensor, but provider not found");
+        Slog.e(TAG, "Provider not found");
         return null;
     }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUtils.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUtils.java
index 6da8650..b3d2419 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUtils.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUtils.java
@@ -75,12 +75,12 @@
 
     /**
      * Legacy getter for {@link android.hardware.biometrics.fingerprint.V2_1} ands its extended
-     * subclasses, which do not support a well defined sensorId from the HAL.
+     * subclasses. Framework-side cache is always stored in the same file, regardless of sensorId.
      */
-    public static FingerprintUtils getInstance() {
+    public static FingerprintUtils getLegacyInstance(int sensorId) {
         // Note that sensorId for legacy services can be hard-coded to 0 since it's only used
         // to index into the sensor states map.
-        return getInstance(0 /* sensorId */, LEGACY_FINGERPRINT_FILE);
+        return getInstance(sensorId, LEGACY_FINGERPRINT_FILE);
     }
 
     private FingerprintUtils(String fileName) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index fd1181b..3e13c45 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricFingerprintConstants;
 import android.hardware.biometrics.BiometricsProtoEnums;
 import android.hardware.biometrics.common.ICancellationSignal;
@@ -59,6 +60,15 @@
     }
 
     @Override
+    public void onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining) {
+        super.onEnrollResult(identifier, remaining);
+
+        if (remaining == 0) {
+            UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
+        }
+    }
+
+    @Override
     protected boolean hasReachedEnrollmentLimit() {
         return FingerprintUtils.getInstance(getSensorId())
                 .getBiometricsForUser(getContext(), getTargetUserId()).size()
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
index 65ce34d..74549b9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
@@ -144,7 +144,7 @@
         Utils.checkPermission(mContext, TEST_BIOMETRIC);
 
         // Fake authentication with any of the existing fingers
-        List<Fingerprint> fingerprints = FingerprintUtils.getInstance()
+        List<Fingerprint> fingerprints = FingerprintUtils.getLegacyInstance(mSensorId)
                 .getBiometricsForUser(mContext, userId);
         if (fingerprints.isEmpty()) {
             Slog.w(TAG, "No fingerprints, returning");
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 7c5b7c9..b8d27aa 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -111,6 +111,7 @@
     @NonNull private final HalResultController mHalResultController;
     @Nullable private IUdfpsOverlayController mUdfpsOverlayController;
     private int mCurrentUserId = UserHandle.USER_NULL;
+    private final int mSensorId;
 
     private final class BiometricTaskStackListener extends TaskStackListener {
         @Override
@@ -167,13 +168,15 @@
             void onHardwareUnavailable();
         }
 
+        private final int mSensorId;
         @NonNull private final Context mContext;
         @NonNull final Handler mHandler;
         @NonNull final BiometricScheduler mScheduler;
         @Nullable private Callback mCallback;
 
-        HalResultController(@NonNull Context context, @NonNull Handler handler,
+        HalResultController(int sensorId, @NonNull Context context, @NonNull Handler handler,
                 @NonNull BiometricScheduler scheduler) {
+            mSensorId = sensorId;
             mContext = context;
             mHandler = handler;
             mScheduler = scheduler;
@@ -194,7 +197,7 @@
                 }
 
                 final int currentUserId = client.getTargetUserId();
-                final CharSequence name = FingerprintUtils.getInstance()
+                final CharSequence name = FingerprintUtils.getLegacyInstance(mSensorId)
                         .getUniqueName(mContext, currentUserId);
                 final Fingerprint fingerprint = new Fingerprint(name, groupId, fingerId, deviceId);
 
@@ -307,6 +310,7 @@
             @NonNull LockoutResetDispatcher lockoutResetDispatcher,
             @NonNull HalResultController controller) {
         mContext = context;
+        mSensorId = sensorId;
         mScheduler = scheduler;
         mHandler = handler;
         mActivityTaskManager = ActivityTaskManager.getInstance();
@@ -361,7 +365,8 @@
         final Handler handler = new Handler(Looper.getMainLooper());
         final BiometricScheduler scheduler =
                 new BiometricScheduler(TAG, gestureAvailabilityDispatcher);
-        final HalResultController controller = new HalResultController(context, handler, scheduler);
+        final HalResultController controller = new HalResultController(sensorId, context, handler,
+                scheduler);
         return new Fingerprint21(context, scheduler, handler, sensorId, strength,
                 lockoutResetDispatcher, controller);
     }
@@ -549,7 +554,7 @@
 
             final FingerprintEnrollClient client = new FingerprintEnrollClient(mContext,
                     mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId,
-                    hardwareAuthToken, opPackageName, FingerprintUtils.getInstance(),
+                    hardwareAuthToken, opPackageName, FingerprintUtils.getLegacyInstance(mSensorId),
                     ENROLL_TIMEOUT_SEC, mSensorProperties.sensorId, mUdfpsOverlayController);
             mScheduler.scheduleClientMonitor(client, new ClientMonitor.Callback() {
                 @Override
@@ -624,7 +629,7 @@
 
            final FingerprintRemovalClient client = new FingerprintRemovalClient(mContext,
                    mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), fingerId,
-                   userId, opPackageName, FingerprintUtils.getInstance(),
+                   userId, opPackageName, FingerprintUtils.getLegacyInstance(mSensorId),
                    mSensorProperties.sensorId, mAuthenticatorIds);
            mScheduler.scheduleClientMonitor(client);
         });
@@ -638,8 +643,8 @@
                     mSensorProperties.sensorId, userId);
             final FingerprintInternalCleanupClient client = new FingerprintInternalCleanupClient(
                     mContext, mLazyDaemon, userId, mContext.getOpPackageName(),
-                    mSensorProperties.sensorId, enrolledList, FingerprintUtils.getInstance(),
-                    mAuthenticatorIds);
+                    mSensorProperties.sensorId, enrolledList,
+                    FingerprintUtils.getLegacyInstance(mSensorId), mAuthenticatorIds);
             mScheduler.scheduleClientMonitor(client);
         });
     }
@@ -657,14 +662,15 @@
     @Override
     public void rename(int sensorId, int fingerId, int userId, @NonNull String name) {
         mHandler.post(() -> {
-            FingerprintUtils.getInstance().renameBiometricForUser(mContext, userId, fingerId, name);
+            FingerprintUtils.getLegacyInstance(mSensorId)
+                    .renameBiometricForUser(mContext, userId, fingerId, name);
         });
     }
 
     @Override
     @NonNull
     public List<Fingerprint> getEnrolledFingerprints(int sensorId, int userId) {
-        return FingerprintUtils.getInstance().getBiometricsForUser(mContext, userId);
+        return FingerprintUtils.getLegacyInstance(mSensorId).getBiometricsForUser(mContext, userId);
     }
 
     @Override
@@ -716,7 +722,7 @@
 
             final long userToken = proto.start(SensorStateProto.USER_STATES);
             proto.write(UserStateProto.USER_ID, userId);
-            proto.write(UserStateProto.NUM_ENROLLED, FingerprintUtils.getInstance()
+            proto.write(UserStateProto.NUM_ENROLLED, FingerprintUtils.getLegacyInstance(mSensorId)
                     .getBiometricsForUser(mContext, userId).size());
             proto.end(userToken);
         }
@@ -737,7 +743,8 @@
 
             proto.write(FingerprintUserStatsProto.USER_ID, userId);
             proto.write(FingerprintUserStatsProto.NUM_FINGERPRINTS,
-                    FingerprintUtils.getInstance().getBiometricsForUser(mContext, userId).size());
+                    FingerprintUtils.getLegacyInstance(mSensorId)
+                            .getBiometricsForUser(mContext, userId).size());
 
             // Normal fingerprint authentications (e.g. lockscreen)
             long countsToken = proto.start(FingerprintUserStatsProto.NORMAL);
@@ -777,7 +784,7 @@
             JSONArray sets = new JSONArray();
             for (UserInfo user : UserManager.get(mContext).getUsers()) {
                 final int userId = user.getUserHandle().getIdentifier();
-                final int N = FingerprintUtils.getInstance()
+                final int N = FingerprintUtils.getLegacyInstance(mSensorId)
                         .getBiometricsForUser(mContext, userId).size();
                 JSONObject set = new JSONObject();
                 set.put("id", userId);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
index e4933e4..791d224 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
@@ -210,9 +210,9 @@
         @NonNull private Fingerprint21UdfpsMock mFingerprint21;
         @Nullable private LastAuthArgs mLastAuthArgs;
 
-        MockHalResultController(@NonNull Context context, @NonNull Handler handler,
+        MockHalResultController(int sensorId, @NonNull Context context, @NonNull Handler handler,
                 @NonNull BiometricScheduler scheduler) {
-            super(context, handler, scheduler);
+            super(sensorId, context, handler, scheduler);
         }
 
         void init(@NonNull RestartAuthRunnable restartAuthRunnable,
@@ -280,7 +280,7 @@
         final TestableBiometricScheduler scheduler =
                 new TestableBiometricScheduler(TAG, gestureAvailabilityDispatcher);
         final MockHalResultController controller =
-                new MockHalResultController(context, handler, scheduler);
+                new MockHalResultController(sensorId, context, handler, scheduler);
         return new Fingerprint21UdfpsMock(context, scheduler, handler, sensorId, strength,
                 lockoutResetDispatcher, controller);
     }
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
index 2a89a88..af61a8b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricFingerprintConstants;
 import android.hardware.biometrics.BiometricsProtoEnums;
 import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
@@ -100,6 +101,15 @@
     }
 
     @Override
+    public void onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining) {
+        super.onEnrollResult(identifier, remaining);
+
+        if (remaining == 0) {
+            UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
+        }
+    }
+
+    @Override
     public void onPointerDown(int x, int y, float minor, float major) {
         UdfpsHelper.onFingerDown(getFreshDaemon(), x, y, minor, major);
     }
diff --git a/services/core/java/com/android/server/camera/OWNERS b/services/core/java/com/android/server/camera/OWNERS
new file mode 100644
index 0000000..f48a95c
--- /dev/null
+++ b/services/core/java/com/android/server/camera/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/av:/camera/OWNERS
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index c789186..1f0fb5e 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -45,8 +45,8 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.Log;
 import android.util.Pair;
-import android.util.Slog;
 
 import java.net.InetAddress;
 import java.util.Arrays;
@@ -279,7 +279,7 @@
     }
 
     public PrivateDnsConfig updatePrivateDns(Network network, PrivateDnsConfig cfg) {
-        Slog.w(TAG, "updatePrivateDns(" + network + ", " + cfg + ")");
+        Log.w(TAG, "updatePrivateDns(" + network + ", " + cfg + ")");
         return (cfg != null)
                 ? mPrivateDnsMap.put(network.netId, cfg)
                 : mPrivateDnsMap.remove(network.netId);
@@ -389,7 +389,7 @@
             mPrivateDnsValidationMap.remove(netId);
         }
 
-        Slog.d(TAG, String.format("sendDnsConfigurationForNetwork(%d, %s, %s, %d, %d, %d, %d, "
+        Log.d(TAG, String.format("sendDnsConfigurationForNetwork(%d, %s, %s, %d, %d, %d, %d, "
                 + "%d, %d, %s, %s)", paramsParcel.netId, Arrays.toString(paramsParcel.servers),
                 Arrays.toString(paramsParcel.domains), paramsParcel.sampleValiditySeconds,
                 paramsParcel.successThreshold, paramsParcel.minSamples,
@@ -400,7 +400,7 @@
         try {
             mDnsResolver.setResolverConfiguration(paramsParcel);
         } catch (RemoteException | ServiceSpecificException e) {
-            Slog.e(TAG, "Error setting DNS configuration: " + e);
+            Log.e(TAG, "Error setting DNS configuration: " + e);
             return;
         }
     }
@@ -431,8 +431,8 @@
                 DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
                 DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
         if (mSampleValidity < 0 || mSampleValidity > 65535) {
-            Slog.w(TAG, "Invalid sampleValidity=" + mSampleValidity + ", using default=" +
-                    DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
+            Log.w(TAG, "Invalid sampleValidity=" + mSampleValidity + ", using default="
+                    + DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
             mSampleValidity = DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS;
         }
 
@@ -440,17 +440,17 @@
                 DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
                 DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
         if (mSuccessThreshold < 0 || mSuccessThreshold > 100) {
-            Slog.w(TAG, "Invalid successThreshold=" + mSuccessThreshold + ", using default=" +
-                    DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
+            Log.w(TAG, "Invalid successThreshold=" + mSuccessThreshold + ", using default="
+                    + DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
             mSuccessThreshold = DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT;
         }
 
         mMinSamples = getIntSetting(DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
         mMaxSamples = getIntSetting(DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
         if (mMinSamples < 0 || mMinSamples > mMaxSamples || mMaxSamples > 64) {
-            Slog.w(TAG, "Invalid sample count (min, max)=(" + mMinSamples + ", " + mMaxSamples +
-                    "), using default=(" + DNS_RESOLVER_DEFAULT_MIN_SAMPLES + ", " +
-                    DNS_RESOLVER_DEFAULT_MAX_SAMPLES + ")");
+            Log.w(TAG, "Invalid sample count (min, max)=(" + mMinSamples + ", " + mMaxSamples
+                    + "), using default=(" + DNS_RESOLVER_DEFAULT_MIN_SAMPLES + ", "
+                    + DNS_RESOLVER_DEFAULT_MAX_SAMPLES + ")");
             mMinSamples = DNS_RESOLVER_DEFAULT_MIN_SAMPLES;
             mMaxSamples = DNS_RESOLVER_DEFAULT_MAX_SAMPLES;
         }
diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
index 17828a0..21ef356 100644
--- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
+++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
@@ -60,8 +60,8 @@
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
 import android.util.DebugUtils;
+import android.util.Log;
 import android.util.Range;
-import android.util.Slog;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
@@ -230,7 +230,7 @@
             mUsageCallback = new UsageCallback() {
                 @Override
                 public void onThresholdReached(int networkType, String subscriberId) {
-                    if (DBG) Slog.d(TAG, "onThresholdReached for network " + network);
+                    if (DBG) Log.d(TAG, "onThresholdReached for network " + network);
                     mMultipathBudget = 0;
                     updateMultipathBudget();
                 }
@@ -252,7 +252,7 @@
             final long bytes = getNetworkTotalBytes(
                     start.toInstant().toEpochMilli(),
                     end.toInstant().toEpochMilli());
-            if (DBG) Slog.d(TAG, "Non-default data usage: " + bytes);
+            if (DBG) Log.d(TAG, "Non-default data usage: " + bytes);
             return bytes;
         }
 
@@ -261,7 +261,7 @@
                 return LocalServices.getService(NetworkStatsManagerInternal.class)
                         .getNetworkTotalBytes(mNetworkTemplate, start, end);
             } catch (RuntimeException e) {
-                Slog.w(TAG, "Failed to get data usage: " + e);
+                Log.w(TAG, "Failed to get data usage: " + e);
                 return -1;
             }
         }
@@ -326,17 +326,17 @@
         void updateMultipathBudget() {
             long quota = LocalServices.getService(NetworkPolicyManagerInternal.class)
                     .getSubscriptionOpportunisticQuota(this.network, QUOTA_TYPE_MULTIPATH);
-            if (DBG) Slog.d(TAG, "Opportunistic quota from data plan: " + quota + " bytes");
+            if (DBG) Log.d(TAG, "Opportunistic quota from data plan: " + quota + " bytes");
 
             // Fallback to user settings-based quota if not available from phone plan
             if (quota == OPPORTUNISTIC_QUOTA_UNKNOWN) {
                 quota = getUserPolicyOpportunisticQuotaBytes();
-                if (DBG) Slog.d(TAG, "Opportunistic quota from user policy: " + quota + " bytes");
+                if (DBG) Log.d(TAG, "Opportunistic quota from user policy: " + quota + " bytes");
             }
 
             if (quota == OPPORTUNISTIC_QUOTA_UNKNOWN) {
                 quota = getDefaultDailyMultipathQuotaBytes();
-                if (DBG) Slog.d(TAG, "Setting quota: " + quota + " bytes");
+                if (DBG) Log.d(TAG, "Setting quota: " + quota + " bytes");
             }
 
             // TODO: re-register if day changed: budget may have run out but should be refreshed.
@@ -344,7 +344,7 @@
                 // If there is already a usage callback pending , there's no need to re-register it
                 // if the quota hasn't changed. The callback will simply fire as expected when the
                 // budget is spent.
-                if (DBG) Slog.d(TAG, "Quota still " + quota + ", not updating.");
+                if (DBG) Log.d(TAG, "Quota still " + quota + ", not updating.");
                 return;
             }
             mQuota = quota;
@@ -364,8 +364,9 @@
             // since last time, so even if this is called very often the budget will not snap to 0
             // as soon as there are less than 2MB left for today.
             if (budget > NetworkStatsManager.MIN_THRESHOLD_BYTES) {
-                if (DBG) Slog.d(TAG, "Setting callback for " + budget +
-                        " bytes on network " + network);
+                if (DBG) {
+                    Log.d(TAG, "Setting callback for " + budget + " bytes on network " + network);
+                }
                 registerUsageCallback(budget);
             } else {
                 maybeUnregisterUsageCallback();
@@ -402,7 +403,7 @@
 
         private void maybeUnregisterUsageCallback() {
             if (haveMultipathBudget()) {
-                if (DBG) Slog.d(TAG, "Unregistering callback, budget was " + mMultipathBudget);
+                if (DBG) Log.d(TAG, "Unregistering callback, budget was " + mMultipathBudget);
                 mStatsManager.unregisterUsageCallback(mUsageCallback);
                 mMultipathBudget = 0;
             }
@@ -467,9 +468,9 @@
                 try {
                     mMultipathTrackers.put(network, new MultipathTracker(network, nc));
                 } catch (IllegalStateException e) {
-                    Slog.e(TAG, "Can't track mobile network " + network + ": " + e.getMessage());
+                    Log.e(TAG, "Can't track mobile network " + network + ": " + e.getMessage());
                 }
-                if (DBG) Slog.d(TAG, "Tracking mobile network " + network);
+                if (DBG) Log.d(TAG, "Tracking mobile network " + network);
             }
 
             @Override
@@ -479,7 +480,7 @@
                     existing.shutdown();
                     mMultipathTrackers.remove(network);
                 }
-                if (DBG) Slog.d(TAG, "No longer tracking mobile network " + network);
+                if (DBG) Log.d(TAG, "No longer tracking mobile network " + network);
             }
         };
 
@@ -524,16 +525,16 @@
 
         @Override
         public void onChange(boolean selfChange) {
-            Slog.wtf(TAG, "Should never be reached.");
+            Log.wtf(TAG, "Should never be reached.");
         }
 
         @Override
         public void onChange(boolean selfChange, Uri uri) {
             if (!Settings.Global.getUriFor(NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES)
                     .equals(uri)) {
-                Slog.wtf(TAG, "Unexpected settings observation: " + uri);
+                Log.wtf(TAG, "Unexpected settings observation: " + uri);
             }
-            if (DBG) Slog.d(TAG, "Settings change: updating budgets.");
+            if (DBG) Log.d(TAG, "Settings change: updating budgets.");
             updateAllMultipathBudgets();
         }
     }
@@ -541,7 +542,7 @@
     private final class ConfigChangeReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (DBG) Slog.d(TAG, "Configuration change: updating budgets.");
+            if (DBG) Log.d(TAG, "Configuration change: updating budgets.");
             updateAllMultipathBudgets();
         }
     }
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 163788f..d9c2e80 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -30,7 +30,7 @@
 import android.os.INetworkManagementService;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
-import android.util.Slog;
+import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
@@ -176,7 +176,7 @@
         try {
             mNMService.registerObserver(this);
         } catch (RemoteException e) {
-            Slog.e(TAG, "Can't register iface observer for clat on " + mNetwork.toShortString());
+            Log.e(TAG, "Can't register iface observer for clat on " + mNetwork.toShortString());
             return;
         }
 
@@ -185,7 +185,7 @@
         try {
             addrStr = mNetd.clatdStart(baseIface, mNat64PrefixInUse.toString());
         } catch (RemoteException | ServiceSpecificException e) {
-            Slog.e(TAG, "Error starting clatd on " + baseIface + ": " + e);
+            Log.e(TAG, "Error starting clatd on " + baseIface + ": " + e);
         }
         mIface = CLAT_PREFIX + baseIface;
         mBaseIface = baseIface;
@@ -193,7 +193,7 @@
         try {
             mIPv6Address = (Inet6Address) InetAddresses.parseNumericAddress(addrStr);
         } catch (ClassCastException | IllegalArgumentException | NullPointerException e) {
-            Slog.e(TAG, "Invalid IPv6 address " + addrStr);
+            Log.e(TAG, "Invalid IPv6 address " + addrStr);
         }
         if (mPrefixDiscoveryRunning && !isPrefixDiscoveryNeeded()) {
             stopPrefixDiscovery();
@@ -218,7 +218,7 @@
         try {
             mNMService.unregisterObserver(this);
         } catch (RemoteException | IllegalStateException e) {
-            Slog.e(TAG, "Error unregistering clatd observer on " + mBaseIface + ": " + e);
+            Log.e(TAG, "Error unregistering clatd observer on " + mBaseIface + ": " + e);
         }
         mNat64PrefixInUse = null;
         mIface = null;
@@ -242,37 +242,37 @@
     @VisibleForTesting
     protected void start() {
         if (isStarted()) {
-            Slog.e(TAG, "startClat: already started");
+            Log.e(TAG, "startClat: already started");
             return;
         }
 
         if (mNetwork.linkProperties == null) {
-            Slog.e(TAG, "startClat: Can't start clat with null LinkProperties");
+            Log.e(TAG, "startClat: Can't start clat with null LinkProperties");
             return;
         }
 
         String baseIface = mNetwork.linkProperties.getInterfaceName();
         if (baseIface == null) {
-            Slog.e(TAG, "startClat: Can't start clat on null interface");
+            Log.e(TAG, "startClat: Can't start clat on null interface");
             return;
         }
         // TODO: should we only do this if mNetd.clatdStart() succeeds?
-        Slog.i(TAG, "Starting clatd on " + baseIface);
+        Log.i(TAG, "Starting clatd on " + baseIface);
         enterStartingState(baseIface);
     }
 
     @VisibleForTesting
     protected void stop() {
         if (!isStarted()) {
-            Slog.e(TAG, "stopClat: already stopped");
+            Log.e(TAG, "stopClat: already stopped");
             return;
         }
 
-        Slog.i(TAG, "Stopping clatd on " + mBaseIface);
+        Log.i(TAG, "Stopping clatd on " + mBaseIface);
         try {
             mNetd.clatdStop(mBaseIface);
         } catch (RemoteException | ServiceSpecificException e) {
-            Slog.e(TAG, "Error stopping clatd on " + mBaseIface + ": " + e);
+            Log.e(TAG, "Error stopping clatd on " + mBaseIface + ": " + e);
         }
 
         String iface = mIface;
@@ -294,7 +294,7 @@
         try {
             mDnsResolver.startPrefix64Discovery(getNetId());
         } catch (RemoteException | ServiceSpecificException e) {
-            Slog.e(TAG, "Error starting prefix discovery on netId " + getNetId() + ": " + e);
+            Log.e(TAG, "Error starting prefix discovery on netId " + getNetId() + ": " + e);
         }
         mPrefixDiscoveryRunning = true;
     }
@@ -303,7 +303,7 @@
         try {
             mDnsResolver.stopPrefix64Discovery(getNetId());
         } catch (RemoteException | ServiceSpecificException e) {
-            Slog.e(TAG, "Error stopping prefix discovery on netId " + getNetId() + ": " + e);
+            Log.e(TAG, "Error stopping prefix discovery on netId " + getNetId() + ": " + e);
         }
         mPrefixDiscoveryRunning = false;
     }
@@ -320,7 +320,7 @@
         try {
             mDnsResolver.setPrefix64(getNetId(), prefixString);
         } catch (RemoteException | ServiceSpecificException e) {
-            Slog.e(TAG, "Error setting NAT64 prefix on netId " + getNetId() + " to "
+            Log.e(TAG, "Error setting NAT64 prefix on netId " + getNetId() + " to "
                     + prefix + ": " + e);
         }
     }
@@ -328,7 +328,7 @@
     private void maybeHandleNat64PrefixChange() {
         final IpPrefix newPrefix = selectNat64Prefix();
         if (!Objects.equals(mNat64PrefixInUse, newPrefix)) {
-            Slog.d(TAG, "NAT64 prefix changed from " + mNat64PrefixInUse + " to "
+            Log.d(TAG, "NAT64 prefix changed from " + mNat64PrefixInUse + " to "
                     + newPrefix);
             stop();
             // It's safe to call update here, even though this method is called from update, because
@@ -418,7 +418,7 @@
             return;
         }
 
-        Slog.d(TAG, "clatd running, updating NAI for " + mIface);
+        Log.d(TAG, "clatd running, updating NAI for " + mIface);
         for (LinkProperties stacked: oldLp.getStackedLinks()) {
             if (Objects.equals(mIface, stacked.getInterfaceName())) {
                 lp.addStackedLink(stacked);
@@ -451,7 +451,7 @@
             return new LinkAddress(
                     InetAddresses.parseNumericAddress(config.ipv4Addr), config.prefixLength);
         } catch (IllegalArgumentException | RemoteException | ServiceSpecificException e) {
-            Slog.e(TAG, "Error getting link properties: " + e);
+            Log.e(TAG, "Error getting link properties: " + e);
             return null;
         }
     }
@@ -480,11 +480,11 @@
 
         LinkAddress clatAddress = getLinkAddress(iface);
         if (clatAddress == null) {
-            Slog.e(TAG, "clatAddress was null for stacked iface " + iface);
+            Log.e(TAG, "clatAddress was null for stacked iface " + iface);
             return;
         }
 
-        Slog.i(TAG, String.format("interface %s is up, adding stacked link %s on top of %s",
+        Log.i(TAG, String.format("interface %s is up, adding stacked link %s on top of %s",
                 mIface, mIface, mBaseIface));
         enterRunningState();
         LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
@@ -503,7 +503,7 @@
             return;
         }
 
-        Slog.i(TAG, "interface " + iface + " removed");
+        Log.i(TAG, "interface " + iface + " removed");
         // If we're running, and the interface was removed, then we didn't call stop(), and it's
         // likely that clatd crashed. Ensure we call stop() so we can start clatd again. Calling
         // stop() will also update LinkProperties, and if clatd crashed, the LinkProperties update
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 7f4fb40..7795ed3 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -35,7 +35,7 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
-import android.util.Slog;
+import android.util.Log;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.widget.Toast;
@@ -175,7 +175,7 @@
         final int previousEventId = mNotificationTypeMap.get(id);
         final NotificationType previousNotifyType = NotificationType.getFromId(previousEventId);
         if (priority(previousNotifyType) > priority(notifyType)) {
-            Slog.d(TAG, String.format(
+            Log.d(TAG, String.format(
                     "ignoring notification %s for network %s with existing notification %s",
                     notifyType, id, previousNotifyType));
             return;
@@ -183,7 +183,7 @@
         clearNotification(id);
 
         if (DBG) {
-            Slog.d(TAG, String.format(
+            Log.d(TAG, String.format(
                     "showNotification tag=%s event=%s transport=%s name=%s highPriority=%s",
                     tag, nameOf(eventId), getTransportName(transportType), name, highPriority));
         }
@@ -253,7 +253,7 @@
             // are sent, but they are not implemented yet.
             return;
         } else {
-            Slog.wtf(TAG, "Unknown notification type " + notifyType + " on network transport "
+            Log.wtf(TAG, "Unknown notification type " + notifyType + " on network transport "
                     + getTransportName(transportType));
             return;
         }
@@ -294,7 +294,7 @@
         try {
             mNotificationManager.notify(tag, eventId, notification);
         } catch (NullPointerException npe) {
-            Slog.d(TAG, "setNotificationVisible: visible notificationManager error", npe);
+            Log.d(TAG, "setNotificationVisible: visible notificationManager error", npe);
         }
     }
 
@@ -317,13 +317,13 @@
         final String tag = tagFor(id);
         final int eventId = mNotificationTypeMap.get(id);
         if (DBG) {
-            Slog.d(TAG, String.format("clearing notification tag=%s event=%s", tag,
+            Log.d(TAG, String.format("clearing notification tag=%s event=%s", tag,
                    nameOf(eventId)));
         }
         try {
             mNotificationManager.cancel(tag, eventId);
         } catch (NullPointerException npe) {
-            Slog.d(TAG, String.format(
+            Log.d(TAG, String.format(
                     "failed to clear notification tag=%s event=%s", tag, nameOf(eventId)), npe);
         }
         mNotificationTypeMap.delete(id);
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index 26cc3ee..5cb3d94 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -35,7 +35,7 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
-import android.util.Slog;
+import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
 
@@ -168,7 +168,7 @@
                 proxyProperties = new ProxyInfo(host, port, exclList);
             }
             if (!proxyProperties.isValid()) {
-                if (DBG) Slog.d(TAG, "Invalid proxy properties, ignoring: " + proxyProperties);
+                if (DBG) Log.d(TAG, "Invalid proxy properties, ignoring: " + proxyProperties);
                 return;
             }
 
@@ -223,7 +223,7 @@
         if (mPacManager.setCurrentProxyScriptUrl(proxyInfo) == PacManager.DONT_SEND_BROADCAST) {
             return;
         }
-        if (DBG) Slog.d(TAG, "sending Proxy Broadcast for " + proxyInfo);
+        if (DBG) Log.d(TAG, "sending Proxy Broadcast for " + proxyInfo);
         Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
                 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
@@ -255,7 +255,7 @@
             if (proxyInfo != null && (!TextUtils.isEmpty(proxyInfo.getHost()) ||
                     !Uri.EMPTY.equals(proxyInfo.getPacFileUrl()))) {
                 if (!proxyInfo.isValid()) {
-                    if (DBG) Slog.d(TAG, "Invalid proxy properties, ignoring: " + proxyInfo);
+                    if (DBG) Log.d(TAG, "Invalid proxy properties, ignoring: " + proxyInfo);
                     return;
                 }
                 mGlobalProxy = new ProxyInfo(proxyInfo);
@@ -296,7 +296,7 @@
         synchronized (mProxyLock) {
             if (Objects.equals(mDefaultProxy, proxyInfo)) return;
             if (proxyInfo != null &&  !proxyInfo.isValid()) {
-                if (DBG) Slog.d(TAG, "Invalid proxy properties, ignoring: " + proxyInfo);
+                if (DBG) Log.d(TAG, "Invalid proxy properties, ignoring: " + proxyInfo);
                 return;
             }
 
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index a2c427b8..027b9af 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -76,8 +76,7 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
-import com.android.server.SystemService.TargetUser;
-import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.permission.LegacyPermissionManagerInternal;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -296,8 +295,8 @@
 
         // Let the package manager query for the sync adapters for a given authority
         // as we grant default permissions to sync adapters for specific authorities.
-        final PermissionManagerServiceInternal permissionManagerInternal =
-                LocalServices.getService(PermissionManagerServiceInternal.class);
+        final LegacyPermissionManagerInternal permissionManagerInternal =
+                LocalServices.getService(LegacyPermissionManagerInternal.class);
         permissionManagerInternal.setSyncAdapterPackagesProvider((authority, userId) -> {
             return getSyncAdapterPackagesForAuthorityAsUser(authority, userId);
         });
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 0b2d4d7..6ae410a 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -3838,9 +3838,12 @@
             }
 
             UserHandle user = new UserHandle(userId);
+            // TODO(b/174186839) Please replace FLAG_MUTABLE_UNAUDITED below
+            // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
             final PendingIntent pendingIntent = PendingIntent
                     .getActivityAsUser(mContext, 0, clickIntent,
-                            PendingIntent.FLAG_CANCEL_CURRENT, null, user);
+                            PendingIntent.FLAG_CANCEL_CURRENT
+                            | PendingIntent.FLAG_MUTABLE_UNAUDITED, null, user);
 
             CharSequence tooManyDeletesDescFormat = mContext.getResources().getText(
                     R.string.contentServiceTooManyDeletesNotificationDesc);
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index d27cb16..668142b 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -1804,10 +1804,8 @@
         int id = -1;
         try {
             id = parser.getAttributeInt(null, "id");
-        } catch (NumberFormatException e) {
+        } catch (XmlPullParserException e) {
             Slog.e(TAG, "error parsing the id of the authority", e);
-        } catch (NullPointerException e) {
-            Slog.e(TAG, "the id of the authority is null", e);
         }
         if (id >= 0) {
             String authorityName = parser.getAttributeValue(null, "authority");
@@ -1920,28 +1918,26 @@
     private void parseExtra(TypedXmlPullParser parser, Bundle extras) {
         String name = parser.getAttributeValue(null, "name");
         String type = parser.getAttributeValue(null, "type");
-        String value1 = parser.getAttributeValue(null, "value1");
-        String value2 = parser.getAttributeValue(null, "value2");
 
         try {
             if ("long".equals(type)) {
-                extras.putLong(name, Long.parseLong(value1));
+                extras.putLong(name, parser.getAttributeLong(null, "value1"));
             } else if ("integer".equals(type)) {
-                extras.putInt(name, Integer.parseInt(value1));
+                extras.putInt(name, parser.getAttributeInt(null, "value1"));
             } else if ("double".equals(type)) {
-                extras.putDouble(name, Double.parseDouble(value1));
+                extras.putDouble(name, parser.getAttributeDouble(null, "value1"));
             } else if ("float".equals(type)) {
-                extras.putFloat(name, Float.parseFloat(value1));
+                extras.putFloat(name, parser.getAttributeFloat(null, "value1"));
             } else if ("boolean".equals(type)) {
-                extras.putBoolean(name, Boolean.parseBoolean(value1));
+                extras.putBoolean(name, parser.getAttributeBoolean(null, "value1"));
             } else if ("string".equals(type)) {
-                extras.putString(name, value1);
+                extras.putString(name, parser.getAttributeValue(null, "value1"));
             } else if ("account".equals(type)) {
+                final String value1 = parser.getAttributeValue(null, "value1");
+                final String value2 = parser.getAttributeValue(null, "value2");
                 extras.putParcelable(name, new Account(value1, value2));
             }
-        } catch (NumberFormatException e) {
-            Slog.e(TAG, "error parsing bundle value", e);
-        } catch (NullPointerException e) {
+        } catch (XmlPullParserException e) {
             Slog.e(TAG, "error parsing bundle value", e);
         }
     }
diff --git a/services/core/java/com/android/server/contentcapture/OWNERS b/services/core/java/com/android/server/contentcapture/OWNERS
new file mode 100644
index 0000000..a28e00a
--- /dev/null
+++ b/services/core/java/com/android/server/contentcapture/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/contentcapture/OWNERS
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index 2a0e219..7a8ba9f 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -668,12 +668,11 @@
                     builder.setUserBrightnessPoint(
                             parser.getAttributeBoolean(null, ATTR_USER_POINT, false));
 
-                    String colorSampleDurationString =
-                            parser.getAttributeValue(null, ATTR_COLOR_SAMPLE_DURATION);
+                    long colorSampleDuration =
+                            parser.getAttributeLong(null, ATTR_COLOR_SAMPLE_DURATION, -1);
                     String colorValueBucketsString =
                             parser.getAttributeValue(null, ATTR_COLOR_VALUE_BUCKETS);
-                    if (colorSampleDurationString != null && colorValueBucketsString != null) {
-                        long colorSampleDuration = Long.parseLong(colorSampleDurationString);
+                    if (colorSampleDuration != -1 && colorValueBucketsString != null) {
                         String[] buckets = colorValueBucketsString.split(",");
                         long[] bucketValues = new long[buckets.length];
                         for (int i = 0; i < bucketValues.length; ++i) {
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 23e5a43..a8e56a1 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -73,15 +73,31 @@
     public static DisplayDeviceConfig create(long physicalDisplayId) {
         DisplayDeviceConfig config;
 
+        config = loadConfigFromDirectory(Environment.getProductDirectory(), physicalDisplayId);
+        if (config != null) {
+            return config;
+        }
+
+        config = loadConfigFromDirectory(Environment.getVendorDirectory(), physicalDisplayId);
+        if (config != null) {
+            return config;
+        }
+
+        return null;
+    }
+
+    private static DisplayDeviceConfig loadConfigFromDirectory(
+            File baseDirectory, long physicalDisplayId) {
+        DisplayDeviceConfig config;
         // Create config using filename from physical ID (including "stable" bit).
-        config = getConfigFromSuffix(STABLE_ID_SUFFIX_FORMAT, physicalDisplayId);
+        config = getConfigFromSuffix(baseDirectory, STABLE_ID_SUFFIX_FORMAT, physicalDisplayId);
         if (config != null) {
             return config;
         }
 
         // Create config using filename from physical ID (excluding "stable" bit).
         final long withoutStableFlag = physicalDisplayId & ~STABLE_FLAG;
-        config = getConfigFromSuffix(NO_SUFFIX_FORMAT, withoutStableFlag);
+        config = getConfigFromSuffix(baseDirectory, NO_SUFFIX_FORMAT, withoutStableFlag);
         if (config != null) {
             return config;
         }
@@ -90,7 +106,7 @@
         final DisplayAddress.Physical physicalAddress =
                 DisplayAddress.fromPhysicalDisplayId(physicalDisplayId);
         int port = physicalAddress.getPort();
-        config = getConfigFromSuffix(PORT_SUFFIX_FORMAT, port);
+        config = getConfigFromSuffix(baseDirectory, PORT_SUFFIX_FORMAT, port);
         if (config != null) {
             return config;
         }
@@ -127,12 +143,13 @@
         return str;
     }
 
-    private static DisplayDeviceConfig getConfigFromSuffix(String suffixFormat, long idNumber) {
+    private static DisplayDeviceConfig getConfigFromSuffix(File baseDirectory,
+            String suffixFormat, long idNumber) {
 
         final String suffix = String.format(suffixFormat, idNumber);
         final String filename = String.format(CONFIG_FILE_FORMAT, suffix);
         final File filePath = Environment.buildPath(
-                Environment.getProductDirectory(), ETC_DIR, DISPLAY_CONFIG_DIR, filename);
+                baseDirectory, ETC_DIR, DISPLAY_CONFIG_DIR, filename);
 
         if (filePath.exists()) {
             final DisplayDeviceConfig config = new DisplayDeviceConfig();
diff --git a/services/core/java/com/android/server/display/PersistentDataStore.java b/services/core/java/com/android/server/display/PersistentDataStore.java
index b0820e8..a62642b 100644
--- a/services/core/java/com/android/server/display/PersistentDataStore.java
+++ b/services/core/java/com/android/server/display/PersistentDataStore.java
@@ -31,17 +31,12 @@
 import android.view.Display;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
 
 import libcore.io.IoUtils;
 
-import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
@@ -49,7 +44,6 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
@@ -628,15 +622,7 @@
                     }
 
                     String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
-                    String timeStampString = parser.getAttributeValue(null, ATTR_TIME_STAMP);
-                    long timeStamp = -1;
-                    if (timeStampString != null) {
-                        try {
-                            timeStamp = Long.parseLong(timeStampString);
-                        } catch (NumberFormatException nfe) {
-                            // Ignore we will just not restore the timestamp.
-                        }
-                    }
+                    long timeStamp = parser.getAttributeLong(null, ATTR_TIME_STAMP, -1);
 
                     try {
                         BrightnessConfiguration config =
diff --git a/services/core/java/com/android/server/dreams/OWNERS b/services/core/java/com/android/server/dreams/OWNERS
index 426f002..3c9bbf8 100644
--- a/services/core/java/com/android/server/dreams/OWNERS
+++ b/services/core/java/com/android/server/dreams/OWNERS
@@ -1,3 +1,3 @@
-dsandler@android.com
+dsandler@google.com
 michaelwr@google.com
 roosa@google.com
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java b/services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java
index 2878a94..a9eb75d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java
@@ -18,9 +18,14 @@
 
 import android.stats.hdmi.HdmiStatsEnums;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.FrameworkStatsLog;
 
-class HdmiCecAtomWriter {
+/**
+ * Provides methods for writing HDMI-CEC statsd atoms.
+ */
+@VisibleForTesting
+public class HdmiCecAtomWriter {
 
     private static final int FEATURE_ABORT_OPCODE_UNKNOWN = 0x100;
     private static final int ERROR_CODE_UNKNOWN = -1;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
index a261fa1..98d130f 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
@@ -253,7 +253,7 @@
                 return STORAGE_GLOBAL_SETTINGS;
             case HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION:
                 return STORAGE_GLOBAL_SETTINGS;
-            case HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP:
+            case HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE:
                 return STORAGE_GLOBAL_SETTINGS;
             case HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST:
                 return STORAGE_SHARED_PREFS;
@@ -271,7 +271,7 @@
                 return Global.HDMI_CONTROL_ENABLED;
             case HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION:
                 return Global.HDMI_CEC_VERSION;
-            case HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP:
+            case HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE:
                 return Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP;
             case HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST:
                 return setting.getName();
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index 19dc017..bbd5ac3 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -635,7 +635,7 @@
      */
     private int incomingMessageDirection(int srcAddress, int dstAddress) {
         boolean sourceIsLocal = false;
-        boolean destinationIsLocal = false;
+        boolean destinationIsLocal = dstAddress == Constants.ADDR_BROADCAST;
         for (HdmiCecLocalDevice localDevice : mService.getHdmiCecNetwork().getLocalDeviceList()) {
             int logicalAddress = localDevice.getDeviceInfo().getLogicalAddress();
             if (logicalAddress == srcAddress) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 9ca1f91..e6cf18b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -160,20 +160,20 @@
         switch (standbyAction) {
             case HdmiControlService.STANDBY_SCREEN_OFF:
                 // Get latest setting value
-                @HdmiControlManager.StandbyBehavior
+                @HdmiControlManager.PowerControlMode
                 String sendStandbyOnSleep = mService.getHdmiCecConfig().getStringValue(
-                        HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP);
+                        HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE);
                 switch (sendStandbyOnSleep) {
-                    case HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV:
+                    case HdmiControlManager.POWER_CONTROL_MODE_TV:
                         mService.sendCecCommand(
                                 HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_TV));
                         break;
-                    case HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST:
+                    case HdmiControlManager.POWER_CONTROL_MODE_BROADCAST:
                         mService.sendCecCommand(
                                 HdmiCecMessageBuilder.buildStandby(mAddress,
                                         Constants.ADDR_BROADCAST));
                         break;
-                    case HdmiControlManager.SEND_STANDBY_ON_SLEEP_NONE:
+                    case HdmiControlManager.POWER_CONTROL_MODE_NONE:
                         break;
                 }
                 break;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
index 59ebdd5..8a1a728 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
@@ -107,8 +107,8 @@
     protected void sendStandby(int deviceId) {
         assertRunOnServiceThread();
         String sendStandbyOnSleep = mService.getHdmiCecConfig().getStringValue(
-                HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP);
-        if (sendStandbyOnSleep.equals(HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST)) {
+                HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE);
+        if (sendStandbyOnSleep.equals(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST)) {
             mService.sendCecCommand(
                     HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_BROADCAST));
             return;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
index 5d75a63..fc21724 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecNetwork.java
@@ -59,7 +59,8 @@
  * Note that the information cached in this class is not guaranteed to be up-to-date, especially OSD
  * names, power states can be outdated.
  */
-class HdmiCecNetwork {
+@VisibleForTesting
+public class HdmiCecNetwork {
     private static final String TAG = "HdmiCecNetwork";
 
     protected final Object mLock;
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 56b73ba..a1d13e9 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -564,7 +564,8 @@
         mTvInputManager.unregisterCallback(callback);
     }
 
-    PowerManager getPowerManager() {
+    @VisibleForTesting
+    protected PowerManager getPowerManager() {
         return mPowerManager;
     }
 
@@ -729,7 +730,8 @@
         Global.putInt(cr, key, toInt(value));
     }
 
-    void writeStringSystemProperty(String key, String value) {
+    @VisibleForTesting
+    protected void writeStringSystemProperty(String key, String value) {
         SystemProperties.set(key, value);
     }
 
@@ -3366,7 +3368,7 @@
     }
 
     @VisibleForTesting
-    HdmiCecAtomWriter getAtomWriter() {
+    protected HdmiCecAtomWriter getAtomWriter() {
         return mAtomWriter;
     }
 
@@ -3395,7 +3397,8 @@
                 HdmiControlService.PERMISSION);
     }
 
-    HdmiCecConfig getHdmiCecConfig() {
+    @VisibleForTesting
+    protected HdmiCecConfig getHdmiCecConfig() {
         return mHdmiCecConfig;
     }
 }
diff --git a/services/core/java/com/android/server/hdmi/OWNERS b/services/core/java/com/android/server/hdmi/OWNERS
new file mode 100644
index 0000000..c3c47ed
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/hardware/hdmi/OWNERS
diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
index f9f97fe..ea6e615 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
@@ -165,9 +165,9 @@
         if (service.isAudioSystemDevice()) {
             return false;
         }
-        @HdmiControlManager.StandbyBehavior String sendStandbyOnSleep =
+        @HdmiControlManager.PowerControlMode String sendStandbyOnSleep =
                 service.getHdmiCecConfig().getStringValue(
-                        HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP);
-        return sendStandbyOnSleep.equals(HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST);
+                        HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE);
+        return sendStandbyOnSleep.equals(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
     }
 }
diff --git a/services/core/java/com/android/server/incident/OWNERS b/services/core/java/com/android/server/incident/OWNERS
new file mode 100644
index 0000000..f766115
--- /dev/null
+++ b/services/core/java/com/android/server/incident/OWNERS
@@ -0,0 +1 @@
+include /cmds/incidentd/OWNERS
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 42aad7d..a0121bb 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -51,6 +51,7 @@
 import android.media.AudioManager;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.CombinedVibrationEffect;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.IBinder;
@@ -264,7 +265,11 @@
     private static native void nativeReloadCalibration(long ptr);
     private static native void nativeVibrate(long ptr, int deviceId, long[] pattern,
             int[] amplitudes, int repeat, int token);
+    private static native void nativeVibrateCombined(long ptr, int deviceId, long[] pattern,
+            SparseArray<int[]> amplitudes, int repeat, int token);
     private static native void nativeCancelVibrate(long ptr, int deviceId, int token);
+    private static native boolean nativeIsVibrating(long ptr, int deviceId);
+    private static native int[] nativeGetVibratorIds(long ptr, int deviceId);
     private static native void nativeReloadKeyboardLayouts(long ptr);
     private static native void nativeReloadDeviceAliases(long ptr);
     private static native String nativeDump(long ptr);
@@ -1801,43 +1806,57 @@
         return result;
     }
 
-    // Binder call
-    @Override
-    public void vibrate(int deviceId, VibrationEffect effect, IBinder token) {
-        long[] pattern;
-        int[] amplitudes;
-        int repeat;
-        if (effect instanceof VibrationEffect.OneShot) {
-            VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) effect;
-            pattern = new long[] { 0, oneShot.getDuration() };
-            int amplitude = oneShot.getAmplitude();
-            // android framework uses DEFAULT_AMPLITUDE to signal that the vibration
-            // should use some built-in default value, denoted here as DEFAULT_VIBRATION_MAGNITUDE
-            if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) {
-                amplitude = DEFAULT_VIBRATION_MAGNITUDE;
-            }
-            amplitudes = new int[] { 0, amplitude };
-            repeat = -1;
-        } else if (effect instanceof VibrationEffect.Waveform) {
-            VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) effect;
-            pattern = waveform.getTimings();
-            amplitudes = waveform.getAmplitudes();
-            for (int i = 0; i < amplitudes.length; i++) {
-                if (amplitudes[i] == VibrationEffect.DEFAULT_AMPLITUDE) {
-                    amplitudes[i] = DEFAULT_VIBRATION_MAGNITUDE;
+    private static class VibrationInfo {
+        private long[] mPattern = new long[0];
+        private int[] mAmplitudes = new int[0];
+        private int mRepeat = -1;
+
+        public long[] getPattern() {
+            return mPattern;
+        }
+
+        public int[] getAmplitudes() {
+            return mAmplitudes;
+        }
+
+        public int getRepeatIndex() {
+            return mRepeat;
+        }
+
+        VibrationInfo(VibrationEffect effect) {
+            if (effect instanceof VibrationEffect.OneShot) {
+                VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) effect;
+                mPattern = new long[] { 0, oneShot.getDuration() };
+                int amplitude = oneShot.getAmplitude();
+                // android framework uses DEFAULT_AMPLITUDE to signal that the vibration
+                // should use some built-in default value, denoted here as
+                // DEFAULT_VIBRATION_MAGNITUDE
+                if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) {
+                    amplitude = DEFAULT_VIBRATION_MAGNITUDE;
                 }
+                mAmplitudes = new int[] { 0, amplitude };
+                mRepeat = -1;
+            } else if (effect instanceof VibrationEffect.Waveform) {
+                VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) effect;
+                mPattern = waveform.getTimings();
+                mAmplitudes = waveform.getAmplitudes();
+                for (int i = 0; i < mAmplitudes.length; i++) {
+                    if (mAmplitudes[i] == VibrationEffect.DEFAULT_AMPLITUDE) {
+                        mAmplitudes[i] = DEFAULT_VIBRATION_MAGNITUDE;
+                    }
+                }
+                mRepeat = waveform.getRepeatIndex();
+                if (mRepeat >= mPattern.length) {
+                    throw new ArrayIndexOutOfBoundsException();
+                }
+            } else {
+                // TODO: Add support for prebaked effects
+                Slog.w(TAG, "Pre-baked effects aren't supported on input devices");
             }
-            repeat = waveform.getRepeatIndex();
-        } else {
-            // TODO: Add support for prebaked effects
-            Log.w(TAG, "Pre-baked effects aren't supported on input devices");
-            return;
         }
+    }
 
-        if (repeat >= pattern.length) {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-
+    private VibratorToken getVibratorToken(int deviceId, IBinder token) {
         VibratorToken v;
         synchronized (mVibratorLock) {
             v = mVibratorTokens.get(token);
@@ -1852,9 +1871,70 @@
                 mVibratorTokens.put(token, v);
             }
         }
+        return v;
+    }
+
+    // Binder call
+    @Override
+    public void vibrate(int deviceId, VibrationEffect effect, IBinder token) {
+        VibrationInfo info = new VibrationInfo(effect);
+        VibratorToken v = getVibratorToken(deviceId, token);
         synchronized (v) {
             v.mVibrating = true;
-            nativeVibrate(mPtr, deviceId, pattern, amplitudes, repeat, v.mTokenValue);
+            nativeVibrate(mPtr, deviceId, info.getPattern(), info.getAmplitudes(),
+                    info.getRepeatIndex(), v.mTokenValue);
+        }
+    }
+
+    // Binder call
+    @Override
+    public int[] getVibratorIds(int deviceId) {
+        return nativeGetVibratorIds(mPtr, deviceId);
+    }
+
+    // Binder call
+    @Override
+    public boolean isVibrating(int deviceId) {
+        return nativeIsVibrating(mPtr, deviceId);
+    }
+
+    // Binder call
+    @Override
+    public void vibrateCombined(int deviceId, CombinedVibrationEffect effect, IBinder token) {
+        VibratorToken v = getVibratorToken(deviceId, token);
+        synchronized (v) {
+            if (!(effect instanceof CombinedVibrationEffect.Mono)
+                    && !(effect instanceof CombinedVibrationEffect.Stereo)) {
+                Slog.e(TAG, "Only Mono and Stereo effects are supported");
+                return;
+            }
+
+            v.mVibrating = true;
+            if (effect instanceof CombinedVibrationEffect.Mono) {
+                CombinedVibrationEffect.Mono mono = (CombinedVibrationEffect.Mono) effect;
+                VibrationInfo info = new VibrationInfo(mono.getEffect());
+                nativeVibrate(mPtr, deviceId, info.getPattern(), info.getAmplitudes(),
+                        info.getRepeatIndex(), v.mTokenValue);
+            } else if (effect instanceof CombinedVibrationEffect.Stereo) {
+                CombinedVibrationEffect.Stereo stereo = (CombinedVibrationEffect.Stereo) effect;
+                SparseArray<VibrationEffect> effects = stereo.getEffects();
+                long[] pattern = new long[0];
+                int repeat = Integer.MIN_VALUE;
+                SparseArray<int[]> amplitudes = new SparseArray<int[]>(effects.size());
+                for (int i = 0; i < effects.size(); i++) {
+                    VibrationInfo info = new VibrationInfo(effects.valueAt(i));
+                    // Pattern of all effects should be same
+                    if (pattern.length == 0) {
+                        pattern = info.getPattern();
+                    }
+                    if (repeat == Integer.MIN_VALUE) {
+                        repeat = info.getRepeatIndex();
+                    }
+                    amplitudes.put(effects.keyAt(i), info.getAmplitudes());
+                }
+                nativeVibrateCombined(mPtr, deviceId, pattern, amplitudes, repeat,
+                        v.mTokenValue);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/input/PersistentDataStore.java b/services/core/java/com/android/server/input/PersistentDataStore.java
index a735a8f..6cec272 100644
--- a/services/core/java/com/android/server/input/PersistentDataStore.java
+++ b/services/core/java/com/android/server/input/PersistentDataStore.java
@@ -510,7 +510,7 @@
                 serializer.startTag(null, "keyboard-layout");
                 serializer.attribute(null, "descriptor", layout);
                 if (layout.equals(mCurrentKeyboardLayout)) {
-                    serializer.attribute(null, "current", "true");
+                    serializer.attributeBoolean(null, "current", true);
                 }
                 serializer.endTag(null, "keyboard-layout");
             }
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index e5c1986..3854f8c 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -57,6 +57,7 @@
 import android.location.ILocationCallback;
 import android.location.ILocationListener;
 import android.location.ILocationManager;
+import android.location.LastLocationRequest;
 import android.location.Location;
 import android.location.LocationManager;
 import android.location.LocationManagerInternal;
@@ -113,7 +114,7 @@
 import com.android.server.location.provider.PassiveLocationProvider;
 import com.android.server.location.provider.PassiveLocationProviderManager;
 import com.android.server.location.provider.proxy.ProxyLocationProvider;
-import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.permission.LegacyPermissionManagerInternal;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -261,8 +262,8 @@
 
         // Let the package manager query which are the default location
         // providers as they get certain permissions granted by default.
-        PermissionManagerServiceInternal permissionManagerInternal = LocalServices.getService(
-                PermissionManagerServiceInternal.class);
+        LegacyPermissionManagerInternal permissionManagerInternal = LocalServices.getService(
+                LegacyPermissionManagerInternal.class);
         permissionManagerInternal.setLocationPackagesProvider(
                 userId -> mContext.getResources().getStringArray(
                         com.android.internal.R.array.config_locationProviderPackageNames));
@@ -588,6 +589,30 @@
                 new String[0]);
     }
 
+    @Nullable
+    @Override
+    public ICancellationSignal getCurrentLocation(String provider, LocationRequest request,
+            ILocationCallback consumer, String packageName, String attributionTag,
+            String listenerId) {
+        CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
+                listenerId);
+        int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
+                identity.getPid());
+        LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel,
+                PERMISSION_COARSE);
+
+        // clients in the system process must have an attribution tag set
+        Preconditions.checkState(identity.getPid() != Process.myPid() || attributionTag != null);
+
+        request = validateLocationRequest(request, identity);
+
+        LocationProviderManager manager = getLocationProviderManager(provider);
+        Preconditions.checkArgument(manager != null,
+                "provider \"" + provider + "\" does not exist");
+
+        return manager.getCurrentLocation(request, identity, permissionLevel, consumer);
+    }
+
     @Override
     public void registerLocationListener(String provider, LocationRequest request,
             ILocationListener listener, String packageName, @Nullable String attributionTag,
@@ -741,7 +766,8 @@
     }
 
     @Override
-    public Location getLastLocation(String provider, String packageName, String attributionTag) {
+    public Location getLastLocation(String provider, LastLocationRequest request,
+            String packageName, String attributionTag) {
         CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag);
         int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
                 identity.getPid());
@@ -751,36 +777,29 @@
         // clients in the system process must have an attribution tag set
         Preconditions.checkArgument(identity.getPid() != Process.myPid() || attributionTag != null);
 
+        request = validateLastLocationRequest(request);
+
         LocationProviderManager manager = getLocationProviderManager(provider);
         if (manager == null) {
             return null;
         }
 
-        return manager.getLastLocation(identity, permissionLevel, false);
+        return manager.getLastLocation(request, identity, permissionLevel);
     }
 
-    @Nullable
-    @Override
-    public ICancellationSignal getCurrentLocation(String provider, LocationRequest request,
-            ILocationCallback consumer, String packageName, String attributionTag,
-            String listenerId) {
-        CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
-                listenerId);
-        int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
-                identity.getPid());
-        LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel,
-                PERMISSION_COARSE);
+    private LastLocationRequest validateLastLocationRequest(LastLocationRequest request) {
+        if (request.isHiddenFromAppOps()) {
+            mContext.enforceCallingOrSelfPermission(
+                    permission.UPDATE_APP_OPS_STATS,
+                    "hiding from app ops requires " + permission.UPDATE_APP_OPS_STATS);
+        }
+        if (request.isLocationSettingsIgnored()) {
+            mContext.enforceCallingOrSelfPermission(
+                    permission.WRITE_SECURE_SETTINGS,
+                    "ignoring location settings requires " + permission.WRITE_SECURE_SETTINGS);
+        }
 
-        // clients in the system process must have an attribution tag set
-        Preconditions.checkState(identity.getPid() != Process.myPid() || attributionTag != null);
-
-        request = validateLocationRequest(request, identity);
-
-        LocationProviderManager manager = getLocationProviderManager(provider);
-        Preconditions.checkArgument(manager != null,
-                "provider \"" + provider + "\" does not exist");
-
-        return manager.getCurrentLocation(request, identity, permissionLevel, consumer);
+        return request;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index c5d7f2c..2fe8bcc 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -49,6 +49,7 @@
 import android.location.Criteria;
 import android.location.ILocationCallback;
 import android.location.ILocationListener;
+import android.location.LastLocationRequest;
 import android.location.Location;
 import android.location.LocationManager;
 import android.location.LocationManagerInternal;
@@ -1467,9 +1468,9 @@
         }
     }
 
-    public @Nullable Location getLastLocation(CallerIdentity identity,
-            @PermissionLevel int permissionLevel, boolean ignoreLocationSettings) {
-        if (!isActive(ignoreLocationSettings, identity)) {
+    public @Nullable Location getLastLocation(LastLocationRequest request,
+            CallerIdentity identity, @PermissionLevel int permissionLevel) {
+        if (!isActive(request.isLocationSettingsIgnored(), identity)) {
             return null;
         }
 
@@ -1483,7 +1484,7 @@
                 getLastLocationUnsafe(
                         identity.getUserId(),
                         permissionLevel,
-                        ignoreLocationSettings,
+                        request.isLocationSettingsIgnored(),
                         Long.MAX_VALUE),
                 permissionLevel);
 
diff --git a/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java b/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java
index b4bcd7b..fd8cf70 100644
--- a/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java
@@ -55,7 +55,7 @@
 
     @Override
     void onInitialize() {
-        mProxy.setListener(new LocationTimeZoneProviderProxy.Listener() {
+        mProxy.initialize(new LocationTimeZoneProviderProxy.Listener() {
             @Override
             public void onReportLocationTimeZoneEvent(
                     @NonNull LocationTimeZoneEvent locationTimeZoneEvent) {
diff --git a/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java b/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java
index b7c7476..c8a1db6 100644
--- a/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java
+++ b/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.content.res.Resources;
 import android.os.Binder;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
@@ -27,6 +28,7 @@
 import android.util.Log;
 import android.util.Slog;
 
+import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.DumpUtils;
 import com.android.server.FgThread;
@@ -179,36 +181,45 @@
     }
 
     private LocationTimeZoneProvider createPrimaryProvider() {
+        Resources resources = mContext.getResources();
+        if (!resources.getBoolean(R.bool.config_enablePrimaryLocationTimeZoneProvider)) {
+            return new NullLocationTimeZoneProvider(mThreadingDomain, PRIMARY_PROVIDER_NAME);
+        }
+
         LocationTimeZoneProviderProxy proxy;
         if (isInSimulationMode(PRIMARY_PROVIDER_NAME)) {
             proxy = new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
         } else {
-            proxy = RealLocationTimeZoneProviderProxy.createAndRegister(
+            proxy = new RealLocationTimeZoneProviderProxy(
                     mContext,
                     mThreadingDomain,
                     PRIMARY_LOCATION_TIME_ZONE_SERVICE_ACTION,
-                    com.android.internal.R.bool.config_enablePrimaryLocationTimeZoneOverlay,
-                    com.android.internal.R.string.config_primaryLocationTimeZoneProviderPackageName
+                    R.bool.config_enablePrimaryLocationTimeZoneOverlay,
+                    R.string.config_primaryLocationTimeZoneProviderPackageName
             );
         }
-        return createLocationTimeZoneProvider(PRIMARY_PROVIDER_NAME, proxy);
+        return new BinderLocationTimeZoneProvider(mThreadingDomain, PRIMARY_PROVIDER_NAME, proxy);
     }
 
     private LocationTimeZoneProvider createSecondaryProvider() {
+        Resources resources = mContext.getResources();
+        if (!resources.getBoolean(R.bool.config_enableSecondaryLocationTimeZoneProvider)) {
+            return new NullLocationTimeZoneProvider(mThreadingDomain, SECONDARY_PROVIDER_NAME);
+        }
+
         LocationTimeZoneProviderProxy proxy;
         if (isInSimulationMode(SECONDARY_PROVIDER_NAME)) {
             proxy = new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
         } else {
-            proxy = RealLocationTimeZoneProviderProxy.createAndRegister(
+            proxy = new RealLocationTimeZoneProviderProxy(
                     mContext,
                     mThreadingDomain,
                     SECONDARY_LOCATION_TIME_ZONE_SERVICE_ACTION,
-                    com.android.internal.R.bool.config_enableSecondaryLocationTimeZoneOverlay,
-                    com.android.internal.R.string
-                            .config_secondaryLocationTimeZoneProviderPackageName
+                    R.bool.config_enableSecondaryLocationTimeZoneOverlay,
+                    R.string.config_secondaryLocationTimeZoneProviderPackageName
             );
         }
-        return createLocationTimeZoneProvider(SECONDARY_PROVIDER_NAME, proxy);
+        return new BinderLocationTimeZoneProvider(mThreadingDomain, SECONDARY_PROVIDER_NAME, proxy);
     }
 
     private boolean isInSimulationMode(String providerName) {
@@ -216,21 +227,6 @@
                 SIMULATION_MODE_SYSTEM_PROPERTY_PREFIX + providerName, false);
     }
 
-    private LocationTimeZoneProvider createLocationTimeZoneProvider(
-            @NonNull String providerName, @NonNull LocationTimeZoneProviderProxy proxy) {
-        LocationTimeZoneProvider provider;
-        if (proxy != null) {
-            debugLog("LocationTimeZoneProvider found for providerName=" + providerName);
-            provider = new BinderLocationTimeZoneProvider(mThreadingDomain,
-                    providerName, proxy);
-        } else {
-            debugLog("No LocationTimeZoneProvider found for providerName=" + providerName
-                    + ": stubbing");
-            provider = new NullLocationTimeZoneProvider(mThreadingDomain, providerName);
-        }
-        return provider;
-    }
-
     @Override
     public void onShellCommand(FileDescriptor in, FileDescriptor out,
             FileDescriptor err, String[] args, ShellCallback callback,
diff --git a/services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderProxy.java b/services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderProxy.java
index 1b4706f..8a0259d 100644
--- a/services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderProxy.java
+++ b/services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderProxy.java
@@ -70,9 +70,11 @@
     }
 
     /**
-     * Sets the listener. The listener can expect to receive all events after this point.
+     * Initializes the proxy. The supplied listener can expect to receive all events after this
+     * point. This method also calls {@link #onInitialize()} for subclasses to handle their own
+     * initialization.
      */
-    void setListener(@NonNull Listener listener) {
+    void initialize(@NonNull Listener listener) {
         Objects.requireNonNull(listener);
         synchronized (mSharedLock) {
             if (mListener != null) {
@@ -80,9 +82,15 @@
             }
             this.mListener = listener;
         }
+        onInitialize();
     }
 
     /**
+     * Initializes the proxy. This is called after {@link #mListener} is set.
+     */
+    abstract void onInitialize();
+
+    /**
      * Sets a new request for the provider.
      */
     abstract void setRequest(@NonNull LocationTimeZoneProviderRequest request);
diff --git a/services/core/java/com/android/server/location/timezone/RealLocationTimeZoneProviderProxy.java b/services/core/java/com/android/server/location/timezone/RealLocationTimeZoneProviderProxy.java
index cd6d359..1a01288 100644
--- a/services/core/java/com/android/server/location/timezone/RealLocationTimeZoneProviderProxy.java
+++ b/services/core/java/com/android/server/location/timezone/RealLocationTimeZoneProviderProxy.java
@@ -41,23 +41,6 @@
  */
 class RealLocationTimeZoneProviderProxy extends LocationTimeZoneProviderProxy {
 
-    /**
-     * Creates and registers this proxy. If no suitable service is available for the proxy, returns
-     * null.
-     */
-    @Nullable
-    static LocationTimeZoneProviderProxy createAndRegister(
-            @NonNull Context context, @NonNull ThreadingDomain threadingDomain,
-            @NonNull String action, int enableOverlayResId, int nonOverlayPackageResId) {
-        RealLocationTimeZoneProviderProxy proxy = new RealLocationTimeZoneProviderProxy(
-                context, threadingDomain, action, enableOverlayResId, nonOverlayPackageResId);
-        if (proxy.register()) {
-            return proxy;
-        } else {
-            return null;
-        }
-    }
-
     @NonNull private final ServiceWatcher mServiceWatcher;
 
     @GuardedBy("mProxyLock")
@@ -66,7 +49,7 @@
     @GuardedBy("mProxyLock")
     @NonNull private LocationTimeZoneProviderRequest mRequest;
 
-    private RealLocationTimeZoneProviderProxy(
+    RealLocationTimeZoneProviderProxy(
             @NonNull Context context, @NonNull ThreadingDomain threadingDomain,
             @NonNull String action, int enableOverlayResId,
             int nonOverlayPackageResId) {
@@ -77,6 +60,13 @@
                 enableOverlayResId, nonOverlayPackageResId);
     }
 
+    @Override
+    void onInitialize() {
+        if (!register()) {
+            throw new IllegalStateException("Unable to register binder proxy");
+        }
+    }
+
     private boolean register() {
         boolean resolves = mServiceWatcher.checkServiceResolves();
         if (resolves) {
diff --git a/services/core/java/com/android/server/location/timezone/SimulatedLocationTimeZoneProviderProxy.java b/services/core/java/com/android/server/location/timezone/SimulatedLocationTimeZoneProviderProxy.java
index 604ff74..5e66a99 100644
--- a/services/core/java/com/android/server/location/timezone/SimulatedLocationTimeZoneProviderProxy.java
+++ b/services/core/java/com/android/server/location/timezone/SimulatedLocationTimeZoneProviderProxy.java
@@ -49,6 +49,11 @@
         mRequest = LocationTimeZoneProviderRequest.EMPTY_REQUEST;
     }
 
+    @Override
+    void onInitialize() {
+        // No-op - nothing to do for the simulated provider.
+    }
+
     void simulate(@NonNull SimulatedBinderProviderEvent event) {
         mThreadingDomain.assertCurrentThread();
 
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
index c4581c8..834cf05 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
@@ -16,8 +16,6 @@
 
 package com.android.server.locksettings;
 
-import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
-
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
 
@@ -271,15 +269,17 @@
     private boolean isNewCredentialSufficient(LockscreenCredential credential) {
         final PasswordMetrics requiredMetrics =
                 mLockPatternUtils.getRequestedPasswordMetrics(mCurrentUserId);
+        final int requiredComplexity =
+                mLockPatternUtils.getRequestedPasswordComplexity(mCurrentUserId);
         final List<PasswordValidationError> errors;
         if (credential.isPassword() || credential.isPin()) {
-            errors = PasswordMetrics.validatePassword(requiredMetrics, PASSWORD_COMPLEXITY_NONE,
+            errors = PasswordMetrics.validatePassword(requiredMetrics, requiredComplexity,
                     credential.isPin(), credential.getCredential());
         } else {
             PasswordMetrics metrics = new PasswordMetrics(
                     credential.isPattern() ? CREDENTIAL_TYPE_PATTERN : CREDENTIAL_TYPE_NONE);
             errors = PasswordMetrics.validatePasswordMetrics(
-                    requiredMetrics, PASSWORD_COMPLEXITY_NONE, false /* isPin */, metrics);
+                    requiredMetrics, requiredComplexity, false /* isPin */, metrics);
         }
         if (!errors.isEmpty()) {
             getOutPrintWriter().println(
diff --git a/services/core/java/com/android/server/locksettings/OWNERS b/services/core/java/com/android/server/locksettings/OWNERS
new file mode 100644
index 0000000..dad6e39
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/OWNERS
@@ -0,0 +1,2 @@
+jaggies@google.com
+kchyn@google.com
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 64c3c28..ea1d8da 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -37,7 +37,7 @@
 import android.security.Credentials;
 import android.security.KeyStore;
 import android.text.TextUtils;
-import android.util.Slog;
+import android.util.Log;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
@@ -128,7 +128,7 @@
         final int egressType = (egressInfo == null) ? TYPE_NONE : egressInfo.getType();
         final String egressIface = (egressProp == null) ?
                 null : egressProp.getInterfaceName();
-        Slog.d(TAG, "handleStateChanged: egress=" + egressType
+        Log.d(TAG, "handleStateChanged: egress=" + egressType
                 + " " + mAcceptedEgressIface + "->" + egressIface);
 
         if (egressDisconnected || egressChanged) {
@@ -149,7 +149,7 @@
 
         } else if (egressInfo.isConnected() && !vpnInfo.isConnectedOrConnecting()) {
             if (mProfile.isValidLockdownProfile()) {
-                Slog.d(TAG, "Active network connected; starting VPN");
+                Log.d(TAG, "Active network connected; starting VPN");
                 EventLogTags.writeLockdownVpnConnecting(egressType);
                 showNotification(R.string.vpn_lockdown_connecting, R.drawable.vpn_disconnected);
 
@@ -160,11 +160,11 @@
                     mVpn.startLegacyVpnPrivileged(mProfile, KeyStore.getInstance(), egressProp);
                 } catch (IllegalStateException e) {
                     mAcceptedEgressIface = null;
-                    Slog.e(TAG, "Failed to start VPN", e);
+                    Log.e(TAG, "Failed to start VPN", e);
                     showNotification(R.string.vpn_lockdown_error, R.drawable.vpn_disconnected);
                 }
             } else {
-                Slog.e(TAG, "Invalid VPN profile; requires IP-based server and DNS");
+                Log.e(TAG, "Invalid VPN profile; requires IP-based server and DNS");
                 showNotification(R.string.vpn_lockdown_error, R.drawable.vpn_disconnected);
             }
 
@@ -172,8 +172,8 @@
             final String iface = vpnConfig.interfaze;
             final List<LinkAddress> sourceAddrs = vpnConfig.addresses;
 
-            Slog.d(TAG, "VPN connected using iface=" + iface +
-                    ", sourceAddr=" + sourceAddrs.toString());
+            Log.d(TAG, "VPN connected using iface=" + iface
+                    + ", sourceAddr=" + sourceAddrs.toString());
             EventLogTags.writeLockdownVpnConnected(egressType);
             showNotification(R.string.vpn_lockdown_connected, R.drawable.vpn_connected);
 
@@ -190,7 +190,7 @@
     }
 
     private void initLocked() {
-        Slog.d(TAG, "initLocked()");
+        Log.d(TAG, "initLocked()");
 
         mVpn.setEnableTeardown(false);
         mVpn.setLockdown(true);
@@ -204,7 +204,7 @@
     }
 
     private void shutdownLocked() {
-        Slog.d(TAG, "shutdownLocked()");
+        Log.d(TAG, "shutdownLocked()");
 
         mAcceptedEgressIface = null;
         mErrorCount = 0;
@@ -222,7 +222,7 @@
      */
     @GuardedBy("mConnService.mVpns")
     public void reset() {
-        Slog.d(TAG, "reset()");
+        Log.d(TAG, "reset()");
         synchronized (mStateLock) {
             // cycle tracker, reset error count, and trigger retry
             shutdownLocked();
diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
index 006d78e..5bd352c 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
@@ -17,11 +17,13 @@
 
 import static android.net.INetd.FIREWALL_CHAIN_DOZABLE;
 import static android.net.INetd.FIREWALL_CHAIN_POWERSAVE;
+import static android.net.INetd.FIREWALL_CHAIN_RESTRICTED;
 import static android.net.INetd.FIREWALL_CHAIN_STANDBY;
 import static android.net.INetd.FIREWALL_RULE_ALLOW;
 import static android.net.INetd.FIREWALL_RULE_DENY;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_RESTRICTED;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
 import static android.os.Process.INVALID_UID;
@@ -339,6 +341,8 @@
                 return FIREWALL_CHAIN_NAME_STANDBY;
             case FIREWALL_CHAIN_POWERSAVE:
                 return FIREWALL_CHAIN_NAME_POWERSAVE;
+            case FIREWALL_CHAIN_RESTRICTED:
+                return FIREWALL_CHAIN_NAME_RESTRICTED;
             default:
                 return String.valueOf(chain);
         }
diff --git a/services/core/java/com/android/server/net/OWNERS b/services/core/java/com/android/server/net/OWNERS
index 28ae6a4..d5c7618 100644
--- a/services/core/java/com/android/server/net/OWNERS
+++ b/services/core/java/com/android/server/net/OWNERS
@@ -2,7 +2,7 @@
 
 codewiz@google.com
 jchalard@google.com
-jsharkey@android.com
+jsharkey@google.com
 junyulai@google.com
 lorenzo@google.com
 reminv@google.com
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 8200ca0..769b781 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -123,7 +123,7 @@
         final Config c = new Config();
         c.caption = "condition provider";
         c.serviceInterface = ConditionProviderService.SERVICE_INTERFACE;
-        c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES;
+        c.secureSettingName = null;
         c.xmlTag = TAG_ENABLED_DND_APPS;
         c.secondarySettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
         c.bindPermission = android.Manifest.permission.BIND_CONDITION_PROVIDER_SERVICE;
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index a7ee272..54e9b37 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -437,9 +437,15 @@
                         }
                     }
                 }
-                Settings.Secure.putStringForUser(
-                        mContext.getContentResolver(), element, value, userId);
-                loadAllowedComponentsFromSettings();
+                if (shouldReflectToSettings()) {
+                    Settings.Secure.putStringForUser(
+                            mContext.getContentResolver(), element, value, userId);
+                }
+
+                for (UserInfo user : mUm.getUsers()) {
+                    addApprovedList(value, user.id, mConfig.secureSettingName.equals(element));
+                }
+                Slog.d(TAG, "Done loading approved values from settings");
                 rebindServices(false, userId);
             }
         }
@@ -498,10 +504,13 @@
                             out.endTag(null, TAG_MANAGED_SERVICES);
 
                             if (!forBackup && isPrimary) {
-                                // Also write values to settings, for observers who haven't migrated yet
-                                Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                                        getConfig().secureSettingName, allowedItems,
-                                        approvedUserId);
+                                if (shouldReflectToSettings()) {
+                                    // Also write values to settings, for observers who haven't
+                                    // migrated yet
+                                    Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                                            getConfig().secureSettingName, allowedItems,
+                                            approvedUserId);
+                                }
                             }
 
                         }
@@ -516,6 +525,13 @@
     }
 
     /**
+     * Returns whether the approved list of services should also be written to the Settings db
+     */
+    protected boolean shouldReflectToSettings() {
+        return false;
+    }
+
+    /**
      * Writes extra xml attributes to {@link #TAG_MANAGED_SERVICES} tag.
      */
     protected void writeExtraAttributes(TypedXmlSerializer out, int userId) throws IOException {}
@@ -530,8 +546,20 @@
      */
     protected void readExtraTag(String tag, TypedXmlPullParser parser) throws IOException {}
 
-    protected void migrateToXml() {
-        loadAllowedComponentsFromSettings();
+    protected final void migrateToXml() {
+        for (UserInfo user : mUm.getUsers()) {
+            final ContentResolver cr = mContext.getContentResolver();
+            addApprovedList(Settings.Secure.getStringForUser(
+                    cr,
+                    getConfig().secureSettingName,
+                    user.id), user.id, true);
+            if (!TextUtils.isEmpty(getConfig().secondarySettingName)) {
+                addApprovedList(Settings.Secure.getStringForUser(
+                        cr,
+                        getConfig().secondarySettingName,
+                        user.id), user.id, false);
+            }
+        }
     }
 
     void readDefaults(TypedXmlPullParser parser) {
@@ -638,23 +666,6 @@
 
     protected abstract String getRequiredPermission();
 
-    private void loadAllowedComponentsFromSettings() {
-        for (UserInfo user : mUm.getUsers()) {
-            final ContentResolver cr = mContext.getContentResolver();
-            addApprovedList(Settings.Secure.getStringForUser(
-                    cr,
-                    getConfig().secureSettingName,
-                    user.id), user.id, true);
-            if (!TextUtils.isEmpty(getConfig().secondarySettingName)) {
-                addApprovedList(Settings.Secure.getStringForUser(
-                        cr,
-                        getConfig().secondarySettingName,
-                        user.id), user.id, false);
-            }
-        }
-        Slog.d(TAG, "Done loading approved values from settings");
-    }
-
     protected void addApprovedList(String approved, int userId, boolean isPrimary) {
         addApprovedList(approved, userId, isPrimary, approved);
     }
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
index 7257f52..c1deb96 100644
--- a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
+++ b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
@@ -293,7 +293,9 @@
                                 .appendPath(file.getAbsolutePath()).build())
                         .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
                         .putExtra(EXTRA_KEY, file.getAbsolutePath()),
-                PendingIntent.FLAG_UPDATE_CURRENT);
+                // TODO(b/174161800) Please replace FLAG_MUTABLE_UNAUDITED below
+                // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
+                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
         mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, deletionTime, pi);
     }
 
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ee860e3..692e97a 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -277,6 +277,7 @@
 import com.android.server.policy.PhoneWindowManager;
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.uri.UriGrantsManagerInternal;
+import com.android.server.utils.quota.MultiRateLimiter;
 import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.BackgroundActivityStartCallback;
 import com.android.server.wm.WindowManagerInternal;
@@ -298,6 +299,7 @@
 import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.nio.charset.StandardCharsets;
+import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
@@ -371,6 +373,20 @@
             RoleManager.ROLE_EMERGENCY
     };
 
+    // Used for rate limiting toasts by package.
+    static final String TOAST_QUOTA_TAG = "toast_quota_tag";
+
+    // This constant defines rate limits applied to showing toasts. The numbers are set in a way
+    // such that an aggressive toast showing strategy would result in a roughly 1.5x longer wait
+    // time (before the package is allowed to show toasts again) each time the toast rate limit is
+    // reached. It's meant to protect the user against apps spamming them with toasts (either
+    // accidentally or on purpose).
+    private static final MultiRateLimiter.RateLimit[] TOAST_RATE_LIMITS = {
+            MultiRateLimiter.RateLimit.create(3, Duration.ofSeconds(20)),
+            MultiRateLimiter.RateLimit.create(5, Duration.ofSeconds(42)),
+            MultiRateLimiter.RateLimit.create(6, Duration.ofSeconds(68)),
+    };
+
     // When #matchesCallFilter is called from the ringer, wait at most
     // 3s to resolve the contacts. This timeout is required since
     // ContactsProvider might take a long time to start up.
@@ -422,6 +438,16 @@
     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
     private static final long NOTIFICATION_TRAMPOLINE_BLOCK = 167676448L;
 
+    /**
+     * Rate limit showing toasts, on a per package basis.
+     *
+     * It limits the effects of {@link android.widget.Toast#show()} calls to prevent overburdening
+     * the user with too many toasts in a limited time. Any attempt to show more toasts than allowed
+     * in a certain time frame will result in the toast being discarded.
+     */
+    @ChangeId
+    private static final long RATE_LIMIT_TOASTS = 154198299L;
+
     private IActivityManager mAm;
     private ActivityTaskManagerInternal mAtm;
     private ActivityManager mActivityManager;
@@ -500,6 +526,9 @@
     @GuardedBy("mToastQueue")
     private boolean mIsCurrentToastShown = false;
 
+    // Used for rate limiting toasts by package.
+    private MultiRateLimiter mToastRateLimiter;
+
     // The last key in this list owns the hardware.
     ArrayList<String> mLights = new ArrayList<>();
 
@@ -1662,6 +1691,11 @@
                 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_HISTORY_ENABLED);
         private final Uri NOTIFICATION_SHOW_MEDIA_ON_QUICK_SETTINGS_URI
                 = Settings.Global.getUriFor(Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS);
+        private final Uri LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS
+                = Settings.Secure.getUriFor(
+                        Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS);
+        private final Uri LOCK_SCREEN_SHOW_NOTIFICATIONS
+                = Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS);
 
         SettingsObserver(Handler handler) {
             super(handler);
@@ -1681,6 +1715,11 @@
                     false, this, UserHandle.USER_ALL);
             resolver.registerContentObserver(NOTIFICATION_SHOW_MEDIA_ON_QUICK_SETTINGS_URI,
                     false, this, UserHandle.USER_ALL);
+
+            resolver.registerContentObserver(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+                    false, this, UserHandle.USER_ALL);
+            resolver.registerContentObserver(LOCK_SCREEN_SHOW_NOTIFICATIONS,
+                    false, this, UserHandle.USER_ALL);
             update(null);
         }
 
@@ -1722,6 +1761,12 @@
             if (uri == null || NOTIFICATION_SHOW_MEDIA_ON_QUICK_SETTINGS_URI.equals(uri)) {
                 mPreferencesHelper.updateMediaNotificationFilteringEnabled();
             }
+            if (uri == null || LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS.equals(uri)) {
+                mPreferencesHelper.updateLockScreenPrivateNotifications();
+            }
+            if (uri == null || LOCK_SCREEN_SHOW_NOTIFICATIONS.equals(uri)) {
+                mPreferencesHelper.updateLockScreenShowNotifications();
+            }
         }
     }
 
@@ -1915,7 +1960,8 @@
             DevicePolicyManagerInternal dpm, IUriGrantsManager ugm,
             UriGrantsManagerInternal ugmInternal, AppOpsManager appOps, UserManager userManager,
             NotificationHistoryManager historyManager, StatsManager statsManager,
-            TelephonyManager telephonyManager, ActivityManagerInternal ami) {
+            TelephonyManager telephonyManager, ActivityManagerInternal ami,
+            MultiRateLimiter toastRateLimiter) {
         mHandler = handler;
         Resources resources = getContext().getResources();
         mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
@@ -2107,6 +2153,8 @@
                 com.android.internal.R.array.config_notificationMsgPkgsAllowedAsConvos));
         mStatsManager = statsManager;
 
+        mToastRateLimiter = toastRateLimiter;
+
         // register for various Intents.
         // If this is called within a test, make sure to unregister the intent receivers by
         // calling onDestroy()
@@ -2217,7 +2265,8 @@
                 mStatsManager = (StatsManager) getContext().getSystemService(
                         Context.STATS_MANAGER),
                 getContext().getSystemService(TelephonyManager.class),
-                LocalServices.getService(ActivityManagerInternal.class));
+                LocalServices.getService(ActivityManagerInternal.class),
+                createToastRateLimiter());
 
         publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
                 DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
@@ -2855,6 +2904,10 @@
         return mInternalService;
     }
 
+    private MultiRateLimiter createToastRateLimiter() {
+        return new MultiRateLimiter.Builder(getContext()).addRateLimits(TOAST_RATE_LIMITS).build();
+    }
+
     @VisibleForTesting
     final IBinder mService = new INotificationManager.Stub() {
         // Toasts
@@ -3591,8 +3644,9 @@
         public ParceledListSlice<ConversationChannelWrapper> getConversations(
                 boolean onlyImportant) {
             enforceSystemOrSystemUI("getConversations");
+            IntArray userIds = mUserProfiles.getCurrentProfileIds();
             ArrayList<ConversationChannelWrapper> conversations =
-                    mPreferencesHelper.getConversations(onlyImportant);
+                    mPreferencesHelper.getConversations(userIds, onlyImportant);
             for (ConversationChannelWrapper conversation : conversations) {
                 if (mShortcutHelper == null) {
                     conversation.setShortcutInfo(null);
@@ -7115,15 +7169,15 @@
         if (record.getSbn().isGroup() && record.getNotification().suppressAlertingDueToGrouping()) {
             return false;
         }
-        // not if in call or the screen's on
-        if (isInCall() || mScreenOn) {
+        // not if in call
+        if (isInCall()) {
             return false;
         }
         // check current user
         if (!isNotificationForCurrentUser(record)) {
             return false;
         }
-
+        // Light, but only when the screen is off
         return true;
     }
 
@@ -7329,10 +7383,21 @@
 
         ToastRecord record = mToastQueue.get(0);
         while (record != null) {
-            if (record.show()) {
+            int userId = UserHandle.getUserId(record.uid);
+            boolean rateLimitingEnabled =
+                    CompatChanges.isChangeEnabled(RATE_LIMIT_TOASTS, record.uid);
+            boolean isWithinQuota =
+                    mToastRateLimiter.isWithinQuota(userId, record.pkg, TOAST_QUOTA_TAG);
+            if ((!rateLimitingEnabled || isWithinQuota) && record.show()) {
                 scheduleDurationReachedLocked(record);
                 mIsCurrentToastShown = true;
+                if (rateLimitingEnabled) {
+                    mToastRateLimiter.noteEvent(userId, record.pkg, TOAST_QUOTA_TAG);
+                }
                 return;
+            } else if (rateLimitingEnabled && !isWithinQuota) {
+                Slog.w(TAG, "Package " + record.pkg + " is above allowed toast quota, the "
+                        + "following toast was blocked and discarded: " + record);
             }
             int index = mToastQueue.indexOf(record);
             if (index >= 0) {
@@ -9462,6 +9527,13 @@
             return null;
         }
 
+        @Override
+        protected boolean shouldReflectToSettings() {
+            // androidx has a public method that reads the approved set of listeners from
+            // Settings so we have to continue writing this list for this type of service
+            return true;
+        }
+
         @GuardedBy("mNotificationLock")
         public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
             if (trim == TRIM_LIGHT) {
diff --git a/services/core/java/com/android/server/notification/OWNERS b/services/core/java/com/android/server/notification/OWNERS
index 5a19656..4dcb799 100644
--- a/services/core/java/com/android/server/notification/OWNERS
+++ b/services/core/java/com/android/server/notification/OWNERS
@@ -1,4 +1,4 @@
-dsandler@android.com
+dsandler@google.com
 juliacr@google.com
 beverlyt@google.com
 pixel@google.com
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 1c0349d..cbd973a 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -52,6 +52,7 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.IntArray;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
@@ -170,6 +171,8 @@
     private final AppOpsManager mAppOps;
 
     private SparseBooleanArray mBadgingEnabled;
+    private SparseBooleanArray mLockScreenShowNotifications;
+    private SparseBooleanArray mLockScreenPrivateNotifications;
     private boolean mBubblesEnabledGlobally = DEFAULT_GLOBAL_ALLOW_BUBBLE;
     private boolean mIsMediaNotificationFilteringEnabled = DEFAULT_MEDIA_NOTIFICATION_FILTERING;
     private boolean mAreChannelsBypassingDnd;
@@ -1379,36 +1382,39 @@
         return null;
     }
 
-    public ArrayList<ConversationChannelWrapper> getConversations(boolean onlyImportant) {
+    public ArrayList<ConversationChannelWrapper> getConversations(IntArray userIds,
+            boolean onlyImportant) {
         synchronized (mPackagePreferences) {
             ArrayList<ConversationChannelWrapper> conversations = new ArrayList<>();
-
             for (PackagePreferences p : mPackagePreferences.values()) {
-                int N = p.channels.size();
-                for (int i = 0; i < N; i++) {
-                    final NotificationChannel nc = p.channels.valueAt(i);
-                    if (!TextUtils.isEmpty(nc.getConversationId()) && !nc.isDeleted()
-                            && !nc.isDemoted()
-                            && (nc.isImportantConversation() || !onlyImportant)) {
-                        ConversationChannelWrapper conversation = new ConversationChannelWrapper();
-                        conversation.setPkg(p.pkg);
-                        conversation.setUid(p.uid);
-                        conversation.setNotificationChannel(nc);
-                        conversation.setParentChannelLabel(
-                                p.channels.get(nc.getParentChannelId()).getName());
-                        boolean blockedByGroup = false;
-                        if (nc.getGroup() != null) {
-                            NotificationChannelGroup group = p.groups.get(nc.getGroup());
-                            if (group != null) {
-                                if (group.isBlocked()) {
-                                    blockedByGroup = true;
-                                } else {
-                                    conversation.setGroupLabel(group.getName());
+                if (userIds.binarySearch(UserHandle.getUserId(p.uid)) >= 0) {
+                    int N = p.channels.size();
+                    for (int i = 0; i < N; i++) {
+                        final NotificationChannel nc = p.channels.valueAt(i);
+                        if (!TextUtils.isEmpty(nc.getConversationId()) && !nc.isDeleted()
+                                && !nc.isDemoted()
+                                && (nc.isImportantConversation() || !onlyImportant)) {
+                            ConversationChannelWrapper conversation =
+                                    new ConversationChannelWrapper();
+                            conversation.setPkg(p.pkg);
+                            conversation.setUid(p.uid);
+                            conversation.setNotificationChannel(nc);
+                            conversation.setParentChannelLabel(
+                                    p.channels.get(nc.getParentChannelId()).getName());
+                            boolean blockedByGroup = false;
+                            if (nc.getGroup() != null) {
+                                NotificationChannelGroup group = p.groups.get(nc.getGroup());
+                                if (group != null) {
+                                    if (group.isBlocked()) {
+                                        blockedByGroup = true;
+                                    } else {
+                                        conversation.setGroupLabel(group.getName());
+                                    }
                                 }
                             }
-                        }
-                        if (!blockedByGroup) {
-                            conversations.add(conversation);
+                            if (!blockedByGroup) {
+                                conversations.add(conversation);
+                            }
                         }
                     }
                 }
@@ -2401,6 +2407,60 @@
         return mBadgingEnabled.get(userId, DEFAULT_SHOW_BADGE);
     }
 
+    public void updateLockScreenPrivateNotifications() {
+        if (mLockScreenPrivateNotifications == null) {
+            mLockScreenPrivateNotifications = new SparseBooleanArray();
+        }
+        boolean changed = false;
+        // update the cached values
+        for (int index = 0; index < mLockScreenPrivateNotifications.size(); index++) {
+            int userId = mLockScreenPrivateNotifications.keyAt(index);
+            final boolean oldValue = mLockScreenPrivateNotifications.get(userId);
+            final boolean newValue = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                    Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 1, userId) != 0;
+            mLockScreenPrivateNotifications.put(userId, newValue);
+            changed |= oldValue != newValue;
+        }
+        if (changed) {
+            updateConfig();
+        }
+    }
+
+    public void updateLockScreenShowNotifications() {
+        if (mLockScreenShowNotifications == null) {
+            mLockScreenShowNotifications = new SparseBooleanArray();
+        }
+        boolean changed = false;
+        // update the cached values
+        for (int index = 0; index < mLockScreenShowNotifications.size(); index++) {
+            int userId = mLockScreenShowNotifications.keyAt(index);
+            final boolean oldValue = mLockScreenShowNotifications.get(userId);
+            final boolean newValue = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                    Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1, userId) != 0;
+            mLockScreenShowNotifications.put(userId, newValue);
+            changed |= oldValue != newValue;
+        }
+        if (changed) {
+            updateConfig();
+        }
+    }
+
+    @Override
+    public boolean canShowNotificationsOnLockscreen(int userId) {
+        if (mLockScreenShowNotifications == null) {
+            mLockScreenShowNotifications = new SparseBooleanArray();
+        }
+        return mLockScreenShowNotifications.get(userId, true);
+    }
+
+    @Override
+    public boolean canShowPrivateNotificationsOnLockScreen(int userId) {
+        if (mLockScreenPrivateNotifications == null) {
+            mLockScreenPrivateNotifications = new SparseBooleanArray();
+        }
+        return mLockScreenPrivateNotifications.get(userId, true);
+    }
+
     public void unlockAllNotificationChannels() {
         synchronized (mPackagePreferences) {
             final int numPackagePreferences = mPackagePreferences.size();
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index b2827ba..8991ced 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -34,6 +34,8 @@
     /** Returns true when feature is enabled that shows media notifications in quick settings. */
     boolean isMediaNotificationFilteringEnabled();
     boolean isGroupBlocked(String packageName, int uid, String groupId);
+    boolean canShowNotificationsOnLockscreen(int userId);
+    boolean canShowPrivateNotificationsOnLockScreen(int userId);
 
     Collection<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
             int uid);
diff --git a/services/core/java/com/android/server/notification/ShortcutHelper.java b/services/core/java/com/android/server/notification/ShortcutHelper.java
index 9c3d6d3..b0be206 100644
--- a/services/core/java/com/android/server/notification/ShortcutHelper.java
+++ b/services/core/java/com/android/server/notification/ShortcutHelper.java
@@ -16,6 +16,7 @@
 
 package com.android.server.notification;
 
+import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_GET_PERSONS_DATA;
 import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_CACHED;
 import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC;
 import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER;
@@ -192,8 +193,8 @@
             LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery();
             query.setPackage(packageName);
             query.setShortcutIds(Arrays.asList(shortcutId));
-            query.setQueryFlags(
-                    FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED_BY_ANY_LAUNCHER | FLAG_MATCH_CACHED);
+            query.setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED_BY_ANY_LAUNCHER
+                    | FLAG_MATCH_CACHED | FLAG_GET_PERSONS_DATA);
             List<ShortcutInfo> shortcuts = mLauncherAppsService.getShortcuts(query, user);
             ShortcutInfo info = shortcuts != null && shortcuts.size() > 0
                     ? shortcuts.get(0)
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index b5ca2ab..3e197fb 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -462,6 +462,8 @@
     }
 
     private PendingIntent createPendingIntent(String pkg, String key, int userId) {
+        // TODO(b/174969959) Please replace FLAG_MUTABLE_UNAUDITED below
+        // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
         return PendingIntent.getBroadcast(mContext,
                 REQUEST_CODE_REPOST,
                 new Intent(REPOST_ACTION)
@@ -469,7 +471,7 @@
                         .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
                         .putExtra(EXTRA_KEY, key)
                         .putExtra(EXTRA_USER_ID, userId),
-                PendingIntent.FLAG_UPDATE_CURRENT);
+                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
     }
 
     public void scheduleRepostsForPersistedNotifications(long currentTime) {
@@ -558,8 +560,8 @@
                         if (value < currentTime) {
                             return;
                         }
-                        out.attribute(null, XML_SNOOZED_NOTIFICATION_TIME,
-                                value.toString());
+                        out.attributeLong(null, XML_SNOOZED_NOTIFICATION_TIME,
+                                value);
                     });
             writeXml(out, mPersistedSnoozedNotificationsWithContext,
                     XML_SNOOZED_NOTIFICATION_CONTEXT,
diff --git a/services/core/java/com/android/server/notification/VisibilityExtractor.java b/services/core/java/com/android/server/notification/VisibilityExtractor.java
index db54846..a363601 100644
--- a/services/core/java/com/android/server/notification/VisibilityExtractor.java
+++ b/services/core/java/com/android/server/notification/VisibilityExtractor.java
@@ -15,8 +15,11 @@
 */
 package com.android.server.notification;
 
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.admin.DevicePolicyManager;
 import android.content.Context;
-import android.service.notification.NotificationListenerService;
+import android.os.UserHandle;
 import android.util.Slog;
 
 /**
@@ -27,9 +30,11 @@
     private static final boolean DBG = false;
 
     private RankingConfig mConfig;
+    private DevicePolicyManager mDpm;
 
     public void initialize(Context ctx, NotificationUsageStats usageStats) {
         if (DBG) Slog.d(TAG, "Initializing  " + getClass().getSimpleName() + ".");
+        mDpm = ctx.getSystemService(DevicePolicyManager.class);
     }
 
     public RankingReconsideration process(NotificationRecord record) {
@@ -43,7 +48,38 @@
             return null;
         }
 
-        record.setPackageVisibilityOverride(record.getChannel().getLockscreenVisibility());
+        int userId = record.getUserId();
+
+        if (userId == UserHandle.USER_ALL) {
+            record.setPackageVisibilityOverride(record.getChannel().getLockscreenVisibility());
+        } else {
+            boolean userCanShowNotifications =
+                    mConfig.canShowNotificationsOnLockscreen(userId);
+            boolean dpmCanShowNotifications = adminAllowsKeyguardFeature(userId,
+                    DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
+            boolean channelCanShowNotifications = record.getChannel().getLockscreenVisibility()
+                    != Notification.VISIBILITY_SECRET;
+
+            if (!userCanShowNotifications || !dpmCanShowNotifications
+                    || !channelCanShowNotifications) {
+                record.setPackageVisibilityOverride(Notification.VISIBILITY_SECRET);
+            } else {
+                // notifications are allowed but should they be redacted?
+
+                boolean userCanShowContents =
+                        mConfig.canShowPrivateNotificationsOnLockScreen(userId);
+                boolean dpmCanShowContents = adminAllowsKeyguardFeature(userId,
+                        DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
+                boolean channelCanShowContents = record.getChannel().getLockscreenVisibility()
+                        != Notification.VISIBILITY_PRIVATE;
+
+                if (!userCanShowContents || !dpmCanShowContents || !channelCanShowContents) {
+                    record.setPackageVisibilityOverride(Notification.VISIBILITY_PRIVATE);
+                } else {
+                    record.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE);
+                }
+            }
+        }
 
         return null;
     }
@@ -57,4 +93,13 @@
     public void setZenHelper(ZenModeHelper helper) {
 
     }
+
+    private boolean adminAllowsKeyguardFeature(int userHandle, int feature) {
+        if (userHandle == UserHandle.USER_ALL) {
+            return true;
+        }
+        final int dpmFlags = mDpm.getKeyguardDisabledFeatures(null /* admin */, userHandle);
+        return (dpmFlags & feature) == 0;
+    }
+
 }
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 94f46ba..5cd22e0 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -81,6 +81,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.util.XmlUtils;
 import com.android.server.LocalServices;
 
 import libcore.io.IoUtils;
@@ -1165,7 +1166,7 @@
         try {
             parser = resources.getXml(R.xml.default_zen_mode_config);
             while (parser.next() != XmlPullParser.END_DOCUMENT) {
-                final ZenModeConfig config = ZenModeConfig.readXml(parser);
+                final ZenModeConfig config = ZenModeConfig.readXml(XmlUtils.makeTyped(parser));
                 if (config != null) return config;
             }
         } catch (Exception e) {
diff --git a/services/core/java/com/android/server/om/OWNERS b/services/core/java/com/android/server/om/OWNERS
new file mode 100644
index 0000000..afb98d4
--- /dev/null
+++ b/services/core/java/com/android/server/om/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/content/om/OWNERS
diff --git a/services/core/java/com/android/server/om/TEST_MAPPING b/services/core/java/com/android/server/om/TEST_MAPPING
index 6edd76f..e8a2a02 100644
--- a/services/core/java/com/android/server/om/TEST_MAPPING
+++ b/services/core/java/com/android/server/om/TEST_MAPPING
@@ -15,9 +15,6 @@
       "name": "OverlayHostTests"
     },
     {
-      "name": "OverlayRemountedTest"
-    },
-    {
       "name": "CtsAppSecurityHostTestCases",
       "options": [
         {
@@ -25,5 +22,10 @@
         }
       ]
     }
+  ],
+  "presubmit-large": [
+    {
+      "name": "OverlayRemountedTest"
+    }
   ]
 }
diff --git a/services/core/java/com/android/server/people/OWNERS b/services/core/java/com/android/server/people/OWNERS
new file mode 100644
index 0000000..3198a5e
--- /dev/null
+++ b/services/core/java/com/android/server/people/OWNERS
@@ -0,0 +1 @@
+include /services/people/OWNERS
diff --git a/services/core/java/com/android/server/pm/DefaultAppProvider.java b/services/core/java/com/android/server/pm/DefaultAppProvider.java
new file mode 100644
index 0000000..a17967f
--- /dev/null
+++ b/services/core/java/com/android/server/pm/DefaultAppProvider.java
@@ -0,0 +1,177 @@
+/*
+ * 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.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.role.RoleManager;
+import android.os.Binder;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import com.android.internal.infra.AndroidFuture;
+import com.android.internal.util.CollectionUtils;
+import com.android.server.FgThread;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * Interacts with {@link RoleManager} to provide and manage default apps.
+ */
+public class DefaultAppProvider {
+    @NonNull
+    private final Supplier<RoleManager> mRoleManagerSupplier;
+
+    /**
+     * Create a new instance of this class
+     *
+     * @param roleManagerSupplier the supplier for {@link RoleManager}
+     */
+    public DefaultAppProvider(@NonNull Supplier<RoleManager> roleManagerSupplier) {
+        mRoleManagerSupplier = roleManagerSupplier;
+    }
+
+    /**
+     * Get the package name of the default browser.
+     *
+     * @param userId the user ID
+     * @return the package name of the default browser, or {@code null} if none
+     */
+    @Nullable
+    public String getDefaultBrowser(@UserIdInt int userId) {
+        return getRoleHolder(RoleManager.ROLE_BROWSER, userId);
+    }
+
+    /**
+     * Set the package name of the default browser.
+     *
+     * @param packageName package name of the default browser, or {@code null} to unset
+     * @param async whether the operation should be asynchronous
+     * @param userId the user ID
+     * @return whether the default browser was successfully set.
+     */
+    public boolean setDefaultBrowser(@Nullable String packageName, boolean async,
+            @UserIdInt int userId) {
+        if (userId == UserHandle.USER_ALL) {
+            return false;
+        }
+        final RoleManager roleManager = mRoleManagerSupplier.get();
+        if (roleManager == null) {
+            return false;
+        }
+        final UserHandle user = UserHandle.of(userId);
+        final Executor executor = FgThread.getExecutor();
+        final AndroidFuture<Void> future = new AndroidFuture<>();
+        final Consumer<Boolean> callback = successful -> {
+            if (successful) {
+                future.complete(null);
+            } else {
+                future.completeExceptionally(new RuntimeException());
+            }
+        };
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            if (packageName != null) {
+                roleManager.addRoleHolderAsUser(RoleManager.ROLE_BROWSER, packageName, 0, user,
+                        executor, callback);
+            } else {
+                roleManager.clearRoleHoldersAsUser(RoleManager.ROLE_BROWSER, 0, user, executor,
+                        callback);
+            }
+            if (!async) {
+                try {
+                    future.get(5, TimeUnit.SECONDS);
+                } catch (InterruptedException | ExecutionException | TimeoutException e) {
+                    Slog.e(PackageManagerService.TAG, "Exception while setting default browser: "
+                            + packageName, e);
+                    return false;
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+        return true;
+    }
+
+    /**
+     * Get the package name of the default dialer.
+     *
+     * @param userId the user ID
+     * @return the package name of the default dialer, or {@code null} if none
+     */
+    @Nullable
+    public String getDefaultDialer(@NonNull int userId) {
+        return getRoleHolder(RoleManager.ROLE_DIALER, userId);
+    }
+
+    /**
+     * Get the package name of the default home.
+     *
+     * @param userId the user ID
+     * @return the package name of the default home, or {@code null} if none
+     */
+    @Nullable
+    public String getDefaultHome(@NonNull int userId) {
+        return getRoleHolder(RoleManager.ROLE_HOME, userId);
+    }
+
+    /**
+     * Set the package name of the default home.
+     *
+     * @param packageName package name of the default home
+     * @param userId the user ID
+     * @param executor the {@link Executor} to execute callback on
+     * @param callback the callback made after the default home as been updated
+     * @return whether the default home was set
+     */
+    public boolean setDefaultHome(@NonNull String packageName, @UserIdInt int userId,
+            @NonNull Executor executor, @NonNull Consumer<Boolean> callback) {
+        final RoleManager roleManager = mRoleManagerSupplier.get();
+        if (roleManager == null) {
+            return false;
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            roleManager.addRoleHolderAsUser(RoleManager.ROLE_HOME, packageName, 0,
+                    UserHandle.of(userId), executor, callback);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+        return true;
+    }
+
+    @Nullable
+    private String getRoleHolder(@NonNull String roleName, @NonNull int userId) {
+        final RoleManager roleManager = mRoleManagerSupplier.get();
+        if (roleManager == null) {
+            return null;
+        }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            return CollectionUtils.firstOrNull(roleManager.getRoleHoldersAsUser(roleName,
+                    UserHandle.of(userId)));
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS
index cca2b83..7a2b7a6 100644
--- a/services/core/java/com/android/server/pm/OWNERS
+++ b/services/core/java/com/android/server/pm/OWNERS
@@ -1,12 +1,12 @@
-hackbod@android.com
 hackbod@google.com
-jsharkey@android.com
+hackbod@google.com
+jsharkey@google.com
 jsharkey@google.com
 narayan@google.com
 patb@google.com
-svetoslavganov@android.com
 svetoslavganov@google.com
-toddke@android.com
+svetoslavganov@google.com
+toddke@google.com
 toddke@google.com
 
 # apex support
@@ -30,9 +30,10 @@
 per-file CrossProfileAppsService.java = omakoto@google.com, yamasani@google.com
 per-file CrossProfileIntentFilter.java = omakoto@google.com, yamasani@google.com
 per-file CrossProfileIntentResolver.java = omakoto@google.com, yamasani@google.com
+per-file RestrictionsSet.java = bookatz@google.com, omakoto@google.com, yamasani@google.com, rubinxu@google.com, sandness@google.com
+per-file UserManagerInternal.java = bookatz@google.com, omakoto@google.com, yamasani@google.com
 per-file UserManagerService.java = bookatz@google.com, omakoto@google.com, yamasani@google.com
 per-file UserRestrictionsUtils.java = omakoto@google.com, rubinxu@google.com, sandness@google.com, yamasani@google.com
-per-file RestrictionsSet.java = bookatz@google.com, omakoto@google.com, yamasani@google.com, rubinxu@google.com, sandness@google.com
 per-file UserSystemPackageInstaller.java = bookatz@google.com, omakoto@google.com, yamasani@google.com
 per-file UserTypeDetails.java = bookatz@google.com, omakoto@google.com, yamasani@google.com
 per-file UserTypeFactory.java = bookatz@google.com, omakoto@google.com, yamasani@google.com
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelper.java b/services/core/java/com/android/server/pm/PackageAbiHelper.java
index 30b1c2c..24a3e52 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelper.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelper.java
@@ -55,7 +55,7 @@
      * If {@code extractLibs} is true, native libraries are extracted from the app if required.
      */
     Pair<Abis, NativeLibraryPaths> derivePackageAbi(AndroidPackage pkg, boolean isUpdatedSystemApp,
-            String cpuAbiOverride) throws PackageManagerException;
+            String cpuAbiOverride, File appLib32InstallDir) throws PackageManagerException;
 
     /**
      * Calculates adjusted ABIs for a set of packages belonging to a shared user so that they all
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
index da4ea16..71b99bd 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -296,7 +296,7 @@
 
     @Override
     public Pair<Abis, NativeLibraryPaths> derivePackageAbi(AndroidPackage pkg,
-            boolean isUpdatedSystemApp, String cpuAbiOverride)
+            boolean isUpdatedSystemApp, String cpuAbiOverride, File appLib32InstallDir)
             throws PackageManagerException {
         // Give ourselves some initial paths; we'll come back for another
         // pass once we've determined ABI below.
@@ -304,7 +304,7 @@
         String pkgRawSecondaryCpuAbi = AndroidPackageUtils.getRawSecondaryCpuAbi(pkg);
         final NativeLibraryPaths initialLibraryPaths = deriveNativeLibraryPaths(
                 new Abis(pkgRawPrimaryCpuAbi, pkgRawSecondaryCpuAbi),
-                PackageManagerService.sAppLib32InstallDir, pkg.getPath(),
+                appLib32InstallDir, pkg.getPath(),
                 pkg.getBaseApkPath(), pkg.isSystem(),
                 isUpdatedSystemApp);
 
@@ -452,7 +452,7 @@
 
         final Abis abis = new Abis(primaryCpuAbi, secondaryCpuAbi);
         return new Pair<>(abis,
-                deriveNativeLibraryPaths(abis, PackageManagerService.sAppLib32InstallDir,
+                deriveNativeLibraryPaths(abis, appLib32InstallDir,
                         pkg.getPath(), pkg.getBaseApkPath(), pkg.isSystem(),
                         isUpdatedSystemApp));
     }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 4cee2e5..34bee95 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -686,11 +686,6 @@
             }
         }
 
-        if (params.whitelistedRestrictedPermissions != null) {
-            mPermissionManager.retainHardAndSoftRestrictedPermissions(
-                    params.whitelistedRestrictedPermissions);
-        }
-
         final int sessionId;
         final PackageInstallerSession session;
         synchronized (mSessions) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index c10d394..4ab1282 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -31,22 +31,16 @@
 import static android.content.pm.PackageManager.INSTALL_STAGED;
 import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
 import static android.content.pm.PackageParser.APEX_FILE_EXTENSION;
-import static android.content.pm.PackageParser.APK_FILE_EXTENSION;
 import static android.system.OsConstants.O_CREAT;
 import static android.system.OsConstants.O_RDONLY;
 import static android.system.OsConstants.O_WRONLY;
 
 import static com.android.internal.util.XmlUtils.readBitmapAttribute;
-import static com.android.internal.util.XmlUtils.readBooleanAttribute;
 import static com.android.internal.util.XmlUtils.readByteArrayAttribute;
-import static com.android.internal.util.XmlUtils.readIntAttribute;
-import static com.android.internal.util.XmlUtils.readLongAttribute;
 import static com.android.internal.util.XmlUtils.readStringAttribute;
 import static com.android.internal.util.XmlUtils.readUriAttribute;
 import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
 import static com.android.internal.util.XmlUtils.writeByteArrayAttribute;
-import static com.android.internal.util.XmlUtils.writeIntAttribute;
-import static com.android.internal.util.XmlUtils.writeLongAttribute;
 import static com.android.internal.util.XmlUtils.writeStringAttribute;
 import static com.android.internal.util.XmlUtils.writeUriAttribute;
 import static com.android.server.pm.PackageInstallerService.prepareStageDir;
@@ -110,6 +104,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.RevocableFileDescriptor;
+import android.os.SELinux;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.incremental.IStorageHealthListener;
@@ -156,7 +151,6 @@
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -483,6 +477,9 @@
     @GuardedBy("mLock")
     private IncrementalFileStorages mIncrementalFileStorages;
 
+    @GuardedBy("mLock")
+    private PackageLite mPackageLite;
+
     private static final FileFilter sAddedApkFilter = new FileFilter() {
         @Override
         public boolean accept(File file) {
@@ -759,6 +756,7 @@
 
             info.mode = params.mode;
             info.installReason = params.installReason;
+            info.installScenario = params.installScenario;
             info.sizeBytes = params.sizeBytes;
             info.appPackageName = mPackageName != null ? mPackageName : params.appPackageName;
             if (includeIcon) {
@@ -1092,6 +1090,31 @@
         }
     }
 
+    @Override
+    public void stageViaHardLink(String path) {
+        final int callingUid = Binder.getCallingUid();
+        if (callingUid != Process.SYSTEM_UID) {
+            throw new SecurityException("link() can only be run by the system");
+        }
+
+        try {
+            final File target = new File(path);
+            final File source = new File(stageDir, target.getName());
+            try {
+                Os.link(path, source.getAbsolutePath());
+                // Grant READ access for APK to be read successfully
+                Os.chmod(source.getAbsolutePath(), 0644);
+            } catch (ErrnoException e) {
+                e.rethrowAsIOException();
+            }
+            if (!SELinux.restorecon(source)) {
+                throw new IOException("Can't relabel file: " + source);
+            }
+        } catch (IOException e) {
+            throw ExceptionUtils.wrap(e);
+        }
+    }
+
     private ParcelFileDescriptor openTargetInternal(String path, int flags, int mode)
             throws IOException, ErrnoException {
         // TODO: this should delegate to DCS so the system process avoids
@@ -2040,7 +2063,7 @@
 
         // TODO(b/136257624): Some logic in this if block probably belongs in
         //  makeInstallParams().
-        if (!params.isMultiPackage && !isApexSession()) {
+        if (!isMultiPackage() && !isApexSession()) {
             Objects.requireNonNull(mPackageName);
             Objects.requireNonNull(mSigningDetails);
             Objects.requireNonNull(mResolvedBaseFile);
@@ -2094,12 +2117,18 @@
                             "Failed to inherit existing install", e);
                 }
             }
+            // For mode inherit existing, it would link/copy existing files to stage dir in the
+            // above block. Therefore, we need to parse the complete package in stage dir here.
+            // Besides, PackageLite may be null for staged sessions that don't complete pre-reboot
+            // verification.
+            mPackageLite = getOrParsePackageLiteLocked(stageDir, /* flags */ 0);
 
             // TODO: surface more granular state from dexopt
             mInternalProgress = 0.5f;
             computeProgressLocked(true);
 
-            extractNativeLibraries(stageDir, params.abiOverride, mayInheritNativeLibs());
+            extractNativeLibraries(mPackageLite, stageDir, params.abiOverride,
+                    mayInheritNativeLibs());
         }
 
         final IPackageInstallObserver2 localObserver;
@@ -2142,7 +2171,7 @@
             copiedParams.installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
         }
         return mPm.new VerificationParams(user, stageDir, localObserver, copiedParams,
-                mInstallSource, mInstallerUid, mSigningDetails, sessionId);
+                mInstallSource, mInstallerUid, mSigningDetails, sessionId, mPackageLite);
     }
 
     private void onVerificationComplete() {
@@ -2215,12 +2244,39 @@
             params.installFlags |= INSTALL_STAGED;
         }
 
+        if (!isMultiPackage() && !isApexSession()) {
+            synchronized (mLock) {
+                // This shouldn't be null, but have this code path just in case.
+                if (mPackageLite == null) {
+                    Slog.wtf(TAG, "Session: " + sessionId + ". Don't have a valid PackageLite.");
+                }
+                mPackageLite = getOrParsePackageLiteLocked(stageDir, /* flags */ 0);
+            }
+        }
+
         synchronized (mLock) {
             return mPm.new InstallParams(stageDir, localObserver, params, mInstallSource, user,
-                    mSigningDetails, mInstallerUid);
+                    mSigningDetails, mInstallerUid, mPackageLite);
         }
     }
 
+    @GuardedBy("mLock")
+    private PackageLite getOrParsePackageLiteLocked(File packageFile, int flags)
+            throws PackageManagerException {
+        if (mPackageLite != null) {
+            return mPackageLite;
+        }
+
+        final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+        final ParseResult<PackageLite> result =
+                ApkLiteParseUtils.parsePackageLite(input, packageFile, flags);
+        if (result.isError()) {
+            throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
+                    result.getErrorMessage(), result.getException());
+        }
+        return result.getResult();
+    }
+
     private static void maybeRenameFile(File from, File to) throws PackageManagerException {
         if (!from.equals(to)) {
             if (!from.renameTo(to)) {
@@ -2366,13 +2422,6 @@
         }
     }
 
-    private static String splitNameToFileName(String splitName) {
-        if (splitName == null) {
-            return "base";
-        }
-        return "split_" + splitName;
-    }
-
     /**
      * Validate install by confirming that all application packages are have
      * consistent package name, version code, and signing certificates.
@@ -2388,6 +2437,8 @@
     @GuardedBy("mLock")
     private void validateApkInstallLocked() throws PackageManagerException {
         ApkLite baseApk = null;
+        PackageLite packageLite = null;
+        mPackageLite = null;
         mPackageName = null;
         mVersionCode = -1;
         mSigningDetails = PackageParser.SigningDetails.UNKNOWN;
@@ -2431,6 +2482,7 @@
 
         // Verify that all staged packages are internally consistent
         final ArraySet<String> stagedSplits = new ArraySet<>();
+        final ArrayMap<String, PackageParser.ApkLite> splitApks = new ArrayMap<>();
         ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
         for (File addedFile : addedFiles) {
             ParseResult<ApkLite> result = ApkLiteParseUtils.parseApkLite(input.reset(),
@@ -2458,8 +2510,7 @@
             assertApkConsistentLocked(String.valueOf(addedFile), apk);
 
             // Take this opportunity to enforce uniform naming
-            final String fileName = splitNameToFileName(apk.splitName);
-            final String targetName = fileName + APK_FILE_EXTENSION;
+            final String targetName = ApkLiteParseUtils.splitNameToFileName(apk);
             if (!FileUtils.isValidExtFilename(targetName)) {
                 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                         "Invalid filename: " + targetName);
@@ -2483,6 +2534,8 @@
             if (apk.splitName == null) {
                 mResolvedBaseFile = targetFile;
                 baseApk = apk;
+            } else {
+                splitApks.put(apk.splitName, apk);
             }
         }
 
@@ -2506,14 +2559,8 @@
                 mVersionCode = pkgInfo.getLongVersionCode();
             }
             if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
-                try {
-                    mSigningDetails = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
-                            pkgInfo.applicationInfo.sourceDir,
-                            PackageParser.SigningDetails.SignatureSchemeVersion.JAR);
-                } catch (PackageParserException e) {
-                    throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
-                            "Couldn't obtain signatures from base APK");
-                }
+                mSigningDetails = unsafeGetCertsWithoutVerification(
+                        pkgInfo.applicationInfo.sourceDir);
             }
         }
 
@@ -2548,6 +2595,17 @@
                 throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT,
                         "Missing split for " + mPackageName);
             }
+            // For mode full install, we compose package lite for future usage instead of
+            // re-parsing it again and again.
+            final ParseResult<PackageLite> pkgLiteResult =
+                    ApkLiteParseUtils.composePackageLiteFromApks(input.reset(), stageDir, baseApk,
+                            splitApks, true);
+            if (pkgLiteResult.isError()) {
+                throw new PackageManagerException(pkgLiteResult.getErrorCode(),
+                        pkgLiteResult.getErrorMessage(), pkgLiteResult.getException());
+            }
+            mPackageLite = pkgLiteResult.getResult();
+            packageLite = mPackageLite;
         } else {
             final ApplicationInfo appInfo = pkgInfo.applicationInfo;
             ParseResult<PackageLite> pkgLiteResult = ApkLiteParseUtils.parsePackageLite(
@@ -2557,22 +2615,20 @@
                         pkgLiteResult.getErrorMessage(), pkgLiteResult.getException());
             }
             final PackageLite existing = pkgLiteResult.getResult();
-            ParseResult<ApkLite> apkLiteResult = ApkLiteParseUtils.parseApkLite(input.reset(),
-                    new File(appInfo.getBaseCodePath()),
-                    PackageParser.PARSE_COLLECT_CERTIFICATES);
-            if (apkLiteResult.isError()) {
-                throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
-                        apkLiteResult.getErrorMessage(), apkLiteResult.getException());
+            packageLite = existing;
+            assertPackageConsistentLocked("Existing", existing.packageName,
+                    existing.getLongVersionCode());
+            final PackageParser.SigningDetails signingDetails =
+                    unsafeGetCertsWithoutVerification(existing.baseCodePath);
+            if (!mSigningDetails.signaturesMatchExactly(signingDetails)) {
+                throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+                        "Existing signatures are inconsistent");
             }
-            final ApkLite existingBase = apkLiteResult.getResult();
-
-            assertApkConsistentLocked("Existing base", existingBase);
 
             // Inherit base if not overridden.
             if (mResolvedBaseFile == null) {
                 mResolvedBaseFile = new File(appInfo.getBaseCodePath());
                 inheritFileLocked(mResolvedBaseFile);
-                baseApk = existingBase;
             }
 
             // Inherit splits if not overridden.
@@ -2659,7 +2715,7 @@
                 }
             }
             // For the case of split required, failed if no splits existed
-            if (baseApk.isSplitRequired) {
+            if (packageLite.isSplitRequired) {
                 final int existingSplits = ArrayUtils.size(existing.splitNames);
                 final boolean allSplitsRemoved = (existingSplits == removeSplitList.size());
                 final boolean onlyBaseFileStaged = (stagedSplits.size() == 1
@@ -2670,7 +2726,7 @@
                 }
             }
         }
-        if (baseApk.useEmbeddedDex) {
+        if (packageLite.useEmbeddedDex) {
             for (File file : mResolvedStagedFiles) {
                 if (file.getName().endsWith(".apk")
                         && !DexManager.auditUncompressedDexInApk(file.getPath())) {
@@ -2683,7 +2739,7 @@
 
         final boolean isInstallerShell = (mInstallerUid == Process.SHELL_UID);
         if (isInstallerShell && isIncrementalInstallation() && mIncrementalFileStorages != null) {
-            if (!baseApk.debuggable && !baseApk.profilableByShell) {
+            if (!packageLite.debuggable && !packageLite.profilableByShell) {
                 mIncrementalFileStorages.disableReadLogs();
             }
         }
@@ -2838,26 +2894,43 @@
     @GuardedBy("mLock")
     private void assertApkConsistentLocked(String tag, ApkLite apk)
             throws PackageManagerException {
-        if (!mPackageName.equals(apk.packageName)) {
-            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
-                    + apk.packageName + " inconsistent with " + mPackageName);
-        }
-        if (params.appPackageName != null && !params.appPackageName.equals(apk.packageName)) {
-            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
-                    + " specified package " + params.appPackageName
-                    + " inconsistent with " + apk.packageName);
-        }
-        if (mVersionCode != apk.getLongVersionCode()) {
-            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
-                    + " version code " + apk.versionCode + " inconsistent with "
-                    + mVersionCode);
-        }
+        assertPackageConsistentLocked(tag, apk.packageName, apk.getLongVersionCode());
         if (!mSigningDetails.signaturesMatchExactly(apk.signingDetails)) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                     tag + " signatures are inconsistent");
         }
     }
 
+    @GuardedBy("mLock")
+    private void assertPackageConsistentLocked(String tag, String packageName,
+            long versionCode) throws PackageManagerException {
+        if (!mPackageName.equals(packageName)) {
+            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
+                    + packageName + " inconsistent with " + mPackageName);
+        }
+        if (params.appPackageName != null && !params.appPackageName.equals(packageName)) {
+            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
+                    + " specified package " + params.appPackageName
+                    + " inconsistent with " + packageName);
+        }
+        if (mVersionCode != versionCode) {
+            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
+                    + " version code " + versionCode + " inconsistent with "
+                    + mVersionCode);
+        }
+    }
+
+    private PackageParser.SigningDetails unsafeGetCertsWithoutVerification(String path)
+            throws PackageManagerException {
+        try {
+            return ApkSignatureVerifier.unsafeGetCertsWithoutVerification(path,
+                    PackageParser.SigningDetails.SignatureSchemeVersion.JAR);
+        } catch (PackageParserException e) {
+            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+                    "Couldn't obtain signatures from APK : " + path);
+        }
+    }
+
     /**
      * Determine if creating hard links between source and destination is
      * possible. That is, do they all live on the same underlying device.
@@ -2989,8 +3062,10 @@
         Slog.d(TAG, "Copied " + fromFiles.size() + " files into " + toDir);
     }
 
-    private void extractNativeLibraries(File packageDir, String abiOverride, boolean inherit)
+    private void extractNativeLibraries(PackageLite packageLite, File packageDir,
+            String abiOverride, boolean inherit)
             throws PackageManagerException {
+        Objects.requireNonNull(packageLite);
         final File libDir = new File(packageDir, NativeLibraryHelper.LIB_DIR_NAME);
         if (!inherit) {
             // Start from a clean slate
@@ -2999,7 +3074,7 @@
 
         NativeLibraryHelper.Handle handle = null;
         try {
-            handle = NativeLibraryHelper.Handle.create(packageDir);
+            handle = NativeLibraryHelper.Handle.create(packageLite);
             final int res = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libDir,
                     abiOverride, isIncrementalInstallation());
             if (res != INSTALL_SUCCEEDED) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8fc9cb7..72dad61 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -152,6 +152,7 @@
 import android.app.admin.IDevicePolicyManager;
 import android.app.admin.SecurityLog;
 import android.app.backup.IBackupManager;
+import android.app.role.RoleManager;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledAfter;
 import android.content.BroadcastReceiver;
@@ -379,6 +380,8 @@
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.permission.LegacyPermissionManagerInternal;
+import com.android.server.pm.permission.LegacyPermissionManagerService;
 import com.android.server.pm.permission.Permission;
 import com.android.server.pm.permission.PermissionManagerService;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
@@ -448,7 +451,6 @@
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
-import java.util.function.Supplier;
 
 /**
  * Keep track of all those APKs everywhere.
@@ -696,10 +698,15 @@
     public static final int REASON_FIRST_BOOT = 0;
     public static final int REASON_BOOT = 1;
     public static final int REASON_INSTALL = 2;
-    public static final int REASON_BACKGROUND_DEXOPT = 3;
-    public static final int REASON_AB_OTA = 4;
-    public static final int REASON_INACTIVE_PACKAGE_DOWNGRADE = 5;
-    public static final int REASON_SHARED = 6;
+    public static final int REASON_INSTALL_FAST = 3;
+    public static final int REASON_INSTALL_BULK = 4;
+    public static final int REASON_INSTALL_BULK_SECONDARY = 5;
+    public static final int REASON_INSTALL_BULK_DOWNGRADED = 6;
+    public static final int REASON_INSTALL_BULK_SECONDARY_DOWNGRADED = 7;
+    public static final int REASON_BACKGROUND_DEXOPT = 8;
+    public static final int REASON_AB_OTA = 9;
+    public static final int REASON_INACTIVE_PACKAGE_DOWNGRADE = 10;
+    public static final int REASON_SHARED = 11;
 
     public static final int REASON_LAST = REASON_SHARED;
 
@@ -732,8 +739,6 @@
     private static final int INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS = 7000;
     private static final int INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS = 60000;
 
-    final ServiceThread mHandlerThread;
-
     final Handler mHandler;
 
     private final ProcessLoggingHandler mProcessLoggingHandler;
@@ -761,12 +766,14 @@
     final Installer mInstaller;
 
     /** Directory where installed applications are stored */
-    private static final File sAppInstallDir =
-            new File(Environment.getDataDirectory(), "app");
+    private final File mAppInstallDir;
     /** Directory where installed application's 32-bit native libraries are copied. */
     @VisibleForTesting
-    static final File sAppLib32InstallDir =
-            new File(Environment.getDataDirectory(), "app-lib");
+    final File mAppLib32InstallDir;
+
+    private static File getAppLib32InstallDir() {
+        return new File(Environment.getDataDirectory(), "app-lib");
+    }
 
     // ----------------------------------------------------------------
 
@@ -832,6 +839,11 @@
 
     boolean mFirstBoot;
 
+    private final boolean mIsEngBuild;
+    private final boolean mIsUserDebugBuild;
+    private final String mIncrementalVersion;
+
+
     PackageManagerInternal.ExternalSourcesPolicy mExternalSourcesPolicy;
 
     @GuardedBy("mAvailableFeatures")
@@ -866,6 +878,8 @@
 
     private final Injector mInjector;
 
+    private final SystemWrapper mSystemWrapper;
+
     /**
      * The list of all system partitions that may contain packages in ascending order of
      * specificity (the more generic, the earlier in the list a partition appears).
@@ -896,6 +910,10 @@
             T produce(Injector injector, PackageManagerService packageManager);
         }
 
+        interface ProducerWithArgument<T, R> {
+            T produce(Injector injector, PackageManagerService packageManager, R argument);
+        }
+
         interface ServiceProducer {
             <T> T produce(Class<T> c);
         }
@@ -924,6 +942,8 @@
         private final Object mInstallLock;
         private final Handler mBackgroundHandler;
         private final Executor mBackgroundExecutor;
+        private final List<ScanPartition> mSystemPartitions;
+
 
         // ----- producers -----
         private final Singleton<ComponentResolver> mComponentResolverProducer;
@@ -940,13 +960,25 @@
         private final Singleton<ViewCompiler> mViewCompilerProducer;
         private final Singleton<IPermissionManager> mPermissionManagerProducer;
         private final Singleton<IncrementalManager> mIncrementalManagerProducer;
+        private final Singleton<DefaultAppProvider> mDefaultAppProviderProducer;
+        private final Singleton<DisplayMetrics> mDisplayMetricsProducer;
+        private final Producer<PackageParser2> mScanningCachingPackageParserProducer;
+        private final Producer<PackageParser2> mScanningPackageParserProducer;
+        private final Producer<PackageParser2> mPreparingPackageParserProducer;
+        private final Singleton<PackageInstallerService> mPackageInstallerServiceProducer;
+        private final ProducerWithArgument<InstantAppResolverConnection, ComponentName>
+                mInstantAppResolverConnectionProducer;
+        private final Singleton<LegacyPermissionManagerInternal>
+                mLegacyPermissionManagerInternalProducer;
         private final SystemWrapper mSystemWrapper;
         private final ServiceProducer mGetLocalServiceProducer;
         private final ServiceProducer mGetSystemServiceProducer;
+        private final Singleton<ModuleInfoProvider> mModuleInfoProviderProducer;
 
         Injector(Context context, Object lock, Installer installer,
                 Object installLock, PackageAbiHelper abiHelper,
                 Handler backgroundHandler,
+                List<ScanPartition> systemPartitions,
                 Producer<ComponentResolver> componentResolverProducer,
                 Producer<PermissionManagerServiceInternal> permissionManagerServiceProducer,
                 Producer<UserManagerService> userManagerProducer,
@@ -961,6 +993,16 @@
                 Producer<IPermissionManager> permissionManagerProducer,
                 Producer<ViewCompiler> viewCompilerProducer,
                 Producer<IncrementalManager> incrementalManagerProducer,
+                Producer<DefaultAppProvider> defaultAppProviderProducer,
+                Producer<DisplayMetrics> displayMetricsProducer,
+                Producer<PackageParser2> scanningCachingPackageParserProducer,
+                Producer<PackageParser2> scanningPackageParserProducer,
+                Producer<PackageParser2> preparingPackageParserProducer,
+                Producer<PackageInstallerService> packageInstallerServiceProducer,
+                ProducerWithArgument<InstantAppResolverConnection, ComponentName> 
+                        instantAppResolverConnectionProducer,
+                Producer<ModuleInfoProvider> moduleInfoProviderProducer,
+                Producer<LegacyPermissionManagerInternal> legacyPermissionManagerInternalProducer,
                 SystemWrapper systemWrapper,
                 ServiceProducer getLocalServiceProducer,
                 ServiceProducer getSystemServiceProducer) {
@@ -971,6 +1013,7 @@
             mInstallLock = installLock;
             mBackgroundHandler = backgroundHandler;
             mBackgroundExecutor = new HandlerExecutor(backgroundHandler);
+            mSystemPartitions = systemPartitions;
             mComponentResolverProducer = new Singleton<>(componentResolverProducer);
             mPermissionManagerServiceProducer = new Singleton<>(permissionManagerServiceProducer);
             mUserManagerProducer = new Singleton<>(userManagerProducer);
@@ -985,6 +1028,16 @@
             mPermissionManagerProducer = new Singleton<>(permissionManagerProducer);
             mViewCompilerProducer = new Singleton<>(viewCompilerProducer);
             mIncrementalManagerProducer = new Singleton<>(incrementalManagerProducer);
+            mDefaultAppProviderProducer = new Singleton<>(defaultAppProviderProducer);
+            mDisplayMetricsProducer = new Singleton<>(displayMetricsProducer);
+            mScanningCachingPackageParserProducer = scanningCachingPackageParserProducer;
+            mScanningPackageParserProducer = scanningPackageParserProducer;
+            mPreparingPackageParserProducer = preparingPackageParserProducer;
+            mPackageInstallerServiceProducer = new Singleton<>(packageInstallerServiceProducer);
+            mInstantAppResolverConnectionProducer = instantAppResolverConnectionProducer;
+            mModuleInfoProviderProducer = new Singleton<>(moduleInfoProviderProducer);
+            mLegacyPermissionManagerInternalProducer = new Singleton<>(
+                    legacyPermissionManagerInternalProducer);
             mSystemWrapper = systemWrapper;
             mGetLocalServiceProducer = getLocalServiceProducer;
             mGetSystemServiceProducer = getSystemServiceProducer;
@@ -1010,6 +1063,10 @@
             return mInstallLock;
         }
 
+        public List<ScanPartition> getSystemPartitions() {
+            return mSystemPartitions;
+        }
+
         public UserManagerService getUserManagerService() {
             return mUserManagerProducer.get(this, mPackageManager);
         }
@@ -1082,6 +1139,10 @@
             return mBackgroundExecutor;
         }
 
+        public DisplayMetrics getDisplayMetrics() {
+            return mDisplayMetricsProducer.get(this, mPackageManager);
+        }
+
         public <T> T getLocalService(Class<T> c) {
             return mGetLocalServiceProducer.produce(c);
         }
@@ -1097,53 +1158,67 @@
         public IncrementalManager getIncrementalManager() {
             return mIncrementalManagerProducer.get(this, mPackageManager);
         }
+
+        public DefaultAppProvider getDefaultAppProvider() {
+            return mDefaultAppProviderProducer.get(this, mPackageManager);
+        }
+
+        public PackageParser2 getScanningCachingPackageParser() {
+            return mScanningCachingPackageParserProducer.produce(this, mPackageManager);
+        }
+        public PackageParser2 getScanningPackageParser() {
+            return mScanningPackageParserProducer.produce(this, mPackageManager);
+        }
+        public PackageParser2 getPreparingPackageParser() {
+            return mPreparingPackageParserProducer.produce(this, mPackageManager);
+        }
+
+        public PackageInstallerService getPackageInstallerService() {
+            return mPackageInstallerServiceProducer.get(this, mPackageManager);
+        }
+
+        public InstantAppResolverConnection getInstantAppResolverConnection(
+                ComponentName instantAppResolverComponent) {
+            return mInstantAppResolverConnectionProducer.produce(
+                    this, mPackageManager, instantAppResolverComponent);
+        }
+
+        public ModuleInfoProvider getModuleInfoProvider() {
+            return mModuleInfoProviderProducer.get(this, mPackageManager);
+        }
+
+        public LegacyPermissionManagerInternal getLegacyPermissionManagerInternal() {
+            return mLegacyPermissionManagerInternalProducer.get(this, mPackageManager);
+        }
     }
 
     /** Provides an abstraction to static access to system state. */
     public interface SystemWrapper {
-        /** @see SystemProperties#get(String) */
-        String getProperty(String key);
-        /** @see SystemProperties#getInt(String, int) */
-        int getPropertyInt(String key, int defValue);
-        /** @see SystemProperties#getBoolean(String, boolean) */
-        boolean getPropertyBoolean(String key, boolean defValue);
-        /** @see SystemProperties#digestOf(String...) */
-        String digestOfProperties(@NonNull String... keys);
-        /** @see SystemProperties#set(String, String) */
-        void setProperty(String key, String value);
-        /** @see Build.VERSION#SDK_INT */
-        int getSdkInt();
+        void disablePackageCaches();
+        void enablePackageCaches();
     }
 
     private static class DefaultSystemWrapper implements SystemWrapper {
+
         @Override
-        public String getProperty(String key) {
-            return SystemProperties.get(key);
+        public void disablePackageCaches() {
+            // disable all package caches that shouldn't apply within system server
+            PackageManager.disableApplicationInfoCache();
+            PackageManager.disablePackageInfoCache();
+            ApplicationPackageManager.invalidateGetPackagesForUidCache();
+            ApplicationPackageManager.disableGetPackagesForUidCache();
+            ApplicationPackageManager.invalidateHasSystemFeatureCache();
+
+            // Avoid invalidation-thrashing by preventing cache invalidations from causing property
+            // writes if the cache isn't enabled yet.  We re-enable writes later when we're
+            // done initializing.
+            PackageManager.corkPackageInfoCache();
         }
 
         @Override
-        public int getPropertyInt(String key, int defValue) {
-            return SystemProperties.getInt(key, defValue);
-        }
-
-        @Override
-        public boolean getPropertyBoolean(String key, boolean defValue) {
-            return SystemProperties.getBoolean(key, defValue);
-        }
-
-        @Override
-        public String digestOfProperties(String... keys) {
-            return SystemProperties.digestOf(keys);
-        }
-
-        @Override
-        public void setProperty(String key, String value) {
-            SystemProperties.set(key, value);
-        }
-
-        @Override
-        public int getSdkInt() {
-            return Build.VERSION.SDK_INT;
+        public void enablePackageCaches() {
+            // Uncork cache invalidations and allow clients to cache package information.
+            PackageManager.uncorkPackageInfoCache();
         }
     }
 
@@ -1154,13 +1229,13 @@
         public ArtManagerService artManagerService;
         public @Nullable String configuratorPackage;
         public int defParseFlags;
+        public DefaultAppProvider defaultAppProvider;
         public DexManager dexManager;
         public List<ScanPartition> dirsToScanAsSystem;
         public @Nullable String documenterPackage;
         public boolean factoryTest;
         public ArrayMap<String, FeatureInfo> availableFeatures;
         public Handler handler;
-        public ServiceThread handlerThread;
         public @Nullable String incidentReportApproverPackage;
         public IncrementalManager incrementalManager;
         public PackageInstallerService installerService;
@@ -1173,6 +1248,7 @@
         public boolean isPreNupgrade;
         public boolean isPreQupgrade;
         public boolean isUpgrade;
+        public LegacyPermissionManagerInternal legacyPermissionManagerInternal;
         public DisplayMetrics Metrics;
         public ModuleInfoProvider moduleInfoProvider;
         public MoveCallbacks moveCallbacks;
@@ -1206,6 +1282,13 @@
         public ArrayMap<String, AndroidPackage> packages;
         public boolean enableFreeCacheV2;
         public int sdkVersion;
+        public SystemWrapper systemWrapper;
+        public File appInstallDir;
+        public File appLib32InstallDir;
+        public boolean isEngBuild;
+        public boolean isUserDebugBuild;
+        public int sdkInt = Build.VERSION.SDK_INT;
+        public String incrementalVersion = Build.VERSION.INCREMENTAL;
     }
 
     private final AppsFilter mAppsFilter;
@@ -1307,6 +1390,10 @@
 
     private final IncrementalManager mIncrementalManager;
 
+    private final DefaultAppProvider mDefaultAppProvider;
+
+    private final LegacyPermissionManagerInternal mLegacyPermissionManager;
+
     private final PackageProperty mPackageProperty = new PackageProperty();
 
     private static class IFVerificationParams {
@@ -1803,7 +1890,7 @@
                             for (int index = 0; i < size && index < numComponents; index++) {
                                 packages[i] = componentsToBroadcast.keyAt(index);
                                 components[i] = componentsToBroadcast.valueAt(index);
-                                final PackageSetting ps = mSettings.mPackages.get(packages[i]);
+                                final PackageSetting ps = mSettings.getPackageLPr(packages[i]);
                                 uids[i] = (ps != null)
                                         ? UserHandle.getUid(packageUserId, ps.appId)
                                         : -1;
@@ -2310,7 +2397,7 @@
                 synchronized (mLock) {
                     newBroadcastAllowList = mAppsFilter.getVisibilityAllowList(
                             getPackageSettingInternal(res.name, Process.SYSTEM_UID),
-                            updateUserIds, mSettings.mPackages);
+                            updateUserIds, mSettings.getPackagesLocked());
                 }
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
                         extras, 0 /*flags*/,
@@ -2747,6 +2834,7 @@
         Injector injector = new Injector(
                 context, lock, installer, installLock, new PackageAbiHelperImpl(),
                 backgroundHandler,
+                SYSTEM_PARTITIONS,
                 (i, pm) -> new ComponentResolver(i.getUserManagerService(), pm.mPmInternal, lock),
                 (i, pm) -> PermissionManagerService.create(context),
                 (i, pm) -> new UserManagerService(context, pm,
@@ -2768,12 +2856,38 @@
                 (i, pm) -> (IPermissionManager) ServiceManager.getService("permissionmgr"),
                 (i, pm) -> new ViewCompiler(i.getInstallLock(), i.getInstaller()),
                 (i, pm) -> (IncrementalManager)
-                        pm.mContext.getSystemService(Context.INCREMENTAL_SERVICE),
+                        i.getContext().getSystemService(Context.INCREMENTAL_SERVICE),
+                (i, pm) -> new DefaultAppProvider(() -> context.getSystemService(
+                        RoleManager.class)),
+                (i, pm) -> new DisplayMetrics(),
+                (i, pm) -> new PackageParser2(pm.mSeparateProcesses, pm.mOnlyCore,
+                        i.getDisplayMetrics(), pm.mCacheDir,
+                        pm.mPackageParserCallback) /* scanningCachingPackageParserProducer */,
+                (i, pm) -> new PackageParser2(pm.mSeparateProcesses, pm.mOnlyCore,
+                        i.getDisplayMetrics(), null,
+                        pm.mPackageParserCallback) /* scanningPackageParserProducer */,
+                (i, pm) -> new PackageParser2(pm.mSeparateProcesses, false, i.getDisplayMetrics(),
+                        null, pm.mPackageParserCallback) /* preparingPackageParserProducer */,
+                // Prepare a supplier of package parser for the staging manager to parse apex file
+                // during the staging installation.
+                (i, pm) -> new PackageInstallerService(
+                        i.getContext(), pm, i::getScanningPackageParser),
+                (i, pm, cn) -> new InstantAppResolverConnection(
+                        i.getContext(), cn, Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE),
+                (i, pm) -> new ModuleInfoProvider(i.getContext(), pm),
+                (i, pm) -> LegacyPermissionManagerService.create(i.getContext()),
                 new DefaultSystemWrapper(),
                 LocalServices::getService,
                 context::getSystemService);
 
-        PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest);
+
+        if (Build.VERSION.SDK_INT <= 0) {
+            Slog.w(TAG, "**** ro.build.version.sdk not set!");
+        }
+
+        PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest,
+                Build.FINGERPRINT, Build.IS_ENG, Build.IS_USERDEBUG, Build.VERSION.SDK_INT,
+                Build.VERSION.INCREMENTAL);
         t.traceEnd(); // "create package manager"
 
         final CompatChange.ChangeListener selinuxChangeListener = packageName -> {
@@ -2833,11 +2947,6 @@
         }
     }
 
-    private static void getDefaultDisplayMetrics(
-            DisplayManager displayManager, DisplayMetrics metrics) {
-        displayManager.getDisplay(Display.DEFAULT_DISPLAY).getMetrics(metrics);
-    }
-
     /**
      * Requests that files preopted on a secondary system partition be copied to the data partition
      * if possible.  Note that the actual copying of the files is accomplished by init for security
@@ -2847,14 +2956,13 @@
     private static void requestCopyPreoptedFiles(Injector injector) {
         final int WAIT_TIME_MS = 100;
         final String CP_PREOPT_PROPERTY = "sys.cppreopt";
-        if (injector.getSystemWrapper().getPropertyInt("ro.cp_system_other_odex", 0) == 1) {
-            injector.getSystemWrapper().setProperty(CP_PREOPT_PROPERTY, "requested");
+        if (SystemProperties.getInt("ro.cp_system_other_odex", 0) == 1) {
+            SystemProperties.set(CP_PREOPT_PROPERTY, "requested");
             // We will wait for up to 100 seconds.
             final long timeStart = SystemClock.uptimeMillis();
             final long timeEnd = timeStart + 100 * 1000;
             long timeNow = timeStart;
-            while (!injector.getSystemWrapper()
-                    .getProperty(CP_PREOPT_PROPERTY).equals("finished")) {
+            while (!SystemProperties.get(CP_PREOPT_PROPERTY).equals("finished")) {
                 try {
                     Thread.sleep(WAIT_TIME_MS);
                 } catch (InterruptedException e) {
@@ -2862,7 +2970,7 @@
                 }
                 timeNow = SystemClock.uptimeMillis();
                 if (timeNow > timeEnd) {
-                    injector.getSystemWrapper().setProperty(CP_PREOPT_PROPERTY, "timed-out");
+                    SystemProperties.set(CP_PREOPT_PROPERTY, "timed-out");
                     Slog.wtf(TAG, "cppreopt did not finish!");
                     break;
                 }
@@ -2939,16 +3047,16 @@
         mPermissionManager = injector.getPermissionManagerServiceInternal();
         mSettings = injector.getSettings();
         mUserManager = injector.getUserManagerService();
-
         mApexManager = testParams.apexManager;
         mArtManagerService = testParams.artManagerService;
         mAvailableFeatures = testParams.availableFeatures;
         mDefParseFlags = testParams.defParseFlags;
+        mDefaultAppProvider = testParams.defaultAppProvider;
+        mLegacyPermissionManager = testParams.legacyPermissionManagerInternal;
         mDexManager = testParams.dexManager;
         mDirsToScanAsSystem = testParams.dirsToScanAsSystem;
         mFactoryTest = testParams.factoryTest;
         mHandler = testParams.handler;
-        mHandlerThread = testParams.handlerThread;
         mIncrementalManager = testParams.incrementalManager;
         mInstallerService = testParams.installerService;
         mInstantAppRegistry = testParams.instantAppRegistry;
@@ -2993,49 +3101,46 @@
         mServicesExtensionPackageName = testParams.servicesExtensionPackageName;
         mSharedSystemSharedLibraryPackageName = testParams.sharedSystemSharedLibraryPackageName;
         mOverlayConfigSignaturePackage = testParams.overlayConfigSignaturePackage;
-
         mResolveComponentName = testParams.resolveComponentName;
         mPackages.putAll(testParams.packages);
         mEnableFreeCacheV2 = testParams.enableFreeCacheV2;
         mSdkVersion = testParams.sdkVersion;
+        mSystemWrapper = testParams.systemWrapper;
+        mAppInstallDir = testParams.appInstallDir;
+        mAppLib32InstallDir = testParams.appLib32InstallDir;
+        mIsEngBuild = testParams.isEngBuild;
+        mIsUserDebugBuild = testParams.isUserDebugBuild;
+        mIncrementalVersion = testParams.incrementalVersion;
     }
 
-    public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) {
-        PackageManager.disableApplicationInfoCache();
-        PackageManager.disablePackageInfoCache();
-        ApplicationPackageManager.invalidateGetPackagesForUidCache();
-        ApplicationPackageManager.disableGetPackagesForUidCache();
-        ApplicationPackageManager.invalidateHasSystemFeatureCache();
-
-        // Avoid invalidation-thrashing by preventing cache invalidations from causing property
-        // writes if the cache isn't enabled yet.  We re-enable writes later when we're
-        // done initializing.
-        PackageManager.corkPackageInfoCache();
+    public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest,
+            final String buildFingerprint, final boolean isEngBuild,
+            final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {
+        mIsEngBuild = isEngBuild;
+        mIsUserDebugBuild = isUserDebugBuild;
+        mSdkVersion = sdkVersion;
+        mIncrementalVersion = incrementalVersion;
+        mInjector = injector;
+        mInjector.getSystemWrapper().disablePackageCaches();
 
         final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
                 Trace.TRACE_TAG_PACKAGE_MANAGER);
         mPendingBroadcasts = new PendingPackageBroadcasts();
 
-        mInjector = injector;
         mInjector.bootstrap(this);
         mLock = injector.getLock();
         mInstallLock = injector.getInstallLock();
         LockGuard.installLock(mLock, LockGuard.INDEX_PACKAGES);
         EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
                 SystemClock.uptimeMillis());
-        mSdkVersion = injector.getSystemWrapper().getSdkInt();
-
-        if (mSdkVersion <= 0) {
-            Slog.w(TAG, "**** ro.build.version.sdk not set!");
-        }
+        mSystemWrapper = injector.getSystemWrapper();
 
         mContext = injector.getContext();
         mFactoryTest = factoryTest;
         mOnlyCore = onlyCore;
-        mMetrics = new DisplayMetrics();
+        mMetrics = injector.getDisplayMetrics();
         mInstaller = injector.getInstaller();
-        mEnableFreeCacheV2 =
-                injector.getSystemWrapper().getPropertyBoolean("fw.free_cache_v2", true);
+        mEnableFreeCacheV2 = SystemProperties.getBoolean("fw.free_cache_v2", true);
 
         // Create sub-components that provide services / data. Order here is important.
         t.traceBegin("createSubComponents");
@@ -3051,6 +3156,8 @@
         mSettings = injector.getSettings();
         mPermissionManagerService = injector.getPermissionManagerService();
         mIncrementalManager = mInjector.getIncrementalManager();
+        mDefaultAppProvider = mInjector.getDefaultAppProvider();
+        mLegacyPermissionManager = mInjector.getLegacyPermissionManagerInternal();
         PlatformCompat platformCompat = mInjector.getCompatibility();
         mPackageParserCallback = new PackageParser2.Callback() {
             @Override
@@ -3086,8 +3193,8 @@
                 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
         t.traceEnd();
 
-        String separateProcesses =
-                injector.getSystemWrapper().getProperty("debug.separate_processes");
+        String separateProcesses = SystemProperties.get("debug.separate_processes");
+
         if (separateProcesses != null && separateProcesses.length() > 0) {
             if ("*".equals(separateProcesses)) {
                 mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES;
@@ -3110,7 +3217,8 @@
         mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
         mViewCompiler = injector.getViewCompiler();
 
-        getDefaultDisplayMetrics(mInjector.getSystemService(DisplayManager.class), mMetrics);
+        mContext.getSystemService(DisplayManager.class)
+                .getDisplay(Display.DEFAULT_DISPLAY).getMetrics(mMetrics);
 
         t.traceBegin("get system config");
         SystemConfig systemConfig = injector.getSystemConfig();
@@ -3132,18 +3240,21 @@
         }
 
         mDirsToScanAsSystem = new ArrayList<>();
-        mDirsToScanAsSystem.addAll(SYSTEM_PARTITIONS);
+        mDirsToScanAsSystem.addAll(injector.getSystemPartitions());
         mDirsToScanAsSystem.addAll(scanPartitions);
         Slog.d(TAG, "Directories scanned as system partitions: " + mDirsToScanAsSystem);
 
+        mAppInstallDir = new File(Environment.getDataDirectory(), "app");
+        mAppLib32InstallDir = getAppLib32InstallDir();
+
         // CHECKSTYLE:OFF IndentationCheck
         synchronized (mInstallLock) {
         // writer
         synchronized (mLock) {
-            mHandlerThread = new ServiceThread(TAG,
+            HandlerThread handlerThread = new ServiceThread(TAG,
                     Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
-            mHandlerThread.start();
-            mHandler = new PackageHandler(mHandlerThread.getLooper());
+            handlerThread.start();
+            mHandler = new PackageHandler(handlerThread.getLooper());
             mProcessLoggingHandler = new ProcessLoggingHandler();
             Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
             mInstantAppRegistry = new InstantAppRegistry(this, mPermissionManager);
@@ -3188,12 +3299,13 @@
 
             // Clean up orphaned packages for which the code path doesn't exist
             // and they are an update to a system app - caused by bug/32321269
-            final int packageSettingCount = mSettings.mPackages.size();
+            final ArrayMap<String, PackageSetting> packageSettings = mSettings.getPackagesLocked();
+            final int packageSettingCount = packageSettings.size();
             for (int i = packageSettingCount - 1; i >= 0; i--) {
-                PackageSetting ps = mSettings.mPackages.valueAt(i);
+                PackageSetting ps = packageSettings.valueAt(i);
                 if (!isExternal(ps) && (ps.getPath() == null || !ps.getPath().exists())
                         && mSettings.getDisabledSystemPkgLPr(ps.name) != null) {
-                    mSettings.mPackages.removeAt(i);
+                    packageSettings.removeAt(i);
                     mSettings.enableSystemPackageLPw(ps.name);
                 }
             }
@@ -3228,9 +3340,10 @@
             File frameworkDir = new File(Environment.getRootDirectory(), "framework");
 
             final VersionInfo ver = mSettings.getInternalVersion();
-            mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);
+            mIsUpgrade =
+                    !buildFingerprint.equals(ver.fingerprint);
             if (mIsUpgrade) {
-                logCriticalInfo(Log.INFO,
+                PackageManagerServiceUtils.logCriticalInfo(Log.INFO,
                         "Upgrading from " + ver.fingerprint + " to " + Build.FINGERPRINT);
             }
 
@@ -3248,13 +3361,13 @@
             // Save the names of pre-existing packages prior to scanning, so we can determine
             // which system packages are completely new due to an upgrade.
             if (isDeviceUpgrading()) {
-                mExistingPackages = new ArraySet<>(mSettings.mPackages.size());
-                for (PackageSetting ps : mSettings.mPackages.values()) {
+                mExistingPackages = new ArraySet<>(packageSettings.size());
+                for (PackageSetting ps : packageSettings.values()) {
                     mExistingPackages.add(ps.name);
                 }
             }
 
-            mCacheDir = preparePackageParserCache(injector);
+            mCacheDir = preparePackageParserCache(mIsEngBuild);
 
             // Set flag to monitor and not change apk file paths when
             // scanning install directories.
@@ -3267,8 +3380,7 @@
             final int systemParseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR;
             final int systemScanFlags = scanFlags | SCAN_AS_SYSTEM;
 
-            PackageParser2 packageParser = new PackageParser2(mSeparateProcesses, mOnlyCore,
-                    mMetrics, mCacheDir, mPackageParserCallback);
+            PackageParser2 packageParser = injector.getScanningCachingPackageParser();
 
             ExecutorService executorService = ParallelPackageParser.makeExecutorService();
             // Prepare apex package info before scanning APKs, these information are needed when
@@ -3331,8 +3443,8 @@
 
                 // Iterates PackageSettings in reversed order because the item could be removed
                 // during the iteration.
-                for (int index = mSettings.mPackages.size() - 1; index >= 0; index--) {
-                    final PackageSetting ps = mSettings.mPackages.valueAt(index);
+                for (int index = packageSettings.size() - 1; index >= 0; index--) {
+                    final PackageSetting ps = packageSettings.valueAt(index);
 
                     /*
                      * If this is not a system app, it can't be a
@@ -3413,7 +3525,7 @@
             if (!mOnlyCore) {
                 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                         SystemClock.uptimeMillis());
-                scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
+                scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
                         packageParser, executorService);
 
             }
@@ -3470,7 +3582,7 @@
                     // previously scanned and known to the system], but, we don't have
                     // a package [ie. there was an error scanning it from the /data
                     // partition], completely remove the package data.
-                    final PackageSetting ps = mSettings.mPackages.get(packageName);
+                    final PackageSetting ps = mSettings.getPackageLPr(packageName);
                     if (ps != null && mPackages.get(packageName) == null) {
                         removePackageDataLIF(ps, userIds, null, 0, false);
 
@@ -3596,7 +3708,7 @@
 
             // Now that we know all the packages we are keeping,
             // read and update their last usage times.
-            mPackageUsage.read(mSettings.mPackages);
+            mPackageUsage.read(packageSettings);
             mCompilerStats.read();
 
             EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
@@ -3689,8 +3801,8 @@
             // profile compilation (without waiting to collect a fresh set of profiles).
             if (mIsUpgrade && !mOnlyCore) {
                 Slog.i(TAG, "Build fingerprint changed; clearing code caches");
-                for (int i = 0; i < mSettings.mPackages.size(); i++) {
-                    final PackageSetting ps = mSettings.mPackages.valueAt(i);
+                for (int i = 0; i < packageSettings.size(); i++) {
+                    final PackageSetting ps = packageSettings.valueAt(i);
                     if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) {
                         // No apps are running this early, so no need to freeze
                         clearAppDataLIF(ps.pkg, UserHandle.USER_ALL,
@@ -3706,9 +3818,9 @@
             // their icons in launcher.
             if (!mOnlyCore && mIsPreQUpgrade) {
                 Slog.i(TAG, "Whitelisting all existing apps to hide their icons");
-                int size = mSettings.mPackages.size();
+                int size = packageSettings.size();
                 for (int i = 0; i < size; i++) {
-                    final PackageSetting ps = mSettings.mPackages.valueAt(i);
+                    final PackageSetting ps = packageSettings.valueAt(i);
                     if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
                         continue;
                     }
@@ -3777,23 +3889,16 @@
                 }
             }
 
-            // Prepare a supplier of package parser for the staging manager to parse apex file
-            // during the staging installation.
-            final Supplier<PackageParser2> apexParserSupplier = () -> new PackageParser2(
-                    mSeparateProcesses, mOnlyCore, mMetrics, null /* cacheDir */,
-                    mPackageParserCallback);
-            mInstallerService = new PackageInstallerService(mContext, this, apexParserSupplier);
-            final Pair<ComponentName, String> instantAppResolverComponent =
-                    getInstantAppResolverLPr();
+            mInstallerService = mInjector.getPackageInstallerService();
+            final ComponentName instantAppResolverComponent = getInstantAppResolverLPr();
             if (instantAppResolverComponent != null) {
                 if (DEBUG_INSTANT) {
                     Slog.d(TAG, "Set ephemeral resolver: " + instantAppResolverComponent);
                 }
-                mInstantAppResolverConnection = new InstantAppResolverConnection(
-                        mContext, instantAppResolverComponent.first,
-                        instantAppResolverComponent.second);
+                mInstantAppResolverConnection =
+                        mInjector.getInstantAppResolverConnection(instantAppResolverComponent);
                 mInstantAppResolverSettingsComponent =
-                        getInstantAppResolverSettingsLPr(instantAppResolverComponent.first);
+                        getInstantAppResolverSettingsLPr(instantAppResolverComponent);
             } else {
                 mInstantAppResolverConnection = null;
                 mInstantAppResolverSettingsComponent = null;
@@ -3823,10 +3928,8 @@
         } // synchronized (mInstallLock)
         // CHECKSTYLE:ON IndentationCheck
 
-        mModuleInfoProvider = new ModuleInfoProvider(mContext, this);
-
-        // Uncork cache invalidations and allow clients to cache package information.
-        PackageManager.uncorkPackageInfoCache();
+        mModuleInfoProvider = mInjector.getModuleInfoProvider();
+        mInjector.getSystemWrapper().enablePackageCaches();
 
         // Now after opening every single application zip, make sure they
         // are all flushed.  Not really needed, but keeps things nice and
@@ -3874,7 +3977,7 @@
                 continue;
             }
             // skip if the package has been disabled by the user
-            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            final PackageSetting ps = mSettings.getPackageLPr(packageName);
             if (ps != null) {
                 final int enabledState = ps.getEnabled(UserHandle.USER_SYSTEM);
                 if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
@@ -3899,7 +4002,7 @@
         // disable any stub still left; these failed to install the full application
         for (int i = systemStubPackageNames.size() - 1; i >= 0; --i) {
             final String pkgName = systemStubPackageNames.get(i);
-            final PackageSetting ps = mSettings.mPackages.get(pkgName);
+            final PackageSetting ps = mSettings.getPackageLPr(pkgName);
             ps.setEnabled(PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                     UserHandle.USER_SYSTEM, "android");
             logCriticalInfo(Log.ERROR, "Stub disabled; pkg: " + pkgName);
@@ -3956,7 +4059,7 @@
                 } finally {
                     // Disable the package; the stub by itself is not runnable
                     synchronized (mLock) {
-                        final PackageSetting stubPs = mSettings.mPackages.get(
+                        final PackageSetting stubPs = mSettings.getPackageLPr(
                                 stubPkg.getPackageName());
                         if (stubPs != null) {
                             stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED,
@@ -4076,19 +4179,18 @@
         setUpInstantAppInstallerActivityLP(getInstantAppInstallerLPr());
     }
 
-    private static @Nullable File preparePackageParserCache(Injector injector) {
+    private @Nullable File preparePackageParserCache(boolean forEngBuild) {
         if (!FORCE_PACKAGE_PARSED_CACHE_ENABLED) {
             if (!DEFAULT_PACKAGE_PARSER_CACHE_ENABLED) {
                 return null;
             }
 
             // Disable package parsing on eng builds to allow for faster incremental development.
-            if (Build.IS_ENG) {
+            if (forEngBuild) {
                 return null;
             }
 
-            if (injector.getSystemWrapper()
-                    .getPropertyBoolean("pm.boot.disable_package_cache", false)) {
+            if (SystemProperties.getBoolean("pm.boot.disable_package_cache", false)) {
                 Slog.i(TAG, "Disabling package parser cache due to system property.");
                 return null;
             }
@@ -4104,8 +4206,7 @@
         // identify cached items. In particular, changing the value of certain
         // feature flags should cause us to invalidate any caches.
         final String cacheName = FORCE_PACKAGE_PARSED_CACHE_ENABLED ? "debug"
-                : injector.getSystemWrapper().digestOfProperties(
-                        "ro.build.fingerprint");
+                : SystemProperties.digestOf("ro.build.fingerprint");
 
         // Reconcile cache directories, keeping only what we'd actually use.
         for (File cacheDir : FileUtils.listFilesOrEmpty(cacheBaseDir)) {
@@ -4134,14 +4235,15 @@
         // NOTE: When no BUILD_NUMBER is set by the build system, it defaults to a build
         // that starts with "eng." to signify that this is an engineering build and not
         // destined for release.
-        if (Build.IS_USERDEBUG && Build.VERSION.INCREMENTAL.startsWith("eng.")) {
+        if (mIsUserDebugBuild && mIncrementalVersion.startsWith("eng.")) {
             Slog.w(TAG, "Wiping cache directory because the system partition changed.");
 
             // Heuristic: If the /system directory has been modified recently due to an "adb sync"
             // or a regular make, then blow away the cache. Note that mtimes are *NOT* reliable
             // in general and should not be used for production changes. In this specific case,
             // we know that they will work.
-            File frameworkDir = new File(Environment.getRootDirectory(), "framework");
+            File frameworkDir =
+                    new File(Environment.getRootDirectory(), "framework");
             if (cacheDir.lastModified() < frameworkDir.lastModified()) {
                 FileUtils.deleteContents(cacheBaseDir);
                 cacheDir = FileUtils.createDir(cacheBaseDir, cacheName);
@@ -4167,7 +4269,7 @@
     public boolean isDeviceUpgrading() {
         // allow instant applications
         // The system property allows testing ota flow when upgraded to the same image.
-        return mIsUpgrade || mInjector.getSystemWrapper().getPropertyBoolean(
+        return mIsUpgrade || SystemProperties.getBoolean(
                 "persist.pm.mock-upgrade", false /* default */);
     }
 
@@ -4301,15 +4403,15 @@
             return null;
         }
         synchronized (mLock) {
-            final Pair<ComponentName, String> instantAppResolver = getInstantAppResolverLPr();
+            final ComponentName instantAppResolver = getInstantAppResolverLPr();
             if (instantAppResolver == null) {
                 return null;
             }
-            return instantAppResolver.first;
+            return instantAppResolver;
         }
     }
 
-    private @Nullable Pair<ComponentName, String> getInstantAppResolverLPr() {
+    private @Nullable ComponentName getInstantAppResolverLPr() {
         final String[] packageArray =
                 mContext.getResources().getStringArray(R.array.config_ephemeralResolverPackage);
         if (packageArray.length == 0 && !Build.IS_DEBUGGABLE) {
@@ -4324,8 +4426,7 @@
                 MATCH_DIRECT_BOOT_AWARE
                 | MATCH_DIRECT_BOOT_UNAWARE
                 | (!Build.IS_DEBUGGABLE ? MATCH_SYSTEM_ONLY : 0);
-        String actionName = Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE;
-        final Intent resolverIntent = new Intent(actionName);
+        final Intent resolverIntent = new Intent(Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE);
         List<ResolveInfo> resolvers = queryIntentServicesInternal(resolverIntent, null,
                 resolveFlags, UserHandle.USER_SYSTEM, callingUid, false /*includeInstantApps*/);
         final int N = resolvers.size();
@@ -4357,7 +4458,7 @@
                 Slog.v(TAG, "Ephemeral resolver found;"
                         + " pkg: " + packageName + ", info:" + info);
             }
-            return new Pair<>(new ComponentName(packageName, info.serviceInfo.name), actionName);
+            return new ComponentName(packageName, info.serviceInfo.name);
         }
         if (DEBUG_INSTANT) {
             Slog.v(TAG, "Ephemeral resolver NOT found");
@@ -4367,7 +4468,7 @@
 
     @GuardedBy("mLock")
     private @Nullable ActivityInfo getInstantAppInstallerLPr() {
-        String[] orderedActions = Build.IS_ENG
+        String[] orderedActions = mIsEngBuild
                 ? new String[]{
                         Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE + "_TEST",
                         Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE}
@@ -4378,7 +4479,7 @@
                 MATCH_DIRECT_BOOT_AWARE
                         | MATCH_DIRECT_BOOT_UNAWARE
                         | Intent.FLAG_IGNORE_EPHEMERAL
-                        | (!Build.IS_ENG ? MATCH_SYSTEM_ONLY : 0);
+                        | (mIsEngBuild ? 0 : MATCH_SYSTEM_ONLY);
         final Intent intent = new Intent();
         intent.addCategory(Intent.CATEGORY_DEFAULT);
         intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
@@ -4398,8 +4499,9 @@
         Iterator<ResolveInfo> iter = matches.iterator();
         while (iter.hasNext()) {
             final ResolveInfo rInfo = iter.next();
-            if (checkPermission(Manifest.permission.INSTALL_PACKAGES,
-                    rInfo.activityInfo.packageName, 0) == PERMISSION_GRANTED || Build.IS_ENG) {
+            if (checkPermission(
+                    Manifest.permission.INSTALL_PACKAGES,
+                    rInfo.activityInfo.packageName, 0) == PERMISSION_GRANTED || mIsEngBuild) {
                 continue;
             }
             iter.remove();
@@ -4627,7 +4729,7 @@
         enforceCrossUserPermission(callingUid, userId, false, false, "checkPackageStartable");
         final boolean userKeyUnlocked = StorageManager.isUserKeyUnlocked(userId);
         synchronized (mLock) {
-            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            final PackageSetting ps = mSettings.getPackageLPr(packageName);
             if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
                 throw new SecurityException("Package " + packageName + " was not found!");
             }
@@ -4743,7 +4845,7 @@
                 return generatePackageInfo(ps, flags, userId);
             }
             if (!matchFactoryOnly && (flags & MATCH_KNOWN_PACKAGES) != 0) {
-                final PackageSetting ps = mSettings.mPackages.get(packageName);
+                final PackageSetting ps = mSettings.getPackageLPr(packageName);
                 if (ps == null) return null;
                 if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
                     return null;
@@ -4951,7 +5053,7 @@
             final int callingUserId = UserHandle.getUserId(callingUid);
             final boolean canViewInstantApps = canViewInstantApps(callingUid, callingUserId);
             for (int i=names.length-1; i>=0; i--) {
-                final PackageSetting ps = mSettings.mPackages.get(names[i]);
+                final PackageSetting ps = mSettings.getPackageLPr(names[i]);
                 boolean translateName = false;
                 if (ps != null && ps.realName != null) {
                     final boolean targetIsInstantApp = ps.getInstantApp(callingUserId);
@@ -4981,7 +5083,7 @@
                 final String cur = mSettings.getRenamedPackageLPr(names[i]);
                 boolean translateName = false;
                 if (cur != null) {
-                    final PackageSetting ps = mSettings.mPackages.get(names[i]);
+                    final PackageSetting ps = mSettings.getPackageLPr(names[i]);
                     final boolean targetIsInstantApp =
                             ps != null && ps.getInstantApp(callingUserId);
                     translateName = !targetIsInstantApp
@@ -5017,7 +5119,7 @@
                 return UserHandle.getUid(userId, p.getUid());
             }
             if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
-                final PackageSetting ps = mSettings.mPackages.get(packageName);
+                final PackageSetting ps = mSettings.getPackageLPr(packageName);
                 if (ps != null && ps.isMatch(flags)
                         && !shouldFilterApplicationLocked(ps, callingUid, userId)) {
                     return UserHandle.getUid(userId, ps.appId);
@@ -5049,7 +5151,7 @@
                 return mPermissionManager.getGidsForUid(UserHandle.getUid(userId, ps.appId));
             }
             if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
-                final PackageSetting ps = mSettings.mPackages.get(packageName);
+                final PackageSetting ps = mSettings.getPackageLPr(packageName);
                 if (ps != null && ps.isMatch(flags)
                         && !shouldFilterApplicationLocked(ps, callingUid, userId)) {
                     return mPermissionManager.getGidsForUid(UserHandle.getUid(userId, ps.appId));
@@ -5075,7 +5177,7 @@
     private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags,
             int filterCallingUid, int userId) {
         if (!mUserManager.exists(userId)) return null;
-        PackageSetting ps = mSettings.mPackages.get(packageName);
+        PackageSetting ps = mSettings.getPackageLPr(packageName);
         if (ps != null) {
             if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
                 return null;
@@ -5133,7 +5235,7 @@
                     TAG, "getApplicationInfo " + packageName
                     + ": " + p);
             if (p != null) {
-                PackageSetting ps = mSettings.mPackages.get(packageName);
+                PackageSetting ps = mSettings.getPackageLPr(packageName);
                 if (ps == null) return null;
                 if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
                     return null;
@@ -5602,7 +5704,7 @@
             if (a == null) {
                 return false;
             }
-            PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
+            PackageSetting ps = mSettings.getPackageLPr(component.getPackageName());
             if (ps == null) {
                 return false;
             }
@@ -5642,7 +5744,7 @@
             }
 
             if (mSettings.isEnabledAndMatchLPr(pkg, a, flags, userId)) {
-                PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
+                PackageSetting ps = mSettings.getPackageLPr(component.getPackageName());
                 if (ps == null) return null;
                 if (shouldFilterApplicationLocked(
                         ps, callingUid, component, TYPE_RECEIVER, userId)) {
@@ -5802,9 +5904,9 @@
     private List<VersionedPackage> getPackagesUsingSharedLibraryLPr(
             SharedLibraryInfo libInfo, int flags, int userId) {
         List<VersionedPackage> versionedPackages = null;
-        final int packageCount = mSettings.mPackages.size();
+        final int packageCount = mSettings.getPackagesLocked().size();
         for (int i = 0; i < packageCount; i++) {
-            PackageSetting ps = mSettings.mPackages.valueAt(i);
+            PackageSetting ps = mSettings.getPackagesLocked().valueAt(i);
 
             if (ps == null) {
                 continue;
@@ -5863,7 +5965,7 @@
 
             AndroidPackage pkg = mPackages.get(s.getPackageName());
             if (mSettings.isEnabledAndMatchLPr(pkg, s, flags, userId)) {
-                PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
+                PackageSetting ps = mSettings.getPackageLPr(component.getPackageName());
                 if (ps == null) return null;
                 if (shouldFilterApplicationLocked(
                         ps, callingUid, component, TYPE_SERVICE, userId)) {
@@ -5897,7 +5999,7 @@
             }
 
             if (mSettings.isEnabledAndMatchLPr(pkg, p, flags, userId)) {
-                PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
+                PackageSetting ps = mSettings.getPackageLPr(component.getPackageName());
                 if (ps == null) return null;
                 if (shouldFilterApplicationLocked(
                         ps, callingUid, component, TYPE_PROVIDER, userId)) {
@@ -6034,7 +6136,7 @@
                 final String packageName = changedPackages.get(i);
                 if (packageName != null) {
                     // Filter out the changes if the calling package should not be able to see it.
-                    final PackageSetting ps = mSettings.mPackages.get(packageName);
+                    final PackageSetting ps = mSettings.getPackageLPr(packageName);
                     if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                         continue;
                     }
@@ -6055,7 +6157,7 @@
             res.addAll(mAvailableFeatures.values());
         }
         final FeatureInfo fi = new FeatureInfo();
-        fi.reqGlEsVersion = mInjector.getSystemWrapper().getPropertyInt("ro.opengles.version",
+        fi.reqGlEsVersion = SystemProperties.getInt("ro.opengles.version",
                 FeatureInfo.GL_ES_VERSION_UNDEFINED);
         res.add(fi);
 
@@ -6781,7 +6883,7 @@
             for (int n = 0; n < count; n++) {
                 final ResolveInfo info = resolvedActivities.get(n);
                 final String packageName = info.activityInfo.packageName;
-                final PackageSetting ps = mSettings.mPackages.get(packageName);
+                final PackageSetting ps = mSettings.getPackageLPr(packageName);
                 if (ps != null) {
                     // only check domain verification status if the app is not a browser
                     if (!info.handleAllWebDataURI) {
@@ -6863,7 +6965,7 @@
                     // If we have an ephemeral app, use it
                     if (ri.activityInfo.applicationInfo.isInstantApp()) {
                         final String packageName = ri.activityInfo.packageName;
-                        final PackageSetting ps = mSettings.mPackages.get(packageName);
+                        final PackageSetting ps = mSettings.getPackageLPr(packageName);
                         final long packedStatus = getDomainVerificationStatusLPr(ps, userId);
                         final int status = (int)(packedStatus >> 32);
                         if (status != INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK) {
@@ -7297,7 +7399,7 @@
 
     private List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(Intent intent,
             String resolvedType, int userId) {
-        CrossProfileIntentResolver resolver = mSettings.getCrossProfileIntentResolvers(userId);
+        CrossProfileIntentResolver resolver = mSettings.getCrossProfileIntentResolver(userId);
         if (resolver != null) {
             return resolver.queryIntent(intent, resolvedType, false /*defaultOnly*/, userId);
         }
@@ -7545,7 +7647,7 @@
             for (int i = instantApps.size() - 1; i >= 0; --i) {
                 final ResolveInfo info = instantApps.get(i);
                 final String packageName = info.activityInfo.packageName;
-                final PackageSetting ps = mSettings.mPackages.get(packageName);
+                final PackageSetting ps = mSettings.getPackageLPr(packageName);
                 if (ps.getInstantApp(userId)) {
                     final long packedStatus = getDomainVerificationStatusLPr(ps, userId);
                     final int status = (int)(packedStatus >> 32);
@@ -7600,7 +7702,7 @@
         if (intent.isWebIntent() && auxiliaryResponse == null) {
             return result;
         }
-        final PackageSetting ps = mSettings.mPackages.get(mInstantAppInstallerActivity.packageName);
+        final PackageSetting ps = mSettings.getPackageLPr(mInstantAppInstallerActivity.packageName);
         if (ps == null
                 || !ps.readUserState(userId).isEnabled(mInstantAppInstallerActivity, 0)) {
             return result;
@@ -7660,7 +7762,7 @@
                 continue;
             }
             String packageName = riTargetUser.activityInfo.packageName;
-            PackageSetting ps = mSettings.mPackages.get(packageName);
+            PackageSetting ps = mSettings.getPackageLPr(packageName);
             if (ps == null) {
                 continue;
             }
@@ -7885,7 +7987,7 @@
             for (int n=0; n<count; n++) {
                 ResolveInfo info = candidates.get(n);
                 String packageName = info.activityInfo.packageName;
-                PackageSetting ps = mSettings.mPackages.get(packageName);
+                PackageSetting ps = mSettings.getPackageLPr(packageName);
                 if (ps != null) {
                     // Add to the special match all list (Browser use case)
                     if (info.handleAllWebDataURI) {
@@ -7964,8 +8066,8 @@
                 } else {
                     // Browser/generic handling case.  If there's a default browser, go straight
                     // to that (but only if there is no other higher-priority match).
-                    final String defaultBrowserPackageName =
-                            mPermissionManager.getDefaultBrowser(userId);
+                    final String defaultBrowserPackageName = mDefaultAppProvider.getDefaultBrowser(
+                            userId);
                     int maxMatchPrio = 0;
                     ResolveInfo defaultBrowserMatch = null;
                     final int numCandidates = matchAllList.size();
@@ -8749,8 +8851,8 @@
         synchronized (mLock) {
             ArrayList<PackageInfo> list;
             if (listUninstalled) {
-                list = new ArrayList<>(mSettings.mPackages.size());
-                for (PackageSetting ps : mSettings.mPackages.values()) {
+                list = new ArrayList<>(mSettings.getPackagesLocked().size());
+                for (PackageSetting ps : mSettings.getPackagesLocked().values()) {
                     if (listFactory) {
                         if (!ps.isSystem()) {
                             continue;
@@ -8862,7 +8964,7 @@
             ArrayList<PackageInfo> list = new ArrayList<>();
             boolean[] tmpBools = new boolean[permissions.length];
             if (listUninstalled) {
-                for (PackageSetting ps : mSettings.mPackages.values()) {
+                for (PackageSetting ps : mSettings.getPackagesLocked().values()) {
                     addPackageHoldingPermissions(list, ps, permissions, tmpBools, flags,
                             userId);
                 }
@@ -8907,8 +9009,8 @@
         synchronized (mLock) {
             ArrayList<ApplicationInfo> list;
             if (listUninstalled) {
-                list = new ArrayList<>(mSettings.mPackages.size());
-                for (PackageSetting ps : mSettings.mPackages.values()) {
+                list = new ArrayList<>(mSettings.getPackagesLocked().size());
+                for (PackageSetting ps : mSettings.getPackagesLocked().values()) {
                     ApplicationInfo ai;
                     int effectiveFlags = flags;
                     if (ps.isSystem()) {
@@ -9000,7 +9102,7 @@
             if (Process.isIsolated(callingUid)) {
                 callingUid = mIsolatedOwners.get(callingUid);
             }
-            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            final PackageSetting ps = mSettings.getPackageLPr(packageName);
             final boolean returnAllowed =
                     ps != null
                     && (isCallerSameApp(packageName, callingUid)
@@ -9099,7 +9201,7 @@
                 if (p.isPersistent()
                         && (!mSafeMode || p.isSystem())
                         && (matchesUnaware || matchesAware)) {
-                    PackageSetting ps = mSettings.mPackages.get(p.getPackageName());
+                    PackageSetting ps = mSettings.getPackageLPr(p.getPackageName());
                     if (ps != null) {
                         ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(p, flags,
                                 ps.readUserState(userId), userId, ps);
@@ -9144,7 +9246,7 @@
             if (!mSettings.isEnabledAndMatchLPr(providerInfo, flags, userId)) {
                 return null;
             }
-            final PackageSetting ps = mSettings.mPackages.get(providerInfo.packageName);
+            final PackageSetting ps = mSettings.getPackageLPr(providerInfo.packageName);
             final ComponentName component =
                     new ComponentName(providerInfo.packageName, providerInfo.name);
             if (shouldFilterApplicationLocked(ps, callingUid, component, TYPE_PROVIDER, userId)) {
@@ -9184,7 +9286,7 @@
                 if (!mSettings.isEnabledAndMatchLPr(providerInfo, flags, userId)) {
                     continue;
                 }
-                final PackageSetting ps = mSettings.mPackages.get(providerInfo.packageName);
+                final PackageSetting ps = mSettings.getPackageLPr(providerInfo.packageName);
                 final ComponentName component =
                         new ComponentName(providerInfo.packageName, providerInfo.name);
                 if (shouldFilterApplicationLocked(
@@ -9213,7 +9315,7 @@
             final int callingUid = Binder.getCallingUid();
             final int callingUserId = UserHandle.getUserId(callingUid);
             String packageName = component.getPackageName();
-            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            final PackageSetting ps = mSettings.getPackageLPr(packageName);
             AndroidPackage pkg = mPackages.get(packageName);
             if (ps == null || pkg == null) return null;
             if (shouldFilterApplicationLocked(
@@ -9445,8 +9547,7 @@
 
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
         final ParsedPackage parsedPackage;
-        try (PackageParser2 pp = new PackageParser2(mSeparateProcesses, mOnlyCore, mMetrics, null,
-                mPackageParserCallback)) {
+        try (PackageParser2 pp = mInjector.getScanningPackageParser()) {
             parsedPackage = pp.parsePackage(scanFile, parseFlags, false);
         } catch (PackageParserException e) {
             throw PackageManagerException.from(e);
@@ -9740,7 +9841,7 @@
                                             pkgName, getSettingsVersionForPackage(parsedPackage)),
                                     Collections.singletonMap(pkgName,
                                             getSharedLibLatestVersionSetting(scanResult))),
-                            mSettings.mKeySetManagerService, mInjector);
+                            mSettings.getKeySetManagerService(), mInjector);
                     appIdCreated = optimisticallyRegisterAppId(scanResult);
                     commitReconciledScanResultLocked(
                             reconcileResult.get(pkgName), mUserManager.getUserIds());
@@ -10051,7 +10152,7 @@
         List<PackageSetting> pkgSettings;
         synchronized (mLock) {
             pkgSettings = PackageManagerServiceUtils.getPackagesForDexopt(
-                    mSettings.mPackages.values(), this);
+                    mSettings.getPackagesLocked().values(), this);
         }
 
         List<AndroidPackage> pkgs = new ArrayList<>(pkgSettings.size());
@@ -10196,7 +10297,7 @@
                 pkgCompilationReason = PackageManagerService.REASON_BACKGROUND_DEXOPT;
             }
 
-            if (mInjector.getSystemWrapper().getPropertyBoolean(PRECOMPILE_LAYOUTS, false)) {
+            if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) {
                 mArtManagerService.compileLayouts(pkg);
             }
 
@@ -10409,7 +10510,7 @@
                 // Package could not be found. Report failure.
                 return PackageDexOptimizer.DEX_OPT_FAILED;
             }
-            mPackageUsage.maybeWriteAsync(mSettings.mPackages);
+            mPackageUsage.maybeWriteAsync(mSettings.getPackagesLocked());
             mCompilerStats.maybeWriteAsync();
         }
         final long callingId = Binder.clearCallingIdentity();
@@ -10639,7 +10740,7 @@
         PackageWatchdog.getInstance(mContext).writeNow();
 
         synchronized (mLock) {
-            mPackageUsage.writeNow(mSettings.mPackages);
+            mPackageUsage.writeNow(mSettings.getPackagesLocked());
 
             // This is the last chance to write out pending restriction settings
             if (mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) {
@@ -10769,7 +10870,7 @@
     private void clearAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) {
         final PackageSetting ps;
         synchronized (mLock) {
-            ps = mSettings.mPackages.get(pkg.getPackageName());
+            ps = mSettings.getPackageLPr(pkg.getPackageName());
         }
         for (int realUserId : resolveUserIds(userId)) {
             final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0;
@@ -10793,7 +10894,7 @@
     private void destroyAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) {
         final PackageSetting ps;
         synchronized (mLock) {
-            ps = mSettings.mPackages.get(pkg.getPackageName());
+            ps = mSettings.getPackageLPr(pkg.getPackageName());
         }
         for (int realUserId : resolveUserIds(userId)) {
             final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0;
@@ -11173,7 +11274,7 @@
     }
 
     private int getVendorPartitionVersion() {
-        final String version = mInjector.getSystemWrapper().getProperty("ro.vndk.version");
+        final String version = SystemProperties.get("ro.vndk.version");
         if (!version.isEmpty()) {
             try {
                 return Integer.parseInt(version);
@@ -11384,7 +11485,7 @@
                 // to allowlist their privileged permissions just like other
                 // priv-apps.
                 synchronized (mLock) {
-                    PackageSetting platformPkgSetting = mSettings.mPackages.get("android");
+                    PackageSetting platformPkgSetting = mSettings.getPackageLPr("android");
                     if ((compareSignatures(platformPkgSetting.signatures.mSigningDetails.signatures,
                             pkg.getSigningDetails().signatures)
                             != PackageManager.SIGNATURE_MATCH)) {
@@ -11506,6 +11607,7 @@
             parsedPackage.setVersionCode(mSdkVersion)
                     .setVersionCodeMajor(0);
         }
+
         final AndroidPackage oldPkg = request.oldPkg;
         final @ParseFlags int parseFlags = request.parseFlags;
         final @ScanFlags int scanFlags = request.scanFlags;
@@ -11545,7 +11647,7 @@
         if (reconciledPkg.installArgs != null) {
             InstallSource installSource = reconciledPkg.installArgs.installSource;
             if (installSource.initiatingPackageName != null) {
-                final PackageSetting ips = mSettings.mPackages.get(
+                final PackageSetting ips = mSettings.getPackageLPr(
                         installSource.initiatingPackageName);
                 if (ips != null) {
                     installSource = installSource.setInitiatingPackageSignatures(
@@ -11575,7 +11677,7 @@
                     reconciledPkg.collectedSharedLibraryInfos, allUsers);
         }
 
-        final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+        final KeySetManagerService ksms = mSettings.getKeySetManagerService();
         if (reconciledPkg.removeAppKeySetData) {
             ksms.removeAppKeySetDataLPw(pkg.getPackageName());
         }
@@ -11937,12 +12039,13 @@
         final String cpuAbiOverride = deriveAbiOverride(request.cpuAbiOverride);
         final boolean isUpdatedSystemApp = pkgSetting.getPkgState().isUpdatedSystemApp();
 
+        final File appLib32InstallDir = getAppLib32InstallDir();
         if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
             if (needToDeriveAbi) {
                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
                 final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> derivedAbi =
                         packageAbiHelper.derivePackageAbi(parsedPackage, isUpdatedSystemApp,
-                                cpuAbiOverride);
+                                cpuAbiOverride, appLib32InstallDir);
                 derivedAbi.first.applyTo(parsedPackage);
                 derivedAbi.second.applyTo(parsedPackage);
                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -11960,7 +12063,7 @@
                     abis.applyTo(pkgSetting);
                     final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
                             packageAbiHelper.deriveNativeLibraryPaths(parsedPackage,
-                                    isUpdatedSystemApp, sAppLib32InstallDir);
+                                    isUpdatedSystemApp, appLib32InstallDir);
                     nativeLibraryPaths.applyTo(parsedPackage);
                 }
             } else {
@@ -11972,7 +12075,7 @@
 
                 final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
                         packageAbiHelper.deriveNativeLibraryPaths(parsedPackage,
-                                isUpdatedSystemApp, sAppLib32InstallDir);
+                                isUpdatedSystemApp, appLib32InstallDir);
                 nativeLibraryPaths.applyTo(parsedPackage);
 
                 if (DEBUG_ABI_SELECTION) {
@@ -11998,7 +12101,7 @@
             // package path (after the rename away from the stage path).
             final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
                     packageAbiHelper.deriveNativeLibraryPaths(parsedPackage, isUpdatedSystemApp,
-                            sAppLib32InstallDir);
+                            appLib32InstallDir);
             nativeLibraryPaths.applyTo(parsedPackage);
         }
 
@@ -12293,7 +12396,7 @@
         }
 
         // Make sure we're not adding any bogus keyset info
-        final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+        final KeySetManagerService ksms = mSettings.getKeySetManagerService();
         ksms.assertScannedPackageValid(pkg);
 
         synchronized (mLock) {
@@ -12511,7 +12614,7 @@
                 }
                 if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) {
                     // Exempt SharedUsers signed with the platform key.
-                    PackageSetting platformPkgSetting = mSettings.mPackages.get("android");
+                    PackageSetting platformPkgSetting = mSettings.getPackageLPr("android");
                     if (!comparePackageSignatures(platformPkgSetting,
                             pkg.getSigningDetails().signatures)) {
                         throw new PackageManagerException("Apps that share a user with a " +
@@ -12685,7 +12788,7 @@
                 continue;
             }
             for (VersionedPackage dependentPackage : dependents) {
-                final PackageSetting ps = mSettings.mPackages.get(
+                final PackageSetting ps = mSettings.getPackageLPr(
                         dependentPackage.getPackageName());
                 if (ps != null) {
                     ps.setOverlayPathsForLibrary(libraryInfo.getName(), null, currentUserId);
@@ -12844,7 +12947,6 @@
 
         synchronized (mLock) {
             // We don't expect installation to fail beyond this point
-
             // Add the new setting to mSettings
             mSettings.insertPackageSettingLPw(pkgSetting, pkg);
             // Add the new setting to mPackages
@@ -12854,7 +12956,7 @@
             }
 
             // Add the package's KeySets to the global KeySetManagerService
-            KeySetManagerService ksms = mSettings.mKeySetManagerService;
+            KeySetManagerService ksms = mSettings.getKeySetManagerService();
             ksms.addScannedPackageLPw(pkg);
 
             mComponentResolver.addAllComponents(pkg, chatty);
@@ -13329,7 +13431,7 @@
                 packageName, extras, 0, null, null, userIds, instantUserIds,
                 mAppsFilter.getVisibilityAllowList(
                         getPackageSettingInternal(packageName, Process.SYSTEM_UID),
-                        userIds, mSettings.mPackages));
+                        userIds, mSettings.getPackagesLocked()));
         if (sendBootCompleted && !ArrayUtils.isEmpty(userIds)) {
             mHandler.post(() -> {
                         for (int userId : userIds) {
@@ -13400,7 +13502,7 @@
             boolean sendRemoved = false;
             // writer
             synchronized (mLock) {
-                pkgSetting = mSettings.mPackages.get(packageName);
+                pkgSetting = mSettings.getPackageLPr(packageName);
                 if (pkgSetting == null) {
                     return false;
                 }
@@ -13466,7 +13568,7 @@
         }
 
         synchronized (mLock) {
-            final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
+            final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName);
             if (pkgSetting == null || !pkgSetting.isSystem()) {
                 return;
             }
@@ -13493,7 +13595,7 @@
         }
 
         synchronized (mLock) {
-            final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
+            final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName);
             // The target app should always be in system
             if (pkgSetting == null || !pkgSetting.isSystem()) {
                 return false;
@@ -13580,7 +13682,7 @@
         try {
             // writer
             synchronized (mLock) {
-                ps = mSettings.mPackages.get(packageName);
+                ps = mSettings.getPackageLPr(packageName);
                 if (ps == null) {
                     return true;
                 }
@@ -13641,7 +13743,7 @@
 
             // writer
             synchronized (mLock) {
-                pkgSetting = mSettings.mPackages.get(packageName);
+                pkgSetting = mSettings.getPackageLPr(packageName);
                 if (pkgSetting == null) {
                     return PackageManager.INSTALL_FAILED_INVALID_URI;
                 }
@@ -13791,7 +13893,7 @@
             final String packageName = packageNames[i];
             final PackageSetting pkgSetting;
             synchronized (mLock) {
-                pkgSetting = mSettings.mPackages.get(packageName);
+                pkgSetting = mSettings.getPackageLPr(packageName);
                 if (pkgSetting == null
                         || shouldFilterApplicationLocked(pkgSetting, callingUid, userId)) {
                     Slog.w(TAG, "Could not find package setting for package: " + packageName
@@ -13889,7 +13991,7 @@
             }
             final PackageSetting pkgSetting;
             synchronized (mLock) {
-                pkgSetting = mSettings.mPackages.get(packageName);
+                pkgSetting = mSettings.getPackageLPr(packageName);
                 if (pkgSetting == null
                         || shouldFilterApplicationLocked(pkgSetting, callingUid, userId)) {
                     Slog.w(TAG, "Could not find package setting for package: " + packageName
@@ -13942,7 +14044,7 @@
 
     private Bundle getSuspendedPackageAppExtrasInternal(String packageName, int userId) {
         synchronized (mLock) {
-            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            final PackageSetting ps = mSettings.getPackageLPr(packageName);
             if (ps == null) {
                 return null;
             }
@@ -13997,7 +14099,7 @@
         enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
                 false /* checkShell */, "isPackageSuspendedForUser for user " + userId);
         synchronized (mLock) {
-            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            final PackageSetting ps = mSettings.getPackageLPr(packageName);
             if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
                 throw new IllegalArgumentException("Unknown target package: " + packageName);
             }
@@ -14015,7 +14117,7 @@
 
     boolean isSuspendingAnyPackages(String suspendingPackage, int userId) {
         synchronized (mLock) {
-            for (final PackageSetting ps : mSettings.mPackages.values()) {
+            for (final PackageSetting ps : mSettings.getPackagesLocked().values()) {
                 if (ps.isSuspendedBy(suspendingPackage, userId)) {
                     return true;
                 }
@@ -14041,7 +14143,7 @@
         final IntArray unsuspendedUids = new IntArray();
         synchronized (mLock) {
             for (String packageName : packagesToChange) {
-                final PackageSetting ps = mSettings.mPackages.get(packageName);
+                final PackageSetting ps = mSettings.getPackageLPr(packageName);
                 if (ps != null && ps.getSuspended(userId)) {
                     ps.removeSuspension(suspendingPackagePredicate, userId);
                     if (!ps.getSuspended(userId)) {
@@ -14082,7 +14184,7 @@
         final IntArray changedUids = new IntArray();
         synchronized (mLock) {
             for (String packageName : packagesToChange) {
-                final PackageSetting ps = mSettings.mPackages.get(packageName);
+                final PackageSetting ps = mSettings.getPackageLPr(packageName);
                 if (ps != null && ps.getDistractionFlags(userId) != 0) {
                     ps.setDistractionFlags(0, userId);
                     changedPackages.add(ps.name);
@@ -14138,7 +14240,7 @@
                 continue;
             }
             synchronized (mLock) {
-                final PackageSetting ps = mSettings.mPackages.get(packageNames[i]);
+                final PackageSetting ps = mSettings.getPackageLPr(packageNames[i]);
                 if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
                     Slog.w(TAG, "Could not find package setting for package: " + packageNames[i]);
                     unactionablePackages.add(packageNames[i]);
@@ -14162,8 +14264,8 @@
         final boolean isCallerOwner = isCallerDeviceOrProfileOwner(userId);
         final long callingId = Binder.clearCallingIdentity();
         try {
-            final String activeLauncherPackageName = mPermissionManager.getDefaultHome(userId);
-            final String dialerPackageName = mPermissionManager.getDefaultDialer(userId);
+            final String activeLauncherPackageName = mDefaultAppProvider.getDefaultHome(userId);
+            final String dialerPackageName = mDefaultAppProvider.getDefaultDialer(userId);
             for (int i = 0; i < packageNames.length; i++) {
                 canSuspend[i] = false;
                 final String packageName = packageNames[i];
@@ -14485,7 +14587,7 @@
             // Check if the developer wants to skip verification for ADB installs
             if ((installFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) != 0) {
                 synchronized (mLock) {
-                    if (mSettings.mPackages.get(pkgInfoLite.packageName) == null) {
+                    if (mSettings.getPackageLPr(pkgInfoLite.packageName) == null) {
                         // Always verify fresh install
                         return true;
                     }
@@ -14552,7 +14654,7 @@
             return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
         }
         synchronized (mLock) {
-            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            final PackageSetting ps = mSettings.getPackageLPr(packageName);
             if (ps == null
                     || shouldFilterApplicationLocked(
                     ps, callingUid, UserHandle.getUserId(callingUid))) {
@@ -14569,7 +14671,7 @@
 
         boolean result = false;
         synchronized (mLock) {
-            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            final PackageSetting ps = mSettings.getPackageLPr(packageName);
             if (shouldFilterApplicationLocked(
                     ps, Binder.getCallingUid(), UserHandle.getCallingUserId())) {
                 return false;
@@ -14590,7 +14692,7 @@
             return ParceledListSlice.emptyList();
         }
         synchronized (mLock) {
-            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            final PackageSetting ps = mSettings.getPackageLPr(packageName);
             if (shouldFilterApplicationLocked(ps, callingUid, UserHandle.getUserId(callingUid))) {
                 return ParceledListSlice.emptyList();
             }
@@ -14655,7 +14757,7 @@
         }
         // writer
         synchronized (mLock) {
-            PackageSetting targetPackageSetting = mSettings.mPackages.get(targetPackage);
+            PackageSetting targetPackageSetting = mSettings.getPackageLPr(targetPackage);
             if (targetPackageSetting == null
                     || shouldFilterApplicationLocked(
                             targetPackageSetting, callingUid, UserHandle.getUserId(callingUid))) {
@@ -14664,7 +14766,7 @@
 
             PackageSetting installerPackageSetting;
             if (installerPackageName != null) {
-                installerPackageSetting = mSettings.mPackages.get(installerPackageName);
+                installerPackageSetting = mSettings.getPackageLPr(installerPackageName);
                 if (installerPackageSetting == null) {
                     throw new IllegalArgumentException("Unknown installer package: "
                             + installerPackageName);
@@ -14706,7 +14808,7 @@
             String targetInstallerPackageName =
                     targetPackageSetting.installSource.installerPackageName;
             PackageSetting targetInstallerPkgSetting = targetInstallerPackageName == null ? null :
-                    mSettings.mPackages.get(targetInstallerPackageName);
+                    mSettings.getPackageLPr(targetInstallerPackageName);
 
             if (targetInstallerPkgSetting != null) {
                 if (compareSignatures(callerSignature,
@@ -14757,7 +14859,7 @@
         mInjector.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(),
                 callerPackageName);
         synchronized (mLock) {
-            PackageSetting ps = mSettings.mPackages.get(packageName);
+            PackageSetting ps = mSettings.getPackageLPr(packageName);
             if (ps == null) {
                 throw new IllegalArgumentException("Unknown target package " + packageName);
             }
@@ -15211,10 +15313,12 @@
         final int autoRevokePermissionsMode;
         final PackageParser.SigningDetails signingDetails;
         final int installReason;
+        final int mInstallScenario;
         @Nullable MultiPackageInstallParams mParentInstallParams;
         final boolean forceQueryableOverride;
         final int mDataLoaderType;
         final long requiredInstalledVersionCode;
+        final PackageLite mPackageLite;
 
         InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
                 int installFlags, InstallSource installSource, String volumeUuid,
@@ -15233,19 +15337,23 @@
             this.autoRevokePermissionsMode = MODE_DEFAULT;
             this.signingDetails = PackageParser.SigningDetails.UNKNOWN;
             this.installReason = PackageManager.INSTALL_REASON_UNKNOWN;
+            this.mInstallScenario = PackageManager.INSTALL_SCENARIO_DEFAULT;
             this.forceQueryableOverride = false;
             this.mDataLoaderType = DataLoaderType.NONE;
             this.requiredInstalledVersionCode = PackageManager.VERSION_CODE_HIGHEST;
+            this.mPackageLite = null;
         }
 
         InstallParams(File stagedDir, IPackageInstallObserver2 observer,
                 PackageInstaller.SessionParams sessionParams, InstallSource installSource,
-                UserHandle user, SigningDetails signingDetails, int installerUid) {
+                UserHandle user, SigningDetails signingDetails, int installerUid,
+                PackageLite packageLite) {
             super(user);
             origin = OriginInfo.fromStagedFile(stagedDir);
             move = null;
             installReason = fixUpInstallReason(
                     installSource.installerPackageName, installerUid, sessionParams.installReason);
+            mInstallScenario = sessionParams.installScenario;
             this.observer = observer;
             installFlags = sessionParams.installFlags;
             this.installSource = installSource;
@@ -15259,6 +15367,7 @@
             mDataLoaderType = (sessionParams.dataLoaderParams != null)
                     ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
             requiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode;
+            mPackageLite = packageLite;
         }
 
         @Override
@@ -15343,7 +15452,8 @@
                     try {
                         mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
                         pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
-                                origin.resolvedPath, installFlags, packageAbiOverride);
+                                mPackageLite, origin.resolvedPath, installFlags,
+                                packageAbiOverride);
                     } catch (InstallerException e) {
                         Slog.w(TAG, "Failed to free cache", e);
                     }
@@ -15404,7 +15514,7 @@
          */
         public void handleStartCopy() {
             PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
-                    origin.resolvedPath, installFlags, packageAbiOverride);
+                    mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride);
 
             // For staged session, there is a delay between its verification and install. Device
             // state can change within this delay and hence we need to re-verify certain conditions.
@@ -15524,9 +15634,11 @@
         private boolean mWaitForEnableRollbackToComplete;
         private int mRet;
 
+        final PackageLite mPackageLite;
+
         VerificationParams(UserHandle user, File stagedDir, IPackageInstallObserver2 observer,
                 PackageInstaller.SessionParams sessionParams, InstallSource installSource,
-                int installerUid, SigningDetails signingDetails, int sessionId) {
+                int installerUid, SigningDetails signingDetails, int sessionId, PackageLite lite) {
             super(user);
             origin = OriginInfo.fromStagedFile(stagedDir);
             this.observer = observer;
@@ -15544,6 +15656,7 @@
             mDataLoaderType = (sessionParams.dataLoaderParams != null)
                     ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
             mSessionId = sessionId;
+            mPackageLite = lite;
         }
 
         @Override
@@ -15561,7 +15674,7 @@
             }
 
             PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
-                    origin.resolvedPath, installFlags, packageAbiOverride);
+                    mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride);
 
             mRet = verifyReplacingVersionCode(pkgLite, requiredInstalledVersionCode, installFlags);
             if (mRet != INSTALL_SUCCEEDED) {
@@ -15969,6 +16082,7 @@
         final int traceCookie;
         final PackageParser.SigningDetails signingDetails;
         final int installReason;
+        final int mInstallScenario;
         final boolean forceQueryableOverride;
         final int mDataLoaderType;
 
@@ -15984,7 +16098,8 @@
                 List<String> whitelistedRestrictedPermissions,
                 int autoRevokePermissionsMode,
                 String traceMethod, int traceCookie, SigningDetails signingDetails,
-                int installReason, boolean forceQueryableOverride, int dataLoaderType) {
+                int installReason, int installScenario, boolean forceQueryableOverride,
+                int dataLoaderType) {
             this.origin = origin;
             this.move = move;
             this.installFlags = installFlags;
@@ -16001,6 +16116,7 @@
             this.traceCookie = traceCookie;
             this.signingDetails = signingDetails;
             this.installReason = installReason;
+            this.mInstallScenario = installScenario;
             this.forceQueryableOverride = forceQueryableOverride;
             this.mDataLoaderType = dataLoaderType;
         }
@@ -16013,7 +16129,8 @@
                     params.grantedRuntimePermissions, params.whitelistedRestrictedPermissions,
                     params.autoRevokePermissionsMode,
                     params.traceMethod, params.traceCookie, params.signingDetails,
-                    params.installReason, params.forceQueryableOverride, params.mDataLoaderType);
+                    params.installReason, params.mInstallScenario, params.forceQueryableOverride,
+                    params.mDataLoaderType);
         }
 
         abstract int copyApk();
@@ -16102,8 +16219,8 @@
             super(OriginInfo.fromNothing(), null, null, 0, InstallSource.EMPTY,
                     null, null, instructionSets, null, null, null, MODE_DEFAULT, null, 0,
                     PackageParser.SigningDetails.UNKNOWN,
-                    PackageManager.INSTALL_REASON_UNKNOWN, false,
-                    DataLoaderType.NONE);
+                    PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.INSTALL_SCENARIO_DEFAULT,
+                    false, DataLoaderType.NONE);
             this.codeFile = (codePath != null) ? new File(codePath) : null;
         }
 
@@ -16490,7 +16607,7 @@
             // For system-bundled packages, we assume that installing an upgraded version
             // of the package implies that the user actually wants to run that new code,
             // so we enable the package.
-            final PackageSetting ps = mSettings.mPackages.get(pkgName);
+            final PackageSetting ps = mSettings.getPackageLPr(pkgName);
             final int userId = installArgs.user.getIdentifier();
             if (ps != null) {
                 if (pkg.isSystem()) {
@@ -16535,7 +16652,7 @@
                                 // TODO(146804378): Support overlaying static shared libraries
                                 continue;
                             }
-                            final PackageSetting libPs = mSettings.mPackages.get(
+                            final PackageSetting libPs = mSettings.getPackageLPr(
                                     sharedLib.getPackageName());
                             if (libPs == null) {
                                 continue;
@@ -16948,8 +17065,7 @@
                                 && compareSignatures(sharedUserSignatures,
                                 parsedPackage.getSigningDetails().signatures)
                                         != PackageManager.SIGNATURE_MATCH) {
-                            if (injector.getSystemWrapper()
-                                    .getPropertyInt("ro.product.first_api_level", 0) <= 29) {
+                            if (SystemProperties.getInt("ro.product.first_api_level", 0) <= 29) {
                                 // Mismatched signatures is an error and silently skipping system
                                 // packages will likely break the device in unforeseen ways.
                                 // However, we allow the device to boot anyway because, prior to Q,
@@ -17139,7 +17255,7 @@
                 reconciledPkg.pkgSetting.lastUpdateTime = System.currentTimeMillis();
 
                 res.removedInfo.broadcastAllowList = mAppsFilter.getVisibilityAllowList(
-                                reconciledPkg.pkgSetting, request.mAllUsers, mSettings.mPackages);
+                        reconciledPkg.pkgSetting, request.mAllUsers, mSettings.getPackagesLocked());
                 if (reconciledPkg.prepareResult.system) {
                     // Remove existing system package
                     removePackageLI(oldPackage, true);
@@ -17163,7 +17279,7 @@
                         executeDeletePackageLIF(reconciledPkg.deletePackageAction, packageName,
                                 true, request.mAllUsers, false, parsedPackage);
                     } catch (SystemDeleteException e) {
-                        if (Build.IS_ENG) {
+                        if (mIsEngBuild) {
                             throw new RuntimeException("Unexpected failure", e);
                             // ignore; not possible for non-system app
                         }
@@ -17184,7 +17300,7 @@
                     }
 
                     // Update the in-memory copy of the previous code paths.
-                    PackageSetting ps1 = mSettings.mPackages.get(
+                    PackageSetting ps1 = mSettings.getPackageLPr(
                             reconciledPkg.prepareResult.existingPackage.getPackageName());
                     if ((reconciledPkg.installArgs.installFlags & PackageManager.DONT_KILL_APP)
                             == 0) {
@@ -17213,7 +17329,7 @@
             AndroidPackage pkg = commitReconciledScanResultLocked(reconciledPkg, request.mAllUsers);
             updateSettingsLI(pkg, reconciledPkg.installArgs, request.mAllUsers, res);
 
-            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            final PackageSetting ps = mSettings.getPackageLPr(packageName);
             if (ps != null) {
                 res.newUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true);
                 ps.setUpdateAvailable(false /*updateAvailable*/);
@@ -17323,7 +17439,7 @@
                 try {
                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
                     reconciledPackages = reconcilePackagesLocked(
-                            reconcileRequest, mSettings.mKeySetManagerService, mInjector);
+                            reconcileRequest, mSettings.getKeySetManagerService(), mInjector);
                 } catch (ReconcileFailure e) {
                     for (InstallRequest request : requests) {
                         request.installResult.setError("Reconciliation failed...", e);
@@ -17430,6 +17546,26 @@
                     resolveUserIds(reconciledPkg.installArgs.user.getIdentifier()),
                     /* updateReferenceProfileContent= */ true);
 
+            // Compute the compilation reason from the installation scenario.
+            final int compilationReason = mDexManager.getCompilationReasonForInstallScenario(
+                    reconciledPkg.installArgs.mInstallScenario);
+
+            // Construct the DexoptOptions early to see if we should skip running dexopt.
+            //
+            // Do not run PackageDexOptimizer through the local performDexOpt
+            // method because `pkg` may not be in `mPackages` yet.
+            //
+            // Also, don't fail application installs if the dexopt step fails.
+            final boolean isBackupOrRestore =
+                    reconciledPkg.installArgs.installReason == INSTALL_REASON_DEVICE_RESTORE
+                    || reconciledPkg.installArgs.installReason == INSTALL_REASON_DEVICE_SETUP;
+
+            final int dexoptFlags = DexoptOptions.DEXOPT_BOOT_COMPLETE
+                    | DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE
+                    | (isBackupOrRestore ? DexoptOptions.DEXOPT_FOR_RESTORE : 0);
+            DexoptOptions dexoptOptions =
+                    new DexoptOptions(packageName, compilationReason, dexoptFlags);
+
             // Check whether we need to dexopt the app.
             //
             // NOTE: it is IMPORTANT to call dexopt:
@@ -17450,34 +17586,28 @@
             // continuous progress to the useur instead of mysteriously blocking somewhere in the
             // middle of running an instant app. The default behaviour can be overridden
             // via gservices.
+            //
+            // Furthermore, dexopt may be skipped, depending on the install scenario and current
+            // state of the device.
+            //
+            // TODO(b/174695087): instantApp and onIncremental should be removed and their install
+            //       path moved to SCENARIO_FAST.
             final boolean performDexopt =
                     (!instantApp || Global.getInt(mContext.getContentResolver(),
                     Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
                     && !pkg.isDebuggable()
-                    && (!onIncremental);
+                    && (!onIncremental)
+                    && dexoptOptions.isCompilationEnabled();
 
             if (performDexopt) {
                 // Compile the layout resources.
-                if (mInjector.getSystemWrapper().getPropertyBoolean(PRECOMPILE_LAYOUTS, false)) {
+                if (SystemProperties.getBoolean(PRECOMPILE_LAYOUTS, false)) {
                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "compileLayouts");
                     mViewCompiler.compileLayouts(pkg);
                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                 }
 
                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
-                // Do not run PackageDexOptimizer through the local performDexOpt
-                // method because `pkg` may not be in `mPackages` yet.
-                //
-                // Also, don't fail application installs if the dexopt step fails.
-                int flags = DexoptOptions.DEXOPT_BOOT_COMPLETE
-                        | DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE;
-                if (reconciledPkg.installArgs.installReason == INSTALL_REASON_DEVICE_RESTORE
-                        || reconciledPkg.installArgs.installReason == INSTALL_REASON_DEVICE_SETUP) {
-                    flags |= DexoptOptions.DEXOPT_FOR_RESTORE;
-                }
-                DexoptOptions dexoptOptions = new DexoptOptions(packageName,
-                        REASON_INSTALL,
-                        flags);
                 ScanResult result = reconciledPkg.scanResult;
 
                 // This mirrors logic from commitReconciledScanResultLocked, where the library files
@@ -17801,7 +17931,7 @@
 
         final SigningDetails sourceSigningDetails = (sourcePackageSetting == null
                 ? SigningDetails.UNKNOWN : sourcePackageSetting.getSigningDetails());
-        final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+        final KeySetManagerService ksms = mSettings.getKeySetManagerService();
         if (sourcePackageName.equals(parsedPackage.getPackageName())
                 && (ksms.shouldCheckUpgradeKeySetLocked(
                 sourcePackageSetting, scanFlags))) {
@@ -17885,8 +18015,7 @@
 
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
         final ParsedPackage parsedPackage;
-        try (PackageParser2 pp = new PackageParser2(mSeparateProcesses, false, mMetrics, null,
-                mPackageParserCallback)) {
+        try (PackageParser2 pp = mInjector.getPreparingPackageParser()) {
             parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false);
             AndroidPackageUtils.validatePackageDexMetadata(parsedPackage);
         } catch (PackageParserException e) {
@@ -17935,8 +18064,8 @@
             if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) {
                 parsedPackage.setSigningDetails(args.signingDetails);
             } else {
-                parsedPackage.setSigningDetails(
-                        ParsingPackageUtils.getSigningDetails(parsedPackage, false /* skipVerify */));
+                parsedPackage.setSigningDetails(ParsingPackageUtils.getSigningDetails(
+                        parsedPackage, false /* skipVerify */));
             }
         } catch (PackageParserException e) {
             throw new PrepareFailure("Failed collect during installPackageLI", e);
@@ -18000,7 +18129,7 @@
                 }
             }
 
-            PackageSetting ps = mSettings.mPackages.get(pkgName);
+            PackageSetting ps = mSettings.getPackageLPr(pkgName);
             if (ps != null) {
                 if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);
 
@@ -18019,7 +18148,7 @@
                 // Quick validity check that we're signed correctly if updating;
                 // we'll check this again later when scanning, but we want to
                 // bail early here before tripping over redefined permissions.
-                final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+                final KeySetManagerService ksms = mSettings.getKeySetManagerService();
                 if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
                     if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) {
                         throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
@@ -18200,7 +18329,7 @@
             scanFlags |= SCAN_MOVE;
 
             synchronized (mLock) {
-                final PackageSetting ps = mSettings.mPackages.get(pkgName);
+                final PackageSetting ps = mSettings.getPackageLPr(pkgName);
                 if (ps == null) {
                     res.setError(INSTALL_FAILED_INTERNAL_ERROR,
                             "Missing settings for moved package " + pkgName);
@@ -18229,7 +18358,7 @@
                 final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
                         derivedAbi = mInjector.getAbiHelper().derivePackageAbi(parsedPackage,
                         isUpdatedSystemAppFromExistingSetting || isUpdatedSystemAppInferred,
-                        abiOverride);
+                        abiOverride, mAppLib32InstallDir);
                 derivedAbi.first.applyTo(parsedPackage);
                 derivedAbi.second.applyTo(parsedPackage);
             } catch (PackageManagerException pme) {
@@ -18298,11 +18427,11 @@
                                 "replacePackageLI: new=" + parsedPackage + ", old=" + oldPackage);
                     }
 
-                    ps = mSettings.mPackages.get(pkgName11);
+                    ps = mSettings.getPackageLPr(pkgName11);
                     disabledPs = mSettings.getDisabledSystemPkgLPr(ps);
 
                     // verify signatures are valid
-                    final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+                    final KeySetManagerService ksms = mSettings.getKeySetManagerService();
                     if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) {
                         if (!ksms.checkUpgradeKeySetLocked(ps, parsedPackage)) {
                             throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
@@ -18505,7 +18634,7 @@
         ArrayMap<String, String> fsverityCandidates = new ArrayMap<>();
         if (legacyMode) {
             synchronized (mLock) {
-                final PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName());
+                final PackageSetting ps = mSettings.getPackageLPr(pkg.getPackageName());
                 if (ps != null && ps.isPrivileged()) {
                     fsverityCandidates.put(pkg.getBaseApkPath(), null);
                     if (pkg.getSplitCodePaths() != null) {
@@ -18923,7 +19052,7 @@
         // Queue up an async operation since the package deletion may take a little while.
         mHandler.post(() -> {
             int returnCode;
-            final PackageSetting ps = mSettings.mPackages.get(internalPackageName);
+            final PackageSetting ps = mSettings.getPackageLPr(internalPackageName);
             boolean doDeletePackage = true;
             if (ps != null) {
                 final boolean targetIsInstantApp =
@@ -19201,7 +19330,7 @@
         int[] allUsers;
         /** enabled state of the uninstalled application */
         synchronized (mLock) {
-            uninstalledPs = mSettings.mPackages.get(packageName);
+            uninstalledPs = mSettings.getPackageLPr(packageName);
             if (uninstalledPs == null) {
                 Slog.w(TAG, "Not removing non-existent package " + packageName);
                 return PackageManager.DELETE_FAILED_INTERNAL_ERROR;
@@ -19500,7 +19629,7 @@
                 synchronized (mLock) {
                     clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL, true);
                     clearDefaultBrowserIfNeeded(packageName);
-                    mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName);
+                    mSettings.getKeySetManagerService().removeAppKeySetDataLPw(packageName);
                     mAppsFilter.removePackage(getPackageSetting(packageName));
                     removedAppId = mSettings.removePackageLPw(packageName);
                     if (outInfo != null) {
@@ -19650,7 +19779,7 @@
                 // We've re-installed the stub; make sure it's disabled here. If package was
                 // originally enabled, we'll install the compressed version of the application
                 // and re-enable it afterward.
-                final PackageSetting stubPs = mSettings.mPackages.get(deletedPkg.getPackageName());
+                final PackageSetting stubPs = mSettings.getPackageLPr(deletedPkg.getPackageName());
                 if (stubPs != null) {
                     int userId = action.user == null
                             ? UserHandle.USER_ALL : action.user.getIdentifier();
@@ -19706,7 +19835,7 @@
 
         // writer
         synchronized (mLock) {
-            PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName());
+            PackageSetting ps = mSettings.getPackageLPr(pkg.getPackageName());
 
             final boolean applyUserRestrictions = origUserHandles != null;
             if (applyUserRestrictions) {
@@ -19799,7 +19928,7 @@
     @Override
     public boolean getBlockUninstallForUser(String packageName, int userId) {
         synchronized (mLock) {
-            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            final PackageSetting ps = mSettings.getPackageLPr(packageName);
             if (ps == null || shouldFilterApplicationLocked(ps, Binder.getCallingUid(), userId)) {
                 return false;
             }
@@ -19811,7 +19940,7 @@
     public boolean setRequiredForSystemUser(String packageName, boolean systemUserApp) {
         enforceSystemOrRoot("setRequiredForSystemUser can only be run by the system or root");
         synchronized (mLock) {
-            PackageSetting ps = mSettings.mPackages.get(packageName);
+            PackageSetting ps = mSettings.getPackageLPr(packageName);
             if (ps == null) {
                 Log.w(TAG, "Package doesn't exist: " + packageName);
                 return false;
@@ -19879,7 +20008,7 @@
             ParsedPackage replacingPackage) {
         final DeletePackageAction action;
         synchronized (mLock) {
-            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            final PackageSetting ps = mSettings.getPackageLPr(packageName);
             final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps);
             action = mayDeletePackageLocked(outInfo, ps, disabledPs, flags, user);
         }
@@ -20169,7 +20298,7 @@
         PackageSetting ps;
         synchronized (mLock) {
             pkg = mPackages.get(packageName);
-            ps = mSettings.mPackages.get(packageName);
+            ps = mSettings.getPackageLPr(packageName);
             if (pkg == null) {
                 if (ps != null) {
                     pkg = ps.pkg;
@@ -20306,7 +20435,7 @@
     private boolean getPackageSizeInfoLI(String packageName, int userId, PackageStats stats) {
         final PackageSetting ps;
         synchronized (mLock) {
-            ps = mSettings.mPackages.get(packageName);
+            ps = mSettings.getPackageLPr(packageName);
             if (ps == null) {
                 Slog.w(TAG, "Failed to find settings for " + packageName);
                 return false;
@@ -20613,10 +20742,10 @@
     }
 
     private void clearDefaultBrowserIfNeededForUser(String packageName, int userId) {
-        final String defaultBrowserPackageName = mPermissionManager.getDefaultBrowser(userId);
+        final String defaultBrowserPackageName = mDefaultAppProvider.getDefaultBrowser(userId);
         if (!TextUtils.isEmpty(defaultBrowserPackageName)) {
             if (packageName.equals(defaultBrowserPackageName)) {
-                mPermissionManager.setDefaultBrowser(null, true, true, userId);
+                mDefaultAppProvider.setDefaultBrowser(null, true, userId);
             }
         }
     }
@@ -20631,14 +20760,13 @@
             // If this browser is restored from user's backup, do not clear
             // default-browser state for this user
             if (installReason != PackageManager.INSTALL_REASON_DEVICE_RESTORE) {
-                mPermissionManager.setDefaultBrowser(null, true, true, userId);
+                mDefaultAppProvider.setDefaultBrowser(null, true, userId);
             }
         }
 
         // We may also need to apply pending (restored) runtime permission grants
         // within these users.
-        mPermissionManager.restoreDelayedRuntimePermissions(packageName,
-                UserHandle.of(userId));
+        mPermissionManager.restoreDelayedRuntimePermissions(packageName, userId);
 
         // Persistent preferred activity might have came into effect due to this
         // install.
@@ -20670,7 +20798,7 @@
             // significant refactoring to keep all default apps in the package
             // manager (cleaner but more work) or have the services provide
             // callbacks to the package manager to request a default app reset.
-            mPermissionManager.setDefaultBrowser(null, true, true, userId);
+            mDefaultAppProvider.setDefaultBrowser(null, true, userId);
             resetNetworkPolicies(userId);
             synchronized (mLock) {
                 scheduleWritePackageRestrictionsLocked(userId);
@@ -20904,8 +21032,7 @@
                             defaultBrowser = mSettings.removeDefaultBrowserPackageNameLPw(userId1);
                         }
                         if (defaultBrowser != null) {
-                            mPermissionManager
-                                    .setDefaultBrowser(defaultBrowser, false, false, userId1);
+                            mDefaultAppProvider.setDefaultBrowser(defaultBrowser, false, userId1);
                         }
                     });
         } catch (Exception e) {
@@ -21145,7 +21272,7 @@
         }
         allHomeCandidates.addAll(resolveInfos);
 
-        final String packageName = mPermissionManager.getDefaultHome(userId);
+        final String packageName = mDefaultAppProvider.getDefaultHome(userId);
         if (packageName == null) {
             return null;
         }
@@ -21199,7 +21326,7 @@
         final String packageName = preferredResolveInfo != null
                 && preferredResolveInfo.activityInfo != null
                 ? preferredResolveInfo.activityInfo.packageName : null;
-        final String currentPackageName = mPermissionManager.getDefaultHome(userId);
+        final String currentPackageName = mDefaultAppProvider.getDefaultHome(userId);
         if (TextUtils.equals(currentPackageName, packageName)) {
             return false;
         }
@@ -21214,12 +21341,12 @@
             // Keep the default home package in RoleManager.
             return false;
         }
-        mPermissionManager.setDefaultHome(packageName, userId, (successful) -> {
-            if (successful) {
-                postPreferredActivityChangedBroadcast(userId);
-            }
-        });
-        return true;
+        return mDefaultAppProvider.setDefaultHome(packageName, userId, mContext.getMainExecutor(),
+                successful -> {
+                    if (successful) {
+                        postPreferredActivityChangedBroadcast(userId);
+                    }
+                });
     }
 
     @Override
@@ -21482,7 +21609,7 @@
     public void setUpdateAvailable(String packageName, boolean updateAvailable) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
         synchronized (mLock) {
-            final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
+            final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName);
             if (pkgSetting != null) {
                 pkgSetting.setUpdateAvailable(updateAvailable);
             }
@@ -21607,7 +21734,7 @@
 
         // reader
         synchronized (mLock) {
-            pkgSetting = mSettings.mPackages.get(packageName);
+            pkgSetting = mSettings.getPackageLPr(packageName);
             if (pkgSetting == null) {
                 if (!isCallerInstantApp) {
                     if (className == null) {
@@ -21871,7 +21998,7 @@
                 return;
             }
             broadcastAllowList = isInstantApp ? null : mAppsFilter.getVisibilityAllowList(setting,
-                    userIds, mSettings.mPackages);
+                    userIds, mSettings.getPackagesLocked());
         }
         sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED,  packageName, extras, flags, null, null,
                 userIds, instantUserIds, broadcastAllowList);
@@ -21891,7 +22018,7 @@
                 true /* checkShell */, "stop package");
         // writer
         synchronized (mLock) {
-            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            final PackageSetting ps = mSettings.getPackageLPr(packageName);
             if (!shouldFilterApplicationLocked(ps, callingUid, userId)
                     && mSettings.setPackageStoppedStateLPw(this, packageName, stopped,
                             allowedByPermission, callingUid, userId)) {
@@ -21910,7 +22037,7 @@
             }
             String installerPackageName = installSource.installerPackageName;
             if (installerPackageName != null) {
-                final PackageSetting ps = mSettings.mPackages.get(installerPackageName);
+                final PackageSetting ps = mSettings.getPackageLPr(installerPackageName);
                 if (ps == null || shouldFilterApplicationLocked(ps, callingUid,
                         UserHandle.getUserId(callingUid))) {
                     installerPackageName = null;
@@ -21939,7 +22066,7 @@
 
             installerPackageName = installSource.installerPackageName;
             if (installerPackageName != null) {
-                final PackageSetting ps = mSettings.mPackages.get(installerPackageName);
+                final PackageSetting ps = mSettings.getPackageLPr(installerPackageName);
                 if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
                     installerPackageName = null;
                 }
@@ -21964,7 +22091,7 @@
                     initiatingPackageName = installerPackageName;
                 } else {
                     initiatingPackageName = installSource.initiatingPackageName;
-                    final PackageSetting ps = mSettings.mPackages.get(initiatingPackageName);
+                    final PackageSetting ps = mSettings.getPackageLPr(initiatingPackageName);
                     if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
                         initiatingPackageName = null;
                     }
@@ -21973,7 +22100,7 @@
 
             originatingPackageName = installSource.originatingPackageName;
             if (originatingPackageName != null) {
-                final PackageSetting ps = mSettings.mPackages.get(originatingPackageName);
+                final PackageSetting ps = mSettings.getPackageLPr(originatingPackageName);
                 if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
                     originatingPackageName = null;
                 }
@@ -22006,7 +22133,7 @@
     @GuardedBy("mLock")
     @Nullable
     private InstallSource getInstallSourceLocked(String packageName, int callingUid) {
-        final PackageSetting ps = mSettings.mPackages.get(packageName);
+        final PackageSetting ps = mSettings.getPackageLPr(packageName);
 
         // Installer info for Apex is not stored in PackageManager
         if (ps == null && mApexManager.isApexPackage(packageName)) {
@@ -22165,6 +22292,24 @@
 
         mPermissionManager.systemReady();
 
+        int[] grantPermissionsUserIds = EMPTY_INT_ARRAY;
+        for (int userId : UserManagerService.getInstance().getUserIds()) {
+            if (mPmInternal.isPermissionUpgradeNeeded(userId)) {
+                grantPermissionsUserIds = ArrayUtils.appendInt(
+                        grantPermissionsUserIds, userId);
+            }
+        }
+        // If we upgraded grant all default permissions before kicking off.
+        for (int userId : grantPermissionsUserIds) {
+            mLegacyPermissionManager.grantDefaultPermissions(userId);
+        }
+        if (grantPermissionsUserIds == EMPTY_INT_ARRAY) {
+            // If we did not grant default permissions, we preload from this the
+            // default permission exceptions lazily to ensure we don't hit the
+            // disk on a new user creation.
+            mLegacyPermissionManager.scheduleReadDefaultPermissionExceptions();
+        }
+
         if (mInstantAppResolverConnection != null) {
             mContext.registerReceiver(new BroadcastReceiver() {
                 @Override
@@ -22669,13 +22814,14 @@
                     && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)
                     && packageName == null) {
                 pw.println();
-                int count = mSettings.mPackages.size();
+                int count = mSettings.getPackagesLocked().size();
                 if (count == 0) {
                     pw.println("No applications!");
                     pw.println();
                 } else {
                     final String prefix = "  ";
-                    Collection<PackageSetting> allPackageSettings = mSettings.mPackages.values();
+                    Collection<PackageSetting> allPackageSettings =
+                            mSettings.getPackagesLocked().values();
                     if (allPackageSettings.size() == 0) {
                         pw.println("No domain preferred apps!");
                         pw.println();
@@ -22732,7 +22878,7 @@
             }
 
             if (!checkin && dumpState.isDumping(DumpState.DUMP_KEYSETS)) {
-                mSettings.mKeySetManagerService.dumpLPr(pw, packageName, dumpState);
+                mSettings.getKeySetManagerService().dumpLPr(pw, packageName, dumpState);
             }
 
             if (dumpState.isDumping(DumpState.DUMP_PACKAGES)) {
@@ -22863,7 +23009,7 @@
         if (ArrayUtils.isEmpty(apkList)) {
            return;
         }
-        String sku = mInjector.getSystemWrapper().getProperty("ro.boot.hardware.sku");
+        String sku = SystemProperties.get("ro.boot.hardware.sku");
         if (!TextUtils.isEmpty(sku) && ArrayUtils.contains(skuArray, sku)) {
             return;
         }
@@ -22959,7 +23105,7 @@
         ipw.increaseIndent();
         Collection<PackageSetting> pkgSettings;
         if (packageName != null) {
-            PackageSetting targetPkgSetting = mSettings.mPackages.get(packageName);
+            PackageSetting targetPkgSetting = mSettings.getPackageLPr(packageName);
             if (targetPkgSetting != null) {
                 pkgSettings = Collections.singletonList(targetPkgSetting);
             } else {
@@ -22967,7 +23113,7 @@
                 return;
             }
         } else {
-            pkgSettings = mSettings.mPackages.values();
+            pkgSettings = mSettings.getPackagesLocked().values();
         }
 
         for (PackageSetting pkgSetting : pkgSettings) {
@@ -23268,7 +23414,7 @@
             // Normalize package name to handle renamed packages
             packageName = normalizePackageNameLPr(packageName);
 
-            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            final PackageSetting ps = mSettings.getPackageLPr(packageName);
             if (ps == null) {
                 throw new PackageManagerException("Package " + packageName + " is unknown");
             } else if (!TextUtils.equals(volumeUuid, ps.volumeUuid)) {
@@ -23285,9 +23431,9 @@
     private List<String> collectAbsoluteCodePaths() {
         synchronized (mLock) {
             List<String> codePaths = new ArrayList<>();
-            final int packageCount = mSettings.mPackages.size();
+            final int packageCount = mSettings.getPackagesLocked().size();
             for (int i = 0; i < packageCount; i++) {
-                final PackageSetting ps = mSettings.mPackages.valueAt(i);
+                final PackageSetting ps = mSettings.getPackagesLocked().valueAt(i);
                 codePaths.add(ps.getPath().getAbsolutePath());
             }
             return codePaths;
@@ -23489,7 +23635,7 @@
     private void prepareAppDataAfterInstallLIF(AndroidPackage pkg) {
         final PackageSetting ps;
         synchronized (mLock) {
-            ps = mSettings.mPackages.get(pkg.getPackageName());
+            ps = mSettings.getPackageLPr(pkg.getPackageName());
             mSettings.writeKernelMappingLPr(ps);
         }
 
@@ -23566,7 +23712,7 @@
 
         final PackageSetting ps;
         synchronized (mLock) {
-            ps = mSettings.mPackages.get(pkg.getPackageName());
+            ps = mSettings.getPackageLPr(pkg.getPackageName());
         }
         final String volumeUuid = pkg.getVolumeUuid();
         final String packageName = pkg.getPackageName();
@@ -23761,7 +23907,7 @@
                 mPackageName = packageName;
                 mWeFroze = mFrozenPackages.add(mPackageName);
 
-                final PackageSetting ps = mSettings.mPackages.get(mPackageName);
+                final PackageSetting ps = mSettings.getPackageLPr(mPackageName);
                 if (ps != null) {
                     killApplication(ps.name, ps.appId, userId, killReason);
                 }
@@ -23843,7 +23989,7 @@
         // reader
         synchronized (mLock) {
             final AndroidPackage pkg = mPackages.get(packageName);
-            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            final PackageSetting ps = mSettings.getPackageLPr(packageName);
             if (pkg == null
                     || ps == null
                     || shouldFilterApplicationLocked(ps, callingUid, user.getIdentifier())) {
@@ -24174,9 +24320,9 @@
     private void removeUnusedPackagesLPw(UserManagerService userManager, final int userId) {
         final boolean DEBUG_CLEAN_APKS = false;
         int [] users = userManager.getUserIds();
-        final int numPackages = mSettings.mPackages.size();
+        final int numPackages = mSettings.getPackagesLocked().size();
         for (int index = 0; index < numPackages; index++) {
-            final PackageSetting ps = mSettings.mPackages.valueAt(index);
+            final PackageSetting ps = mSettings.getPackagesLocked().valueAt(index);
             if (ps.pkg == null) {
                 continue;
             }
@@ -24245,14 +24391,9 @@
             Slog.d(TAG, "onNewUserCreated(id=" + userId
                     + ", convertedFromPreCreated=" + convertedFromPreCreated + ")");
         }
-        if (!convertedFromPreCreated) {
-            mPermissionManager.onNewUserCreated(userId);
-            return;
-        }
-        if (!readPermissionStateForUser(userId)) {
-            // Could not read the existing permissions, re-grant them.
-            Slog.i(TAG, "re-granting permissions for pre-created user " + userId);
-            mPermissionManager.onNewUserCreated(userId);
+        if (!convertedFromPreCreated || !readPermissionStateForUser(userId)) {
+            mPermissionManager.onUserCreated(userId);
+            mLegacyPermissionManager.grantDefaultPermissions(userId);
         }
     }
 
@@ -24345,7 +24486,7 @@
                 Slog.w(TAG, "KeySet requested for filtered package: " + packageName);
                 throw new IllegalArgumentException("Unknown package: " + packageName);
             }
-            final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+            final KeySetManagerService ksms = mSettings.getKeySetManagerService();
             return new KeySet(ksms.getKeySetByAliasAndPackageNameLPr(packageName, alias));
         }
     }
@@ -24374,7 +24515,7 @@
                     && Process.SYSTEM_UID != callingUid) {
                 throw new SecurityException("May not access signing KeySet of other apps.");
             }
-            final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+            final KeySetManagerService ksms = mSettings.getKeySetManagerService();
             return new KeySet(ksms.getSigningKeySetByPackageNameLPr(packageName));
         }
     }
@@ -24398,7 +24539,7 @@
             }
             IBinder ksh = ks.getToken();
             if (ksh instanceof KeySetHandle) {
-                final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+                final KeySetManagerService ksms = mSettings.getKeySetManagerService();
                 return ksms.packageIsSignedByLPr(packageName, (KeySetHandle) ksh);
             }
             return false;
@@ -24424,7 +24565,7 @@
             }
             IBinder ksh = ks.getToken();
             if (ksh instanceof KeySetHandle) {
-                final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+                final KeySetManagerService ksms = mSettings.getKeySetManagerService();
                 return ksms.packageIsSignedByExactlyLPr(packageName, (KeySetHandle) ksh);
             }
             return false;
@@ -24433,7 +24574,7 @@
 
     @GuardedBy("mLock")
     private void deletePackageIfUnusedLPr(final String packageName) {
-        PackageSetting ps = mSettings.mPackages.get(packageName);
+        PackageSetting ps = mSettings.getPackageLPr(packageName);
         if (ps == null) {
             return;
         }
@@ -24769,7 +24910,7 @@
 
         @Override
         public boolean isPlatformSigned(String packageName) {
-            PackageSetting packageSetting = mSettings.mPackages.get(packageName);
+            PackageSetting packageSetting = mSettings.getPackageLPr(packageName);
             if (packageSetting == null) {
                 return false;
             }
@@ -24969,7 +25110,7 @@
         private String[] getKnownPackageNamesInternal(int knownPackage, int userId) {
             switch (knownPackage) {
                 case PackageManagerInternal.PACKAGE_BROWSER:
-                    return new String[]{mPermissionManager.getDefaultBrowser(userId)};
+                    return new String[] { mDefaultAppProvider.getDefaultBrowser(userId) };
                 case PackageManagerInternal.PACKAGE_INSTALLER:
                     return filterOnlySystemPackages(mRequiredInstallerPackage);
                 case PackageManagerInternal.PACKAGE_SETUP_WIZARD:
@@ -25058,7 +25199,7 @@
         @Override
         public long getCeDataInode(String packageName, int userId) {
             synchronized (mLock) {
-                final PackageSetting ps = mSettings.mPackages.get(packageName);
+                final PackageSetting ps = mSettings.getPackageLPr(packageName);
                 if (ps != null) {
                     return ps.getCeDataInode(userId);
                 }
@@ -25069,7 +25210,7 @@
         @Override
         public Bundle getSuspendedPackageLauncherExtras(String packageName, int userId) {
             synchronized (mLock) {
-                final PackageSetting ps = mSettings.mPackages.get(packageName);
+                final PackageSetting ps = mSettings.getPackageLPr(packageName);
                 final Bundle allExtras = new Bundle();
                 if (ps != null) {
                     final PackageUserState pus = ps.readUserState(userId);
@@ -25091,7 +25232,7 @@
         @Override
         public boolean isPackageSuspended(String packageName, int userId) {
             synchronized (mLock) {
-                final PackageSetting ps = mSettings.mPackages.get(packageName);
+                final PackageSetting ps = mSettings.getPackageLPr(packageName);
                 return (ps != null) ? ps.getSuspended(userId) : false;
             }
         }
@@ -25136,7 +25277,7 @@
         @Override
         public String getSuspendingPackage(String suspendedPackage, int userId) {
             synchronized (mLock) {
-                final PackageSetting ps = mSettings.mPackages.get(suspendedPackage);
+                final PackageSetting ps = mSettings.getPackageLPr(suspendedPackage);
                 if (ps != null) {
                     final PackageUserState pus = ps.readUserState(userId);
                     if (pus.suspended) {
@@ -25158,7 +25299,7 @@
         public SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage,
                 String suspendingPackage, int userId) {
             synchronized (mLock) {
-                final PackageSetting ps = mSettings.mPackages.get(suspendedPackage);
+                final PackageSetting ps = mSettings.getPackageLPr(suspendedPackage);
                 if (ps != null) {
                     final PackageUserState pus = ps.readUserState(userId);
                     if (pus.suspended) {
@@ -25174,7 +25315,7 @@
         @Override
         public int getDistractingPackageRestrictions(String packageName, int userId) {
             synchronized (mLock) {
-                final PackageSetting ps = mSettings.mPackages.get(packageName);
+                final PackageSetting ps = mSettings.getPackageLPr(packageName);
                 return (ps != null) ? ps.getDistractionFlags(userId) : RESTRICTION_NONE;
             }
         }
@@ -25270,7 +25411,7 @@
         @Override
         public boolean isPackageEphemeral(int userId, String packageName) {
             synchronized (mLock) {
-                final PackageSetting ps = mSettings.mPackages.get(packageName);
+                final PackageSetting ps = mSettings.getPackageLPr(packageName);
                 return ps != null ? ps.getInstantApp(userId) : false;
             }
         }
@@ -25461,7 +25602,7 @@
                             continue;
                         }
                         for (VersionedPackage dependent : dependents) {
-                            final PackageSetting ps = mSettings.mPackages.get(
+                            final PackageSetting ps = mSettings.getPackageLPr(
                                     dependent.getPackageName());
                             if (ps == null) {
                                 continue;
@@ -25472,7 +25613,7 @@
                     }
                 }
 
-                final PackageSetting ps = mSettings.mPackages.get(targetPackageName);
+                final PackageSetting ps = mSettings.getPackageLPr(targetPackageName);
                 ps.setOverlayPaths(overlayPaths, userId);
 
                 outUpdatedPackageNames.add(targetPackageName);
@@ -25542,7 +25683,7 @@
         @Override
         public boolean canAccessComponent(int callingUid, ComponentName component, int userId) {
             synchronized (mLock) {
-                final PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
+                final PackageSetting ps = mSettings.getPackageLPr(component.getPackageName());
                 return ps != null && !PackageManagerService.this.shouldFilterApplicationLocked(
                         ps, callingUid, component, TYPE_UNKNOWN, userId);
             }
@@ -25608,8 +25749,8 @@
         @Override
         public void forEachPackageSetting(Consumer<PackageSetting> actionLocked) {
             synchronized (mLock) {
-                for (int index = 0; index < mSettings.mPackages.size(); index++) {
-                    actionLocked.accept(mSettings.mPackages.valueAt(index));
+                for (int index = 0; index < mSettings.getPackagesLocked().size(); index++) {
+                    actionLocked.accept(mSettings.getPackagesLocked().valueAt(index));
                 }
             }
         }
@@ -25785,7 +25926,7 @@
                     return false;
                 }
                 final PackageSetting installerPackageSetting =
-                        mSettings.mPackages.get(packageSetting.installSource.installerPackageName);
+                        mSettings.getPackageLPr(packageSetting.installSource.installerPackageName);
                 return installerPackageSetting != null
                         && UserHandle.isSameApp(installerPackageSetting.appId, callingUid);
             }
@@ -25799,18 +25940,6 @@
         }
 
         @Override
-        public void setReadExternalStorageEnforced(boolean enforced) {
-            synchronized (mLock) {
-                if (mSettings.mReadExternalStorageEnforced != null
-                        && mSettings.mReadExternalStorageEnforced == enforced) {
-                    return;
-                }
-                mSettings.mReadExternalStorageEnforced = enforced ? Boolean.TRUE : Boolean.FALSE;
-                writeSettingsLPrTEMP();
-            }
-        }
-
-        @Override
         public void setIntegrityVerificationResult(int verificationId, int verificationResult) {
             final Message msg = mHandler.obtainMessage(INTEGRITY_VERIFICATION_COMPLETE);
             msg.arg1 = verificationId;
@@ -25886,7 +26015,7 @@
                 PackageManagerInternal.InstalledLoadingProgressCallback callback) {
             final PackageSetting ps;
             synchronized (mLock) {
-                ps = mSettings.mPackages.get(packageName);
+                ps = mSettings.getPackageLPr(packageName);
                 if (ps == null) {
                     Slog.w(TAG, "Failed unregistering loading progress callback. Package "
                             + packageName + " is not installed");
@@ -25949,7 +26078,7 @@
     @GuardedBy("mLock")
     @NonNull
     private String[] getSharedUserPackagesForPackageLocked(String packageName, int userId) {
-        final PackageSetting packageSetting = mSettings.mPackages.get(packageName);
+        final PackageSetting packageSetting = mSettings.getPackageLPr(packageName);
         if (packageSetting == null || !packageSetting.isSharedUser()) {
             return EmptyArray.STRING;
         }
@@ -26026,7 +26155,7 @@
         synchronized (mLock) {
             packageName = resolveInternalPackageNameInternalLocked(
                     packageName, PackageManager.VERSION_CODE_HIGHEST, callingUid);
-            return mSettings.mPackages.get(packageName);
+            return mSettings.getPackageLPr(packageName);
         }
     }
 
@@ -26117,7 +26246,7 @@
         enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
                 false /* checkShell */, "get install reason");
         synchronized (mLock) {
-            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            final PackageSetting ps = mSettings.getPackageLPr(packageName);
             if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
                 return PackageManager.INSTALL_REASON_UNKNOWN;
             }
@@ -26290,7 +26419,7 @@
         long currentTimeInMillis = System.currentTimeMillis();
         synchronized (mLock) {
             for (AndroidPackage pkg : mPackages.values()) {
-                PackageSetting ps =  mSettings.mPackages.get(pkg.getPackageName());
+                PackageSetting ps =  mSettings.getPackageLPr(pkg.getPackageName());
                 if (ps == null) {
                     continue;
                 }
@@ -26402,7 +26531,7 @@
 
     @Override
     public void setMimeGroup(String packageName, String mimeGroup, List<String> mimeTypes) {
-        boolean changed = mSettings.mPackages.get(packageName)
+        boolean changed = mSettings.getPackageLPr(packageName)
                 .setMimeGroup(mimeGroup, mimeTypes);
 
         if (changed) {
@@ -26412,7 +26541,7 @@
 
     @Override
     public List<String> getMimeGroup(String packageName, String mimeGroup) {
-        return mSettings.mPackages.get(packageName).getMimeGroup(mimeGroup);
+        return mSettings.getPackageLPr(packageName).getMimeGroup(mimeGroup);
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index 5fc5bac..9cd55a6 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -18,6 +18,8 @@
 
 import android.os.SystemProperties;
 
+import com.android.server.pm.dex.DexoptOptions;
+
 import dalvik.system.DexFile;
 
 /**
@@ -26,10 +28,22 @@
 public class PackageManagerServiceCompilerMapping {
     // Names for compilation reasons.
     public static final String REASON_STRINGS[] = {
-            "first-boot", "boot", "install", "bg-dexopt", "ab-ota", "inactive", "shared"
+        "first-boot",
+        "boot",
+        "install",
+        "install-fast",
+        "install-bulk",
+        "install-bulk-secondary",
+        "install-bulk-downgraded",
+        "install-bulk-secondary-downgraded",
+        "bg-dexopt",
+        "ab-ota",
+        "inactive",
+        // "shared" must be the last entry
+        "shared"
     };
 
-    static final int REASON_SHARED_INDEX = 6;
+    static final int REASON_SHARED_INDEX = REASON_STRINGS.length - 1;
 
     // Static block to ensure the strings array is of the right length.
     static {
@@ -53,8 +67,9 @@
     // exception in case the reason or value are invalid.
     private static String getAndCheckValidity(int reason) {
         String sysPropValue = SystemProperties.get(getSystemPropertyName(reason));
-        if (sysPropValue == null || sysPropValue.isEmpty() ||
-                !DexFile.isValidCompilerFilter(sysPropValue)) {
+        if (sysPropValue == null || sysPropValue.isEmpty()
+                || !(sysPropValue.equals(DexoptOptions.COMPILER_FILTER_NOOP)
+                        || DexFile.isValidCompilerFilter(sysPropValue))) {
             throw new IllegalStateException("Value \"" + sysPropValue +"\" not valid "
                     + "(reason " + REASON_STRINGS[reason] + ")");
         } else if (!isFilterAllowedForReason(reason, sysPropValue)) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 9f1d656..c77eda1 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -819,8 +819,8 @@
     /**
      * Parse given package and return minimal details.
      */
-    public static PackageInfoLite getMinimalPackageInfo(Context context, String packagePath,
-            int flags, String abiOverride) {
+    public static PackageInfoLite getMinimalPackageInfo(Context context,
+            PackageParser.PackageLite pkg, String packagePath, int flags, String abiOverride) {
         final PackageInfoLite ret = new PackageInfoLite();
         if (packagePath == null) {
             Slog.i(TAG, "Invalid package file " + packagePath);
@@ -829,14 +829,10 @@
         }
 
         final File packageFile = new File(packagePath);
-        final PackageParser.PackageLite pkg;
         final long sizeBytes;
         try {
-            pkg = PackageParser.parsePackageLite(packageFile, 0);
             sizeBytes = PackageHelper.calculateInstalledSize(pkg, abiOverride);
-        } catch (PackageParserException | IOException e) {
-            Slog.w(TAG, "Failed to parse package at " + packagePath + ": " + e);
-
+        } catch (IOException e) {
             if (!packageFile.exists()) {
                 ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_URI;
             } else {
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 9720819a..318b229 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -553,7 +553,8 @@
                                     + apkLiteResult.getErrorMessage(),
                             apkLiteResult.getException());
                 }
-                PackageLite pkgLite = new PackageLite(null, apkLiteResult.getResult(), null, null,
+                final ApkLite apkLite = apkLiteResult.getResult();
+                PackageLite pkgLite = new PackageLite(null, apkLite.codePath, apkLite, null, null,
                         null, null, null, null);
                 sessionSize += PackageHelper.calculateInstalledSize(pkgLite,
                         params.sessionParams.abiOverride, fd.getFileDescriptor());
@@ -2323,7 +2324,7 @@
             getErrPrintWriter().println("Error: no enforcement specified");
             return 1;
         }
-        mPermissionManager.setPermissionEnforced(permission, Boolean.parseBoolean(enforcedRaw));
+        // Permissions are always enforced now.
         return 0;
     }
 
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index f47b4b4..2d5034e 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -362,8 +362,6 @@
         }
     }
 
-    Boolean mReadExternalStorageEnforced;
-
     /** Device identity for the purpose of package verification. */
     private VerifierDeviceIdentity mVerifierDeviceIdentity;
 
@@ -475,6 +473,14 @@
         return mPackages.get(pkgName);
     }
 
+    ArrayMap<String, PackageSetting> getPackagesLocked() {
+        return mPackages;
+    }
+
+    KeySetManagerService getKeySetManagerService() {
+        return mKeySetManagerService;
+    }
+
     String getRenamedPackageLPr(String pkgName) {
         return mRenamedPackages.get(pkgName);
     }
@@ -1969,28 +1975,28 @@
                     serializer.attributeLong(null, ATTR_CE_DATA_INODE, ustate.ceDataInode);
                 }
                 if (!ustate.installed) {
-                    serializer.attribute(null, ATTR_INSTALLED, "false");
+                    serializer.attributeBoolean(null, ATTR_INSTALLED, false);
                 }
                 if (ustate.stopped) {
-                    serializer.attribute(null, ATTR_STOPPED, "true");
+                    serializer.attributeBoolean(null, ATTR_STOPPED, true);
                 }
                 if (ustate.notLaunched) {
-                    serializer.attribute(null, ATTR_NOT_LAUNCHED, "true");
+                    serializer.attributeBoolean(null, ATTR_NOT_LAUNCHED, true);
                 }
                 if (ustate.hidden) {
-                    serializer.attribute(null, ATTR_HIDDEN, "true");
+                    serializer.attributeBoolean(null, ATTR_HIDDEN, true);
                 }
                 if (ustate.distractionFlags != 0) {
                     serializer.attributeInt(null, ATTR_DISTRACTION_FLAGS, ustate.distractionFlags);
                 }
                 if (ustate.suspended) {
-                    serializer.attribute(null, ATTR_SUSPENDED, "true");
+                    serializer.attributeBoolean(null, ATTR_SUSPENDED, true);
                 }
                 if (ustate.instantApp) {
-                    serializer.attribute(null, ATTR_INSTANT_APP, "true");
+                    serializer.attributeBoolean(null, ATTR_INSTANT_APP, true);
                 }
                 if (ustate.virtualPreload) {
-                    serializer.attribute(null, ATTR_VIRTUAL_PRELOAD, "true");
+                    serializer.attributeBoolean(null, ATTR_VIRTUAL_PRELOAD, true);
                 }
                 if (ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
                     serializer.attributeInt(null, ATTR_ENABLED, ustate.enabled);
@@ -2334,13 +2340,6 @@
                 serializer.endTag(null, "verifier");
             }
 
-            if (mReadExternalStorageEnforced != null) {
-                serializer.startTag(null, TAG_READ_EXTERNAL_STORAGE);
-                serializer.attribute(
-                        null, ATTR_ENFORCEMENT, mReadExternalStorageEnforced ? "1" : "0");
-                serializer.endTag(null, TAG_READ_EXTERNAL_STORAGE);
-            }
-
             serializer.startTag(null, "permission-trees");
             mPermissions.writePermissionTrees(serializer);
             serializer.endTag(null, "permission-trees");
@@ -2731,7 +2730,7 @@
             serializer.attributeInt(null, "sharedUserId", pkg.appId);
         }
         if (pkg.uidError) {
-            serializer.attribute(null, "uidError", "true");
+            serializer.attributeBoolean(null, "uidError", true);
         }
         InstallSource installSource = pkg.installSource;
         if (installSource.installerPackageName != null) {
@@ -2742,13 +2741,13 @@
                     installSource.installerAttributionTag);
         }
         if (installSource.isOrphaned) {
-            serializer.attribute(null, "isOrphaned", "true");
+            serializer.attributeBoolean(null, "isOrphaned", true);
         }
         if (installSource.initiatingPackageName != null) {
             serializer.attribute(null, "installInitiator", installSource.initiatingPackageName);
         }
         if (installSource.isInitiatingPackageUninstalled) {
-            serializer.attribute(null, "installInitiatorUninstalled", "true");
+            serializer.attributeBoolean(null, "installInitiatorUninstalled", true);
         }
         if (installSource.originatingPackageName != null) {
             serializer.attribute(null, "installOriginator", installSource.originatingPackageName);
@@ -2760,16 +2759,16 @@
             serializer.attributeInt(null, "categoryHint", pkg.categoryHint);
         }
         if (pkg.updateAvailable) {
-            serializer.attribute(null, "updateAvailable", "true");
+            serializer.attributeBoolean(null, "updateAvailable", true);
         }
         if (pkg.forceQueryableOverride) {
-            serializer.attribute(null, "forceQueryable", "true");
+            serializer.attributeBoolean(null, "forceQueryable", true);
         }
         if (pkg.isPackageStartable()) {
-            serializer.attribute(null, "isStartable", "true");
+            serializer.attributeBoolean(null, "isStartable", true);
         }
         if (pkg.isPackageLoading()) {
-            serializer.attribute(null, "isLoading", "true");
+            serializer.attributeBoolean(null, "isLoading", true);
         }
 
         writeUsesStaticLibLPw(serializer, pkg.usesStaticLibraries, pkg.usesStaticLibrariesVersions);
@@ -2951,9 +2950,7 @@
                                 + e.getMessage());
                     }
                 } else if (TAG_READ_EXTERNAL_STORAGE.equals(tagName)) {
-                    final String enforcement = parser.getAttributeValue(null, ATTR_ENFORCEMENT);
-                    mReadExternalStorageEnforced =
-                            "1".equals(enforcement) ? Boolean.TRUE : Boolean.FALSE;
+                    // No longer used.
                 } else if (tagName.equals("keyset-settings")) {
                     mKeySetManagerService.readKeySetsLPw(parser, mKeySetRefs);
                 } else if (TAG_VERSION.equals(tagName)) {
@@ -3500,14 +3497,14 @@
         String systemStr = null;
         String installerPackageName = null;
         String installerAttributionTag = null;
-        String isOrphaned = null;
+        boolean isOrphaned = false;
         String installOriginatingPackageName = null;
         String installInitiatingPackageName = null;
-        String installInitiatorUninstalled = null;
+        boolean installInitiatorUninstalled = false;
         String volumeUuid = null;
-        String updateAvailable = null;
+        boolean updateAvailable = false;
         int categoryHint = ApplicationInfo.CATEGORY_UNDEFINED;
-        String uidError = null;
+        boolean uidError = false;
         int pkgFlags = 0;
         int pkgPrivateFlags = 0;
         long timeStamp = 0;
@@ -3515,14 +3512,14 @@
         long lastUpdateTime = 0;
         PackageSetting packageSetting = null;
         long versionCode = 0;
-        String installedForceQueryable = null;
-        String isStartable = null;
-        String isLoading = null;
+        boolean installedForceQueryable = false;
+        boolean isStartable = false;
+        boolean isLoading = false;
         try {
             name = parser.getAttributeValue(null, ATTR_NAME);
             realName = parser.getAttributeValue(null, "realName");
             userId = parser.getAttributeInt(null, "userId", 0);
-            uidError = parser.getAttributeValue(null, "uidError");
+            uidError = parser.getAttributeBoolean(null, "uidError", false);
             sharedUserId = parser.getAttributeInt(null, "sharedUserId", 0);
             codePathStr = parser.getAttributeValue(null, "codePath");
 
@@ -3532,10 +3529,10 @@
             primaryCpuAbiString = parser.getAttributeValue(null, "primaryCpuAbi");
             secondaryCpuAbiString = parser.getAttributeValue(null, "secondaryCpuAbi");
             cpuAbiOverrideString = parser.getAttributeValue(null, "cpuAbiOverride");
-            updateAvailable = parser.getAttributeValue(null, "updateAvailable");
-            installedForceQueryable = parser.getAttributeValue(null, "forceQueryable");
-            isStartable = parser.getAttributeValue(null, "isStartable");
-            isLoading = parser.getAttributeValue(null, "isLoading");
+            updateAvailable = parser.getAttributeBoolean(null, "updateAvailable", false);
+            installedForceQueryable = parser.getAttributeBoolean(null, "forceQueryable", false);
+            isStartable = parser.getAttributeBoolean(null, "isStartable", false);
+            isLoading = parser.getAttributeBoolean(null, "isLoading", false);
 
             if (primaryCpuAbiString == null && legacyCpuAbiString != null) {
                 primaryCpuAbiString = legacyCpuAbiString;
@@ -3544,11 +3541,11 @@
             versionCode = parser.getAttributeLong(null, "version", 0);
             installerPackageName = parser.getAttributeValue(null, "installer");
             installerAttributionTag = parser.getAttributeValue(null, "installerAttributionTag");
-            isOrphaned = parser.getAttributeValue(null, "isOrphaned");
+            isOrphaned = parser.getAttributeBoolean(null, "isOrphaned", false);
             installInitiatingPackageName = parser.getAttributeValue(null, "installInitiator");
             installOriginatingPackageName = parser.getAttributeValue(null, "installOriginator");
-            installInitiatorUninstalled = parser.getAttributeValue(null,
-                    "installInitiatorUninstalled");
+            installInitiatorUninstalled = parser.getAttributeBoolean(null,
+                    "installInitiatorUninstalled", false);
             volumeUuid = parser.getAttributeValue(null, "volumeUuid");
             categoryHint = parser.getAttributeInt(null, "categoryHint",
                     ApplicationInfo.CATEGORY_UNDEFINED);
@@ -3670,21 +3667,20 @@
                             + userId + " at " + parser.getPositionDescription());
         }
         if (packageSetting != null) {
-            packageSetting.uidError = "true".equals(uidError);
+            packageSetting.uidError = uidError;
             InstallSource installSource = InstallSource.create(
                     installInitiatingPackageName, installOriginatingPackageName,
-                    installerPackageName, installerAttributionTag, "true".equals(isOrphaned),
-                    "true".equals(installInitiatorUninstalled));
+                    installerPackageName, installerAttributionTag, isOrphaned,
+                    installInitiatorUninstalled);
             packageSetting.installSource = installSource;
             packageSetting.volumeUuid = volumeUuid;
             packageSetting.categoryHint = categoryHint;
             packageSetting.legacyNativeLibraryPathString = legacyNativeLibraryPathStr;
             packageSetting.primaryCpuAbiString = primaryCpuAbiString;
             packageSetting.secondaryCpuAbiString = secondaryCpuAbiString;
-            packageSetting.updateAvailable = "true".equals(updateAvailable);
-            packageSetting.forceQueryableOverride = "true".equals(installedForceQueryable);
-            packageSetting.incrementalStates = new IncrementalStates("true".equals(isStartable),
-                    "true".equals(isLoading));
+            packageSetting.updateAvailable = updateAvailable;
+            packageSetting.forceQueryableOverride = installedForceQueryable;
+            packageSetting.incrementalStates = new IncrementalStates(isStartable, isLoading);
             // Handle legacy string here for single-user mode
             final String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED);
             if (enabledStr != null) {
@@ -3914,7 +3910,7 @@
         {
             name = parser.getAttributeValue(null, ATTR_NAME);
             int userId = parser.getAttributeInt(null, "userId", 0);
-            if ("true".equals(parser.getAttributeValue(null, "system"))) {
+            if (parser.getAttributeBoolean(null, "system", false)) {
                 pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
             }
             if (name == null) {
@@ -4893,8 +4889,7 @@
             DumpState dumpState) {
         LegacyPermissionSettings.dumpPermissions(pw, packageName, permissionNames,
                 mPermissionDataProvider.getLegacyPermissions(),
-                mPermissionDataProvider.getAllAppOpPermissionPackages(),
-                (mReadExternalStorageEnforced == Boolean.TRUE), dumpState);
+                mPermissionDataProvider.getAllAppOpPermissionPackages(), true, dumpState);
     }
 
     void dumpSharedUsersLPr(PrintWriter pw, String packageName, ArraySet<String> permissionNames,
@@ -5554,7 +5549,8 @@
         return mPreferredActivities.get(userId);
     }
 
-    CrossProfileIntentResolver getCrossProfileIntentResolvers(int userId) {
+    @Nullable
+    CrossProfileIntentResolver getCrossProfileIntentResolver(int userId) {
         return mCrossProfileIntentResolvers.get(userId);
     }
 
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index 7d48d0a..e913829 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -30,6 +30,14 @@
       ]
     },
     {
+      "name": "FrameworksMockingServicesTests",
+      "options": [
+        {
+          "include-filter": "com.android.server.pm."
+        }
+      ]
+    },
+    {
       "name": "CtsContentTestCases",
       "options": [
         {
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index 47d0a3d5..c182d68 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -57,6 +57,20 @@
     }
 
     /**
+     * Listener for user lifecycle events.
+     *
+     * <p><b>NOTE: </b>implementations MUST not block the current thread.
+     */
+    public interface UserLifecycleListener {
+
+        /** Called when a new user is created. */
+        default void onUserCreated(UserInfo user) {}
+
+        /** Called when an existing user is removed. */
+        default void onUserRemoved(UserInfo user) {}
+    }
+
+    /**
      * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to set
      * restrictions enforced by the user.
      *
@@ -97,6 +111,12 @@
     /** Remove a {@link UserRestrictionsListener}. */
     public abstract void removeUserRestrictionsListener(UserRestrictionsListener listener);
 
+    /** Adds a {@link UserLifecycleListener}. */
+    public abstract void addUserLifecycleListener(UserLifecycleListener listener);
+
+    /** Removes a {@link UserLifecycleListener}. */
+    public abstract void removeUserLifecycleListener(UserLifecycleListener listener);
+
     /**
      * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to update
      * whether the device is managed by device owner.
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index cc814bcc..ccbf73c 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -110,6 +110,7 @@
 import com.android.server.LockGuard;
 import com.android.server.SystemService;
 import com.android.server.am.UserState;
+import com.android.server.pm.UserManagerInternal.UserLifecycleListener;
 import com.android.server.pm.UserManagerInternal.UserRestrictionsListener;
 import com.android.server.storage.DeviceStorageMonitorInternal;
 import com.android.server.utils.TimingsTraceAndSlog;
@@ -438,6 +439,9 @@
     private final ArrayList<UserRestrictionsListener> mUserRestrictionsListeners =
             new ArrayList<>();
 
+    @GuardedBy("mUserRemovedListeners")
+    private final ArrayList<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
+
     private final LockPatternUtils mLockPatternUtils;
 
     private final String ACTION_DISABLE_QUIET_MODE_AFTER_UNLOCK =
@@ -2918,16 +2922,16 @@
             serializer.attribute(null,  ATTR_ICON_PATH, userInfo.iconPath);
         }
         if (userInfo.partial) {
-            serializer.attribute(null, ATTR_PARTIAL, "true");
+            serializer.attributeBoolean(null, ATTR_PARTIAL, true);
         }
         if (userInfo.preCreated) {
-            serializer.attribute(null, ATTR_PRE_CREATED, "true");
+            serializer.attributeBoolean(null, ATTR_PRE_CREATED, true);
         }
         if (userInfo.convertedFromPreCreated) {
-            serializer.attribute(null, ATTR_CONVERTED_FROM_PRE_CREATED, "true");
+            serializer.attributeBoolean(null, ATTR_CONVERTED_FROM_PRE_CREATED, true);
         }
         if (userInfo.guestToRemove) {
-            serializer.attribute(null, ATTR_GUEST_TO_REMOVE, "true");
+            serializer.attributeBoolean(null, ATTR_GUEST_TO_REMOVE, true);
         }
         if (userInfo.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID) {
             serializer.attributeInt(null, ATTR_PROFILE_GROUP_ID, userInfo.profileGroupId);
@@ -3121,22 +3125,10 @@
             profileBadge = parser.getAttributeInt(null, ATTR_PROFILE_BADGE, 0);
             restrictedProfileParentId = parser.getAttributeInt(null,
                     ATTR_RESTRICTED_PROFILE_PARENT_ID, UserInfo.NO_PROFILE_GROUP_ID);
-            String valueString = parser.getAttributeValue(null, ATTR_PARTIAL);
-            if ("true".equals(valueString)) {
-                partial = true;
-            }
-            valueString = parser.getAttributeValue(null, ATTR_PRE_CREATED);
-            if ("true".equals(valueString)) {
-                preCreated = true;
-            }
-            valueString = parser.getAttributeValue(null, ATTR_CONVERTED_FROM_PRE_CREATED);
-            if ("true".equals(valueString)) {
-                converted = true;
-            }
-            valueString = parser.getAttributeValue(null, ATTR_GUEST_TO_REMOVE);
-            if ("true".equals(valueString)) {
-                guestToRemove = true;
-            }
+            partial = parser.getAttributeBoolean(null, ATTR_PARTIAL, false);
+            preCreated = parser.getAttributeBoolean(null, ATTR_PRE_CREATED, false);
+            converted = parser.getAttributeBoolean(null, ATTR_CONVERTED_FROM_PRE_CREATED, false);
+            guestToRemove = parser.getAttributeBoolean(null, ATTR_GUEST_TO_REMOVE, false);
 
             seedAccountName = parser.getAttributeValue(null, ATTR_SEED_ACCOUNT_NAME);
             seedAccountType = parser.getAttributeValue(null, ATTR_SEED_ACCOUNT_TYPE);
@@ -3645,6 +3637,14 @@
     }
 
     private void dispatchUserAdded(@NonNull UserInfo userInfo) {
+        // Notify internal listeners first...
+        synchronized (mUserLifecycleListeners) {
+            for (int i = 0; i < mUserLifecycleListeners.size(); i++) {
+                mUserLifecycleListeners.get(i).onUserCreated(userInfo);
+            }
+        }
+
+        //...then external ones
         Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
         addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userInfo.id);
         // Also, add the UserHandle for mainline modules which can't use the @hide
@@ -4030,13 +4030,19 @@
             user = getUserInfoLU(userId);
         }
         if (user != null && user.preCreated) {
-            Slog.i(LOG_TAG, "Removing a precreated user with user id: " + userId);
+            Slog.i(LOG_TAG, "Removing a pre-created user with user id: " + userId);
             // Don't want to fire ACTION_USER_REMOVED, so cleanup the state and exit early.
             LocalServices.getService(ActivityTaskManagerInternal.class).onUserStopped(userId);
             removeUserState(userId);
             return;
         }
 
+        synchronized (mUserLifecycleListeners) {
+            for (int i = 0; i < mUserLifecycleListeners.size(); i++) {
+                mUserLifecycleListeners.get(i).onUserRemoved(user);
+            }
+        }
+
         // Let other services shutdown any activity and clean up their state before completely
         // wiping the user's system directory and removing from the user list
         final long ident = Binder.clearCallingIdentity();
@@ -4257,10 +4263,9 @@
         if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_ENTRY)) {
             String key = parser.getAttributeValue(null, ATTR_KEY);
             String valType = parser.getAttributeValue(null, ATTR_VALUE_TYPE);
-            String multiple = parser.getAttributeValue(null, ATTR_MULTIPLE);
-            if (multiple != null) {
+            int count = parser.getAttributeInt(null, ATTR_MULTIPLE, -1);
+            if (count != -1) {
                 values.clear();
-                int count = Integer.parseInt(multiple);
                 while (count > 0 && (type = parser.next()) != XmlPullParser.END_DOCUMENT) {
                     if (type == XmlPullParser.START_TAG
                             && parser.getName().equals(TAG_VALUE)) {
@@ -4973,6 +4978,15 @@
             pw.println("  System user allocations: " + mUser0Allocations.get());
         }
 
+        pw.println();
+        pw.println("Number of listeners for");
+        synchronized (mUserRestrictionsListeners) {
+            pw.println("  restrictions: " + mUserRestrictionsListeners.size());
+        }
+        synchronized (mUserLifecycleListeners) {
+            pw.println("  user lifecycle events: " + mUserLifecycleListeners.size());
+        }
+
         // Dump UserTypes
         pw.println();
         pw.println("User types version: " + mUserTypeVersion);
@@ -5091,6 +5105,20 @@
         }
 
         @Override
+        public void addUserLifecycleListener(UserLifecycleListener listener) {
+            synchronized (mUserLifecycleListeners) {
+                mUserLifecycleListeners.add(listener);
+            }
+        }
+
+        @Override
+        public void removeUserLifecycleListener(UserLifecycleListener listener) {
+            synchronized (mUserLifecycleListeners) {
+                mUserLifecycleListeners.remove(listener);
+            }
+        }
+
+        @Override
         public void setDeviceManaged(boolean isManaged) {
             synchronized (mUsersLock) {
                 mIsDeviceManaged = isManaged;
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 0ac3030..51dff40 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -344,7 +344,7 @@
             }
             if (USER_RESTRICTIONS.contains(key)) {
                 if (restrictions.getBoolean(key)) {
-                    serializer.attribute(null, key, "true");
+                    serializer.attributeBoolean(null, key, true);
                 }
                 continue;
             }
@@ -360,9 +360,9 @@
     public static void readRestrictions(TypedXmlPullParser parser, Bundle restrictions) {
         restrictions.clear();
         for (String key : USER_RESTRICTIONS) {
-            final String value = parser.getAttributeValue(null, key);
-            if (value != null) {
-                restrictions.putBoolean(key, Boolean.parseBoolean(value));
+            final boolean value = parser.getAttributeBoolean(null, key, false);
+            if (value) {
+                restrictions.putBoolean(key, true);
             }
         }
     }
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index 1d3aecd..1ffbf60 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -30,6 +30,7 @@
 import static android.os.UserManager.USER_TYPE_FULL_SECONDARY;
 import static android.os.UserManager.USER_TYPE_FULL_SYSTEM;
 import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
+import static android.os.UserManager.USER_TYPE_PROFILE_TEST;
 import static android.os.UserManager.USER_TYPE_SYSTEM_HEADLESS;
 
 import static com.android.server.pm.UserTypeDetails.UNLIMITED_NUMBER_OF_USERS;
@@ -37,6 +38,7 @@
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.UserManager;
 import android.util.ArrayMap;
@@ -98,6 +100,9 @@
         builders.put(USER_TYPE_FULL_DEMO, getDefaultTypeFullDemo());
         builders.put(USER_TYPE_FULL_RESTRICTED, getDefaultTypeFullRestricted());
         builders.put(USER_TYPE_SYSTEM_HEADLESS, getDefaultTypeSystemHeadless());
+        if (Build.IS_DEBUGGABLE) {
+            builders.put(USER_TYPE_PROFILE_TEST, getDefaultTypeProfileTest());
+        }
 
         return builders;
     }
@@ -132,6 +137,37 @@
     }
 
     /**
+     * Returns the Builder for the default {@link UserManager#USER_TYPE_PROFILE_TEST}
+     * configuration (for userdebug builds). For now it just uses managed profile badges.
+     */
+    private static UserTypeDetails.Builder getDefaultTypeProfileTest() {
+        final Bundle restrictions = new Bundle();
+        restrictions.putBoolean(UserManager.DISALLOW_FUN, true);
+
+        return new UserTypeDetails.Builder()
+                .setName(USER_TYPE_PROFILE_TEST)
+                .setBaseType(FLAG_PROFILE)
+                .setMaxAllowedPerParent(2)
+                .setLabel(0)
+                .setIconBadge(com.android.internal.R.drawable.ic_corp_icon_badge_case)
+                .setBadgePlain(com.android.internal.R.drawable.ic_corp_badge_case)
+                .setBadgeNoBackground(com.android.internal.R.drawable.ic_corp_badge_no_background)
+                .setBadgeLabels(
+                        com.android.internal.R.string.managed_profile_label_badge,
+                        com.android.internal.R.string.managed_profile_label_badge_2,
+                        com.android.internal.R.string.managed_profile_label_badge_3)
+                .setBadgeColors(
+                        com.android.internal.R.color.profile_badge_1,
+                        com.android.internal.R.color.profile_badge_2,
+                        com.android.internal.R.color.profile_badge_3)
+                .setDarkThemeBadgeColors(
+                        com.android.internal.R.color.profile_badge_1_dark,
+                        com.android.internal.R.color.profile_badge_2_dark,
+                        com.android.internal.R.color.profile_badge_3_dark)
+                .setDefaultRestrictions(restrictions);
+    }
+
+    /**
      * Returns the Builder for the default {@link UserManager#USER_TYPE_FULL_SECONDARY}
      * configuration.
      */
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index fadd0c8..139654e 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -579,6 +579,8 @@
     // Constants used for logging compilation reason to TRON.
     // DO NOT CHANGE existing values.
     //
+    // In the below constants, the abbreviation DM stands for "DEX metadata".
+    //
     // NOTE: '-1' value is reserved for the case where we cannot produce a valid
     // PackageOptimizationInfo because the ArtManagerInternal is not ready to be used by the
     // ActivityMetricsLoggers.
@@ -591,7 +593,18 @@
     private static final int TRON_COMPILATION_REASON_AB_OTA = 6;
     private static final int TRON_COMPILATION_REASON_INACTIVE = 7;
     private static final int TRON_COMPILATION_REASON_SHARED = 8;
-    private static final int TRON_COMPILATION_REASON_INSTALL_WITH_DEX_METADATA = 9;
+    private static final int TRON_COMPILATION_REASON_INSTALL_WITH_DM = 9;
+    private static final int TRON_COMPILATION_REASON_INSTALL_FAST = 10;
+    private static final int TRON_COMPILATION_REASON_INSTALL_BULK = 11;
+    private static final int TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY = 12;
+    private static final int TRON_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED = 13;
+    private static final int TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED = 14;
+    private static final int TRON_COMPILATION_REASON_INSTALL_FAST_WITH_DM = 15;
+    private static final int TRON_COMPILATION_REASON_INSTALL_BULK_WITH_DM = 16;
+    private static final int TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_WITH_DM = 17;
+    private static final int TRON_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED_WITH_DM = 18;
+    private static final int
+            TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED_WITH_DM = 19;
 
     // The annotation to add as a suffix to the compilation reason when dexopt was
     // performed with dex metadata.
@@ -611,10 +624,30 @@
             case "ab-ota" : return TRON_COMPILATION_REASON_AB_OTA;
             case "inactive" : return TRON_COMPILATION_REASON_INACTIVE;
             case "shared" : return TRON_COMPILATION_REASON_SHARED;
-            // This is a special marker for dex metadata installation that does not
+            case "install-fast" :
+                return TRON_COMPILATION_REASON_INSTALL_FAST;
+            case "install-bulk" :
+                return TRON_COMPILATION_REASON_INSTALL_BULK;
+            case "install-bulk-secondary" :
+                return TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY;
+            case "install-bulk-downgraded" :
+                return TRON_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED;
+            case "install-bulk-secondary-downgraded" :
+                return TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED;
+            // These are special markers for dex metadata installation that do not
             // have an equivalent as a system property.
             case "install" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION :
-                return TRON_COMPILATION_REASON_INSTALL_WITH_DEX_METADATA;
+                return TRON_COMPILATION_REASON_INSTALL_WITH_DM;
+            case "install-fast" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION :
+                return TRON_COMPILATION_REASON_INSTALL_FAST_WITH_DM;
+            case "install-bulk" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION :
+                return TRON_COMPILATION_REASON_INSTALL_BULK_WITH_DM;
+            case "install-bulk-secondary" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION :
+                return TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_WITH_DM;
+            case "install-bulk-downgraded" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION :
+                return TRON_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED_WITH_DM;
+            case "install-bulk-secondary-downgraded" + DEXOPT_REASON_WITH_DEX_METADATA_ANNOTATION :
+                return TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED_WITH_DM;
             default: return TRON_COMPILATION_REASON_UNKNOWN;
         }
     }
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 3074250..cc6d80a 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -27,8 +27,11 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.PackagePartitions;
+import android.os.BatteryManager;
 import android.os.FileUtils;
+import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -107,6 +110,13 @@
     @GuardedBy("mInstallLock")
     private final Installer mInstaller;
 
+    private BatteryManager mBatteryManager = null;
+    private PowerManager mPowerManager = null;
+
+    // An integer percentage value used to determine when the device is considered to be on low
+    // power for compilation purposes.
+    private final int mCriticalBatteryLevel;
+
     // Possible outcomes of a dex search.
     private static int DEX_SEARCH_NOT_FOUND = 0;  // dex file not found
     private static int DEX_SEARCH_FOUND_PRIMARY = 1;  // dex file is the primary/base apk
@@ -123,6 +133,23 @@
         mInstaller = installer;
         mInstallLock = installLock;
         mDynamicCodeLogger = new DynamicCodeLogger(pms, installer);
+
+        // This is currently checked to handle tests that pass in a null context.
+        // TODO(b/174783329): Modify the tests to pass in a mocked Context, PowerManager,
+        //      and BatteryManager.
+        if (mContext != null) {
+            mPowerManager = mContext.getSystemService(PowerManager.class);
+
+            if (mPowerManager == null) {
+                Slog.wtf(TAG, "Power Manager is unavailable at time of Dex Manager start");
+            }
+
+            mCriticalBatteryLevel = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_criticalBatteryWarningLevel);
+        } else {
+            // This value will never be used as the Battery Manager null check will fail first.
+            mCriticalBatteryLevel = 0;
+        }
     }
 
     public DynamicCodeLogger getDynamicCodeLogger() {
@@ -905,6 +932,74 @@
         }
     }
 
+    /**
+     * Translates install scenarios into compilation reasons.  This process can be influenced
+     * by the state of the device.
+     */
+    public int getCompilationReasonForInstallScenario(int installScenario) {
+        // Compute the compilation reason from the installation scenario.
+
+        boolean resourcesAreCritical = areBatteryThermalOrMemoryCritical();
+        switch (installScenario) {
+            case PackageManager.INSTALL_SCENARIO_DEFAULT: {
+                return PackageManagerService.REASON_INSTALL;
+            }
+            case PackageManager.INSTALL_SCENARIO_FAST: {
+                return PackageManagerService.REASON_INSTALL_FAST;
+            }
+            case PackageManager.INSTALL_SCENARIO_BULK: {
+                if (resourcesAreCritical) {
+                    return PackageManagerService.REASON_INSTALL_BULK_DOWNGRADED;
+                } else {
+                    return PackageManagerService.REASON_INSTALL_BULK;
+                }
+            }
+            case PackageManager.INSTALL_SCENARIO_BULK_SECONDARY: {
+                if (resourcesAreCritical) {
+                    return PackageManagerService.REASON_INSTALL_BULK_SECONDARY_DOWNGRADED;
+                } else {
+                    return PackageManagerService.REASON_INSTALL_BULK_SECONDARY;
+                }
+            }
+            default: {
+                throw new IllegalArgumentException("Invalid installation scenario");
+            }
+        }
+    }
+
+    /**
+     * Fetches the battery manager object and caches it if it hasn't been fetched already.
+     */
+    private BatteryManager getBatteryManager() {
+        if (mBatteryManager == null) {
+            mBatteryManager = mContext.getSystemService(BatteryManager.class);
+        }
+
+        return mBatteryManager;
+    }
+
+    /**
+     * Returns true if the battery level, device temperature, or memory usage are considered to be
+     * in a critical state.
+     */
+    private boolean areBatteryThermalOrMemoryCritical() {
+        BatteryManager batteryManager = getBatteryManager();
+        boolean isBtmCritical = (batteryManager != null
+                && batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_STATUS)
+                    == BatteryManager.BATTERY_STATUS_DISCHARGING
+                && batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
+                    <= mCriticalBatteryLevel)
+                || (mPowerManager != null
+                    && mPowerManager.getCurrentThermalStatus()
+                        >= PowerManager.THERMAL_STATUS_SEVERE);
+
+        if (DEBUG) {
+            Log.d(TAG, "Battery, thermal, or memory are critical: " + isBtmCritical);
+        }
+
+        return isBtmCritical;
+    }
+
     public static class RegisterDexModuleResult {
         public RegisterDexModuleResult() {
             this(false, null);
diff --git a/services/core/java/com/android/server/pm/dex/DexoptOptions.java b/services/core/java/com/android/server/pm/dex/DexoptOptions.java
index 68f3886..ea23316 100644
--- a/services/core/java/com/android/server/pm/dex/DexoptOptions.java
+++ b/services/core/java/com/android/server/pm/dex/DexoptOptions.java
@@ -65,6 +65,12 @@
     // or device setup and should be scheduled appropriately.
     public static final int DEXOPT_FOR_RESTORE = 1 << 11; // TODO(b/135202722): remove
 
+    /**
+     * A value indicating that dexopt shouldn't be run.  This string is only used when loading
+     * filters from the `pm.dexopt.install*` properties and is not propagated to dex2oat.
+     */
+    public static final String COMPILER_FILTER_NOOP = "skip";
+
     // The name of package to optimize.
     private final String mPackageName;
 
@@ -176,6 +182,10 @@
         return mCompilationReason;
     }
 
+    public boolean isCompilationEnabled() {
+        return !mCompilerFilter.equals(COMPILER_FILTER_NOOP);
+    }
+
     /**
      * Creates a new set of DexoptOptions which are the same with the exception of the compiler
      * filter (set to the given value).
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 1656472..44a2187 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -41,8 +41,9 @@
 import android.os.Build;
 import android.os.Environment;
 import android.os.Handler;
-import android.os.Looper;
+import android.os.HandlerThread;
 import android.os.Message;
+import android.os.Process;
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
 import android.permission.PermissionManager;
@@ -67,8 +68,9 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.XmlUtils;
 import com.android.server.LocalServices;
-import com.android.server.pm.permission.PermissionManagerServiceInternal.PackagesProvider;
-import com.android.server.pm.permission.PermissionManagerServiceInternal.SyncAdapterPackagesProvider;
+import com.android.server.ServiceThread;
+import com.android.server.pm.permission.LegacyPermissionManagerInternal.PackagesProvider;
+import com.android.server.pm.permission.LegacyPermissionManagerInternal.SyncAdapterPackagesProvider;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -96,7 +98,7 @@
  * to have an interface defined in the package manager but have the impl next to other
  * policy stuff like PhoneWindowManager
  */
-public final class DefaultPermissionGrantPolicy {
+final class DefaultPermissionGrantPolicy {
     private static final String TAG = "DefaultPermGrantPolicy"; // must be <= 23 chars
     private static final boolean DEBUG = false;
 
@@ -291,9 +293,12 @@
         }
     };
 
-    DefaultPermissionGrantPolicy(Context context, Looper looper) {
+    DefaultPermissionGrantPolicy(@NonNull Context context) {
         mContext = context;
-        mHandler = new Handler(looper) {
+        HandlerThread handlerThread = new ServiceThread(TAG,
+                Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
+        handlerThread.start();
+        mHandler = new Handler(handlerThread.getLooper()) {
             @Override
             public void handleMessage(Message msg) {
                 if (msg.what == MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS) {
@@ -998,12 +1003,6 @@
         }
     }
 
-    public void grantDefaultPermissionsToDefaultBrowser(String packageName, int userId) {
-        Log.i(TAG, "Granting permissions to default browser for user:" + userId);
-        grantPermissionsToSystemPackage(NO_PM_CACHE, packageName, userId,
-                FOREGROUND_LOCATION_PERMISSIONS);
-    }
-
     private String getDefaultSystemHandlerActivityPackage(PackageManagerWrapper pm,
             String intentAction, int userId) {
         return getDefaultSystemHandlerActivityPackage(pm, new Intent(intentAction), userId);
diff --git a/services/core/java/com/android/server/pm/permission/LegacyPermission.java b/services/core/java/com/android/server/pm/permission/LegacyPermission.java
index 6a4eb63..ca3a2e2 100644
--- a/services/core/java/com/android/server/pm/permission/LegacyPermission.java
+++ b/services/core/java/com/android/server/pm/permission/LegacyPermission.java
@@ -167,16 +167,12 @@
 
     private static int readInt(@NonNull TypedXmlPullParser parser, @Nullable String namespace,
             @NonNull String name, int defaultValue) {
-        final String value = parser.getAttributeValue(namespace, name);
-        if (value == null) {
-            return defaultValue;
-        }
         try {
-            return Integer.parseInt(value);
-        } catch (NumberFormatException e) {
+            return parser.getAttributeInt(namespace, name);
+        } catch (Exception ignored) {
             PackageManagerService.reportSettingsProblem(Log.WARN,
                     "Error in package manager settings: attribute " + name
-                            + " has bad integer value " + value + " at "
+                            + " has bad integer value at "
                             + parser.getPositionDescription());
             return defaultValue;
         }
diff --git a/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerInternal.java b/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerInternal.java
new file mode 100644
index 0000000..a098484
--- /dev/null
+++ b/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerInternal.java
@@ -0,0 +1,172 @@
+/*
+ * 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.pm.permission;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+
+/**
+ * The internal interface for {@link LegacyPermissionManagerService}.
+ */
+public interface LegacyPermissionManagerInternal {
+    /**
+     * Sets the dialer application packages provider.
+     * @param provider The provider.
+     */
+    void setDialerAppPackagesProvider(PackagesProvider provider);
+
+    /**
+     * Set the location extra packages provider.
+     * @param provider The packages provider.
+     */
+    void setLocationExtraPackagesProvider(PackagesProvider provider);
+
+    /**
+     * Sets the location provider packages provider.
+     * @param provider The packages provider.
+     */
+    void setLocationPackagesProvider(PackagesProvider provider);
+
+    /**
+     * Sets the SIM call manager packages provider.
+     * @param provider The provider.
+     */
+    void setSimCallManagerPackagesProvider(PackagesProvider provider);
+
+    /**
+     * Sets the SMS application packages provider.
+     * @param provider The provider.
+     */
+    void setSmsAppPackagesProvider(PackagesProvider provider);
+
+    /**
+     * Sets the sync adapter packages provider.
+     * @param provider The provider.
+     */
+    void setSyncAdapterPackagesProvider(SyncAdapterPackagesProvider provider);
+
+    /**
+     * Sets the Use Open Wifi packages provider.
+     * @param provider The packages provider.
+     */
+    void setUseOpenWifiAppPackagesProvider(PackagesProvider provider);
+
+    /**
+     * Sets the voice interaction packages provider.
+     * @param provider The packages provider.
+     */
+    void setVoiceInteractionPackagesProvider(PackagesProvider provider);
+
+    /**
+     * Requests granting of the default permissions to the current default Use Open Wifi app.
+     * @param packageName The default use open wifi package name.
+     * @param userId The user for which to grant the permissions.
+     */
+    void grantDefaultPermissionsToDefaultSimCallManager(@NonNull String packageName,
+            @UserIdInt int userId);
+
+    /**
+     * Requests granting of the default permissions to the current default Use Open Wifi app.
+     * @param packageName The default use open wifi package name.
+     * @param userId The user for which to grant the permissions.
+     */
+    void grantDefaultPermissionsToDefaultUseOpenWifiApp(@NonNull String packageName,
+            @UserIdInt int userId);
+
+    /**
+     * Grant the default permissions for a user.
+     *
+     * @param userId the user ID
+     */
+    void grantDefaultPermissions(@UserIdInt int userId);
+
+    /**
+     * Schedule reading the default permission exceptions file.
+     */
+    void scheduleReadDefaultPermissionExceptions();
+
+    // TODO(zhanghai): The following methods should be moved to a new AIDL to support
+    //  the legacy PermissionManager directly in a later CL.
+
+    /**
+     * Grant default permissions to currently active LUI app
+     * @param packageName The package name for the LUI app
+     * @param userId The user ID
+     */
+    void grantDefaultPermissionsToActiveLuiApp(String packageName, int userId);
+
+    /**
+     * Revoke default permissions to currently active LUI app
+     * @param packageNames The package names for the LUI apps
+     * @param userId The user ID
+     */
+    void revokeDefaultPermissionsFromLuiApps(String[] packageNames, int userId);
+
+    /**
+     * Grant default permissions to currently active Ims services
+     * @param packageNames The package names for the Ims services
+     * @param userId The user ID
+     */
+    void grantDefaultPermissionsToEnabledImsServices(String[] packageNames, int userId);
+
+    /**
+     * Grant default permissions to currently enabled telephony data services
+     * @param packageNames The package name for the services
+     * @param userId The user ID
+     */
+    void grantDefaultPermissionsToEnabledTelephonyDataServices(String[] packageNames, int userId);
+
+    /**
+     * Revoke default permissions to currently active telephony data services
+     * @param packageNames The package name for the services
+     * @param userId The IDhandle
+     */
+    void revokeDefaultPermissionsFromDisabledTelephonyDataServices(String[] packageNames,
+            int userId);
+
+    /**
+     * Grant default permissions to currently enabled carrier apps
+     * @param packageNames Package names of the apps to be granted permissions
+     * @param userId The user ID
+     */
+    void grantDefaultPermissionsToEnabledCarrierApps(String[] packageNames, int userId);
+
+    /**
+     * Provider for package names.
+     */
+    interface PackagesProvider {
+        /**
+         * Gets the packages for a given user.
+         * @param userId The user id.
+         * @return The package names.
+         */
+        String[] getPackages(int userId);
+    }
+
+    /**
+     * Provider for package names.
+     */
+    interface SyncAdapterPackagesProvider {
+        /**
+         * Gets the sync adapter packages for given authority and user.
+         * @param authority The authority.
+         * @param userId The user id.
+         * @return The package names.
+         */
+        String[] getPackages(String authority, int userId);
+    }
+}
diff --git a/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerService.java b/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerService.java
new file mode 100644
index 0000000..0c0a8df
--- /dev/null
+++ b/services/core/java/com/android/server/pm/permission/LegacyPermissionManagerService.java
@@ -0,0 +1,181 @@
+/*
+ * 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.pm.permission;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.Binder;
+
+import com.android.server.LocalServices;
+import com.android.server.pm.PackageManagerServiceUtils;
+
+/**
+ * Legacy permission manager service.
+ */
+public class LegacyPermissionManagerService {
+    @NonNull
+    private final DefaultPermissionGrantPolicy mDefaultPermissionGrantPolicy;
+
+    /**
+     * Get or create an instance of this class for use by other components.
+     * <p>
+     * This method is not thread-safe.
+     *
+     * @param context the {@link Context}
+     * @return the internal instance
+     */
+    @NonNull
+    public static LegacyPermissionManagerInternal create(@NonNull Context context) {
+        LegacyPermissionManagerInternal legacyPermissionManagerInternal = LocalServices.getService(
+                LegacyPermissionManagerInternal.class);
+        if (legacyPermissionManagerInternal == null) {
+            new LegacyPermissionManagerService(context);
+            legacyPermissionManagerInternal = LocalServices.getService(
+                    LegacyPermissionManagerInternal.class);
+        }
+        return legacyPermissionManagerInternal;
+    }
+
+    private LegacyPermissionManagerService(@NonNull Context context) {
+        mDefaultPermissionGrantPolicy = new DefaultPermissionGrantPolicy(context);
+        LocalServices.addService(LegacyPermissionManagerInternal.class, new Internal());
+    }
+
+    private class Internal implements LegacyPermissionManagerInternal {
+        @Override
+        public void setDialerAppPackagesProvider(PackagesProvider provider) {
+            mDefaultPermissionGrantPolicy.setDialerAppPackagesProvider(provider);
+        }
+
+        @Override
+        public void setLocationExtraPackagesProvider(PackagesProvider provider) {
+            mDefaultPermissionGrantPolicy.setLocationExtraPackagesProvider(provider);
+        }
+
+        @Override
+        public void setLocationPackagesProvider(PackagesProvider provider) {
+            mDefaultPermissionGrantPolicy.setLocationPackagesProvider(provider);
+        }
+
+        @Override
+        public void setSimCallManagerPackagesProvider(PackagesProvider provider) {
+            mDefaultPermissionGrantPolicy.setSimCallManagerPackagesProvider(provider);
+        }
+
+        @Override
+        public void setSmsAppPackagesProvider(PackagesProvider provider) {
+            mDefaultPermissionGrantPolicy.setSmsAppPackagesProvider(provider);
+        }
+
+        @Override
+        public void setSyncAdapterPackagesProvider(SyncAdapterPackagesProvider provider) {
+            mDefaultPermissionGrantPolicy.setSyncAdapterPackagesProvider(provider);
+        }
+
+        @Override
+        public void setUseOpenWifiAppPackagesProvider(PackagesProvider provider) {
+            mDefaultPermissionGrantPolicy.setUseOpenWifiAppPackagesProvider(provider);
+        }
+
+        @Override
+        public void setVoiceInteractionPackagesProvider(PackagesProvider provider) {
+            mDefaultPermissionGrantPolicy.setVoiceInteractionPackagesProvider(provider);
+        }
+
+        @Override
+        public void grantDefaultPermissionsToDefaultSimCallManager(String packageName, int userId) {
+            mDefaultPermissionGrantPolicy.grantDefaultPermissionsToDefaultSimCallManager(
+                    packageName, userId);
+        }
+
+        @Override
+        public void grantDefaultPermissionsToDefaultUseOpenWifiApp(String packageName, int userId) {
+            mDefaultPermissionGrantPolicy.grantDefaultPermissionsToDefaultUseOpenWifiApp(
+                    packageName, userId);
+        }
+
+        @Override
+        public void grantDefaultPermissions(int userId) {
+            mDefaultPermissionGrantPolicy.grantDefaultPermissions(userId);
+        }
+
+        @Override
+        public void scheduleReadDefaultPermissionExceptions() {
+            mDefaultPermissionGrantPolicy.scheduleReadDefaultPermissionExceptions();
+        }
+
+        // TODO(zhanghai): The following methods should be moved to a new AIDL to support
+        //  the legacy PermissionManager directly in a later CL.
+
+        @Override
+        public void grantDefaultPermissionsToActiveLuiApp(String packageName, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            PackageManagerServiceUtils.enforceSystemOrPhoneCaller(
+                    "grantDefaultPermissionsToActiveLuiApp", callingUid);
+            Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+                    .grantDefaultPermissionsToActiveLuiApp(packageName, userId));
+        }
+
+        @Override
+        public void revokeDefaultPermissionsFromLuiApps(String[] packageNames, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            PackageManagerServiceUtils.enforceSystemOrPhoneCaller(
+                    "revokeDefaultPermissionsFromLuiApps", callingUid);
+            Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+                    .revokeDefaultPermissionsFromLuiApps(packageNames, userId));
+        }
+
+        @Override
+        public void grantDefaultPermissionsToEnabledImsServices(String[] packageNames, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            PackageManagerServiceUtils.enforceSystemOrPhoneCaller(
+                    "grantDefaultPermissionsToEnabledImsServices", callingUid);
+            Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+                    .grantDefaultPermissionsToEnabledImsServices(packageNames, userId));
+        }
+
+        @Override
+        public void grantDefaultPermissionsToEnabledTelephonyDataServices(
+                String[] packageNames, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            PackageManagerServiceUtils.enforceSystemOrPhoneCaller(
+                    "grantDefaultPermissionsToEnabledTelephonyDataServices", callingUid);
+            Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+                    .grantDefaultPermissionsToEnabledTelephonyDataServices(packageNames, userId));
+        }
+
+        @Override
+        public void revokeDefaultPermissionsFromDisabledTelephonyDataServices(
+                String[] packageNames, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            PackageManagerServiceUtils.enforceSystemOrPhoneCaller(
+                    "revokeDefaultPermissionsFromDisabledTelephonyDataServices", callingUid);
+            Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+                    .revokeDefaultPermissionsFromDisabledTelephonyDataServices(packageNames,
+                            userId));
+        }
+
+        @Override
+        public void grantDefaultPermissionsToEnabledCarrierApps(String[] packageNames, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            PackageManagerServiceUtils.enforceSystemOrPhoneCaller(
+                    "grantPermissionsToEnabledCarrierApps", callingUid);
+            Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+                    .grantDefaultPermissionsToEnabledCarrierApps(packageNames, userId));
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/permission/OWNERS b/services/core/java/com/android/server/pm/permission/OWNERS
index 0e88862..6e67830 100644
--- a/services/core/java/com/android/server/pm/permission/OWNERS
+++ b/services/core/java/com/android/server/pm/permission/OWNERS
@@ -1,7 +1,7 @@
 moltmann@google.com
 zhanghai@google.com
-per-file DefaultPermissionGrantPolicy.java = hackbod@android.com
-per-file DefaultPermissionGrantPolicy.java = jsharkey@android.com
+per-file DefaultPermissionGrantPolicy.java = hackbod@google.com
+per-file DefaultPermissionGrantPolicy.java = jsharkey@google.com
 per-file DefaultPermissionGrantPolicy.java = svetoslavganov@google.com
 per-file DefaultPermissionGrantPolicy.java = toddke@google.com
 per-file DefaultPermissionGrantPolicy.java = yamasani@google.com
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 48e18f1..389010a 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -114,8 +114,6 @@
 import android.permission.PermissionControllerManager;
 import android.permission.PermissionManager;
 import android.permission.PermissionManagerInternal;
-import android.permission.PermissionManagerInternal.CheckPermissionDelegate;
-import android.permission.PermissionManagerInternal.OnRuntimePermissionStateChangedListener;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -138,6 +136,7 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IntPair;
 import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.TriFunction;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
@@ -145,15 +144,12 @@
 import com.android.server.SystemConfig;
 import com.android.server.Watchdog;
 import com.android.server.pm.ApexManager;
-import com.android.server.pm.PackageManagerServiceUtils;
 import com.android.server.pm.PackageSetting;
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.pm.UserManagerService;
 import com.android.server.pm.parsing.PackageInfoUtils;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
-import com.android.server.pm.permission.PermissionManagerServiceInternal.DefaultBrowserProvider;
-import com.android.server.pm.permission.PermissionManagerServiceInternal.DefaultDialerProvider;
-import com.android.server.pm.permission.PermissionManagerServiceInternal.DefaultHomeProvider;
+import com.android.server.pm.permission.PermissionManagerServiceInternal.OnRuntimePermissionStateChangedListener;
 import com.android.server.policy.PermissionPolicyInternal;
 import com.android.server.policy.SoftRestrictedPermissionPolicy;
 
@@ -176,7 +172,7 @@
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
-import java.util.function.Consumer;
+import java.util.function.BiFunction;
 
 /**
  * Manages all permissions and handles permissions related tasks.
@@ -242,9 +238,6 @@
     private final SparseArray<OneTimePermissionUserManager> mOneTimePermissionUserManagers =
             new SparseArray<>();
 
-    /** Default permission policy to provide proper behaviour out-of-the-box */
-    private final DefaultPermissionGrantPolicy mDefaultPermissionGrantPolicy;
-
     /** App ops manager */
     private final AppOpsManager mAppOpsManager;
 
@@ -304,15 +297,6 @@
     @NonNull
     private final OnPermissionChangeListeners mOnPermissionChangeListeners;
 
-    @GuardedBy("mLock")
-    private DefaultBrowserProvider mDefaultBrowserProvider;
-
-    @GuardedBy("mLock")
-    private DefaultDialerProvider mDefaultDialerProvider;
-
-    @GuardedBy("mLock")
-    private DefaultHomeProvider mDefaultHomeProvider;
-
     // TODO: Take a look at the methods defined in the callback.
     // The callback was initially created to support the split between permission
     // manager and the package manager. However, it's started to be used for other
@@ -402,8 +386,6 @@
         mHandler = new Handler(mHandlerThread.getLooper());
         Watchdog.getInstance().addThread(mHandler);
 
-        mDefaultPermissionGrantPolicy = new DefaultPermissionGrantPolicy(
-                context, mHandlerThread.getLooper());
         SystemConfig systemConfig = SystemConfig.getInstance();
         mSystemPermissions = systemConfig.getSystemPermissions();
         mGlobalGids = systemConfig.getGlobalGids();
@@ -2018,145 +2000,41 @@
     }
 
     @Override
-    public String getDefaultBrowser(int userId) {
-        final int callingUid = Binder.getCallingUid();
-        if (UserHandle.getUserId(callingUid) != userId) {
-            mContext.enforceCallingOrSelfPermission(
-                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
-        }
-        if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
-            return null;
-        }
-        DefaultBrowserProvider provider;
-        synchronized (mLock) {
-            provider = mDefaultBrowserProvider;
-        }
-        return provider != null ? provider.getDefaultBrowser(userId) : null;
-    }
-
-    @Override
-    public boolean setDefaultBrowser(String packageName, int userId) {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
-        if (UserHandle.getCallingUserId() != userId) {
-            mContext.enforceCallingOrSelfPermission(
-                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
-        }
-        return setDefaultBrowserInternal(packageName, false, true, userId);
-    }
-
-    private boolean setDefaultBrowserInternal(String packageName, boolean async,
-            boolean doGrant, int userId) {
-        if (userId == UserHandle.USER_ALL) {
-            return false;
-        }
-        DefaultBrowserProvider provider;
-        synchronized (mLock) {
-            provider = mDefaultBrowserProvider;
-        }
-        if (provider == null) {
-            return false;
-        }
-        if (async) {
-            provider.setDefaultBrowserAsync(packageName, userId);
-        } else {
-            if (!provider.setDefaultBrowser(packageName, userId)) {
-                return false;
-            }
-        }
-        if (doGrant && packageName != null) {
-            mDefaultPermissionGrantPolicy.grantDefaultPermissionsToDefaultBrowser(packageName,
-                    userId);
-        }
-        return true;
-    }
-
-    @Override
     public void grantDefaultPermissionsToEnabledCarrierApps(String[] packageNames, int userId) {
-        final int callingUid = Binder.getCallingUid();
-        PackageManagerServiceUtils
-                .enforceSystemOrPhoneCaller("grantPermissionsToEnabledCarrierApps", callingUid);
-        Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
-                .grantDefaultPermissionsToEnabledCarrierApps(packageNames, userId));
+        LocalServices.getService(LegacyPermissionManagerInternal.class)
+                .grantDefaultPermissionsToEnabledCarrierApps(packageNames, userId);
     }
 
     @Override
     public void grantDefaultPermissionsToEnabledImsServices(String[] packageNames, int userId) {
-        final int callingUid = Binder.getCallingUid();
-        PackageManagerServiceUtils.enforceSystemOrPhoneCaller(
-                "grantDefaultPermissionsToEnabledImsServices", callingUid);
-        Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
-                .grantDefaultPermissionsToEnabledImsServices(packageNames, userId));
+        LocalServices.getService(LegacyPermissionManagerInternal.class)
+                .grantDefaultPermissionsToEnabledImsServices(packageNames, userId);
     }
 
     @Override
     public void grantDefaultPermissionsToEnabledTelephonyDataServices(
             String[] packageNames, int userId) {
-        final int callingUid = Binder.getCallingUid();
-        PackageManagerServiceUtils.enforceSystemOrPhoneCaller(
-                "grantDefaultPermissionsToEnabledTelephonyDataServices", callingUid);
-        Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
-                .grantDefaultPermissionsToEnabledTelephonyDataServices(packageNames, userId));
+        LocalServices.getService(LegacyPermissionManagerInternal.class)
+                .grantDefaultPermissionsToEnabledTelephonyDataServices(packageNames, userId);
     }
 
     @Override
     public void revokeDefaultPermissionsFromDisabledTelephonyDataServices(
             String[] packageNames, int userId) {
-        final int callingUid = Binder.getCallingUid();
-        PackageManagerServiceUtils.enforceSystemOrPhoneCaller(
-                "revokeDefaultPermissionsFromDisabledTelephonyDataServices", callingUid);
-        Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
-                .revokeDefaultPermissionsFromDisabledTelephonyDataServices(packageNames, userId));
+        LocalServices.getService(LegacyPermissionManagerInternal.class)
+                .revokeDefaultPermissionsFromDisabledTelephonyDataServices(packageNames, userId);
     }
 
     @Override
     public void grantDefaultPermissionsToActiveLuiApp(String packageName, int userId) {
-        final int callingUid = Binder.getCallingUid();
-        PackageManagerServiceUtils
-                .enforceSystemOrPhoneCaller("grantDefaultPermissionsToActiveLuiApp", callingUid);
-        Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
-                .grantDefaultPermissionsToActiveLuiApp(packageName, userId));
+        LocalServices.getService(LegacyPermissionManagerInternal.class)
+                .grantDefaultPermissionsToActiveLuiApp(packageName, userId);
     }
 
     @Override
     public void revokeDefaultPermissionsFromLuiApps(String[] packageNames, int userId) {
-        final int callingUid = Binder.getCallingUid();
-        PackageManagerServiceUtils
-                .enforceSystemOrPhoneCaller("revokeDefaultPermissionsFromLuiApps", callingUid);
-        Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
-                .revokeDefaultPermissionsFromLuiApps(packageNames, userId));
-    }
-
-    @Override
-    public void setPermissionEnforced(String permName, boolean enforced) {
-        // TODO: Now that we no longer change GID for storage, this should to away.
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
-                "setPermissionEnforced");
-        if (READ_EXTERNAL_STORAGE.equals(permName)) {
-            mPackageManagerInt.setReadExternalStorageEnforced(enforced);
-            // kill any non-foreground processes so we restart them and
-            // grant/revoke the GID.
-            final IActivityManager am = ActivityManager.getService();
-            if (am != null) {
-                final long token = Binder.clearCallingIdentity();
-                try {
-                    am.killProcessesBelowForeground("setPermissionEnforcement");
-                } catch (RemoteException e) {
-                } finally {
-                    Binder.restoreCallingIdentity(token);
-                }
-            }
-        } else {
-            throw new IllegalArgumentException("No selective enforcement for " + permName);
-        }
-    }
-
-    /** @deprecated */
-    @Override
-    @Deprecated
-    public boolean isPermissionEnforced(String permName) {
-        // allow instant applications
-        return true;
+        LocalServices.getService(LegacyPermissionManagerInternal.class)
+                .revokeDefaultPermissionsFromLuiApps(packageNames, userId);
     }
 
     /**
@@ -2263,19 +2141,20 @@
      *
      * <p>Can not be called on main thread.
      *
-     * @param user The user the data should be extracted for
+     * @param userId The user ID the data should be extracted for
      *
      * @return The state as a xml file
      */
-    private @Nullable byte[] backupRuntimePermissions(@NonNull UserHandle user) {
+    @Nullable
+    private byte[] backupRuntimePermissions(@UserIdInt int userId) {
         CompletableFuture<byte[]> backup = new CompletableFuture<>();
-        mPermissionControllerManager.getRuntimePermissionBackup(user, mContext.getMainExecutor(),
-                backup::complete);
+        mPermissionControllerManager.getRuntimePermissionBackup(UserHandle.of(userId),
+                mContext.getMainExecutor(), backup::complete);
 
         try {
             return backup.get(BACKUP_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
         } catch (InterruptedException | ExecutionException  | TimeoutException e) {
-            Slog.e(TAG, "Cannot create permission backup for " + user, e);
+            Slog.e(TAG, "Cannot create permission backup for user " + userId, e);
             return null;
         }
     }
@@ -2287,13 +2166,14 @@
      * applied via {@link #restoreDelayedRuntimePermissions}.
      *
      * @param backup The state as an xml file
-     * @param user The user the data should be restored for
+     * @param userId The user ID the data should be restored for
      */
-    private void restoreRuntimePermissions(@NonNull byte[] backup, @NonNull UserHandle user) {
+    private void restoreRuntimePermissions(@NonNull byte[] backup, @UserIdInt int userId) {
         synchronized (mLock) {
-            mHasNoDelayedPermBackup.delete(user.getIdentifier());
+            mHasNoDelayedPermBackup.delete(userId);
         }
-        mPermissionControllerManager.stageAndApplyRuntimePermissionsBackup(backup, user);
+        mPermissionControllerManager.stageAndApplyRuntimePermissionsBackup(backup,
+                UserHandle.of(userId));
     }
 
     /**
@@ -2302,24 +2182,24 @@
      * <p>Can not be called on main thread.
      *
      * @param packageName The package that is newly installed
-     * @param user The user the package is installed for
+     * @param userId The user ID the package is installed for
      *
      * @see #restoreRuntimePermissions
      */
     private void restoreDelayedRuntimePermissions(@NonNull String packageName,
-            @NonNull UserHandle user) {
+            @UserIdInt int userId) {
         synchronized (mLock) {
-            if (mHasNoDelayedPermBackup.get(user.getIdentifier(), false)) {
+            if (mHasNoDelayedPermBackup.get(userId, false)) {
                 return;
             }
         }
-        mPermissionControllerManager.applyStagedRuntimePermissionBackup(packageName, user,
-                mContext.getMainExecutor(), (hasMoreBackup) -> {
+        mPermissionControllerManager.applyStagedRuntimePermissionBackup(packageName,
+                UserHandle.of(userId), mContext.getMainExecutor(), (hasMoreBackup) -> {
                     if (hasMoreBackup) {
                         return;
                     }
                     synchronized (mLock) {
-                        mHasNoDelayedPermBackup.put(user.getIdentifier(), true);
+                        mHasNoDelayedPermBackup.put(userId, true);
                     }
                 });
     }
@@ -2360,6 +2240,32 @@
         }
     }
 
+    private void startShellPermissionIdentityDelegationInternal(int uid,
+            @NonNull String packageName, @Nullable List<String> permissionNames) {
+        synchronized (mLock) {
+            final CheckPermissionDelegate oldDelegate = mCheckPermissionDelegate;
+            if (oldDelegate != null && oldDelegate.getDelegatedUid() != uid) {
+                throw new SecurityException(
+                        "Shell can delegate permissions only to one UID at a time");
+            }
+            final ShellDelegate delegate = new ShellDelegate(uid, packageName, permissionNames);
+            setCheckPermissionDelegateLocked(delegate);
+        }
+    }
+
+    private void stopShellPermissionIdentityDelegationInternal() {
+        synchronized (mLock) {
+            setCheckPermissionDelegateLocked(null);
+        }
+    }
+
+    private void setCheckPermissionDelegateLocked(@Nullable CheckPermissionDelegate delegate) {
+        if (delegate != null || mCheckPermissionDelegate != null) {
+            PackageManager.invalidatePackageInfoCache();
+        }
+        mCheckPermissionDelegate = delegate;
+    }
+
     /**
      * If the app is updated, and has scoped storage permissions, then it is possible that the
      * app updated in an attempt to get unscoped storage. If so, revoke all storage permissions.
@@ -4621,24 +4527,6 @@
 
         mPermissionControllerManager = mContext.getSystemService(PermissionControllerManager.class);
         mPermissionPolicyInternal = LocalServices.getService(PermissionPolicyInternal.class);
-
-        int[] grantPermissionsUserIds = EMPTY_INT_ARRAY;
-        for (int userId : UserManagerService.getInstance().getUserIds()) {
-            if (mPackageManagerInt.isPermissionUpgradeNeeded(userId)) {
-                grantPermissionsUserIds = ArrayUtils.appendInt(
-                        grantPermissionsUserIds, userId);
-            }
-        }
-        // If we upgraded grant all default permissions before kicking off.
-        for (int userId : grantPermissionsUserIds) {
-            mDefaultPermissionGrantPolicy.grantDefaultPermissions(userId);
-        }
-        if (grantPermissionsUserIds == EMPTY_INT_ARRAY) {
-            // If we did not grant default permissions, we preload from this the
-            // default permission exceptions lazily to ensure we don't hit the
-            // disk on a new user creation.
-            mDefaultPermissionGrantPolicy.scheduleReadDefaultPermissionExceptions();
-        }
     }
 
     private static String getVolumeUuidForPackage(AndroidPackage pkg) {
@@ -5098,7 +4986,7 @@
         }
     }
 
-    private class PermissionManagerServiceInternalImpl extends PermissionManagerServiceInternal {
+    private class PermissionManagerServiceInternalImpl implements PermissionManagerServiceInternal {
         @Override
         public void systemReady() {
             PermissionManagerService.this.systemReady();
@@ -5123,6 +5011,7 @@
         }
         @Override
         public void onUserRemoved(@UserIdInt int userId) {
+            Preconditions.checkArgumentNonNegative(userId, "userId");
             PermissionManagerService.this.onUserRemoved(userId);
         }
         @NonNull
@@ -5202,20 +5091,26 @@
             return matchingPermissions;
         }
 
+        @Nullable
         @Override
-        public @Nullable byte[] backupRuntimePermissions(@NonNull UserHandle user) {
-            return PermissionManagerService.this.backupRuntimePermissions(user);
+        public byte[] backupRuntimePermissions(@UserIdInt int userId) {
+            Preconditions.checkArgumentNonNegative(userId, "userId");
+            return PermissionManagerService.this.backupRuntimePermissions(userId);
         }
 
         @Override
-        public void restoreRuntimePermissions(@NonNull byte[] backup, @NonNull UserHandle user) {
-            PermissionManagerService.this.restoreRuntimePermissions(backup, user);
+        public void restoreRuntimePermissions(@NonNull byte[] backup, @UserIdInt int userId) {
+            Objects.requireNonNull(backup, "backup");
+            Preconditions.checkArgumentNonNegative(userId, "userId");
+            PermissionManagerService.this.restoreRuntimePermissions(backup, userId);
         }
 
         @Override
         public void restoreDelayedRuntimePermissions(@NonNull String packageName,
-                @NonNull UserHandle user) {
-            PermissionManagerService.this.restoreDelayedRuntimePermissions(packageName, user);
+                @UserIdInt int userId) {
+            Objects.requireNonNull(packageName, "packageName");
+            Preconditions.checkArgumentNonNegative(userId, "userId");
+            PermissionManagerService.this.restoreDelayedRuntimePermissions(packageName, userId);
         }
 
         @Override
@@ -5233,163 +5128,23 @@
         }
 
         @Override
-        public CheckPermissionDelegate getCheckPermissionDelegate() {
-            synchronized (mLock) {
-                return mCheckPermissionDelegate;
-            }
+        public void startShellPermissionIdentityDelegation(int uid, @NonNull String packageName,
+                @Nullable List<String> permissionNames) {
+            Objects.requireNonNull(packageName, "packageName");
+            startShellPermissionIdentityDelegationInternal(uid, packageName, permissionNames);
         }
 
         @Override
-        public void setCheckPermissionDelegate(CheckPermissionDelegate delegate) {
-            synchronized (mLock) {
-                if (delegate != null || mCheckPermissionDelegate != null) {
-                    PackageManager.invalidatePackageInfoCache();
-                }
-                mCheckPermissionDelegate = delegate;
-            }
+        public void stopShellPermissionIdentityDelegation() {
+            stopShellPermissionIdentityDelegationInternal();
         }
 
         @Override
-        public void setDefaultBrowserProvider(@NonNull DefaultBrowserProvider provider) {
-            synchronized (mLock) {
-                mDefaultBrowserProvider = provider;
-            }
-        }
-
-        @Override
-        public void setDefaultBrowser(String packageName, boolean async, boolean doGrant,
-                int userId) {
-            setDefaultBrowserInternal(packageName, async, doGrant, userId);
-        }
-
-        @Override
-        public void setDefaultDialerProvider(@NonNull DefaultDialerProvider provider) {
-            synchronized (mLock) {
-                mDefaultDialerProvider = provider;
-            }
-        }
-
-        @Override
-        public void setDefaultHomeProvider(@NonNull DefaultHomeProvider provider) {
-            synchronized (mLock) {
-                mDefaultHomeProvider = provider;
-            }
-        }
-
-        @Override
-        public void setDefaultHome(String packageName, int userId, Consumer<Boolean> callback) {
-            if (userId == UserHandle.USER_ALL) {
-                return;
-            }
-            DefaultHomeProvider provider;
-            synchronized (mLock) {
-                provider = mDefaultHomeProvider;
-            }
-            if (provider == null) {
-                return;
-            }
-            provider.setDefaultHomeAsync(packageName, userId, callback);
-        }
-
-        @Override
-        public void setDialerAppPackagesProvider(PackagesProvider provider) {
-            mDefaultPermissionGrantPolicy.setDialerAppPackagesProvider(provider);
-        }
-
-        @Override
-        public void setLocationExtraPackagesProvider(PackagesProvider provider) {
-            mDefaultPermissionGrantPolicy.setLocationExtraPackagesProvider(provider);
-        }
-
-        @Override
-        public void setLocationPackagesProvider(PackagesProvider provider) {
-            mDefaultPermissionGrantPolicy.setLocationPackagesProvider(provider);
-        }
-
-        @Override
-        public void setSimCallManagerPackagesProvider(PackagesProvider provider) {
-            mDefaultPermissionGrantPolicy.setSimCallManagerPackagesProvider(provider);
-        }
-
-        @Override
-        public void setSmsAppPackagesProvider(PackagesProvider provider) {
-            mDefaultPermissionGrantPolicy.setSmsAppPackagesProvider(provider);
-        }
-
-        @Override
-        public void setSyncAdapterPackagesProvider(SyncAdapterPackagesProvider provider) {
-            mDefaultPermissionGrantPolicy.setSyncAdapterPackagesProvider(provider);
-        }
-
-        @Override
-        public void setUseOpenWifiAppPackagesProvider(PackagesProvider provider) {
-            mDefaultPermissionGrantPolicy.setUseOpenWifiAppPackagesProvider(provider);
-        }
-
-        @Override
-        public void setVoiceInteractionPackagesProvider(PackagesProvider provider) {
-            mDefaultPermissionGrantPolicy.setVoiceInteractionPackagesProvider(provider);
-        }
-
-        @Override
-        public String getDefaultBrowser(int userId) {
-            DefaultBrowserProvider provider;
-            synchronized (mLock) {
-                provider = mDefaultBrowserProvider;
-            }
-            return provider != null ? provider.getDefaultBrowser(userId) : null;
-        }
-
-        @Override
-        public String getDefaultDialer(int userId) {
-            DefaultDialerProvider provider;
-            synchronized (mLock) {
-                provider = mDefaultDialerProvider;
-            }
-            return provider != null ? provider.getDefaultDialer(userId) : null;
-        }
-
-        @Override
-        public String getDefaultHome(int userId) {
-            DefaultHomeProvider provider;
-            synchronized (mLock) {
-                provider = mDefaultHomeProvider;
-            }
-            return provider != null ? provider.getDefaultHome(userId) : null;
-        }
-
-        @Override
-        public void grantDefaultPermissionsToDefaultSimCallManager(String packageName, int userId) {
-            mDefaultPermissionGrantPolicy.grantDefaultPermissionsToDefaultSimCallManager(
-                    packageName, userId);
-        }
-
-        @Override
-        public void grantDefaultPermissionsToDefaultUseOpenWifiApp(String packageName, int userId) {
-            mDefaultPermissionGrantPolicy.grantDefaultPermissionsToDefaultUseOpenWifiApp(
-                    packageName, userId);
-        }
-
-        @Override
-        public void onNewUserCreated(int userId) {
+        public void onUserCreated(@UserIdInt int userId) {
+            Preconditions.checkArgumentNonNegative(userId, "userId");
             // NOTE: This adds UPDATE_PERMISSIONS_REPLACE_PKG
             PermissionManagerService.this.updateAllPermissions(StorageManager.UUID_PRIVATE_INTERNAL,
                     true, mDefaultPermissionCallback);
-            mDefaultPermissionGrantPolicy.grantDefaultPermissions(userId);
-        }
-
-        @Override
-        public void retainHardAndSoftRestrictedPermissions(@NonNull List<String> permissionNames) {
-            synchronized (mLock) {
-                Iterator<String> iterator = permissionNames.iterator();
-                while (iterator.hasNext()) {
-                    final String permissionName = iterator.next();
-                    final Permission permission = mRegistry.getPermission(permissionName);
-                    if (permission == null || !permission.isHardOrSoftRestricted()) {
-                        iterator.remove();
-                    }
-                }
-            }
         }
 
         @Override
@@ -5545,6 +5300,102 @@
     }
 
     /**
+     * Interface to intercept permission checks and optionally pass through to the original
+     * implementation.
+     */
+    private interface CheckPermissionDelegate {
+        /**
+         * Get the UID whose permission checks is being delegated.
+         *
+         * @return the UID
+         */
+        int getDelegatedUid();
+
+        /**
+         * Check whether the given package has been granted the specified permission.
+         *
+         * @param permissionName the name of the permission to be checked
+         * @param packageName the name of the package to be checked
+         * @param userId the user ID
+         * @param superImpl the original implementation that can be delegated to
+         * @return {@link android.content.pm.PackageManager.PERMISSION_GRANTED} if the package has
+         * the permission, or {@link android.content.pm.PackageManager.PERMISSION_DENITED} otherwise
+         *
+         * @see android.content.pm.PackageManager#checkPermission(String, String)
+         */
+        int checkPermission(@NonNull String permissionName, @NonNull String packageName,
+                @UserIdInt int userId,
+                @NonNull TriFunction<String, String, Integer, Integer> superImpl);
+
+        /**
+         * Check whether the given UID has been granted the specified permission.
+         *
+         * @param permissionName the name of the permission to be checked
+         * @param uid the UID to be checked
+         * @param superImpl the original implementation that can be delegated to
+         * @return {@link android.content.pm.PackageManager.PERMISSION_GRANTED} if the package has
+         * the permission, or {@link android.content.pm.PackageManager.PERMISSION_DENITED} otherwise
+         */
+        int checkUidPermission(@NonNull String permissionName, int uid,
+                BiFunction<String, Integer, Integer> superImpl);
+    }
+
+    private class ShellDelegate implements CheckPermissionDelegate {
+        private final int mDelegatedUid;
+        @NonNull
+        private final String mDelegatedPackageName;
+        @Nullable
+        private final List<String> mDelegatedPermissionNames;
+
+        public ShellDelegate(int delegatedUid, @NonNull String delegatedPackageName,
+                @Nullable List<String> delegatedPermissionNames) {
+            mDelegatedUid = delegatedUid;
+            mDelegatedPackageName = delegatedPackageName;
+            mDelegatedPermissionNames = delegatedPermissionNames;
+        }
+
+        @Override
+        public int getDelegatedUid() {
+            return mDelegatedUid;
+        }
+
+        @Override
+        public int checkPermission(@NonNull String permissionName, @NonNull String packageName,
+                int userId, @NonNull TriFunction<String, String, Integer, Integer> superImpl) {
+            if (mDelegatedPackageName.equals(packageName)
+                    && isDelegatedPermission(permissionName)) {
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    return superImpl.apply(permissionName, "com.android.shell", userId);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+            return superImpl.apply(permissionName, packageName, userId);
+        }
+
+        @Override
+        public int checkUidPermission(@NonNull String permissionName, int uid,
+                @NonNull BiFunction<String, Integer, Integer> superImpl) {
+            if (uid == mDelegatedUid && isDelegatedPermission(permissionName)) {
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    return superImpl.apply(permissionName, Process.SHELL_UID);
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+            return superImpl.apply(permissionName, uid);
+        }
+
+        private boolean isDelegatedPermission(@NonNull String permissionName) {
+            // null permissions means all permissions are targeted
+            return mDelegatedPermissionNames == null
+                    || mDelegatedPermissionNames.contains(permissionName);
+        }
+    }
+
+    /**
      * Allows injection of services and method responses to facilitate testing.
      *
      * <p>Test classes can create a mock of this class and pass it to the PermissionManagerService
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index f924651..0817d4f 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -30,119 +30,31 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
-import java.util.function.Consumer;
 
 /**
  * Internal interfaces services.
  *
- * TODO: Should be merged into PermissionManagerInternal, but currently uses internal classes.
+ * TODO: Move into module.
  */
-public abstract class PermissionManagerServiceInternal extends PermissionManagerInternal
-        implements LegacyPermissionDataProvider {
+public interface PermissionManagerServiceInternal extends PermissionManagerInternal,
+        LegacyPermissionDataProvider {
     /**
-     * Provider for package names.
+     * Adds a listener for runtime permission state (permissions or flags) changes.
+     *
+     * @param listener The listener.
      */
-    public interface PackagesProvider {
-
-        /**
-         * Gets the packages for a given user.
-         * @param userId The user id.
-         * @return The package names.
-         */
-        String[] getPackages(int userId);
-    }
+    void addOnRuntimePermissionStateChangedListener(
+            @NonNull OnRuntimePermissionStateChangedListener listener);
 
     /**
-     * Provider for package names.
+     * Removes a listener for runtime permission state (permissions or flags) changes.
+     *
+     * @param listener The listener.
      */
-    public interface SyncAdapterPackagesProvider {
+    void removeOnRuntimePermissionStateChangedListener(
+            @NonNull OnRuntimePermissionStateChangedListener listener);
 
-        /**
-         * Gets the sync adapter packages for given authority and user.
-         * @param authority The authority.
-         * @param userId The user id.
-         * @return The package names.
-         */
-        String[] getPackages(String authority, int userId);
-    }
-
-    /**
-     * Provider for default browser
-     */
-    public interface DefaultBrowserProvider {
-
-        /**
-         * Get the package name of the default browser.
-         *
-         * @param userId the user id
-         *
-         * @return the package name of the default browser, or {@code null} if none
-         */
-        @Nullable
-        String getDefaultBrowser(@UserIdInt int userId);
-
-        /**
-         * Set the package name of the default browser.
-         *
-         * @param packageName package name of the default browser, or {@code null} to remove
-         * @param userId the user id
-         *
-         * @return whether the default browser was successfully set.
-         */
-        boolean setDefaultBrowser(@Nullable String packageName, @UserIdInt int userId);
-
-        /**
-         * Set the package name of the default browser asynchronously.
-         *
-         * @param packageName package name of the default browser, or {@code null} to remove
-         * @param userId the user id
-         */
-        void setDefaultBrowserAsync(@Nullable String packageName, @UserIdInt int userId);
-    }
-
-    /**
-     * Provider for default dialer
-     */
-    public interface DefaultDialerProvider {
-
-        /**
-         * Get the package name of the default dialer.
-         *
-         * @param userId the user id
-         *
-         * @return the package name of the default dialer, or {@code null} if none
-         */
-        @Nullable
-        String getDefaultDialer(@UserIdInt int userId);
-    }
-
-    /**
-     * Provider for default home
-     */
-    public interface DefaultHomeProvider {
-
-        /**
-         * Get the package name of the default home.
-         *
-         * @param userId the user id
-         *
-         * @return the package name of the default home, or {@code null} if none
-         */
-        @Nullable
-        String getDefaultHome(@UserIdInt int userId);
-
-        /**
-         * Set the package name of the default home.
-         *
-         * @param packageName package name of the default home, or {@code null} to remove
-         * @param userId the user id
-         * @param callback the callback made after the default home as been updated
-         */
-        void setDefaultHomeAsync(@Nullable String packageName, @UserIdInt int userId,
-                @NonNull Consumer<Boolean> callback);
-    }
-
-    public abstract void systemReady();
+    void systemReady();
 
     /**
      * Get whether permission review is required for a package.
@@ -152,7 +64,7 @@
      * @return whether permission review is required
      */
     //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
-    public abstract boolean isPermissionsReviewRequired(@NonNull String packageName,
+    boolean isPermissionsReviewRequired(@NonNull String packageName,
             @UserIdInt int userId);
 
     /**
@@ -167,7 +79,7 @@
      * @param allPackages All currently known packages
      * @param callback Callback to call after permission changes
      */
-    public abstract void updateAllPermissions(@Nullable String volumeUuid, boolean sdkUpdate);
+    void updateAllPermissions(@Nullable String volumeUuid, boolean sdkUpdate);
 
     /**
      * Reset the runtime permission state changes for a package.
@@ -178,7 +90,7 @@
      * @param userId the user ID
      */
     //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
-    public abstract void resetRuntimePermissions(@NonNull AndroidPackage pkg,
+    void resetRuntimePermissions(@NonNull AndroidPackage pkg,
             @UserIdInt int userId);
 
     /**
@@ -187,7 +99,7 @@
      * @param userId the user ID
      */
     //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
-    public abstract void resetAllRuntimePermissions(@UserIdInt int userId);
+    void resetAllRuntimePermissions(@UserIdInt int userId);
 
     /**
      * Read legacy permission state from package settings.
@@ -196,7 +108,7 @@
      * {@code PackageSetting} which is a implementation detail that permission should not know.
      * Instead, it should retrieve the legacy state via a defined API.
      */
-    public abstract void readLegacyPermissionStateTEMP();
+    void readLegacyPermissionStateTEMP();
 
     /**
      * Write legacy permission state to package settings.
@@ -204,12 +116,7 @@
      * TODO(zhanghai): This is a temporary method and should be removed once we migrated persistence
      * for permission.
      */
-    public abstract void writeLegacyPermissionStateTEMP();
-
-    /**
-     * Notify that a user has been removed and its permission state should be removed as well.
-     */
-    public abstract void onUserRemoved(@UserIdInt int userId);
+    void writeLegacyPermissionStateTEMP();
 
     /**
      * Get all the permissions granted to a package.
@@ -220,8 +127,7 @@
      */
     //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
     @NonNull
-    public abstract Set<String> getGrantedPermissions(@NonNull String packageName,
-            @UserIdInt int userId);
+    Set<String> getGrantedPermissions(@NonNull String packageName, @UserIdInt int userId);
 
     /**
      * Get the GIDs of a permission.
@@ -232,7 +138,7 @@
      */
     //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
     @NonNull
-    public abstract int[] getPermissionGids(@NonNull String permissionName, @UserIdInt int userId);
+    int[] getPermissionGids(@NonNull String permissionName, @UserIdInt int userId);
 
     /**
      * Get the packages that have requested an app op permission.
@@ -242,172 +148,40 @@
      */
     //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
     @NonNull
-    public abstract String[] getAppOpPermissionPackages(@NonNull String permissionName);
+    String[] getAppOpPermissionPackages(@NonNull String permissionName);
 
     /** HACK HACK methods to allow for partial migration of data to the PermissionManager class */
     @Nullable
-    public abstract Permission getPermissionTEMP(@NonNull String permName);
+    Permission getPermissionTEMP(@NonNull String permName);
 
     /** Get all permissions that have a certain protection */
-    public abstract @NonNull ArrayList<PermissionInfo> getAllPermissionsWithProtection(
+    @NonNull
+    ArrayList<PermissionInfo> getAllPermissionsWithProtection(
             @PermissionInfo.Protection int protection);
 
     /** Get all permissions that have certain protection flags */
-    public abstract @NonNull ArrayList<PermissionInfo> getAllPermissionsWithProtectionFlags(
+    @NonNull ArrayList<PermissionInfo> getAllPermissionsWithProtectionFlags(
             @PermissionInfo.ProtectionFlags int protectionFlags);
 
     /**
-     * Returns the delegate used to influence permission checking.
+     * Start delegate the permission identity of the shell UID to the given UID.
      *
-     * @return The delegate instance.
+     * @param uid the UID to delegate shell permission identity to
+     * @param packageName the name of the package to delegate shell permission identity to
+     * @param permissionNames the names of the permissions to delegate shell permission identity
+     *                       for, or {@code null} for all permissions
      */
-    public abstract @Nullable CheckPermissionDelegate getCheckPermissionDelegate();
+    //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+    void startShellPermissionIdentityDelegation(int uid,
+            @NonNull String packageName, @Nullable List<String> permissionNames);
 
     /**
-     * Sets the delegate used to influence permission checking.
+     * Stop delegating the permission identity of the shell UID.
      *
-     * @param delegate A delegate instance or {@code null} to clear.
+     * @see #startShellPermissionIdentityDelegation(int, String, List)
      */
-    public abstract void setCheckPermissionDelegate(@Nullable CheckPermissionDelegate delegate);
-
-    /**
-     * Sets the dialer application packages provider.
-     * @param provider The provider.
-     */
-    public abstract void setDialerAppPackagesProvider(PackagesProvider provider);
-
-    /**
-     * Set the location extra packages provider.
-     * @param provider The packages provider.
-     */
-    public abstract  void setLocationExtraPackagesProvider(PackagesProvider provider);
-
-    /**
-     * Sets the location provider packages provider.
-     * @param provider The packages provider.
-     */
-    public abstract void setLocationPackagesProvider(PackagesProvider provider);
-
-    /**
-     * Sets the SIM call manager packages provider.
-     * @param provider The provider.
-     */
-    public abstract void setSimCallManagerPackagesProvider(PackagesProvider provider);
-
-    /**
-     * Sets the SMS application packages provider.
-     * @param provider The provider.
-     */
-    public abstract void setSmsAppPackagesProvider(PackagesProvider provider);
-
-    /**
-     * Sets the sync adapter packages provider.
-     * @param provider The provider.
-     */
-    public abstract void setSyncAdapterPackagesProvider(SyncAdapterPackagesProvider provider);
-
-    /**
-     * Sets the Use Open Wifi packages provider.
-     * @param provider The packages provider.
-     */
-    public abstract void setUseOpenWifiAppPackagesProvider(PackagesProvider provider);
-
-    /**
-     * Sets the voice interaction packages provider.
-     * @param provider The packages provider.
-     */
-    public abstract void setVoiceInteractionPackagesProvider(PackagesProvider provider);
-
-    /**
-     * Sets the default browser provider.
-     *
-     * @param provider the provider
-     */
-    public abstract void setDefaultBrowserProvider(@NonNull DefaultBrowserProvider provider);
-
-    /**
-     * Sets the package name of the default browser provider for the given user.
-     *
-     * @param packageName The package name of the default browser or {@code null}
-     *          to clear the default browser
-     * @param async If {@code true}, set the default browser asynchronously,
-     *          otherwise set it synchronously
-     * @param doGrant If {@code true} and if {@code packageName} is not {@code null},
-     *          perform default permission grants on the browser, otherwise skip the
-     *          default permission grants.
-     * @param userId The user to set the default browser for.
-     */
-    public abstract void setDefaultBrowser(@Nullable String packageName, boolean async,
-            boolean doGrant, @UserIdInt int userId);
-
-    /**
-     * Sets the default dialer provider.
-     *
-     * @param provider the provider
-     */
-    public abstract void setDefaultDialerProvider(@NonNull DefaultDialerProvider provider);
-
-    /**
-     * Sets the default home provider.
-     *
-     * @param provider the provider
-     */
-    public abstract void setDefaultHomeProvider(@NonNull DefaultHomeProvider provider);
-
-    /**
-     * Asynchronously sets the package name of the default home provider for the given user.
-     *
-     * @param packageName The package name of the default home or {@code null}
-     *          to clear the default browser
-     * @param userId The user to set the default browser for
-     * @param callback Invoked after the default home has been set
-     */
-    public abstract void setDefaultHome(@Nullable String packageName, @UserIdInt int userId,
-            @NonNull Consumer<Boolean> callback);
-
-    /**
-     * Returns the default browser package name for the given user.
-     */
-    @Nullable
-    public abstract String getDefaultBrowser(@UserIdInt int userId);
-
-    /**
-     * Returns the default dialer package name for the given user.
-     */
-    @Nullable
-    public abstract String getDefaultDialer(@UserIdInt int userId);
-
-    /**
-     * Returns the default home package name for the given user.
-     */
-    @Nullable
-    public abstract String getDefaultHome(@UserIdInt int userId);
-
-    /**
-     * Requests granting of the default permissions to the current default Use Open Wifi app.
-     * @param packageName The default use open wifi package name.
-     * @param userId The user for which to grant the permissions.
-     */
-    public abstract void grantDefaultPermissionsToDefaultSimCallManager(
-            @NonNull String packageName, @UserIdInt int userId);
-
-    /**
-     * Requests granting of the default permissions to the current default Use Open Wifi app.
-     * @param packageName The default use open wifi package name.
-     * @param userId The user for which to grant the permissions.
-     */
-    public abstract void grantDefaultPermissionsToDefaultUseOpenWifiApp(
-            @NonNull String packageName, @UserIdInt int userId);
-
-    /** Called when a new user has been created. */
-    public abstract void onNewUserCreated(@UserIdInt int userId);
-
-    /**
-     * Removes invalid permissions which are not {@link PermissionInfo#FLAG_HARD_RESTRICTED} or
-     * {@link PermissionInfo#FLAG_SOFT_RESTRICTED} from the input.
-     */
-    public abstract void retainHardAndSoftRestrictedPermissions(
-            @NonNull List<String> permissionNames);
+    //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+    void stopShellPermissionIdentityDelegation();
 
     /**
      * Read legacy permissions from legacy permission settings.
@@ -416,8 +190,7 @@
      * {@code LegacyPermissionSettings} which is a implementation detail that permission should not
      * know. Instead, it should retrieve the legacy permissions via a defined API.
      */
-    public abstract void readLegacyPermissionsTEMP(
-            @NonNull LegacyPermissionSettings legacyPermissionSettings);
+    void readLegacyPermissionsTEMP(@NonNull LegacyPermissionSettings legacyPermissionSettings);
 
     /**
      * Write legacy permissions to legacy permission settings.
@@ -425,8 +198,23 @@
      * TODO(zhanghai): This is a temporary method and should be removed once we migrated persistence
      * for permission.
      */
-    public abstract void writeLegacyPermissionsTEMP(
-            @NonNull LegacyPermissionSettings legacyPermissionSettings);
+    void writeLegacyPermissionsTEMP(@NonNull LegacyPermissionSettings legacyPermissionSettings);
+
+    /**
+     * Callback when a user has been created.
+     *
+     * @param userId the created user ID
+     */
+    //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+    void onUserCreated(@UserIdInt int userId);
+
+    /**
+     * Callback when a user has been removed.
+     *
+     * @param userId the removed user ID
+     */
+    //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+    void onUserRemoved(@UserIdInt int userId);
 
     /**
      * Callback when a package has been added.
@@ -436,7 +224,7 @@
      * @param oldPkg the old package, or {@code null} if none
      */
     //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
-    public abstract void onPackageAdded(@NonNull AndroidPackage pkg, boolean isInstantApp,
+    void onPackageAdded(@NonNull AndroidPackage pkg, boolean isInstantApp,
             @Nullable AndroidPackage oldPkg);
 
     /**
@@ -447,8 +235,8 @@
      * @param userId the user ID this package is installed for
      */
     //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
-    public abstract void onPackageInstalled(@NonNull AndroidPackage pkg,
-            @NonNull PackageInstalledParams params, @UserIdInt int userId);
+    void onPackageInstalled(@NonNull AndroidPackage pkg, @NonNull PackageInstalledParams params,
+            @UserIdInt int userId);
 
     /**
      * Callback when a package has been removed.
@@ -456,7 +244,7 @@
      * @param pkg the removed package
      */
     //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
-    public abstract void onPackageRemoved(@NonNull AndroidPackage pkg);
+    void onPackageRemoved(@NonNull AndroidPackage pkg);
 
     /**
      * Callback when a package has been uninstalled.
@@ -473,9 +261,8 @@
      * @param userId the user ID the package is uninstalled for
      */
     //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
-    public abstract void onPackageUninstalled(@NonNull String packageName, int appId,
-            @Nullable AndroidPackage pkg, @NonNull List<AndroidPackage> sharedUserPkgs,
-            @UserIdInt int userId);
+    void onPackageUninstalled(@NonNull String packageName, int appId, @Nullable AndroidPackage pkg,
+            @NonNull List<AndroidPackage> sharedUserPkgs, @UserIdInt int userId);
 
     /**
      * Check whether a permission can be propagated to instant app.
@@ -483,7 +270,23 @@
      * @param permissionName the name of the permission
      * @return whether the permission can be propagated
      */
-    public abstract boolean canPropagatePermissionToInstantApp(@NonNull String permissionName);
+    boolean canPropagatePermissionToInstantApp(@NonNull String permissionName);
+
+    /**
+     * Listener for package permission state (permissions or flags) changes.
+     */
+    interface OnRuntimePermissionStateChangedListener {
+
+        /**
+         * Called when the runtime permission state (permissions or flags) changed.
+         *
+         * @param packageName The package for which the change happened.
+         * @param userId the user id for which the change happened.
+         */
+        @Nullable
+        void onRuntimePermissionStateChanged(@NonNull String packageName,
+                @UserIdInt int userId);
+    }
 
     /**
      * The permission-related parameters passed in for package installation.
@@ -491,7 +294,7 @@
      * @see android.content.pm.PackageInstaller.SessionParams
      */
     //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
-    public static final class PackageInstalledParams {
+    final class PackageInstalledParams {
         /**
          * A static instance whose parameters are all in their default state.
          */
diff --git a/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java b/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
index 321bb8c..cc1f8d6 100644
--- a/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
+++ b/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
@@ -158,7 +158,6 @@
         // switch there is no need to register for a callback.
         boolean shouldListenToLidSwitch = false;
 
-        final SensorManager sensorManager = mContext.getSystemService(SensorManager.class);
         // The set of Sensor(s) that this instance should register to receive SensorEvent(s) from.
         final ArraySet<Sensor> sensorsToListenTo = new ArraySet<>();
 
@@ -182,19 +181,10 @@
             List<SensorCondition> sensorConditions = conditions.getSensor();
             for (int j = 0; j < sensorConditions.size(); j++) {
                 SensorCondition sensorCondition = sensorConditions.get(j);
-                final int expectedSensorType = sensorCondition.getType().intValue();
+                final String expectedSensorType = sensorCondition.getType();
                 final String expectedSensorName = sensorCondition.getName();
 
-                List<Sensor> sensors = sensorManager.getSensorList(expectedSensorType);
-                Sensor foundSensor = null;
-                for (int sensorIndex = 0; sensorIndex < sensors.size(); sensorIndex++) {
-                    Sensor sensor = sensors.get(sensorIndex);
-                    if (sensor.getName().equals(expectedSensorName)) {
-                        foundSensor = sensor;
-                        break;
-                    }
-                }
-
+                final Sensor foundSensor = findSensor(expectedSensorType, expectedSensorName);
                 if (foundSensor == null) {
                     throw new IllegalStateException("Failed to find Sensor with type: "
                             + expectedSensorType + " and name: " + expectedSensorName);
@@ -221,12 +211,33 @@
             inputManager.registerLidSwitchCallback(this);
         }
 
+        final SensorManager sensorManager = mContext.getSystemService(SensorManager.class);
         for (int i = 0; i < sensorsToListenTo.size(); i++) {
             Sensor sensor = sensorsToListenTo.valueAt(i);
             sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_FASTEST);
         }
     }
 
+    @Nullable
+    private Sensor findSensor(String type, String name) {
+        final SensorManager sensorManager = mContext.getSystemService(SensorManager.class);
+        final List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
+        for (int sensorIndex = 0; sensorIndex < sensors.size(); sensorIndex++) {
+            final Sensor sensor = sensors.get(sensorIndex);
+            final String sensorType = sensor.getStringType();
+            final String sensorName = sensor.getName();
+
+            if (sensorType == null || sensorName == null) {
+                continue;
+            }
+
+            if (sensorType.equals(type) && sensorName.equals(name)) {
+                return sensor;
+            }
+        }
+        return null;
+    }
+
     @Override
     public void setListener(Listener listener) {
         synchronized (mLock) {
diff --git a/services/core/java/com/android/server/policy/KeyCombinationManager.java b/services/core/java/com/android/server/policy/KeyCombinationManager.java
new file mode 100644
index 0000000..84ac124
--- /dev/null
+++ b/services/core/java/com/android/server/policy/KeyCombinationManager.java
@@ -0,0 +1,229 @@
+/*
+ * 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.policy;
+
+import static android.view.KeyEvent.KEYCODE_POWER;
+
+import android.os.SystemClock;
+import android.util.SparseLongArray;
+import android.view.KeyEvent;
+
+import com.android.internal.util.ToBooleanFunction;
+
+import java.util.ArrayList;
+import java.util.function.Consumer;
+
+/**
+ * Handles a mapping of two keys combination.
+ */
+public class KeyCombinationManager {
+    private static final String TAG = "KeyCombinationManager";
+
+    // Store the received down time of keycode.
+    private final SparseLongArray mDownTimes = new SparseLongArray(2);
+    private final ArrayList<TwoKeysCombinationRule> mRules = new ArrayList();
+
+    // Selected rules according to current key down.
+    private final ArrayList<TwoKeysCombinationRule> mActiveRules = new ArrayList();
+    // The rule has been triggered by current keys.
+    private TwoKeysCombinationRule mTriggeredRule;
+
+    // Keys in a key combination must be pressed within this interval of each other.
+    private static final long COMBINE_KEY_DELAY_MILLIS = 150;
+
+    /**
+     *  Rule definition for two keys combination.
+     *  E.g : define volume_down + power key.
+     *  <pre class="prettyprint">
+     *  TwoKeysCombinationRule rule =
+     *      new TwoKeysCombinationRule(KEYCODE_VOLUME_DOWN, KEYCODE_POWER) {
+     *           boolean preCondition() { // check if it needs to intercept key }
+     *           void execute() { // trigger action }
+     *           void cancel() { // cancel action }
+     *       };
+     *  </pre>
+     */
+    abstract static class TwoKeysCombinationRule {
+        private int mKeyCode1;
+        private int mKeyCode2;
+
+        TwoKeysCombinationRule(int keyCode1, int keyCode2) {
+            mKeyCode1 = keyCode1;
+            mKeyCode2 = keyCode2;
+        }
+
+        boolean preCondition() {
+            return true;
+        }
+
+        boolean shouldInterceptKey(int keyCode) {
+            return preCondition() && (keyCode == mKeyCode1 || keyCode == mKeyCode2);
+        }
+
+        boolean shouldInterceptKeys(SparseLongArray downTimes) {
+            final long now = SystemClock.uptimeMillis();
+            if (downTimes.get(mKeyCode1) > 0
+                    && downTimes.get(mKeyCode2) > 0
+                    && now <= downTimes.get(mKeyCode1) + COMBINE_KEY_DELAY_MILLIS
+                    && now <= downTimes.get(mKeyCode2) + COMBINE_KEY_DELAY_MILLIS) {
+                return true;
+            }
+            return false;
+        }
+
+        abstract void execute();
+        abstract void cancel();
+
+        @Override
+        public String toString() {
+            return "KeyCode1 = " + KeyEvent.keyCodeToString(mKeyCode1)
+                    + ", KeyCode2 = " +  KeyEvent.keyCodeToString(mKeyCode2);
+        }
+    }
+
+    public KeyCombinationManager() {
+    }
+
+    void addRule(TwoKeysCombinationRule rule) {
+        mRules.add(rule);
+    }
+
+    /**
+     * Check if the key event could be triggered by combine key rule before dispatching to a window.
+     */
+    void interceptKey(KeyEvent event, boolean interactive) {
+        final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
+        final int keyCode = event.getKeyCode();
+        final int count = mActiveRules.size();
+        final long eventTime = event.getEventTime();
+
+        if (interactive && down) {
+            if (mDownTimes.size() > 0) {
+                if (count > 0
+                        && eventTime > mDownTimes.valueAt(0) + COMBINE_KEY_DELAY_MILLIS) {
+                    // exceed time from first key down.
+                    forAllRules(mActiveRules, (rule)-> rule.cancel());
+                    mActiveRules.clear();
+                    return;
+                } else if (count == 0) { // has some key down but no active rule exist.
+                    return;
+                }
+            }
+
+            if (mDownTimes.get(keyCode) == 0) {
+                mDownTimes.put(keyCode, eventTime);
+            } else {
+                // ignore old key, maybe a repeat key.
+                return;
+            }
+
+            if (mDownTimes.size() == 1) {
+                mTriggeredRule = null;
+                // check first key and pick active rules.
+                forAllRules(mRules, (rule)-> {
+                    if (rule.shouldInterceptKey(keyCode)) {
+                        mActiveRules.add(rule);
+                    }
+                });
+            } else {
+                // Ignore if rule already triggered.
+                if (mTriggeredRule != null) {
+                    return;
+                }
+
+                // check if second key can trigger rule, or remove the non-match rule.
+                forAllActiveRules((rule) -> {
+                    if (!rule.shouldInterceptKeys(mDownTimes)) {
+                        return false;
+                    }
+                    rule.execute();
+                    mTriggeredRule = rule;
+                    return true;
+                });
+                mActiveRules.clear();
+                if (mTriggeredRule != null) {
+                    mActiveRules.add(mTriggeredRule);
+                }
+            }
+        } else {
+            mDownTimes.delete(keyCode);
+            for (int index = count - 1; index >= 0; index--) {
+                final TwoKeysCombinationRule rule = mActiveRules.get(index);
+                if (rule.shouldInterceptKey(keyCode)) {
+                    rule.cancel();
+                    mActiveRules.remove(index);
+                }
+            }
+        }
+    }
+
+    /**
+     * Return the interceptTimeout to tell InputDispatcher when is ready to deliver to window.
+     */
+    long getKeyInterceptTimeout(int keyCode) {
+        if (forAllActiveRules((rule) -> rule.shouldInterceptKey(keyCode))) {
+            return mDownTimes.get(keyCode) + COMBINE_KEY_DELAY_MILLIS;
+        }
+        return 0;
+    }
+
+    /**
+     * True if the key event had been handled.
+     */
+    boolean isKeyConsumed(KeyEvent event) {
+        if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) {
+            return false;
+        }
+        return mTriggeredRule != null && mTriggeredRule.shouldInterceptKey(event.getKeyCode());
+    }
+
+    /**
+     * True if power key is the candidate.
+     */
+    boolean isPowerKeyIntercepted() {
+        if (forAllActiveRules((rule) -> rule.shouldInterceptKey(KEYCODE_POWER))) {
+            // return false if only if power key pressed.
+            return mDownTimes.size() > 1 || mDownTimes.get(KEYCODE_POWER) == 0;
+        }
+        return false;
+    }
+
+    /**
+     * Traverse each item of rules.
+     */
+    private void forAllRules(
+            ArrayList<TwoKeysCombinationRule> rules, Consumer<TwoKeysCombinationRule> callback) {
+        final int count = rules.size();
+        for (int index = 0; index < count; index++) {
+            final TwoKeysCombinationRule rule = rules.get(index);
+            callback.accept(rule);
+        }
+    }
+
+    /**
+     * Traverse each item of active rules until some rule can be applied, otherwise return false.
+     */
+    private boolean forAllActiveRules(ToBooleanFunction<TwoKeysCombinationRule> callback) {
+        final int count = mActiveRules.size();
+        for (int index = 0; index < count; index++) {
+            final TwoKeysCombinationRule rule = mActiveRules.get(index);
+            if (callback.apply(rule)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/services/core/java/com/android/server/policy/OWNERS b/services/core/java/com/android/server/policy/OWNERS
new file mode 100644
index 0000000..0862c05
--- /dev/null
+++ b/services/core/java/com/android/server/policy/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 8beec35eb..ea985df 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -35,7 +35,13 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.Display.STATE_OFF;
+import static android.view.KeyEvent.KEYCODE_BACK;
+import static android.view.KeyEvent.KEYCODE_DPAD_CENTER;
+import static android.view.KeyEvent.KEYCODE_DPAD_DOWN;
+import static android.view.KeyEvent.KEYCODE_POWER;
 import static android.view.KeyEvent.KEYCODE_UNKNOWN;
+import static android.view.KeyEvent.KEYCODE_VOLUME_DOWN;
+import static android.view.KeyEvent.KEYCODE_VOLUME_UP;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
@@ -202,6 +208,7 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemServiceManager;
 import com.android.server.inputmethod.InputMethodManagerInternal;
+import com.android.server.policy.KeyCombinationManager.TwoKeysCombinationRule;
 import com.android.server.policy.keyguard.KeyguardServiceDelegate;
 import com.android.server.policy.keyguard.KeyguardServiceDelegate.DrawnListener;
 import com.android.server.policy.keyguard.KeyguardStateMonitor.StateCallback;
@@ -405,7 +412,7 @@
     private boolean mEnableCarDockHomeCapture = true;
 
     boolean mBootMessageNeedsHiding;
-    KeyguardServiceDelegate mKeyguardDelegate;
+    private KeyguardServiceDelegate mKeyguardDelegate;
     private boolean mKeyguardBound;
     final Runnable mWindowManagerDrawCallback = new Runnable() {
         @Override
@@ -422,8 +429,8 @@
         }
     };
 
-    GlobalActions mGlobalActions;
-    Handler mHandler;
+    private GlobalActions mGlobalActions;
+    private Handler mHandler;
 
     // FIXME This state is shared between the input reader and handler thread.
     // Technically it's broken and buggy but it has been like this for many years
@@ -547,34 +554,14 @@
     private boolean mGoToSleepOnButtonPressTheaterMode;
 
     // Screenshot trigger states
-    // Time to volume and power must be pressed within this interval of each other.
-    private static final long SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS = 150;
     // Increase the chord delay when taking a screenshot from the keyguard
     private static final float KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER = 2.5f;
-    private boolean mScreenshotChordEnabled;
-    private boolean mScreenshotChordVolumeDownKeyTriggered;
-    private long mScreenshotChordVolumeDownKeyTime;
-    private boolean mScreenshotChordVolumeDownKeyConsumed;
-    private boolean mA11yShortcutChordVolumeUpKeyTriggered;
-    private long mA11yShortcutChordVolumeUpKeyTime;
-    private boolean mA11yShortcutChordVolumeUpKeyConsumed;
-
-    private boolean mScreenshotChordPowerKeyTriggered;
-    private long mScreenshotChordPowerKeyTime;
 
     // Ringer toggle should reuse timing and triggering from screenshot power and a11y vol up
-    private int mRingerToggleChord = VOLUME_HUSH_OFF;
+    int mRingerToggleChord = VOLUME_HUSH_OFF;
 
     private static final long BUGREPORT_TV_GESTURE_TIMEOUT_MILLIS = 1000;
 
-    private boolean mBugreportTvKey1Pressed;
-    private boolean mBugreportTvKey2Pressed;
-    private boolean mBugreportTvScheduled;
-
-    private boolean mAccessibilityTvKey1Pressed;
-    private boolean mAccessibilityTvKey2Pressed;
-    private boolean mAccessibilityTvScheduled;
-
     /* The number of steps between min and max brightness */
     private static final int BRIGHTNESS_STEPS = 10;
 
@@ -603,6 +590,8 @@
 
     private int mPowerButtonSuppressionDelayMillis = POWER_BUTTON_SUPPRESSION_DELAY_DEFAULT_MILLIS;
 
+    private KeyCombinationManager mKeyCombinationManager;
+
     private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3;
     private static final int MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK = 4;
     private static final int MSG_KEYGUARD_DRAWN_COMPLETE = 5;
@@ -900,15 +889,6 @@
 
         mWindowManagerFuncs.onPowerKeyDown(interactive);
 
-        // Latch power key state to detect screenshot chord.
-        if (interactive && !mScreenshotChordPowerKeyTriggered
-                && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
-            mScreenshotChordPowerKeyTriggered = true;
-            mScreenshotChordPowerKeyTime = event.getDownTime();
-            interceptScreenshotChord();
-            interceptRingerToggleChord();
-        }
-
         // Stop ringing or end call if configured to do so when power is pressed.
         TelecomManager telecomManager = getTelecommService();
         boolean hungUp = false;
@@ -946,9 +926,8 @@
 
         // If the power key has still not yet been handled, then detect short
         // press, long press, or multi press and decide what to do.
-        mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
-                || mA11yShortcutChordVolumeUpKeyTriggered || gesturedServiceIntercepted
-                || handledByPowerManager;
+        mPowerKeyHandled = hungUp || gesturedServiceIntercepted
+                || handledByPowerManager || mKeyCombinationManager.isPowerKeyIntercepted();
         if (!mPowerKeyHandled) {
             if (interactive) {
                 // When interactive, we're already awake.
@@ -1004,8 +983,6 @@
 
     private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {
         final boolean handled = canceled || mPowerKeyHandled;
-        mScreenshotChordPowerKeyTriggered = false;
-        cancelPendingScreenshotChordAction();
         cancelPendingPowerKeyAction();
 
         if (!handled) {
@@ -1315,52 +1292,22 @@
     }
 
     private void interceptScreenshotChord() {
-        if (mScreenshotChordEnabled
-                && mScreenshotChordVolumeDownKeyTriggered && mScreenshotChordPowerKeyTriggered
-                && !mA11yShortcutChordVolumeUpKeyTriggered) {
-            final long now = SystemClock.uptimeMillis();
-            if (now <= mScreenshotChordVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS
-                    && now <= mScreenshotChordPowerKeyTime
-                            + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {
-                mScreenshotChordVolumeDownKeyConsumed = true;
-                cancelPendingPowerKeyAction();
-                mScreenshotRunnable.setScreenshotType(TAKE_SCREENSHOT_FULLSCREEN);
-                mScreenshotRunnable.setScreenshotSource(SCREENSHOT_KEY_CHORD);
-                mHandler.postDelayed(mScreenshotRunnable, getScreenshotChordLongPressDelay());
-            }
-        }
+        mHandler.removeCallbacks(mScreenshotRunnable);
+        mScreenshotRunnable.setScreenshotType(TAKE_SCREENSHOT_FULLSCREEN);
+        mScreenshotRunnable.setScreenshotSource(SCREENSHOT_KEY_CHORD);
+        mHandler.postDelayed(mScreenshotRunnable, getScreenshotChordLongPressDelay());
     }
 
     private void interceptAccessibilityShortcutChord() {
-        if (mAccessibilityShortcutController.isAccessibilityShortcutAvailable(isKeyguardLocked())
-                && mScreenshotChordVolumeDownKeyTriggered && mA11yShortcutChordVolumeUpKeyTriggered
-                && !mScreenshotChordPowerKeyTriggered) {
-            final long now = SystemClock.uptimeMillis();
-            if (now <= mScreenshotChordVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS
-                    && now <= mA11yShortcutChordVolumeUpKeyTime
-                    + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {
-                mScreenshotChordVolumeDownKeyConsumed = true;
-                mA11yShortcutChordVolumeUpKeyConsumed = true;
-                mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_ACCESSIBILITY_SHORTCUT),
-                        getAccessibilityShortcutTimeout());
-            }
-        }
+        mHandler.removeMessages(MSG_ACCESSIBILITY_SHORTCUT);
+        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_ACCESSIBILITY_SHORTCUT),
+                getAccessibilityShortcutTimeout());
     }
 
     private void interceptRingerToggleChord() {
-        if (mRingerToggleChord != Settings.Secure.VOLUME_HUSH_OFF
-                && mScreenshotChordPowerKeyTriggered && mA11yShortcutChordVolumeUpKeyTriggered) {
-            final long now = SystemClock.uptimeMillis();
-            if (now <= mA11yShortcutChordVolumeUpKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS
-                    && now <= mScreenshotChordPowerKeyTime
-                    + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {
-                mA11yShortcutChordVolumeUpKeyConsumed = true;
-                cancelPendingPowerKeyAction();
-
-                mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RINGER_TOGGLE_CHORD),
-                        getRingerToggleChordDelay());
-            }
-        }
+        mHandler.removeMessages(MSG_RINGER_TOGGLE_CHORD);
+        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RINGER_TOGGLE_CHORD),
+                getRingerToggleChordDelay());
     }
 
     private long getAccessibilityShortcutTimeout() {
@@ -1942,9 +1889,6 @@
         mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(),
                 com.android.internal.R.array.config_safeModeEnabledVibePattern);
 
-        mScreenshotChordEnabled = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_enableScreenshotChord);
-
         mGlobalKeyManager = new GlobalKeyManager(mContext);
 
         // Controls rotation and the like.
@@ -1980,6 +1924,92 @@
                         mWindowManagerFuncs.onKeyguardShowingAndNotOccludedChanged();
                     }
                 });
+        initKeyCombinationRules();
+    }
+
+    private void initKeyCombinationRules() {
+        mKeyCombinationManager = new KeyCombinationManager();
+        final boolean screenshotChordEnabled = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_enableScreenshotChord);
+
+        if (screenshotChordEnabled) {
+            mKeyCombinationManager.addRule(
+                    new TwoKeysCombinationRule(KEYCODE_VOLUME_DOWN, KEYCODE_POWER) {
+                        @Override
+                        void execute() {
+                            cancelPendingPowerKeyAction();
+                            interceptScreenshotChord();
+                        }
+                        @Override
+                        void cancel() {
+                            cancelPendingScreenshotChordAction();
+                        }
+                    });
+        }
+
+        mKeyCombinationManager.addRule(
+                new TwoKeysCombinationRule(KEYCODE_VOLUME_DOWN, KEYCODE_VOLUME_UP) {
+                    @Override
+                    boolean preCondition() {
+                        return mAccessibilityShortcutController
+                                .isAccessibilityShortcutAvailable(isKeyguardLocked());
+                    }
+                    @Override
+                    void execute() {
+                        interceptAccessibilityShortcutChord();
+                    }
+                    @Override
+                    void cancel() {
+                        cancelPendingAccessibilityShortcutAction();
+                    }
+                });
+
+        mKeyCombinationManager.addRule(
+                new TwoKeysCombinationRule(KEYCODE_VOLUME_UP, KEYCODE_POWER) {
+                    @Override
+                    boolean preCondition() {
+                        return mRingerToggleChord != VOLUME_HUSH_OFF;
+                    }
+                    @Override
+                    void execute() {
+                        cancelPendingPowerKeyAction();
+                        interceptRingerToggleChord();
+                    }
+                    @Override
+                    void cancel() {
+                        cancelPendingRingerToggleChordAction();
+                    }
+                });
+
+        if (mHasFeatureLeanback) {
+            mKeyCombinationManager.addRule(
+                    new TwoKeysCombinationRule(KEYCODE_BACK, KEYCODE_DPAD_DOWN) {
+                        @Override
+                        void execute() {
+                            cancelPendingBackKeyAction();
+                            interceptAccessibilityGestureTv();
+                        }
+
+                        @Override
+                        void cancel() {
+                            cancelAccessibilityGestureTv();
+                        }
+                    });
+
+            mKeyCombinationManager.addRule(
+                    new TwoKeysCombinationRule(KEYCODE_DPAD_CENTER, KEYCODE_BACK) {
+                        @Override
+                        void execute() {
+                            cancelPendingBackKeyAction();
+                            interceptBugreportGestureTv();
+                        }
+
+                        @Override
+                        void cancel() {
+                            cancelBugreportGestureTv();
+                        }
+                    });
+        }
     }
 
     /**
@@ -2383,15 +2413,6 @@
             wm = (WindowManager) context.getSystemService(WINDOW_SERVICE);
             view = win.getDecorView();
 
-            // Ignore to show splash screen if the decorView is not opaque.
-            if (!view.isOpaque()) {
-                if (DEBUG_SPLASH_SCREEN) {
-                    Slog.d(TAG, "addSplashScreen: the view of " + packageName
-                            + " is not opaque, cancel it");
-                }
-                return null;
-            }
-
             if (DEBUG_SPLASH_SCREEN) Slog.d(TAG, "Adding splash screen window for "
                 + packageName + " / " + appToken + ": " + (view.getParent() != null ? view : null));
 
@@ -2552,70 +2573,15 @@
                     + repeatCount + " keyguardOn=" + keyguardOn + " canceled=" + canceled);
         }
 
-        // If we think we might have a volume down & power key chord on the way
-        // but we're not sure, then tell the dispatcher to wait a little while and
-        // try again later before dispatching.
-        if (mScreenshotChordEnabled && (flags & KeyEvent.FLAG_FALLBACK) == 0) {
-            if (mScreenshotChordVolumeDownKeyTriggered && !mScreenshotChordPowerKeyTriggered) {
-                final long now = SystemClock.uptimeMillis();
-                final long timeoutTime = mScreenshotChordVolumeDownKeyTime
-                        + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS;
-                if (now < timeoutTime) {
-                    return timeoutTime - now;
-                }
-            }
-            if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
-                    && mScreenshotChordVolumeDownKeyConsumed) {
-                if (!down) {
-                    mScreenshotChordVolumeDownKeyConsumed = false;
-                }
-                return -1;
-            }
+        if (mKeyCombinationManager.isKeyConsumed(event)) {
+            return -1;
         }
 
-        // If an accessibility shortcut might be partially complete, hold off dispatching until we
-        // know if it is complete or not
-        if (mAccessibilityShortcutController.isAccessibilityShortcutAvailable(false)
-                && (flags & KeyEvent.FLAG_FALLBACK) == 0) {
-            if (mScreenshotChordVolumeDownKeyTriggered ^ mA11yShortcutChordVolumeUpKeyTriggered) {
-                final long now = SystemClock.uptimeMillis();
-                final long timeoutTime = (mScreenshotChordVolumeDownKeyTriggered
-                        ? mScreenshotChordVolumeDownKeyTime : mA11yShortcutChordVolumeUpKeyTime)
-                        + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS;
-                if (now < timeoutTime) {
-                    return timeoutTime - now;
-                }
-            }
-            if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN && mScreenshotChordVolumeDownKeyConsumed) {
-                if (!down) {
-                    mScreenshotChordVolumeDownKeyConsumed = false;
-                }
-                return -1;
-            }
-            if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mA11yShortcutChordVolumeUpKeyConsumed) {
-                if (!down) {
-                    mA11yShortcutChordVolumeUpKeyConsumed = false;
-                }
-                return -1;
-            }
-        }
-
-        // If a ringer toggle chord could be on the way but we're not sure, then tell the dispatcher
-        // to wait a little while and try again later before dispatching.
-        if (mRingerToggleChord != VOLUME_HUSH_OFF && (flags & KeyEvent.FLAG_FALLBACK) == 0) {
-            if (mA11yShortcutChordVolumeUpKeyTriggered && !mScreenshotChordPowerKeyTriggered) {
-                final long now = SystemClock.uptimeMillis();
-                final long timeoutTime = mA11yShortcutChordVolumeUpKeyTime
-                        + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS;
-                if (now < timeoutTime) {
-                    return timeoutTime - now;
-                }
-            }
-            if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mA11yShortcutChordVolumeUpKeyConsumed) {
-                if (!down) {
-                    mA11yShortcutChordVolumeUpKeyConsumed = false;
-                }
-                return -1;
+        if ((flags & KeyEvent.FLAG_FALLBACK) == 0) {
+            final long now = SystemClock.uptimeMillis();
+            final long interceptTimeout = mKeyCombinationManager.getKeyInterceptTimeout(keyCode);
+            if (now < interceptTimeout) {
+                return interceptTimeout - now;
             }
         }
 
@@ -2774,8 +2740,6 @@
         } else if (keyCode == KeyEvent.KEYCODE_TAB && event.isMetaPressed()) {
             // Pass through keyboard navigation keys.
             return 0;
-        } else if (mHasFeatureLeanback && interceptBugreportGestureTv(keyCode, down)) {
-            return -1;
         } else if (keyCode == KeyEvent.KEYCODE_ALL_APPS) {
             if (!down) {
                 mHandler.removeMessages(MSG_HANDLE_ALL_APPS);
@@ -2978,53 +2942,30 @@
     /**
      * TV only: recognizes a remote control gesture for capturing a bug report.
      */
-    private boolean interceptBugreportGestureTv(int keyCode, boolean down) {
+    private void interceptBugreportGestureTv() {
+        mHandler.removeMessages(MSG_BUGREPORT_TV);
         // The bugreport capture chord is a long press on DPAD CENTER and BACK simultaneously.
-        if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
-            mBugreportTvKey1Pressed = down;
-        } else if (keyCode == KeyEvent.KEYCODE_BACK) {
-            mBugreportTvKey2Pressed = down;
-        }
+        Message msg = Message.obtain(mHandler, MSG_BUGREPORT_TV);
+        msg.setAsynchronous(true);
+        mHandler.sendMessageDelayed(msg, BUGREPORT_TV_GESTURE_TIMEOUT_MILLIS);
+    }
 
-        if (mBugreportTvKey1Pressed && mBugreportTvKey2Pressed) {
-            if (!mBugreportTvScheduled) {
-                mBugreportTvScheduled = true;
-                Message msg = Message.obtain(mHandler, MSG_BUGREPORT_TV);
-                msg.setAsynchronous(true);
-                mHandler.sendMessageDelayed(msg, BUGREPORT_TV_GESTURE_TIMEOUT_MILLIS);
-            }
-        } else if (mBugreportTvScheduled) {
-            mHandler.removeMessages(MSG_BUGREPORT_TV);
-            mBugreportTvScheduled = false;
-        }
-
-        return mBugreportTvScheduled;
+    private void cancelBugreportGestureTv() {
+        mHandler.removeMessages(MSG_BUGREPORT_TV);
     }
 
     /**
      * TV only: recognizes a remote control gesture as Accessibility shortcut.
      * Shortcut: Long press (BACK + DPAD_DOWN)
      */
-    private boolean interceptAccessibilityGestureTv(int keyCode, boolean down) {
-        if (keyCode == KeyEvent.KEYCODE_BACK) {
-            mAccessibilityTvKey1Pressed = down;
-        } else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
-            mAccessibilityTvKey2Pressed = down;
-        }
-
-        if (mAccessibilityTvKey1Pressed && mAccessibilityTvKey2Pressed) {
-            if (!mAccessibilityTvScheduled) {
-                mAccessibilityTvScheduled = true;
-                Message msg = Message.obtain(mHandler, MSG_ACCESSIBILITY_TV);
-                msg.setAsynchronous(true);
-                mHandler.sendMessageDelayed(msg, getAccessibilityShortcutTimeout());
-            }
-        } else if (mAccessibilityTvScheduled) {
-            mHandler.removeMessages(MSG_ACCESSIBILITY_TV);
-            mAccessibilityTvScheduled = false;
-        }
-
-        return mAccessibilityTvScheduled;
+    private void interceptAccessibilityGestureTv() {
+        mHandler.removeMessages(MSG_ACCESSIBILITY_TV);
+        Message msg = Message.obtain(mHandler, MSG_ACCESSIBILITY_TV);
+        msg.setAsynchronous(true);
+        mHandler.sendMessageDelayed(msg, getAccessibilityShortcutTimeout());
+    }
+    private void cancelAccessibilityGestureTv() {
+        mHandler.removeMessages(MSG_ACCESSIBILITY_TV);
     }
 
     private void requestBugreportForTv() {
@@ -3547,16 +3488,14 @@
         final int displayId = event.getDisplayId();
         final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
 
-        // If screen is off then we treat the case where the keyguard is open but hidden
-        // the same as if it were open and in front.
-        // This will prevent any keys other than the power button from waking the screen
-        // when the keyguard is hidden by another activity.
-        final boolean keyguardActive = (mKeyguardDelegate == null ? false :
-                                            (interactive ?
-                                                isKeyguardShowingAndNotOccluded() :
-                                                mKeyguardDelegate.isShowing()));
-
         if (DEBUG_INPUT) {
+            // If screen is off then we treat the case where the keyguard is open but hidden
+            // the same as if it were open and in front.
+            // This will prevent any keys other than the power button from waking the screen
+            // when the keyguard is hidden by another activity.
+            final boolean keyguardActive = (mKeyguardDelegate != null
+                    && (interactive ? isKeyguardShowingAndNotOccluded() :
+                    mKeyguardDelegate.isShowing()));
             Log.d(TAG, "interceptKeyTq keycode=" + keyCode
                     + " interactive=" + interactive + " keyguardActive=" + keyguardActive
                     + " policyFlags=" + Integer.toHexString(policyFlags));
@@ -3581,7 +3520,7 @@
                 // Reset the pending key
                 mPendingWakeKey = PENDING_KEY_NULL;
             }
-        } else if (!interactive && shouldDispatchInputWhenNonInteractive(displayId, keyCode)) {
+        } else if (shouldDispatchInputWhenNonInteractive(displayId, keyCode)) {
             // If we're currently dozing with the screen on and the keyguard showing, pass the key
             // to the application but preserve its wake key status to make sure we still move
             // from dozing to fully interactive if we would normally go from off to fully
@@ -3613,6 +3552,10 @@
             return result;
         }
 
+        if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
+            mKeyCombinationManager.interceptKey(event, interactive);
+        }
+
         // Enable haptics if down and virtual key without multiple repetitions. If this is a hard
         // virtual key such as a navigation bar button, only vibrate if flag is enabled.
         final boolean isNavBarVirtKey = ((event.getFlags() & KeyEvent.FLAG_VIRTUAL_HARD_KEY) != 0);
@@ -3640,46 +3583,6 @@
             case KeyEvent.KEYCODE_VOLUME_DOWN:
             case KeyEvent.KEYCODE_VOLUME_UP:
             case KeyEvent.KEYCODE_VOLUME_MUTE: {
-                if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
-                    if (down) {
-                        // Any activity on the vol down button stops the ringer toggle shortcut
-                        cancelPendingRingerToggleChordAction();
-
-                        if (interactive && !mScreenshotChordVolumeDownKeyTriggered
-                                && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
-                            mScreenshotChordVolumeDownKeyTriggered = true;
-                            mScreenshotChordVolumeDownKeyTime = event.getDownTime();
-                            mScreenshotChordVolumeDownKeyConsumed = false;
-                            cancelPendingPowerKeyAction();
-                            interceptScreenshotChord();
-                            interceptAccessibilityShortcutChord();
-                        }
-                    } else {
-                        mScreenshotChordVolumeDownKeyTriggered = false;
-                        cancelPendingScreenshotChordAction();
-                        cancelPendingAccessibilityShortcutAction();
-                    }
-                } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
-                    if (down) {
-                        if (interactive && !mA11yShortcutChordVolumeUpKeyTriggered
-                                && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
-                            mA11yShortcutChordVolumeUpKeyTriggered = true;
-                            mA11yShortcutChordVolumeUpKeyTime = event.getDownTime();
-                            mA11yShortcutChordVolumeUpKeyConsumed = false;
-                            cancelPendingPowerKeyAction();
-                            cancelPendingScreenshotChordAction();
-                            cancelPendingRingerToggleChordAction();
-
-                            interceptAccessibilityShortcutChord();
-                            interceptRingerToggleChord();
-                        }
-                    } else {
-                        mA11yShortcutChordVolumeUpKeyTriggered = false;
-                        cancelPendingScreenshotChordAction();
-                        cancelPendingAccessibilityShortcutAction();
-                        cancelPendingRingerToggleChordAction();
-                    }
-                }
                 if (down) {
                     sendSystemKeyToStatusBarAsync(event.getKeyCode());
 
@@ -3784,7 +3687,6 @@
                         KeyEvent.actionToString(event.getAction()),
                         mPowerKeyHandled ? 1 : 0, mPowerKeyPressCounter);
                 // Any activity on the power button stops the accessibility shortcut
-                cancelPendingAccessibilityShortcutAction();
                 result &= ~ACTION_PASS_TO_USER;
                 isWakeKey = false; // wake-up will be handled separately
                 if (down) {
@@ -3922,22 +3824,6 @@
             }
         }
 
-        // Intercept the Accessibility keychord for TV (DPAD_DOWN + Back) before the keyevent is
-        // processed through interceptKeyEventBeforeDispatch since Talkback may consume this event
-        // before it has a chance to reach that method.
-        if (mHasFeatureLeanback) {
-            switch (keyCode) {
-                case KeyEvent.KEYCODE_DPAD_DOWN:
-                case KeyEvent.KEYCODE_BACK: {
-                    boolean handled = interceptAccessibilityGestureTv(keyCode, down);
-                    if (handled) {
-                        result &= ~ACTION_PASS_TO_USER;
-                    }
-                    break;
-                }
-            }
-        }
-
         // Intercept the Accessibility keychord (CTRL + ALT + Z) for keyboard users.
         if (mAccessibilityShortcutController.isAccessibilityShortcutAvailable(isKeyguardLocked())) {
             switch (keyCode) {
@@ -5388,14 +5274,6 @@
                 pw.print(!mAllowLockscreenWhenOnDisplays.isEmpty());
                 pw.print(" mLockScreenTimeout="); pw.print(mLockScreenTimeout);
                 pw.print(" mLockScreenTimerActive="); pw.println(mLockScreenTimerActive);
-        if (mHasFeatureLeanback) {
-            pw.print(prefix);
-            pw.print("mAccessibilityTvKey1Pressed="); pw.println(mAccessibilityTvKey1Pressed);
-            pw.print(prefix);
-            pw.print("mAccessibilityTvKey2Pressed="); pw.println(mAccessibilityTvKey2Pressed);
-            pw.print(prefix);
-            pw.print("mAccessibilityTvScheduled="); pw.println(mAccessibilityTvScheduled);
-        }
 
         mGlobalKeyManager.dump(prefix, pw);
 
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
index 1e4e0a6..68d038b 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -368,12 +368,6 @@
         }
     }
 
-    boolean setAdaptivePolicyLocked(String settings, String deviceSpecificSettings, int reason) {
-        return setAdaptivePolicyLocked(
-                BatterySaverPolicy.Policy.fromSettings(settings, deviceSpecificSettings),
-                reason);
-    }
-
     boolean setAdaptivePolicyLocked(BatterySaverPolicyConfig config, int reason) {
         return setAdaptivePolicyLocked(BatterySaverPolicy.Policy.fromConfig(config), reason);
     }
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
index ccd4e0f..8eb66cd 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
@@ -26,6 +26,7 @@
 import android.os.PowerManager;
 import android.os.PowerManager.ServiceType;
 import android.os.PowerSaveState;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -48,6 +49,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * Class to decide whether to turn on battery saver mode for specific services.
@@ -57,60 +59,81 @@
  *
  * Test: atest com.android.server.power.batterysaver.BatterySaverPolicyTest
  */
-public class BatterySaverPolicy extends ContentObserver {
+public class BatterySaverPolicy extends ContentObserver implements
+        DeviceConfig.OnPropertiesChangedListener {
     private static final String TAG = "BatterySaverPolicy";
 
     static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE.
 
-    private static final String KEY_GPS_MODE = "gps_mode";
-    private static final String KEY_VIBRATION_DISABLED = "vibration_disabled";
-    private static final String KEY_ANIMATION_DISABLED = "animation_disabled";
-    private static final String KEY_SOUNDTRIGGER_DISABLED = "soundtrigger_disabled";
+    @VisibleForTesting
+    static final String KEY_LOCATION_MODE = "location_mode";
+    @VisibleForTesting
+    static final String KEY_DISABLE_VIBRATION = "disable_vibration";
+    @VisibleForTesting
+    static final String KEY_DISABLE_ANIMATION = "disable_animation";
+    @VisibleForTesting
+    static final String KEY_DISABLE_SOUNDTRIGGER = "disable_soundtrigger";
 
     /**
-     * Disable turning on the network firewall when Battery Saver is turned on.
-     * If set to false, the firewall WILL be turned on when Battery Saver is turned on.
-     * If set to true, the firewall WILL NOT be turned on when Battery Saver is turned on.
+     * Turn on the network firewall when Battery Saver is turned on.
+     * If set to false, the firewall WILL NOT be turned on when Battery Saver is turned on.
+     * If set to true, the firewall WILL be turned on when Battery Saver is turned on.
      */
-    private static final String KEY_ACTIVATE_FIREWALL_DISABLED = "firewall_disabled";
+    @VisibleForTesting
+    static final String KEY_ENABLE_FIREWALL = "enable_firewall";
 
     /**
-     * Disable turning on the special low power screen brightness dimming when Battery Saver is
+     * Turn on the special low power screen brightness dimming when Battery Saver is
      * turned on.
-     * If set to false, the screen brightness dimming WILL be turned on by Battery Saver.
-     * If set to true, the screen brightness WILL NOT be turned on by Battery Saver.
+     * If set to false, the screen brightness dimming WILL NOT be turned on by Battery Saver.
+     * If set to true, the screen brightness WILL be turned on by Battery Saver.
      */
-    private static final String KEY_ADJUST_BRIGHTNESS_DISABLED = "adjust_brightness_disabled";
+    @VisibleForTesting
+    static final String KEY_ENABLE_BRIGHTNESS_ADJUSTMENT = "enable_brightness_adjustment";
 
     /**
-     * Disable turning on Data Saver when Battery Saver is turned on.
-     * If set to false, Data Saver WILL be turned on when Battery Saver is turned on.
-     * If set to true, Data Saver WILL NOT be turned on when Battery Saver is turned on.
+     * Turn on Data Saver when Battery Saver is turned on.
+     * If set to false, Data Saver WILL NOT be turned on when Battery Saver is turned on.
+     * If set to true, Data Saver WILL be turned on when Battery Saver is turned on.
      */
-    private static final String KEY_ACTIVATE_DATASAVER_DISABLED = "datasaver_disabled";
+    @VisibleForTesting
+    static final String KEY_ENABLE_DATASAVER = "enable_datasaver";
 
     /**
      * {@code true} if the Policy should advertise to the rest of the system that battery saver
      * is enabled. This advertising could cause other system components to change their
      * behavior. This will not affect other policy flags and what they change.
      */
-    private static final String KEY_ADVERTISE_IS_ENABLED = "advertise_is_enabled";
+    @VisibleForTesting
+    static final String KEY_ADVERTISE_IS_ENABLED = "advertise_is_enabled";
 
-    private static final String KEY_LAUNCH_BOOST_DISABLED = "launch_boost_disabled";
-    private static final String KEY_ADJUST_BRIGHTNESS_FACTOR = "adjust_brightness_factor";
-    private static final String KEY_FULLBACKUP_DEFERRED = "fullbackup_deferred";
-    private static final String KEY_KEYVALUE_DEFERRED = "keyvaluebackup_deferred";
-    private static final String KEY_FORCE_ALL_APPS_STANDBY = "force_all_apps_standby";
-    private static final String KEY_FORCE_BACKGROUND_CHECK = "force_background_check";
-    private static final String KEY_OPTIONAL_SENSORS_DISABLED = "optional_sensors_disabled";
-    private static final String KEY_AOD_DISABLED = "aod_disabled";
+    @VisibleForTesting
+    static final String KEY_DISABLE_LAUNCH_BOOST = "disable_launch_boost";
+    @VisibleForTesting
+    static final String KEY_ADJUST_BRIGHTNESS_FACTOR = "adjust_brightness_factor";
+    @VisibleForTesting
+    static final String KEY_DEFER_FULL_BACKUP = "defer_full_backup";
+    @VisibleForTesting
+    static final String KEY_DEFER_KEYVALUE_BACKUP = "defer_keyvalue_backup";
+    @VisibleForTesting
+    static final String KEY_FORCE_ALL_APPS_STANDBY = "force_all_apps_standby";
+    @VisibleForTesting
+    static final String KEY_FORCE_BACKGROUND_CHECK = "force_background_check";
+    @VisibleForTesting
+    static final String KEY_DISABLE_OPTIONAL_SENSORS = "disable_optional_sensors";
+    @VisibleForTesting
+    static final String KEY_DISABLE_AOD = "disable_aod";
     // Go into deep Doze as soon as the screen turns off.
-    private static final String KEY_QUICK_DOZE_ENABLED = "quick_doze_enabled";
-    private static final String KEY_ENABLE_NIGHT_MODE = "enable_night_mode";
+    @VisibleForTesting
+    static final String KEY_ENABLE_QUICK_DOZE = "enable_quick_doze";
+    @VisibleForTesting
+    static final String KEY_ENABLE_NIGHT_MODE = "enable_night_mode";
 
     private static final String KEY_CPU_FREQ_INTERACTIVE = "cpufreq-i";
     private static final String KEY_CPU_FREQ_NONINTERACTIVE = "cpufreq-n";
 
+    private static final String KEY_SUFFIX_ADAPTIVE = "_adaptive";
+
     @VisibleForTesting
     static final Policy OFF_POLICY = new Policy(
             1f,    /* adjustBrightnessFactor */
@@ -173,10 +196,7 @@
     private String mDeviceSpecificSettingsSource; // For dump() only.
 
     @GuardedBy("mLock")
-    private String mAdaptiveSettings;
-
-    @GuardedBy("mLock")
-    private String mAdaptiveDeviceSpecificSettings;
+    private DeviceConfig.Properties mLastDeviceConfigProperties;
 
     /**
      * A short string describing which battery saver is now enabled, which we dump in the eventlog.
@@ -261,10 +281,6 @@
                 Settings.Global.BATTERY_SAVER_CONSTANTS), false, this);
         mContentResolver.registerContentObserver(Settings.Global.getUriFor(
                 Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS), false, this);
-        mContentResolver.registerContentObserver(Settings.Global.getUriFor(
-                Settings.Global.BATTERY_SAVER_ADAPTIVE_CONSTANTS), false, this);
-        mContentResolver.registerContentObserver(Settings.Global.getUriFor(
-                Settings.Global.BATTERY_SAVER_ADAPTIVE_DEVICE_SPECIFIC_CONSTANTS), false, this);
 
         final AccessibilityManager acm = mContext.getSystemService(AccessibilityManager.class);
 
@@ -277,6 +293,10 @@
         mAutomotiveProjectionActive.initialize(
                 uiModeManager.getActiveProjectionTypes() != UiModeManager.PROJECTION_TYPE_NONE);
 
+        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_BATTERY_SAVER,
+                mContext.getMainExecutor(), this);
+        mLastDeviceConfigProperties =
+                DeviceConfig.getProperties(DeviceConfig.NAMESPACE_BATTERY_SAVER);
         onChange(true, null);
     }
 
@@ -305,7 +325,7 @@
 
     /**
      * Notifies listeners of a policy change on the handler thread only if the current policy level
-     * is not {@link POLICY_LEVEL_OFF}.
+     * is not {@link #POLICY_LEVEL_OFF}.
      */
     private void maybeNotifyListenersOfPolicyChange() {
         final BatterySaverPolicyListener[] listeners;
@@ -330,6 +350,55 @@
         refreshSettings();
     }
 
+    @Override
+    public void onPropertiesChanged(DeviceConfig.Properties properties) {
+        // Need to get all of the flags atomically.
+        mLastDeviceConfigProperties =
+                DeviceConfig.getProperties(DeviceConfig.NAMESPACE_BATTERY_SAVER);
+        Policy newAdaptivePolicy = null;
+        Policy newFullPolicy = null;
+
+        boolean changed = false;
+
+        synchronized (mLock) {
+            for (String name : properties.getKeyset()) {
+                if (name == null) {
+                    continue;
+                }
+                if (name.endsWith(KEY_SUFFIX_ADAPTIVE)) {
+                    if (newAdaptivePolicy == null) {
+                        newAdaptivePolicy = Policy.fromSettings("", "",
+                                mLastDeviceConfigProperties, KEY_SUFFIX_ADAPTIVE,
+                                DEFAULT_ADAPTIVE_POLICY);
+                    }
+                } else if (newFullPolicy == null) {
+                    newFullPolicy = Policy.fromSettings(mSettings, mDeviceSpecificSettings,
+                            mLastDeviceConfigProperties, null, DEFAULT_FULL_POLICY);
+                }
+            }
+
+            if (newFullPolicy != null && !mFullPolicy.equals(newFullPolicy)) {
+                mFullPolicy = newFullPolicy;
+                changed |= (mPolicyLevel == POLICY_LEVEL_FULL);
+            }
+
+            if (newAdaptivePolicy != null && !mAdaptivePolicy.equals(newAdaptivePolicy)) {
+                mDefaultAdaptivePolicy = newAdaptivePolicy;
+                // This will override any config set by an external source. This should be fine
+                // for now.
+                // TODO(119261320): make sure it doesn't override what's set externally
+                mAdaptivePolicy = mDefaultAdaptivePolicy;
+                changed |= (mPolicyLevel == POLICY_LEVEL_ADAPTIVE);
+            }
+
+            updatePolicyDependenciesLocked();
+        }
+
+        if (changed) {
+            maybeNotifyListenersOfPolicyChange();
+        }
+    }
+
     private void refreshSettings() {
         synchronized (mLock) {
             // Load the non-device-specific setting.
@@ -349,13 +418,7 @@
                 mDeviceSpecificSettingsSource = "(overlay)";
             }
 
-            final String adaptiveSetting =
-                    getGlobalSetting(Settings.Global.BATTERY_SAVER_ADAPTIVE_CONSTANTS);
-            final String adaptiveDeviceSpecificSetting = getGlobalSetting(
-                    Settings.Global.BATTERY_SAVER_ADAPTIVE_DEVICE_SPECIFIC_CONSTANTS);
-
-            if (!updateConstantsLocked(setting, deviceSpecificSetting,
-                    adaptiveSetting, adaptiveDeviceSpecificSetting)) {
+            if (!updateConstantsLocked(setting, deviceSpecificSetting)) {
                 // Nothing of note changed.
                 return;
             }
@@ -366,47 +429,34 @@
 
     @GuardedBy("mLock")
     @VisibleForTesting
-    void updateConstantsLocked(final String setting, final String deviceSpecificSetting) {
-        updateConstantsLocked(setting, deviceSpecificSetting, "", "");
-    }
-
     /** @return true if the currently active policy changed. */
-    private boolean updateConstantsLocked(String setting, String deviceSpecificSetting,
-            String adaptiveSetting, String adaptiveDeviceSpecificSetting) {
+    boolean updateConstantsLocked(String setting, String deviceSpecificSetting) {
         setting = TextUtils.emptyIfNull(setting);
         deviceSpecificSetting = TextUtils.emptyIfNull(deviceSpecificSetting);
-        adaptiveSetting = TextUtils.emptyIfNull(adaptiveSetting);
-        adaptiveDeviceSpecificSetting = TextUtils.emptyIfNull(adaptiveDeviceSpecificSetting);
 
         if (setting.equals(mSettings)
-                && deviceSpecificSetting.equals(mDeviceSpecificSettings)
-                && adaptiveSetting.equals(mAdaptiveSettings)
-                && adaptiveDeviceSpecificSetting.equals(mAdaptiveDeviceSpecificSettings)) {
+                && deviceSpecificSetting.equals(mDeviceSpecificSettings)) {
             return false;
         }
 
         mSettings = setting;
         mDeviceSpecificSettings = deviceSpecificSetting;
-        mAdaptiveSettings = adaptiveSetting;
-        mAdaptiveDeviceSpecificSettings = adaptiveDeviceSpecificSetting;
 
         if (DEBUG) {
             Slog.i(TAG, "mSettings=" + mSettings);
             Slog.i(TAG, "mDeviceSpecificSettings=" + mDeviceSpecificSettings);
-            Slog.i(TAG, "mAdaptiveSettings=" + mAdaptiveSettings);
-            Slog.i(TAG, "mAdaptiveDeviceSpecificSettings=" + mAdaptiveDeviceSpecificSettings);
         }
 
         boolean changed = false;
         Policy newFullPolicy = Policy.fromSettings(setting, deviceSpecificSetting,
-                DEFAULT_FULL_POLICY);
+                mLastDeviceConfigProperties, null, DEFAULT_FULL_POLICY);
         if (mPolicyLevel == POLICY_LEVEL_FULL && !mFullPolicy.equals(newFullPolicy)) {
             changed = true;
         }
         mFullPolicy = newFullPolicy;
 
-        mDefaultAdaptivePolicy = Policy.fromSettings(adaptiveSetting, adaptiveDeviceSpecificSetting,
-                DEFAULT_ADAPTIVE_POLICY);
+        mDefaultAdaptivePolicy = Policy.fromSettings("", "",
+                mLastDeviceConfigProperties, KEY_SUFFIX_ADAPTIVE, DEFAULT_ADAPTIVE_POLICY);
         if (mPolicyLevel == POLICY_LEVEL_ADAPTIVE
                 && !mAdaptivePolicy.equals(mDefaultAdaptivePolicy)) {
             changed = true;
@@ -509,7 +559,7 @@
          * {@code true} if full backup is deferred in battery saver mode.
          *
          * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-         * @see #KEY_FULLBACKUP_DEFERRED
+         * @see #KEY_DEFER_FULL_BACKUP
          */
         public final boolean deferFullBackup;
 
@@ -517,7 +567,7 @@
          * {@code true} if key value backup is deferred in battery saver mode.
          *
          * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-         * @see #KEY_KEYVALUE_DEFERRED
+         * @see #KEY_DEFER_KEYVALUE_BACKUP
          */
         public final boolean deferKeyValueBackup;
 
@@ -525,7 +575,7 @@
          * {@code true} if animation is disabled in battery saver mode.
          *
          * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-         * @see #KEY_ANIMATION_DISABLED
+         * @see #KEY_DISABLE_ANIMATION
          */
         public final boolean disableAnimation;
 
@@ -549,7 +599,7 @@
          * in battery saver mode.
          *
          * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-         * @see #KEY_SOUNDTRIGGER_DISABLED
+         * @see #KEY_DISABLE_SOUNDTRIGGER
          */
         public final boolean disableSoundTrigger;
 
@@ -557,7 +607,7 @@
          * {@code true} if vibration is disabled in battery saver mode.
          *
          * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-         * @see #KEY_VIBRATION_DISABLED
+         * @see #KEY_DISABLE_VIBRATION
          */
         public final boolean disableVibration;
 
@@ -566,7 +616,7 @@
          * mode.
          *
          * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-         * @see #KEY_ADJUST_BRIGHTNESS_DISABLED
+         * @see #KEY_ENABLE_BRIGHTNESS_ADJUSTMENT
          */
         public final boolean enableAdjustBrightness;
 
@@ -574,7 +624,7 @@
          * {@code true} if data saver should be turned on in battery saver mode.
          *
          * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-         * @see #KEY_ACTIVATE_DATASAVER_DISABLED
+         * @see #KEY_ENABLE_DATASAVER
          */
         public final boolean enableDataSaver;
 
@@ -582,7 +632,7 @@
          * {@code true} if network policy firewall should be turned on in battery saver mode.
          *
          * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-         * @see #KEY_ACTIVATE_FIREWALL_DISABLED
+         * @see #KEY_ENABLE_FIREWALL
          */
         public final boolean enableFirewall;
 
@@ -627,7 +677,7 @@
          * previously called gpsMode.
          *
          * @see Settings.Global#BATTERY_SAVER_CONSTANTS
-         * @see #KEY_GPS_MODE
+         * @see #KEY_LOCATION_MODE
          */
         public final int locationMode;
 
@@ -745,13 +795,17 @@
             );
         }
 
-        static Policy fromSettings(String settings, String deviceSpecificSettings) {
-            return fromSettings(settings, deviceSpecificSettings, OFF_POLICY);
+        @VisibleForTesting
+        static Policy fromSettings(String settings, String deviceSpecificSettings,
+                DeviceConfig.Properties properties, String configSuffix) {
+            return fromSettings(settings, deviceSpecificSettings, properties, configSuffix,
+                    OFF_POLICY);
         }
 
-        static Policy fromSettings(String settings, String deviceSpecificSettings,
-                Policy defaultPolicy) {
+        private static Policy fromSettings(String settings, String deviceSpecificSettings,
+                DeviceConfig.Properties properties, String configSuffix, Policy defaultPolicy) {
             final KeyValueListParser parser = new KeyValueListParser(',');
+            configSuffix = TextUtils.emptyIfNull(configSuffix);
 
             // Device-specific parameters.
             try {
@@ -771,40 +825,63 @@
                 Slog.wtf(TAG, "Bad battery saver constants: " + settings);
             }
 
-            float adjustBrightnessFactor = parser.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR,
-                    defaultPolicy.adjustBrightnessFactor);
-            boolean advertiseIsEnabled = parser.getBoolean(KEY_ADVERTISE_IS_ENABLED,
-                    defaultPolicy.advertiseIsEnabled);
-            boolean deferFullBackup = parser.getBoolean(KEY_FULLBACKUP_DEFERRED,
-                    defaultPolicy.deferFullBackup);
-            boolean deferKeyValueBackup = parser.getBoolean(KEY_KEYVALUE_DEFERRED,
-                    defaultPolicy.deferKeyValueBackup);
-            boolean disableAnimation = parser.getBoolean(KEY_ANIMATION_DISABLED,
-                    defaultPolicy.disableAnimation);
-            boolean disableAod = parser.getBoolean(KEY_AOD_DISABLED, defaultPolicy.disableAod);
-            boolean disableLaunchBoost = parser.getBoolean(KEY_LAUNCH_BOOST_DISABLED,
-                    defaultPolicy.disableLaunchBoost);
-            boolean disableOptionalSensors = parser.getBoolean(KEY_OPTIONAL_SENSORS_DISABLED,
-                    defaultPolicy.disableOptionalSensors);
-            boolean disableSoundTrigger = parser.getBoolean(KEY_SOUNDTRIGGER_DISABLED,
-                    defaultPolicy.disableSoundTrigger);
-            boolean disableVibrationConfig = parser.getBoolean(KEY_VIBRATION_DISABLED,
-                    defaultPolicy.disableVibration);
-            boolean enableAdjustBrightness = !parser.getBoolean(KEY_ADJUST_BRIGHTNESS_DISABLED,
-                    !defaultPolicy.enableAdjustBrightness);
-            boolean enableDataSaver = !parser.getBoolean(KEY_ACTIVATE_DATASAVER_DISABLED,
-                    !defaultPolicy.enableDataSaver);
-            boolean enableFirewall = !parser.getBoolean(KEY_ACTIVATE_FIREWALL_DISABLED,
-                    !defaultPolicy.enableFirewall);
-            boolean enableNightMode = parser.getBoolean(KEY_ENABLE_NIGHT_MODE,
-                    defaultPolicy.enableNightMode);
-            boolean enableQuickDoze = parser.getBoolean(KEY_QUICK_DOZE_ENABLED,
-                    defaultPolicy.enableQuickDoze);
-            boolean forceAllAppsStandby = parser.getBoolean(KEY_FORCE_ALL_APPS_STANDBY,
-                    defaultPolicy.forceAllAppsStandby);
-            boolean forceBackgroundCheck = parser.getBoolean(KEY_FORCE_BACKGROUND_CHECK,
-                    defaultPolicy.forceBackgroundCheck);
-            int locationMode = parser.getInt(KEY_GPS_MODE, defaultPolicy.locationMode);
+            // The Settings value overrides everything, since that will be set by the user.
+            // The DeviceConfig value takes second place, with the default as the last choice.
+            final float adjustBrightnessFactor = parser.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR,
+                    properties.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR + configSuffix,
+                            defaultPolicy.adjustBrightnessFactor));
+            final boolean advertiseIsEnabled = parser.getBoolean(KEY_ADVERTISE_IS_ENABLED,
+                    properties.getBoolean(KEY_ADVERTISE_IS_ENABLED + configSuffix,
+                            defaultPolicy.advertiseIsEnabled));
+            final boolean deferFullBackup = parser.getBoolean(KEY_DEFER_FULL_BACKUP,
+                    properties.getBoolean(KEY_DEFER_FULL_BACKUP + configSuffix,
+                            defaultPolicy.deferFullBackup));
+            final boolean deferKeyValueBackup = parser.getBoolean(KEY_DEFER_KEYVALUE_BACKUP,
+                    properties.getBoolean(KEY_DEFER_KEYVALUE_BACKUP + configSuffix,
+                            defaultPolicy.deferKeyValueBackup));
+            final boolean disableAnimation = parser.getBoolean(KEY_DISABLE_ANIMATION,
+                    properties.getBoolean(KEY_DISABLE_ANIMATION + configSuffix,
+                            defaultPolicy.disableAnimation));
+            final boolean disableAod = parser.getBoolean(KEY_DISABLE_AOD,
+                    properties.getBoolean(KEY_DISABLE_AOD + configSuffix,
+                            defaultPolicy.disableAod));
+            final boolean disableLaunchBoost = parser.getBoolean(KEY_DISABLE_LAUNCH_BOOST,
+                    properties.getBoolean(KEY_DISABLE_LAUNCH_BOOST + configSuffix,
+                            defaultPolicy.disableLaunchBoost));
+            final boolean disableOptionalSensors = parser.getBoolean(KEY_DISABLE_OPTIONAL_SENSORS,
+                    properties.getBoolean(KEY_DISABLE_OPTIONAL_SENSORS + configSuffix,
+                            defaultPolicy.disableOptionalSensors));
+            final boolean disableSoundTrigger = parser.getBoolean(KEY_DISABLE_SOUNDTRIGGER,
+                    properties.getBoolean(KEY_DISABLE_SOUNDTRIGGER + configSuffix,
+                            defaultPolicy.disableSoundTrigger));
+            final boolean disableVibrationConfig = parser.getBoolean(KEY_DISABLE_VIBRATION,
+                    properties.getBoolean(KEY_DISABLE_VIBRATION + configSuffix,
+                            defaultPolicy.disableVibration));
+            final boolean enableBrightnessAdjustment = parser.getBoolean(
+                    KEY_ENABLE_BRIGHTNESS_ADJUSTMENT,
+                    properties.getBoolean(KEY_ENABLE_BRIGHTNESS_ADJUSTMENT + configSuffix,
+                            defaultPolicy.enableAdjustBrightness));
+            final boolean enableDataSaver = parser.getBoolean(KEY_ENABLE_DATASAVER,
+                    properties.getBoolean(KEY_ENABLE_DATASAVER + configSuffix,
+                            defaultPolicy.enableDataSaver));
+            final boolean enableFirewall = parser.getBoolean(KEY_ENABLE_FIREWALL,
+                    properties.getBoolean(KEY_ENABLE_FIREWALL + configSuffix,
+                            defaultPolicy.enableFirewall));
+            final boolean enableNightMode = parser.getBoolean(KEY_ENABLE_NIGHT_MODE,
+                    properties.getBoolean(KEY_ENABLE_NIGHT_MODE + configSuffix,
+                            defaultPolicy.enableNightMode));
+            final boolean enableQuickDoze = parser.getBoolean(KEY_ENABLE_QUICK_DOZE,
+                    properties.getBoolean(KEY_ENABLE_QUICK_DOZE + configSuffix,
+                            defaultPolicy.enableQuickDoze));
+            final boolean forceAllAppsStandby = parser.getBoolean(KEY_FORCE_ALL_APPS_STANDBY,
+                    properties.getBoolean(KEY_FORCE_ALL_APPS_STANDBY + configSuffix,
+                            defaultPolicy.forceAllAppsStandby));
+            final boolean forceBackgroundCheck = parser.getBoolean(KEY_FORCE_BACKGROUND_CHECK,
+                    properties.getBoolean(KEY_FORCE_BACKGROUND_CHECK + configSuffix,
+                            defaultPolicy.forceBackgroundCheck));
+            final int locationMode = parser.getInt(KEY_LOCATION_MODE,
+                    properties.getInt(KEY_LOCATION_MODE + configSuffix,
+                            defaultPolicy.locationMode));
 
             return new Policy(
                     adjustBrightnessFactor,
@@ -818,7 +895,7 @@
                     disableSoundTrigger,
                     /* disableVibration */
                     disableVibrationConfig,
-                    enableAdjustBrightness,
+                    enableBrightnessAdjustment,
                     enableDataSaver,
                     enableFirewall,
                     enableNightMode,
@@ -1049,16 +1126,18 @@
             ipw.increaseIndent();
             ipw.println("value: " + mDeviceSpecificSettings);
             ipw.decreaseIndent();
-
-            ipw.println("Adaptive Settings: " + Settings.Global.BATTERY_SAVER_ADAPTIVE_CONSTANTS);
+            ipw.println("DeviceConfig: " + DeviceConfig.NAMESPACE_BATTERY_SAVER);
             ipw.increaseIndent();
-            ipw.println("value: " + mAdaptiveSettings);
-            ipw.decreaseIndent();
-            ipw.println("Adaptive Device Specific Settings: "
-                    + Settings.Global.BATTERY_SAVER_ADAPTIVE_DEVICE_SPECIFIC_CONSTANTS);
-            ipw.increaseIndent();
-            ipw.println("value: " + mAdaptiveDeviceSpecificSettings);
-            ipw.decreaseIndent();
+            final Set<String> keys = mLastDeviceConfigProperties.getKeyset();
+            if (keys.size() == 0) {
+                ipw.println("N/A");
+            } else {
+                for (final String key : keys) {
+                    ipw.print(key);
+                    ipw.print(": ");
+                    ipw.println(mLastDeviceConfigProperties.getString(key, null));
+                }
+            }
 
             ipw.println("mAccessibilityEnabled=" + mAccessibilityEnabled.get());
             ipw.println("mAutomotiveProjectionActive=" + mAutomotiveProjectionActive.get());
@@ -1078,22 +1157,22 @@
         pw.println("Policy '" + label + "'");
         pw.increaseIndent();
         pw.println(KEY_ADVERTISE_IS_ENABLED + "=" + p.advertiseIsEnabled);
-        pw.println(KEY_VIBRATION_DISABLED + "=" + p.disableVibration);
-        pw.println(KEY_ANIMATION_DISABLED + "=" + p.disableAnimation);
-        pw.println(KEY_FULLBACKUP_DEFERRED + "=" + p.deferFullBackup);
-        pw.println(KEY_KEYVALUE_DEFERRED + "=" + p.deferKeyValueBackup);
-        pw.println(KEY_ACTIVATE_FIREWALL_DISABLED + "=" + !p.enableFirewall);
-        pw.println(KEY_ACTIVATE_DATASAVER_DISABLED + "=" + !p.enableDataSaver);
-        pw.println(KEY_LAUNCH_BOOST_DISABLED + "=" + p.disableLaunchBoost);
-        pw.println(KEY_ADJUST_BRIGHTNESS_DISABLED + "=" + !p.enableAdjustBrightness);
+        pw.println(KEY_DISABLE_VIBRATION + "=" + p.disableVibration);
+        pw.println(KEY_DISABLE_ANIMATION + "=" + p.disableAnimation);
+        pw.println(KEY_DEFER_FULL_BACKUP + "=" + p.deferFullBackup);
+        pw.println(KEY_DEFER_KEYVALUE_BACKUP + "=" + p.deferKeyValueBackup);
+        pw.println(KEY_ENABLE_FIREWALL + "=" + p.enableFirewall);
+        pw.println(KEY_ENABLE_DATASAVER + "=" + p.enableDataSaver);
+        pw.println(KEY_DISABLE_LAUNCH_BOOST + "=" + p.disableLaunchBoost);
+        pw.println(KEY_ENABLE_BRIGHTNESS_ADJUSTMENT + "=" + p.enableAdjustBrightness);
         pw.println(KEY_ADJUST_BRIGHTNESS_FACTOR + "=" + p.adjustBrightnessFactor);
-        pw.println(KEY_GPS_MODE + "=" + p.locationMode);
+        pw.println(KEY_LOCATION_MODE + "=" + p.locationMode);
         pw.println(KEY_FORCE_ALL_APPS_STANDBY + "=" + p.forceAllAppsStandby);
         pw.println(KEY_FORCE_BACKGROUND_CHECK + "=" + p.forceBackgroundCheck);
-        pw.println(KEY_OPTIONAL_SENSORS_DISABLED + "=" + p.disableOptionalSensors);
-        pw.println(KEY_AOD_DISABLED + "=" + p.disableAod);
-        pw.println(KEY_SOUNDTRIGGER_DISABLED + "=" + p.disableSoundTrigger);
-        pw.println(KEY_QUICK_DOZE_ENABLED + "=" + p.enableQuickDoze);
+        pw.println(KEY_DISABLE_OPTIONAL_SENSORS + "=" + p.disableOptionalSensors);
+        pw.println(KEY_DISABLE_AOD + "=" + p.disableAod);
+        pw.println(KEY_DISABLE_SOUNDTRIGGER + "=" + p.disableSoundTrigger);
+        pw.println(KEY_ENABLE_QUICK_DOZE + "=" + p.enableQuickDoze);
         pw.println(KEY_ENABLE_NIGHT_MODE + "=" + p.enableNightMode);
 
         pw.println("Interactive File values:");
diff --git a/services/core/java/com/android/server/powerstats/OWNERS b/services/core/java/com/android/server/powerstats/OWNERS
new file mode 100644
index 0000000..d68066b
--- /dev/null
+++ b/services/core/java/com/android/server/powerstats/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/power/OWNERS
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index ab6ada2..eb15c80 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -71,7 +71,6 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.pm.UserManagerInternal;
-import com.android.server.pm.permission.PermissionManagerServiceInternal;
 
 import java.io.ByteArrayOutputStream;
 import java.io.FileDescriptor;
@@ -83,7 +82,6 @@
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
-import java.util.function.Consumer;
 
 /**
  * Service for role management.
@@ -162,12 +160,6 @@
 
         LocalServices.addService(RoleManagerInternal.class, new Internal());
 
-        PermissionManagerServiceInternal permissionManagerInternal =
-                LocalServices.getService(PermissionManagerServiceInternal.class);
-        permissionManagerInternal.setDefaultBrowserProvider(new DefaultBrowserProvider());
-        permissionManagerInternal.setDefaultDialerProvider(new DefaultDialerProvider());
-        permissionManagerInternal.setDefaultHomeProvider(new DefaultHomeProvider());
-
         registerUserRemovedReceiver();
     }
 
@@ -657,12 +649,78 @@
                     resultReceiver);
         }
 
+        @Nullable
         @Override
-        public String getDefaultSmsPackage(int userId) {
+        public String getBrowserRoleHolder(@UserIdInt int userId) {
+            final int callingUid = Binder.getCallingUid();
+            if (UserHandle.getUserId(callingUid) != userId) {
+                getContext().enforceCallingOrSelfPermission(
+                        android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
+            }
+            final PackageManagerInternal packageManager = LocalServices.getService(
+                    PackageManagerInternal.class);
+            if (packageManager.getInstantAppPackageName(callingUid) != null) {
+                return null;
+            }
+
             final long identity = Binder.clearCallingIdentity();
             try {
-                return CollectionUtils.firstOrNull(
-                        getRoleHoldersAsUser(RoleManager.ROLE_SMS, userId));
+                return CollectionUtils.firstOrNull(getRoleHoldersAsUser(RoleManager.ROLE_BROWSER,
+                        userId));
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public boolean setBrowserRoleHolder(@Nullable String packageName, @UserIdInt int userId) {
+            final Context context = getContext();
+            context.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
+            if (UserHandle.getCallingUserId() != userId) {
+                context.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
+            }
+
+            if (!mUserManagerInternal.exists(userId)) {
+                return false;
+            }
+
+            final AndroidFuture<Void> future = new AndroidFuture<>();
+            final RemoteCallback callback = new RemoteCallback(result -> {
+                boolean successful = result != null;
+                if (successful) {
+                    future.complete(null);
+                } else {
+                    future.completeExceptionally(new RuntimeException());
+                }
+            });
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                if (packageName != null) {
+                    addRoleHolderAsUser(RoleManager.ROLE_BROWSER, packageName, 0, userId, callback);
+                } else {
+                    clearRoleHoldersAsUser(RoleManager.ROLE_BROWSER, 0, userId, callback);
+                }
+                try {
+                    future.get(5, TimeUnit.SECONDS);
+                } catch (InterruptedException | ExecutionException | TimeoutException e) {
+                    Slog.e(LOG_TAG, "Exception while setting default browser: " + packageName, e);
+                    return false;
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+
+            return true;
+        }
+
+        @Override
+        public String getSmsRoleHolder(int userId) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                return CollectionUtils.firstOrNull(getRoleHoldersAsUser(RoleManager.ROLE_SMS,
+                        userId));
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -718,100 +776,4 @@
             return getOrCreateUserState(userId).getRolesAndHolders();
         }
     }
-
-    private class DefaultBrowserProvider implements
-            PermissionManagerServiceInternal.DefaultBrowserProvider {
-
-        @Nullable
-        @Override
-        public String getDefaultBrowser(@UserIdInt int userId) {
-            return CollectionUtils.firstOrNull(getOrCreateUserState(userId).getRoleHolders(
-                    RoleManager.ROLE_BROWSER));
-        }
-
-        @Override
-        public boolean setDefaultBrowser(@Nullable String packageName, @UserIdInt int userId) {
-            AndroidFuture<Void> future = new AndroidFuture<>();
-            RemoteCallback callback = new RemoteCallback(result -> {
-                boolean successful = result != null;
-                if (successful) {
-                    future.complete(null);
-                } else {
-                    future.completeExceptionally(new RuntimeException());
-                }
-            });
-            if (packageName != null) {
-                getOrCreateController(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER,
-                        packageName, 0, callback);
-            } else {
-                getOrCreateController(userId).onClearRoleHolders(RoleManager.ROLE_BROWSER, 0,
-                        callback);
-            }
-            try {
-                future.get(5, TimeUnit.SECONDS);
-                return true;
-            } catch (InterruptedException | ExecutionException | TimeoutException e) {
-                Slog.e(LOG_TAG, "Exception while setting default browser: " + packageName, e);
-                return false;
-            }
-        }
-
-        @Override
-        public void setDefaultBrowserAsync(@Nullable String packageName, @UserIdInt int userId) {
-            RemoteCallback callback = new RemoteCallback(result -> {
-                boolean successful = result != null;
-                if (!successful) {
-                    Slog.e(LOG_TAG, "Failed to set default browser: " + packageName);
-                }
-            });
-            if (packageName != null) {
-                getOrCreateController(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER,
-                        packageName, 0, callback);
-            } else {
-                getOrCreateController(userId).onClearRoleHolders(RoleManager.ROLE_BROWSER, 0,
-                        callback);
-            }
-        }
-    }
-
-    private class DefaultDialerProvider implements
-            PermissionManagerServiceInternal.DefaultDialerProvider {
-
-        @Nullable
-        @Override
-        public String getDefaultDialer(@UserIdInt int userId) {
-            return CollectionUtils.firstOrNull(getOrCreateUserState(userId).getRoleHolders(
-                    RoleManager.ROLE_DIALER));
-        }
-    }
-
-    private class DefaultHomeProvider implements
-            PermissionManagerServiceInternal.DefaultHomeProvider {
-
-        @Nullable
-        @Override
-        public String getDefaultHome(@UserIdInt int userId) {
-            return CollectionUtils.firstOrNull(getOrCreateUserState(userId).getRoleHolders(
-                    RoleManager.ROLE_HOME));
-        }
-
-        @Override
-        public void setDefaultHomeAsync(@Nullable String packageName, @UserIdInt int userId,
-                @NonNull Consumer<Boolean> callback) {
-            RemoteCallback remoteCallback = new RemoteCallback(result -> {
-                boolean successful = result != null;
-                if (!successful) {
-                    Slog.e(LOG_TAG, "Failed to set default home: " + packageName);
-                }
-                callback.accept(successful);
-            });
-            if (packageName != null) {
-                getOrCreateController(userId).onAddRoleHolder(RoleManager.ROLE_HOME,
-                        packageName, 0, remoteCallback);
-            } else {
-                getOrCreateController(userId).onClearRoleHolders(RoleManager.ROLE_HOME, 0,
-                        remoteCallback);
-            }
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/rollback/OWNERS b/services/core/java/com/android/server/rollback/OWNERS
new file mode 100644
index 0000000..7feb85f
--- /dev/null
+++ b/services/core/java/com/android/server/rollback/OWNERS
@@ -0,0 +1 @@
+olilan@google.com
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index 63ed416..d9b6702 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -581,9 +581,18 @@
                             ParcelFileDescriptor.MODE_READ_ONLY)) {
                         final long token = Binder.clearCallingIdentity();
                         try {
-                            session.write(packageCodePath.getName(), 0,
-                                    packageCodePath.length(),
-                                    fd);
+                            boolean fallbackToCopy = false;
+                            try {
+                                // Populate apk/apex files using hard links to avoid copy
+                                session.stageViaHardLink(packageCodePath.getAbsolutePath());
+                            } catch (Exception ignore) {
+                                fallbackToCopy = true;
+                            }
+                            if (fallbackToCopy) {
+                                session.write(packageCodePath.getName(), 0,
+                                        packageCodePath.length(),
+                                        fd);
+                            }
                         } finally {
                             Binder.restoreCallingIdentity(token);
                         }
diff --git a/services/core/java/com/android/server/slice/OWNERS b/services/core/java/com/android/server/slice/OWNERS
new file mode 100644
index 0000000..3d0859f
--- /dev/null
+++ b/services/core/java/com/android/server/slice/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/app/slice/OWNERS
diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java
index ee9694f..ee0e5ba 100644
--- a/services/core/java/com/android/server/slice/SliceManagerService.java
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -256,11 +256,6 @@
                 }
             }
         }
-        // Fallback to allowing uri permissions through.
-        if (mContext.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
-                == PERMISSION_GRANTED) {
-            return PackageManager.PERMISSION_GRANTED;
-        }
         return PackageManager.PERMISSION_DENIED;
     }
 
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 d3b1ac6..cf20cf4 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -502,6 +502,8 @@
                         synchronized (mProcessSystemIonHeapSizeLock) {
                             return pullProcessSystemIonHeapSizeLocked(atomTag, data);
                         }
+                    case FrameworkStatsLog.SYSTEM_MEMORY:
+                        return pullSystemMemory(atomTag, data);
                     case FrameworkStatsLog.TEMPERATURE:
                         synchronized (mTemperatureLock) {
                             return pullTemperatureLocked(atomTag, data);
@@ -796,6 +798,7 @@
         registerSystemIonHeapSize();
         registerIonHeapSize();
         registerProcessSystemIonHeapSize();
+        registerSystemMemory();
         registerTemperature();
         registerCoolingDevice();
         registerBinderCallsStats();
@@ -1913,6 +1916,30 @@
         return StatsManager.PULL_SUCCESS;
     }
 
+    private void registerSystemMemory() {
+        int tagId = FrameworkStatsLog.SYSTEM_MEMORY;
+        mStatsManager.setPullAtomCallback(
+                tagId,
+                null, // use default PullAtomMetadata values
+                DIRECT_EXECUTOR,
+                mStatsCallbackImpl
+        );
+    }
+
+    int pullSystemMemory(int atomTag, List<StatsEvent> pulledData) {
+        SystemMemoryUtil.Metrics metrics = SystemMemoryUtil.getMetrics();
+        pulledData.add(
+                FrameworkStatsLog.buildStatsEvent(
+                        atomTag,
+                        metrics.unreclaimableSlabKb,
+                        metrics.vmallocUsedKb,
+                        metrics.pageTablesKb,
+                        metrics.kernelStackKb,
+                        metrics.totalIonKb,
+                        metrics.unaccountedKb));
+        return StatsManager.PULL_SUCCESS;
+    }
+
     private void registerTemperature() {
         int tagId = FrameworkStatsLog.TEMPERATURE;
         mStatsManager.setPullAtomCallback(
diff --git a/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java b/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java
new file mode 100644
index 0000000..99fc7c1
--- /dev/null
+++ b/services/core/java/com/android/server/stats/pull/SystemMemoryUtil.java
@@ -0,0 +1,77 @@
+/*
+ * 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.stats.pull;
+
+import android.os.Debug;
+
+/**
+ * Snapshots system-wide memory stats and computes unaccounted memory.
+ * Thread-safe.
+ */
+final class SystemMemoryUtil {
+    private SystemMemoryUtil() {}
+
+    static Metrics getMetrics() {
+        int totalIonKb = (int) Debug.getIonHeapsSizeKb();
+
+        long[] mInfos = new long[Debug.MEMINFO_COUNT];
+        Debug.getMemInfo(mInfos);
+
+        long kReclaimableKb = mInfos[Debug.MEMINFO_KRECLAIMABLE];
+        // Note: MEMINFO_KRECLAIMABLE includes MEMINFO_SLAB_RECLAIMABLE and ION pools.
+        // Fall back to using MEMINFO_SLAB_RECLAIMABLE in case of older kernels that do
+        // not include KReclaimable meminfo field.
+        if (kReclaimableKb == 0) {
+            kReclaimableKb = mInfos[Debug.MEMINFO_SLAB_RECLAIMABLE];
+        }
+
+        long accountedKb = mInfos[Debug.MEMINFO_FREE]
+                + mInfos[Debug.MEMINFO_ZRAM_TOTAL]
+                + mInfos[Debug.MEMINFO_BUFFERS]
+                + mInfos[Debug.MEMINFO_ACTIVE]
+                + mInfos[Debug.MEMINFO_INACTIVE]
+                + mInfos[Debug.MEMINFO_UNEVICTABLE]
+                + mInfos[Debug.MEMINFO_SLAB_UNRECLAIMABLE]
+                + kReclaimableKb
+                + mInfos[Debug.MEMINFO_VM_ALLOC_USED]
+                + mInfos[Debug.MEMINFO_PAGE_TABLES]
+                + Math.max(totalIonKb, 0);
+
+        if (!Debug.isVmapStack()) {
+            // See b/146088882
+            accountedKb += mInfos[Debug.MEMINFO_KERNEL_STACK];
+        }
+
+        Metrics result = new Metrics();
+        result.unreclaimableSlabKb = (int) mInfos[Debug.MEMINFO_SLAB_UNRECLAIMABLE];
+        result.vmallocUsedKb = (int) mInfos[Debug.MEMINFO_VM_ALLOC_USED];
+        result.pageTablesKb = (int) mInfos[Debug.MEMINFO_PAGE_TABLES];
+        result.kernelStackKb = (int) mInfos[Debug.MEMINFO_KERNEL_STACK];
+        result.totalIonKb = totalIonKb;
+        result.unaccountedKb = (int) (mInfos[Debug.MEMINFO_TOTAL] - accountedKb);
+        return result;
+    }
+
+    static final class Metrics {
+        public int unreclaimableSlabKb;
+        public int vmallocUsedKb;
+        public int pageTablesKb;
+        public int kernelStackKb;
+        public int totalIonKb;
+        public int unaccountedKb;
+    }
+}
diff --git a/services/core/java/com/android/server/statusbar/OWNERS b/services/core/java/com/android/server/statusbar/OWNERS
new file mode 100644
index 0000000..2e96c97
--- /dev/null
+++ b/services/core/java/com/android/server/statusbar/OWNERS
@@ -0,0 +1 @@
+include /packages/SystemUI/OWNERS
diff --git a/services/core/java/com/android/server/storage/OWNERS b/services/core/java/com/android/server/storage/OWNERS
new file mode 100644
index 0000000..6f9dbea
--- /dev/null
+++ b/services/core/java/com/android/server/storage/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/os/storage/OWNERS
diff --git a/services/core/java/com/android/server/telecom/TelecomLoaderService.java b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
index 52ad893..f0c96e1 100644
--- a/services/core/java/com/android/server/telecom/TelecomLoaderService.java
+++ b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
@@ -42,7 +42,7 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.pm.UserManagerService;
-import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.permission.LegacyPermissionManagerInternal;
 
 /**
  * Starts the telecom component by binding to its ITelecomService implementation. Telecom is setup
@@ -65,8 +65,8 @@
                 ServiceManager.addService(Context.TELECOM_SERVICE, telecomService.asBinder());
 
                 synchronized (mLock) {
-                    final PermissionManagerServiceInternal permissionManager =
-                            LocalServices.getService(PermissionManagerServiceInternal.class);
+                    final LegacyPermissionManagerInternal permissionManager =
+                            LocalServices.getService(LegacyPermissionManagerInternal.class);
                     if (mDefaultSimCallManagerRequests != null) {
                         if (mDefaultSimCallManagerRequests != null) {
                             TelecomManager telecomManager =
@@ -165,8 +165,8 @@
 
 
     private void registerDefaultAppProviders() {
-        final PermissionManagerServiceInternal permissionManager =
-                LocalServices.getService(PermissionManagerServiceInternal.class);
+        final LegacyPermissionManagerInternal permissionManager =
+                LocalServices.getService(LegacyPermissionManagerInternal.class);
 
         // Set a callback for the permission grant policy to query the default sms app.
         permissionManager.setSmsAppPackagesProvider(userId -> {
@@ -244,15 +244,16 @@
     }
 
     private void updateSimCallManagerPermissions(int userId) {
-        final PermissionManagerServiceInternal permissionManager =
-                LocalServices.getService(PermissionManagerServiceInternal.class);
+        final LegacyPermissionManagerInternal permissionManager =
+                LocalServices.getService(LegacyPermissionManagerInternal.class);
         TelecomManager telecomManager =
             (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
         PhoneAccountHandle phoneAccount = telecomManager.getSimCallManager(userId);
         if (phoneAccount != null) {
             Slog.i(TAG, "updating sim call manager permissions for userId:" + userId);
             String packageName = phoneAccount.getComponentName().getPackageName();
-            permissionManager.grantDefaultPermissionsToDefaultSimCallManager(packageName, userId);
+            permissionManager.grantDefaultPermissionsToDefaultSimCallManager(packageName,
+                    userId);
         }
     }
 }
diff --git a/services/core/java/com/android/server/textclassifier/OWNERS b/services/core/java/com/android/server/textclassifier/OWNERS
new file mode 100644
index 0000000..46b3cb8
--- /dev/null
+++ b/services/core/java/com/android/server/textclassifier/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/textclassifier/OWNERS
diff --git a/services/core/java/com/android/server/timedetector/OWNERS b/services/core/java/com/android/server/timedetector/OWNERS
new file mode 100644
index 0000000..09447a9
--- /dev/null
+++ b/services/core/java/com/android/server/timedetector/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/app/timezone/OWNERS
diff --git a/services/core/java/com/android/server/timezone/OWNERS b/services/core/java/com/android/server/timezone/OWNERS
new file mode 100644
index 0000000..09447a9
--- /dev/null
+++ b/services/core/java/com/android/server/timezone/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/app/timezone/OWNERS
diff --git a/services/core/java/com/android/server/timezonedetector/GeolocationTimeZoneSuggestion.java b/services/core/java/com/android/server/timezonedetector/GeolocationTimeZoneSuggestion.java
index 118899a..1867ee2 100644
--- a/services/core/java/com/android/server/timezonedetector/GeolocationTimeZoneSuggestion.java
+++ b/services/core/java/com/android/server/timezonedetector/GeolocationTimeZoneSuggestion.java
@@ -61,7 +61,7 @@
  */
 public final class GeolocationTimeZoneSuggestion {
 
-    @NonNull private final List<String> mZoneIds;
+    @Nullable private final List<String> mZoneIds;
     @Nullable private ArrayList<String> mDebugInfo;
 
     public GeolocationTimeZoneSuggestion(@Nullable List<String> zoneIds) {
diff --git a/services/core/java/com/android/server/timezonedetector/OWNERS b/services/core/java/com/android/server/timezonedetector/OWNERS
new file mode 100644
index 0000000..09447a9
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/app/timezone/OWNERS
diff --git a/services/core/java/com/android/server/trust/OWNERS b/services/core/java/com/android/server/trust/OWNERS
new file mode 100644
index 0000000..b039c4b
--- /dev/null
+++ b/services/core/java/com/android/server/trust/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/app/trust/OWNERS
diff --git a/services/core/java/com/android/server/tv/OWNERS b/services/core/java/com/android/server/tv/OWNERS
new file mode 100644
index 0000000..305027c
--- /dev/null
+++ b/services/core/java/com/android/server/tv/OWNERS
@@ -0,0 +1 @@
+include /media/java/android/media/tv/OWNERS
diff --git a/services/core/java/com/android/server/tv/PersistentDataStore.java b/services/core/java/com/android/server/tv/PersistentDataStore.java
index d3c9b3b..72556a7 100644
--- a/services/core/java/com/android/server/tv/PersistentDataStore.java
+++ b/services/core/java/com/android/server/tv/PersistentDataStore.java
@@ -30,23 +30,17 @@
 import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
-import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
 
 import libcore.io.IoUtils;
 
-import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -246,12 +240,7 @@
             if (parser.getName().equals(TAG_BLOCKED_RATINGS)) {
                 loadBlockedRatingsFromXml(parser);
             } else if (parser.getName().equals(TAG_PARENTAL_CONTROLS)) {
-                String enabled = parser.getAttributeValue(null, ATTR_ENABLED);
-                if (TextUtils.isEmpty(enabled)) {
-                    throw new XmlPullParserException(
-                            "Missing " + ATTR_ENABLED + " attribute on " + TAG_PARENTAL_CONTROLS);
-                }
-                mParentalControlsEnabled = Boolean.parseBoolean(enabled);
+                mParentalControlsEnabled = parser.getAttributeBoolean(null, ATTR_ENABLED);
             }
         }
     }
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 608012e..1754e59 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -84,6 +84,7 @@
 import android.view.Surface;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.DumpUtils;
@@ -1442,8 +1443,8 @@
                 if (sessionState != null) {
                     int state = surface == null
                             ?
-                            FrameworkStatsLog.TIF_TUNE_STATE_CHANGED__STATE__SURFACE_ATTACHED
-                            : FrameworkStatsLog.TIF_TUNE_STATE_CHANGED__STATE__SURFACE_DETACHED;
+                            FrameworkStatsLog.TIF_TUNE_STATE_CHANGED__STATE__SURFACE_DETACHED
+                            : FrameworkStatsLog.TIF_TUNE_STATE_CHANGED__STATE__SURFACE_ATTACHED;
                     logTuneStateChanged(state, sessionState,
                             TvInputManagerService.getTvInputState(sessionState, userState));
                 }
@@ -2972,15 +2973,7 @@
                         getUserStateLocked(mCurrentUserId));
                 try {
                     mSessionState.client.onVideoUnavailable(reason, mSessionState.seq);
-                    int loggedReason = reason + FrameworkStatsLog
-                            .TIF_TUNE_STATE_CHANGED__STATE__VIDEO_UNAVAILABLE_REASON_UNKNOWN;
-                    if (loggedReason < FrameworkStatsLog
-                            .TIF_TUNE_STATE_CHANGED__STATE__VIDEO_UNAVAILABLE_REASON_UNKNOWN
-                            || loggedReason > FrameworkStatsLog
-                            .TIF_TUNE_STATE_CHANGED__STATE__VIDEO_UNAVAILABLE_REASON_CAS_UNKNOWN) {
-                        loggedReason = FrameworkStatsLog
-                                .TIF_TUNE_STATE_CHANGED__STATE__VIDEO_UNAVAILABLE_REASON_UNKNOWN;
-                    }
+                    int loggedReason = getVideoUnavailableReasonForStatsd(reason);
                     logTuneStateChanged(loggedReason, mSessionState, tvInputState);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "error in onVideoUnavailable", e);
@@ -3167,6 +3160,21 @@
         }
     }
 
+    @VisibleForTesting
+    static int getVideoUnavailableReasonForStatsd(
+            @TvInputManager.VideoUnavailableReason int reason) {
+        int loggedReason = reason + FrameworkStatsLog
+                .TIF_TUNE_STATE_CHANGED__STATE__VIDEO_UNAVAILABLE_REASON_UNKNOWN;
+        if (loggedReason < FrameworkStatsLog
+                .TIF_TUNE_STATE_CHANGED__STATE__VIDEO_UNAVAILABLE_REASON_UNKNOWN
+                || loggedReason > FrameworkStatsLog
+                .TIF_TUNE_STATE_CHANGED__STATE__VIDEO_UNAVAILABLE_REASON_CAS_UNKNOWN) {
+            loggedReason = FrameworkStatsLog
+                    .TIF_TUNE_STATE_CHANGED__STATE__VIDEO_UNAVAILABLE_REASON_UNKNOWN;
+        }
+        return loggedReason;
+    }
+
     private UserState getUserStateLocked(int userId) {
         return mUserStates.get(userId);
     }
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java b/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java
index beb11ed..7f49eea 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java
@@ -192,8 +192,9 @@
         }
     }
 
-    private int readAttributeToInt(String attributeName, TypedXmlPullParser parser) {
-        return Integer.valueOf(parser.getAttributeValue(null, attributeName));
+    private int readAttributeToInt(String attributeName, TypedXmlPullParser parser)
+            throws XmlPullParserException {
+        return parser.getAttributeInt(null, attributeName);
     }
 
     private void addNewUseCasePriority(int useCase, int fgPriority, int bgPriority) {
diff --git a/services/core/java/com/android/server/uri/OWNERS b/services/core/java/com/android/server/uri/OWNERS
new file mode 100644
index 0000000..cdc07ed
--- /dev/null
+++ b/services/core/java/com/android/server/uri/OWNERS
@@ -0,0 +1,3 @@
+jsharkey@android.com
+jsharkey@google.com
+varunshah@google.com
diff --git a/services/core/java/com/android/server/utils/quota/MultiRateLimiter.java b/services/core/java/com/android/server/utils/quota/MultiRateLimiter.java
new file mode 100644
index 0000000..fdbe4b4
--- /dev/null
+++ b/services/core/java/com/android/server/utils/quota/MultiRateLimiter.java
@@ -0,0 +1,183 @@
+/*
+ * 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.utils.quota;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Can be used to rate limit events per app based on multiple rates at the same time. For example,
+ * it can limit an event to happen only:
+ *
+ * <li>5 times in 20 seconds</li>
+ * and
+ * <li>6 times in 40 seconds</li>
+ * and
+ * <li>10 times in 1 hour</li>
+ *
+ * <p><br>
+ * All listed rates apply at the same time, and the UPTC will be out of quota if it doesn't satisfy
+ * all the given rates. The underlying mechanism used is
+ * {@link com.android.server.utils.quota.CountQuotaTracker}, so all its conditions apply, as well
+ * as an additional constraint: all the user-package-tag combinations (UPTC) are considered to be in
+ * the same {@link com.android.server.utils.quota.Category}.
+ * </p>
+ *
+ * @hide
+ */
+public class MultiRateLimiter {
+
+    private static final CountQuotaTracker[] EMPTY_TRACKER_ARRAY = {};
+
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
+    private final CountQuotaTracker[] mQuotaTrackers;
+
+    private MultiRateLimiter(List<CountQuotaTracker> quotaTrackers) {
+        mQuotaTrackers = quotaTrackers.toArray(EMPTY_TRACKER_ARRAY);
+    }
+
+    /** Record that an event happened and count it towards the given quota. */
+    public void noteEvent(int userId, @NonNull String packageName, @Nullable String tag) {
+        synchronized (mLock) {
+            noteEventLocked(userId, packageName, tag);
+        }
+    }
+
+    /** Check whether the given UPTC is allowed to trigger an event. */
+    public boolean isWithinQuota(int userId, @NonNull String packageName, @Nullable String tag) {
+        synchronized (mLock) {
+            return isWithinQuotaLocked(userId, packageName, tag);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void noteEventLocked(int userId, @NonNull String packageName, @Nullable String tag) {
+        for (CountQuotaTracker quotaTracker : mQuotaTrackers) {
+            quotaTracker.noteEvent(userId, packageName, tag);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private boolean isWithinQuotaLocked(int userId, @NonNull String packageName,
+            @Nullable String tag) {
+        for (CountQuotaTracker quotaTracker : mQuotaTrackers) {
+            if (!quotaTracker.isWithinQuota(userId, packageName, tag)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /** Can create a new {@link MultiRateLimiter}. */
+    public static class Builder {
+
+        private final List<CountQuotaTracker> mQuotaTrackers;
+        private final Context mContext;
+        private final Categorizer mCategorizer;
+        private final Category mCategory;
+        @Nullable private final QuotaTracker.Injector mInjector;
+
+        /**
+         * Creates a new builder and allows to inject an object that can be used
+         * to manipulate elapsed time in tests.
+         */
+        @VisibleForTesting
+        Builder(Context context, QuotaTracker.Injector injector) {
+            this.mQuotaTrackers = new ArrayList<>();
+            this.mContext = context;
+            this.mInjector = injector;
+            this.mCategorizer = Categorizer.SINGLE_CATEGORIZER;
+            this.mCategory = Category.SINGLE_CATEGORY;
+        }
+
+        /** Creates a new builder for {@link MultiRateLimiter}. */
+        public Builder(Context context) {
+            this(context, null);
+        }
+
+        /**
+         * Adds another rate limit to be used in {@link MultiRateLimiter}.
+         *
+         * @param limit The maximum event count an app can have in the rolling time window.
+         * @param windowSize The rolling time window to use when checking quota usage.
+         */
+        public Builder addRateLimit(int limit, Duration windowSize) {
+            CountQuotaTracker countQuotaTracker;
+            if (mInjector != null) {
+                countQuotaTracker = new CountQuotaTracker(mContext, mCategorizer, mInjector);
+            } else {
+                countQuotaTracker = new CountQuotaTracker(mContext, mCategorizer);
+            }
+            countQuotaTracker.setCountLimit(mCategory, limit, windowSize.toMillis());
+            mQuotaTrackers.add(countQuotaTracker);
+            return this;
+        }
+
+        /** Adds another rate limit to be used in {@link MultiRateLimiter}. */
+        public Builder addRateLimit(@NonNull RateLimit rateLimit) {
+            return addRateLimit(rateLimit.mLimit, rateLimit.mWindowSize);
+        }
+
+        /** Adds all given rate limits that will be used in {@link MultiRateLimiter}. */
+        public Builder addRateLimits(@NonNull RateLimit[] rateLimits) {
+            for (RateLimit rateLimit : rateLimits) {
+                addRateLimit(rateLimit);
+            }
+            return this;
+        }
+
+        /**
+         * Return a new {@link com.android.server.utils.quota.MultiRateLimiter} using set rate
+         * limit.
+         */
+        public MultiRateLimiter build() {
+            return new MultiRateLimiter(mQuotaTrackers);
+        }
+    }
+
+    /** Helper class that describes a rate limit. */
+    public static class RateLimit {
+        public final int mLimit;
+        public final Duration mWindowSize;
+
+        /**
+         * @param limit The maximum count of some occurrence in the rolling time window.
+         * @param windowSize The rolling time window to use when checking quota usage.
+         */
+        private RateLimit(int limit, Duration windowSize) {
+            this.mLimit = limit;
+            this.mWindowSize = windowSize;
+        }
+
+        /**
+         * @param limit The maximum count of some occurrence in the rolling time window.
+         * @param windowSize The rolling time window to use when checking quota usage.
+         */
+        public static RateLimit create(int limit, Duration windowSize) {
+            return new RateLimit(limit, windowSize);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/vibrator/OWNERS b/services/core/java/com/android/server/vibrator/OWNERS
new file mode 100644
index 0000000..7e7335d
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/OWNERS
@@ -0,0 +1 @@
+michaelwr@google.com
diff --git a/services/core/java/com/android/server/wallpaper/OWNERS b/services/core/java/com/android/server/wallpaper/OWNERS
new file mode 100644
index 0000000..8ff0f74
--- /dev/null
+++ b/services/core/java/com/android/server/wallpaper/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/wallpaper/OWNERS
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index c3d5874..3198453 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2984,7 +2984,7 @@
         }
 
         if (wallpaper.allowBackup) {
-            out.attribute(null, "backup", "true");
+            out.attributeBoolean(null, "backup", true);
         }
 
         out.endTag(null, tag);
@@ -3249,7 +3249,7 @@
             wallpaper.primaryColors = new WallpaperColors(primary, secondary, tertiary, colorHints);
         }
         wallpaper.name = parser.getAttributeValue(null, "name");
-        wallpaper.allowBackup = "true".equals(parser.getAttributeValue(null, "backup"));
+        wallpaper.allowBackup = parser.getAttributeBoolean(null, "backup", false);
     }
 
     // Called by SystemBackupAgent after files are restored to disk.
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
new file mode 100644
index 0000000..9f1152c
--- /dev/null
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -0,0 +1,1046 @@
+/*
+ * 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.wm;
+
+import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+import static android.service.voice.VoiceInteractionSession.SHOW_SOURCE_APPLICATION;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IMMERSIVE;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
+import static com.android.server.wm.ActivityTaskManagerService.TAG_SWITCH;
+import static com.android.server.wm.ActivityTaskManagerService.enforceNotIsolatedCaller;
+import static com.android.server.wm.Task.ActivityState.DESTROYED;
+import static com.android.server.wm.Task.ActivityState.DESTROYING;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.ActivityTaskManager;
+import android.app.IActivityClientController;
+import android.app.PictureInPictureParams;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.PersistableBundle;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.service.voice.VoiceInteractionManagerInternal;
+import android.util.Slog;
+import android.view.RemoteAnimationDefinition;
+
+import com.android.internal.app.AssistUtils;
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.server.LocalServices;
+import com.android.server.Watchdog;
+import com.android.server.uri.NeededUriGrants;
+import com.android.server.vr.VrManagerInternal;
+
+import java.util.Arrays;
+
+/**
+ * Server side implementation for the client activity to interact with system.
+ *
+ * @see android.app.ActivityClient
+ */
+class ActivityClientController extends IActivityClientController.Stub {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityClientController" : TAG_ATM;
+    private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
+
+    private final ActivityTaskManagerService mService;
+    private final WindowManagerGlobalLock mGlobalLock;
+    private final ActivityTaskSupervisor mTaskSupervisor;
+    private final Context mContext;
+
+    /** Wrapper around VoiceInteractionServiceManager. */
+    private AssistUtils mAssistUtils;
+
+    ActivityClientController(ActivityTaskManagerService service) {
+        mService = service;
+        mGlobalLock = service.mGlobalLock;
+        mTaskSupervisor = service.mTaskSupervisor;
+        mContext = service.mContext;
+    }
+
+    void onSystemReady() {
+        mAssistUtils = new AssistUtils(mContext);
+    }
+
+    @Override
+    public void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityIdle");
+                final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+                if (r == null) {
+                    return;
+                }
+                mTaskSupervisor.activityIdleInternal(r, false /* fromTimeout */,
+                        false /* processPausingActivities */, config);
+                if (stopProfiling && r.hasProcess()) {
+                    r.app.clearProfilerIfNeeded();
+                }
+            }
+        } finally {
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
+    public void activityResumed(IBinder token) {
+        final long origId = Binder.clearCallingIdentity();
+        synchronized (mGlobalLock) {
+            ActivityRecord.activityResumedLocked(token);
+        }
+        Binder.restoreCallingIdentity(origId);
+    }
+
+    @Override
+    public void activityTopResumedStateLost() {
+        final long origId = Binder.clearCallingIdentity();
+        synchronized (mGlobalLock) {
+            mTaskSupervisor.handleTopResumedStateReleased(false /* timeout */);
+        }
+        Binder.restoreCallingIdentity(origId);
+    }
+
+    @Override
+    public void activityPaused(IBinder token) {
+        final long origId = Binder.clearCallingIdentity();
+        synchronized (mGlobalLock) {
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityPaused");
+            final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+            if (r != null) {
+                r.activityPaused(false);
+            }
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+        }
+        Binder.restoreCallingIdentity(origId);
+    }
+
+    @Override
+    public void activityStopped(IBinder token, Bundle icicle, PersistableBundle persistentState,
+            CharSequence description) {
+        if (DEBUG_ALL) Slog.v(TAG, "Activity stopped: token=" + token);
+
+        // Refuse possible leaked file descriptors.
+        if (icicle != null && icicle.hasFileDescriptors()) {
+            throw new IllegalArgumentException("File descriptors passed in Bundle");
+        }
+
+        final long origId = Binder.clearCallingIdentity();
+
+        String restartingName = null;
+        int restartingUid = 0;
+        final ActivityRecord r;
+        synchronized (mGlobalLock) {
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityStopped");
+            r = ActivityRecord.isInStackLocked(token);
+            if (r != null) {
+                if (r.attachedToProcess() && r.isState(Task.ActivityState.RESTARTING_PROCESS)) {
+                    // The activity was requested to restart from
+                    // {@link #restartActivityProcessIfVisible}.
+                    restartingName = r.app.mName;
+                    restartingUid = r.app.mUid;
+                }
+                r.activityStopped(icicle, persistentState, description);
+            }
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+        }
+
+        if (restartingName != null) {
+            // In order to let the foreground activity can be restarted with its saved state from
+            // {@link android.app.Activity#onSaveInstanceState}, the kill operation is postponed
+            // until the activity reports stopped with the state. And the activity record will be
+            // kept because the record state is restarting, then the activity will be restarted
+            // immediately if it is still the top one.
+            mTaskSupervisor.removeRestartTimeouts(r);
+            mService.mAmInternal.killProcess(restartingName, restartingUid,
+                    "restartActivityProcess");
+        }
+        mService.mAmInternal.trimApplications();
+
+        Binder.restoreCallingIdentity(origId);
+    }
+
+    @Override
+    public void activityDestroyed(IBinder token) {
+        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "ACTIVITY DESTROYED: " + token);
+        final long origId = Binder.clearCallingIdentity();
+        synchronized (mGlobalLock) {
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityDestroyed");
+            try {
+                final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+                if (r != null) {
+                    r.destroyed("activityDestroyed");
+                }
+            } finally {
+                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+                Binder.restoreCallingIdentity(origId);
+            }
+        }
+    }
+
+    @Override
+    public void activityRelaunched(IBinder token) {
+        final long origId = Binder.clearCallingIdentity();
+        synchronized (mGlobalLock) {
+            mTaskSupervisor.activityRelaunchedLocked(token);
+        }
+        Binder.restoreCallingIdentity(origId);
+    }
+
+    @Override
+    public void reportSizeConfigurations(IBinder token, int[] horizontalSizeConfiguration,
+            int[] verticalSizeConfigurations, int[] smallestSizeConfigurations) {
+        ProtoLog.v(WM_DEBUG_CONFIGURATION, "Report configuration: %s %s %s",
+                token, Arrays.toString(horizontalSizeConfiguration),
+                Arrays.toString(verticalSizeConfigurations));
+        synchronized (mGlobalLock) {
+            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            if (r != null) {
+                r.setSizeConfigurations(horizontalSizeConfiguration, verticalSizeConfigurations,
+                        smallestSizeConfigurations);
+            }
+        }
+    }
+
+    /**
+     * Attempts to move a task backwards in z-order (the order of activities within the task is
+     * unchanged).
+     *
+     * There are several possible results of this call:
+     * - if the task is locked, then we will show the lock toast.
+     * - if there is a task behind the provided task, then that task is made visible and resumed as
+     * this task is moved to the back.
+     * - otherwise, if there are no other tasks in the root task:
+     * - if this task is in the pinned mode, then we remove the task completely, which will
+     * have the effect of moving the task to the top or bottom of the fullscreen root task
+     * (depending on whether it is visible).
+     * - otherwise, we simply return home and hide this task.
+     *
+     * @param token   A reference to the activity we wish to move.
+     * @param nonRoot If false then this only works if the activity is the root
+     *                of a task; if true it will work for any activity in a task.
+     * @return Returns true if the move completed, false if not.
+     */
+    @Override
+    public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
+        enforceNotIsolatedCaller("moveActivityTaskToBack");
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final int taskId = ActivityRecord.getTaskForActivityLocked(token, !nonRoot);
+                final Task task = mService.mRootWindowContainer.anyTaskForId(taskId);
+                if (task != null) {
+                    return ActivityRecord.getStackLocked(token).moveTaskToBack(task);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+        return false;
+    }
+
+    @Override
+    public boolean shouldUpRecreateTask(IBinder token, String destAffinity) {
+        synchronized (mGlobalLock) {
+            final ActivityRecord srec = ActivityRecord.forTokenLocked(token);
+            if (srec != null) {
+                return srec.getRootTask().shouldUpRecreateTaskLocked(srec, destAffinity);
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean navigateUpTo(IBinder token, Intent destIntent, int resultCode,
+            Intent resultData) {
+        final ActivityRecord r;
+        synchronized (mGlobalLock) {
+            r = ActivityRecord.isInStackLocked(token);
+            if (r == null) {
+                return false;
+            }
+        }
+
+        // Carefully collect grants without holding lock.
+        final NeededUriGrants destGrants = mService.collectGrants(destIntent, r);
+        final NeededUriGrants resultGrants = mService.collectGrants(resultData, r.resultTo);
+
+        synchronized (mGlobalLock) {
+            return r.getRootTask().navigateUpTo(
+                    r, destIntent, destGrants, resultCode, resultData, resultGrants);
+        }
+    }
+
+    @Override
+    public boolean releaseActivityInstance(IBinder token) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+                if (r == null || !r.isDestroyable()) {
+                    return false;
+                }
+                r.destroyImmediately("app-req");
+                return r.isState(DESTROYING, DESTROYED);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    /**
+     * This is the internal entry point for handling Activity.finish().
+     *
+     * @param token      The Binder token referencing the Activity we want to finish.
+     * @param resultCode Result code, if any, from this Activity.
+     * @param resultData Result data (Intent), if any, from this Activity.
+     * @param finishTask Whether to finish the task associated with this Activity.
+     * @return Returns true if the activity successfully finished, or false if it is still running.
+     */
+    @Override
+    public boolean finishActivity(IBinder token, int resultCode, Intent resultData,
+            int finishTask) {
+        // Refuse possible leaked file descriptors.
+        if (resultData != null && resultData.hasFileDescriptors()) {
+            throw new IllegalArgumentException("File descriptors passed in Intent");
+        }
+
+        final ActivityRecord r;
+        synchronized (mGlobalLock) {
+            r = ActivityRecord.isInStackLocked(token);
+            if (r == null) {
+                return true;
+            }
+        }
+
+        // Carefully collect grants without holding lock.
+        final NeededUriGrants resultGrants = mService.collectGrants(resultData, r.resultTo);
+
+        synchronized (mGlobalLock) {
+            // Check again in case activity was removed when collecting grants.
+            if (!r.isInHistory()) {
+                return true;
+            }
+
+            // Keep track of the root activity of the task before we finish it.
+            final Task tr = r.getTask();
+            final ActivityRecord rootR = tr.getRootActivity();
+            if (rootR == null) {
+                Slog.w(TAG, "Finishing task with all activities already finished");
+            }
+            // Do not allow task to finish if last task in lockTask mode. Launchable priv-apps can
+            // finish.
+            if (mService.getLockTaskController().activityBlockedFromFinish(r)) {
+                return false;
+            }
+
+            // TODO: There is a dup. of this block of code in ActivityStack.navigateUpToLocked
+            // We should consolidate.
+            if (mService.mController != null) {
+                // Find the first activity that is not finishing.
+                final ActivityRecord next =
+                        r.getRootTask().topRunningActivity(token, INVALID_TASK_ID);
+                if (next != null) {
+                    // ask watcher if this is allowed
+                    boolean resumeOK = true;
+                    try {
+                        resumeOK = mService.mController.activityResuming(next.packageName);
+                    } catch (RemoteException e) {
+                        mService.mController = null;
+                        Watchdog.getInstance().setActivityController(null);
+                    }
+
+                    if (!resumeOK) {
+                        Slog.i(TAG, "Not finishing activity because controller resumed");
+                        return false;
+                    }
+                }
+            }
+
+            // Note down that the process has finished an activity and is in background activity
+            // starts grace period.
+            if (r.app != null) {
+                r.app.setLastActivityFinishTimeIfNeeded(SystemClock.uptimeMillis());
+            }
+
+            final long origId = Binder.clearCallingIdentity();
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "finishActivity");
+            try {
+                final boolean res;
+                final boolean finishWithRootActivity =
+                        finishTask == Activity.FINISH_TASK_WITH_ROOT_ACTIVITY;
+                if (finishTask == Activity.FINISH_TASK_WITH_ACTIVITY
+                        || (finishWithRootActivity && r == rootR)) {
+                    // If requested, remove the task that is associated to this activity only if it
+                    // was the root activity in the task. The result code and data is ignored
+                    // because we don't support returning them across task boundaries. Also, to
+                    // keep backwards compatibility we remove the task from recents when finishing
+                    // task with root activity.
+                    mTaskSupervisor.removeTask(tr, false /*killProcess*/,
+                            finishWithRootActivity, "finish-activity");
+                    res = true;
+                    // Explicitly dismissing the activity so reset its relaunch flag.
+                    r.mRelaunchReason = RELAUNCH_REASON_NONE;
+                } else {
+                    r.finishIfPossible(resultCode, resultData, resultGrants,
+                            "app-request", true /* oomAdj */);
+                    res = r.finishing;
+                    if (!res) {
+                        Slog.i(TAG, "Failed to finish by app-request");
+                    }
+                }
+                return res;
+            } finally {
+                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+                Binder.restoreCallingIdentity(origId);
+            }
+        }
+    }
+
+    @Override
+    public boolean finishActivityAffinity(IBinder token) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+                if (r == null) {
+                    return false;
+                }
+
+                // Do not allow task to finish if last task in lockTask mode. Launchable priv-apps
+                // can finish.
+                if (mService.getLockTaskController().activityBlockedFromFinish(r)) {
+                    return false;
+                }
+
+                r.getTask().forAllActivities(activity -> r.finishIfSameAffinity(activity),
+                        r /* boundary */, true /* includeBoundary */,
+                        true /* traverseTopToBottom */);
+                return true;
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
+    public void finishSubActivity(IBinder token, String resultWho, int requestCode) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+                if (r == null) return;
+
+                // TODO: This should probably only loop over the task since you need to be in the
+                // same task to return results.
+                r.getRootTask().forAllActivities(activity -> {
+                    activity.finishIfSubActivity(r /* parent */, resultWho, requestCode);
+                }, true /* traverseTopToBottom */);
+
+                mService.updateOomAdj();
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
+    public boolean isTopOfTask(IBinder token) {
+        synchronized (mGlobalLock) {
+            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            return r != null && r.getTask().getTopNonFinishingActivity() == r;
+        }
+    }
+
+    @Override
+    public boolean willActivityBeVisible(IBinder token) {
+        synchronized (mGlobalLock) {
+            final Task rootTask = ActivityRecord.getStackLocked(token);
+            return rootTask != null && rootTask.willActivityBeVisible(token);
+        }
+    }
+
+    @Override
+    public int getDisplayId(IBinder activityToken) {
+        synchronized (mGlobalLock) {
+            final Task rootTask = ActivityRecord.getStackLocked(activityToken);
+            if (rootTask != null) {
+                final int displayId = rootTask.getDisplayId();
+                return displayId != INVALID_DISPLAY ? displayId : DEFAULT_DISPLAY;
+            }
+            return DEFAULT_DISPLAY;
+        }
+    }
+
+    @Override
+    public int getTaskForActivity(IBinder token, boolean onlyRoot) {
+        synchronized (mGlobalLock) {
+            return ActivityRecord.getTaskForActivityLocked(token, onlyRoot);
+        }
+    }
+
+    @Override
+    public ComponentName getCallingActivity(IBinder token) {
+        synchronized (mGlobalLock) {
+            final ActivityRecord r = getCallingRecord(token);
+            return r != null ? r.intent.getComponent() : null;
+        }
+    }
+
+    @Override
+    public String getCallingPackage(IBinder token) {
+        synchronized (mGlobalLock) {
+            final ActivityRecord r = getCallingRecord(token);
+            return r != null ? r.info.packageName : null;
+        }
+    }
+
+    private static ActivityRecord getCallingRecord(IBinder token) {
+        final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+        return r != null ? r.resultTo : null;
+    }
+
+    @Override
+    public Bundle getActivityOptions(IBinder token) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+                if (r == null) {
+                    return null;
+                }
+                final ActivityOptions activityOptions = r.takeOptionsLocked(true /* fromClient */);
+                return activityOptions != null ? activityOptions.toBundle() : null;
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
+    public void setRequestedOrientation(IBinder token, int requestedOrientation) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+                if (r != null) {
+                    r.setRequestedOrientation(requestedOrientation);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
+    public int getRequestedOrientation(IBinder token) {
+        synchronized (mGlobalLock) {
+            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            return r != null
+                    ? r.getRequestedOrientation() : ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+        }
+    }
+
+    @Override
+    public boolean convertFromTranslucent(IBinder token) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+                return r != null && r.setOccludesParent(true);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
+    public boolean convertToTranslucent(IBinder token, Bundle options) {
+        final SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle(options);
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+                if (r == null) {
+                    return false;
+                }
+                final ActivityRecord under = r.getTask().getActivityBelow(r);
+                if (under != null) {
+                    under.returningOptions = safeOptions != null ? safeOptions.getOptions(r) : null;
+                }
+                return r.setOccludesParent(false);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
+    public boolean isImmersive(IBinder token) {
+        synchronized (mGlobalLock) {
+            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            if (r == null) {
+                throw new IllegalArgumentException();
+            }
+            return r.immersive;
+        }
+    }
+
+    @Override
+    public void setImmersive(IBinder token, boolean immersive) {
+        synchronized (mGlobalLock) {
+            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            if (r == null) {
+                throw new IllegalArgumentException();
+            }
+            r.immersive = immersive;
+
+            // Update associated state if we're frontmost.
+            if (r.isFocusedActivityOnDisplay()) {
+                ProtoLog.d(WM_DEBUG_IMMERSIVE, "Frontmost changed immersion: %s", r);
+                mService.applyUpdateLockStateLocked(r);
+            }
+        }
+    }
+
+    @Override
+    public boolean enterPictureInPictureMode(IBinder token, final PictureInPictureParams params) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final ActivityRecord r = ensureValidPictureInPictureActivityParams(
+                        "enterPictureInPictureMode", token, params);
+                return mService.enterPictureInPictureMode(r, params);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
+    public void setPictureInPictureParams(IBinder token, final PictureInPictureParams params) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final ActivityRecord r = ensureValidPictureInPictureActivityParams(
+                        "setPictureInPictureParams", token, params);
+
+                // Only update the saved args from the args that are set.
+                r.setPictureInPictureParams(params);
+                if (r.inPinnedWindowingMode()) {
+                    // If the activity is already in picture-in-picture, update the pinned task now
+                    // if it is not already expanding to fullscreen. Otherwise, the arguments will
+                    // be used the next time the activity enters PiP.
+                    final Task rootTask = r.getRootTask();
+                    rootTask.setPictureInPictureAspectRatio(
+                            r.pictureInPictureArgs.getAspectRatio());
+                    rootTask.setPictureInPictureActions(r.pictureInPictureArgs.getActions());
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    /**
+     * Checks the state of the system and the activity associated with the given {@param token} to
+     * verify that picture-in-picture is supported for that activity.
+     *
+     * @return the activity record for the given {@param token} if all the checks pass.
+     */
+    private ActivityRecord ensureValidPictureInPictureActivityParams(String caller,
+            IBinder token, PictureInPictureParams params) {
+        if (!mService.mSupportsPictureInPicture) {
+            throw new IllegalStateException(caller
+                    + ": Device doesn't support picture-in-picture mode.");
+        }
+
+        final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+        if (r == null) {
+            throw new IllegalStateException(caller
+                    + ": Can't find activity for token=" + token);
+        }
+
+        if (!r.supportsPictureInPicture()) {
+            throw new IllegalStateException(caller
+                    + ": Current activity does not support picture-in-picture.");
+        }
+
+        if (params.hasSetAspectRatio()
+                && !mService.mWindowManager.isValidPictureInPictureAspectRatio(
+                r.mDisplayContent, params.getAspectRatio())) {
+            final float minAspectRatio = mContext.getResources().getFloat(
+                    com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
+            final float maxAspectRatio = mContext.getResources().getFloat(
+                    com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio);
+            throw new IllegalArgumentException(String.format(caller
+                            + ": Aspect ratio is too extreme (must be between %f and %f).",
+                    minAspectRatio, maxAspectRatio));
+        }
+
+        // Truncate the number of actions if necessary.
+        params.truncateActions(ActivityTaskManager.getMaxNumPictureInPictureActions(mContext));
+        return r;
+    }
+
+    @Override
+    public void toggleFreeformWindowingMode(IBinder token) {
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+                if (r == null) {
+                    throw new IllegalArgumentException(
+                            "toggleFreeformWindowingMode: No activity record matching token="
+                                    + token);
+                }
+
+                final Task rootTask = r.getRootTask();
+                if (rootTask == null) {
+                    throw new IllegalStateException("toggleFreeformWindowingMode: the activity "
+                            + "doesn't have a root task");
+                }
+
+                if (!rootTask.inFreeformWindowingMode()
+                        && rootTask.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
+                    throw new IllegalStateException("toggleFreeformWindowingMode: You can only "
+                            + "toggle between fullscreen and freeform.");
+                }
+
+                if (rootTask.inFreeformWindowingMode()) {
+                    rootTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+                } else if (!mService.mSizeCompatFreeform && r.inSizeCompatMode()) {
+                    throw new IllegalStateException("Size-compat windows are currently not"
+                            + "freeform-enabled");
+                } else if (rootTask.getParent().inFreeformWindowingMode()) {
+                    // If the window is on a freeform display, set it to undefined. It will be
+                    // resolved to freeform and it can adjust windowing mode when the display mode
+                    // changes in runtime.
+                    rootTask.setWindowingMode(WINDOWING_MODE_UNDEFINED);
+                } else {
+                    rootTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
+    public void startLockTaskModeByToken(IBinder token) {
+        synchronized (mGlobalLock) {
+            final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+            if (r != null) {
+                mService.startLockTaskMode(r.getTask(), false /* isSystemCaller */);
+            }
+        }
+    }
+
+    @Override
+    public void stopLockTaskModeByToken(IBinder token) {
+        mService.stopLockTaskModeInternal(token, false /* isSystemCaller */);
+    }
+
+    @Override
+    public void showLockTaskEscapeMessage(IBinder token) {
+        synchronized (mGlobalLock) {
+            if (ActivityRecord.forTokenLocked(token) != null) {
+                mService.getLockTaskController().showLockTaskToast();
+            }
+        }
+    }
+
+    @Override
+    public void setTaskDescription(IBinder token, ActivityManager.TaskDescription td) {
+        synchronized (mGlobalLock) {
+            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            if (r != null) {
+                r.setTaskDescription(td);
+            }
+        }
+    }
+
+    @Override
+    public boolean showAssistFromActivity(IBinder token, Bundle args) {
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final ActivityRecord caller = ActivityRecord.forTokenLocked(token);
+                final Task topRootTask = mService.getTopDisplayFocusedRootTask();
+                final ActivityRecord top = topRootTask != null
+                        ? topRootTask.getTopNonFinishingActivity() : null;
+                if (top != caller) {
+                    Slog.w(TAG, "showAssistFromActivity failed: caller " + caller
+                            + " is not current top " + top);
+                    return false;
+                }
+                if (!top.nowVisible) {
+                    Slog.w(TAG, "showAssistFromActivity failed: caller " + caller
+                            + " is not visible");
+                    return false;
+                }
+            }
+            return mAssistUtils.showSessionForActiveService(args, SHOW_SOURCE_APPLICATION,
+                    null /* showCallback */, token);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
+    public boolean isRootVoiceInteraction(IBinder token) {
+        synchronized (mGlobalLock) {
+            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            return r != null && r.rootVoiceInteraction;
+        }
+    }
+
+    @Override
+    public void startLocalVoiceInteraction(IBinder callingActivity, Bundle options) {
+        Slog.i(TAG, "Activity tried to startLocalVoiceInteraction");
+        synchronized (mGlobalLock) {
+            final Task topRootTask = mService.getTopDisplayFocusedRootTask();
+            final ActivityRecord activity = topRootTask != null
+                    ? topRootTask.getTopNonFinishingActivity() : null;
+            if (ActivityRecord.forTokenLocked(callingActivity) != activity) {
+                throw new SecurityException("Only focused activity can call startVoiceInteraction");
+            }
+            if (mService.mRunningVoice != null || activity.getTask().voiceSession != null
+                    || activity.voiceSession != null) {
+                Slog.w(TAG, "Already in a voice interaction, cannot start new voice interaction");
+                return;
+            }
+            if (activity.pendingVoiceInteractionStart) {
+                Slog.w(TAG, "Pending start of voice interaction already.");
+                return;
+            }
+            activity.pendingVoiceInteractionStart = true;
+        }
+        LocalServices.getService(VoiceInteractionManagerInternal.class)
+                .startLocalVoiceInteraction(callingActivity, options);
+    }
+
+    @Override
+    public void stopLocalVoiceInteraction(IBinder callingActivity) {
+        LocalServices.getService(VoiceInteractionManagerInternal.class)
+                .stopLocalVoiceInteraction(callingActivity);
+    }
+
+    @Override
+    public void setShowWhenLocked(IBinder token, boolean showWhenLocked) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+                if (r != null) {
+                    r.setShowWhenLocked(showWhenLocked);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
+    public void setInheritShowWhenLocked(IBinder token, boolean inheritShowWhenLocked) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+                if (r != null) {
+                    r.setInheritShowWhenLocked(inheritShowWhenLocked);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
+    public void setTurnScreenOn(IBinder token, boolean turnScreenOn) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+                if (r != null) {
+                    r.setTurnScreenOn(turnScreenOn);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
+    public void reportActivityFullyDrawn(IBinder token, boolean restoredFromBundle) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+                if (r != null) {
+                    r.reportFullyDrawnLocked(restoredFromBundle);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
+    public void overridePendingTransition(IBinder token, String packageName,
+            int enterAnim, int exitAnim) {
+        final long origId = Binder.clearCallingIdentity();
+        synchronized (mGlobalLock) {
+            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            if (r != null && r.isState(Task.ActivityState.RESUMED, Task.ActivityState.PAUSING)) {
+                r.mDisplayContent.mAppTransition.overridePendingAppTransition(
+                        packageName, enterAnim, exitAnim, null, null);
+            }
+        }
+        Binder.restoreCallingIdentity(origId);
+    }
+
+    @Override
+    public int setVrMode(IBinder token, boolean enabled, ComponentName packageName) {
+        mService.enforceSystemHasVrFeature();
+
+        final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
+        final ActivityRecord r;
+        synchronized (mGlobalLock) {
+            r = ActivityRecord.isInStackLocked(token);
+        }
+        if (r == null) {
+            throw new IllegalArgumentException();
+        }
+
+        final int err;
+        if ((err = vrService.hasVrPackage(packageName, r.mUserId)) != VrManagerInternal.NO_ERROR) {
+            return err;
+        }
+
+        // Clear the binder calling uid since this path may call moveToTask().
+        final long callingId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                r.requestedVrComponent = (enabled) ? packageName : null;
+
+                // Update associated state if this activity is currently focused.
+                if (r.isFocusedActivityOnDisplay()) {
+                    mService.applyUpdateVrModeLocked(r);
+                }
+                return 0;
+            }
+        } finally {
+            Binder.restoreCallingIdentity(callingId);
+        }
+    }
+
+    @Override
+    public void setDisablePreviewScreenshots(IBinder token, boolean disable) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+                if (r != null) {
+                    r.setDisablePreviewScreenshots(disable);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
+    public void registerRemoteAnimations(IBinder token, RemoteAnimationDefinition definition) {
+        mService.mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
+                "registerRemoteAnimations");
+        definition.setCallingPidUid(Binder.getCallingPid(), Binder.getCallingUid());
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+                if (r != null) {
+                    r.registerRemoteAnimations(definition);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
+    public void unregisterRemoteAnimations(IBinder token) {
+        mService.mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
+                "unregisterRemoteAnimations");
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+                if (r != null) {
+                    r.unregisterRemoteAnimations();
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
+    public void onBackPressedOnTaskRoot(IBinder token) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+                if (r == null) {
+                    return;
+                }
+                if (mService.mWindowOrganizerController.mTaskOrganizerController
+                        .handleInterceptBackPressedOnTaskRoot(r.getRootTask())) {
+                    // This task is handled by a task organizer that has requested the back pressed
+                    // callback.
+                } else {
+                    moveActivityTaskToBack(token, false /* nonRoot */);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 1b8cc08..743796b 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -925,8 +925,9 @@
         if (mVoiceInteraction) {
             pw.println(prefix + "mVoiceInteraction=true");
         }
-        pw.print(prefix); pw.print("mOccludesParent="); pw.print(mOccludesParent);
-        pw.print(" mOrientation="); pw.println(mOrientation);
+        pw.print(prefix); pw.print("mOccludesParent="); pw.println(mOccludesParent);
+        pw.print(prefix); pw.print("mOrientation=");
+        pw.println(ActivityInfo.screenOrientationToString(mOrientation));
         pw.println(prefix + "mVisibleRequested=" + mVisibleRequested
                 + " mVisible=" + mVisible + " mClientVisible=" + mClientVisible
                 + ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "")
@@ -1011,6 +1012,9 @@
             if (info.supportsSizeChanges) {
                 pw.println(prefix + "supportsSizeChanges=true");
             }
+            if (info.configChanges != 0) {
+                pw.println(prefix + "configChanges=0x" + Integer.toHexString(info.configChanges));
+            }
         }
     }
 
@@ -4032,7 +4036,7 @@
                 if (mDisplayContent != null) {
                     mDisplayContent.setLayoutNeeded();
                 }
-                mWmService.mH.obtainMessage(H.NOTIFY_ACTIVITY_DRAWN, token).sendToTarget();
+                mWmService.mH.obtainMessage(H.NOTIFY_ACTIVITY_DRAWN, this).sendToTarget();
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 3710120..8298dfd 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -33,8 +33,6 @@
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.ActivityTaskManager.RESIZE_MODE_PRESERVE_WINDOW;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -62,7 +60,6 @@
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL;
 import static android.provider.Settings.Global.HIDE_ERROR_DIALOGS;
 import static android.provider.Settings.System.FONT_SCALE;
-import static android.service.voice.VoiceInteractionSession.SHOW_SOURCE_APPLICATION;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
@@ -95,15 +92,8 @@
 import static com.android.server.am.EventLogTags.writeBootProgressEnableScreen;
 import static com.android.server.am.EventLogTags.writeConfigurationChanged;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_FOCUS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_IMMERSIVE;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ROOT_TASK;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
@@ -121,8 +111,6 @@
 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
 import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_ONLY;
 import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS;
-import static com.android.server.wm.Task.ActivityState.DESTROYED;
-import static com.android.server.wm.Task.ActivityState.DESTROYING;
 import static com.android.server.wm.Task.REPARENT_KEEP_ROOT_TASK_AT_FRONT;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
@@ -132,7 +120,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
-import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.ActivityOptions;
@@ -143,6 +130,7 @@
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
 import android.app.Dialog;
+import android.app.IActivityClientController;
 import android.app.IActivityController;
 import android.app.IActivityTaskManager;
 import android.app.IApplicationThread;
@@ -197,7 +185,6 @@
 import android.os.LocaleList;
 import android.os.Looper;
 import android.os.Message;
-import android.os.PersistableBundle;
 import android.os.PowerManager;
 import android.os.PowerManagerInternal;
 import android.os.Process;
@@ -237,7 +224,6 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.AssistUtils;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.app.ProcessMap;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
@@ -249,8 +235,6 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.FrameworkStatsLog;
-import com.android.internal.util.function.pooled.PooledConsumer;
-import com.android.internal.util.function.pooled.PooledFunction;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.AttributeCache;
 import com.android.server.LocalServices;
@@ -271,7 +255,6 @@
 import com.android.server.policy.PermissionPolicyInternal;
 import com.android.server.uri.NeededUriGrants;
 import com.android.server.uri.UriGrantsManagerInternal;
-import com.android.server.vr.VrManagerInternal;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -308,11 +291,6 @@
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityTaskManagerService" : TAG_ATM;
     static final String TAG_ROOT_TASK = TAG + POSTFIX_ROOT_TASK;
     static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
-    private static final String TAG_IMMERSIVE = TAG + POSTFIX_IMMERSIVE;
-    private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
-    private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
-    private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
-    private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
 
     // How long we wait until we timeout on key dispatching during instrumentation.
     static final long INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MILLIS = 60 * 1000;
@@ -385,6 +363,7 @@
      */
     final Object mGlobalLockWithoutBoost = mGlobalLock;
     ActivityTaskSupervisor mTaskSupervisor;
+    ActivityClientController mActivityClientController;
     RootWindowContainer mRootWindowContainer;
     WindowManagerService mWindowManager;
     private UserManagerService mUserManager;
@@ -418,9 +397,6 @@
     /** State of external calls telling us if the device is awake or asleep. */
     private boolean mKeyguardShown = false;
 
-    // Wrapper around VoiceInteractionServiceManager
-    private AssistUtils mAssistUtils;
-
     // VoiceInteraction session ID that changes for each new request except when
     // being called for multi-window assist in a single session.
     private int mViSessionId = 1000;
@@ -763,10 +739,10 @@
             final PackageManager pm = mContext.getPackageManager();
             mHasHeavyWeightFeature = pm.hasSystemFeature(FEATURE_CANT_SAVE_STATE);
             mHasLeanbackFeature = pm.hasSystemFeature(FEATURE_LEANBACK);
-            mAssistUtils = new AssistUtils(mContext);
             mVrController.onSystemReady();
             mRecentTasks.onSystemReadyLocked();
             mTaskSupervisor.onSystemReady();
+            mActivityClientController.onSystemReady();
             mBlockActivityAfterHomeEnabled = DeviceConfig.getBoolean(
                     DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                     BLOCK_ACTIVITY_STARTS_AFTER_HOME_FLAG, false);
@@ -872,6 +848,7 @@
         mCompatModePackages = new CompatModePackages(this, systemDir, mH);
         mPendingIntentController = intentController;
         mTaskSupervisor = createTaskSupervisor();
+        mActivityClientController = new ActivityClientController(this);
 
         mTaskChangeNotificationController =
                 new TaskChangeNotificationController(mGlobalLock, mTaskSupervisor, mH);
@@ -1698,311 +1675,9 @@
         return mAmInternal.getActivityInfoForUser(aInfo, userId);
     }
 
-    /**
-     * This is the internal entry point for handling Activity.finish().
-     *
-     * @param token      The Binder token referencing the Activity we want to finish.
-     * @param resultCode Result code, if any, from this Activity.
-     * @param resultData Result data (Intent), if any, from this Activity.
-     * @param finishTask Whether to finish the task associated with this Activity.
-     * @return Returns true if the activity successfully finished, or false if it is still running.
-     */
     @Override
-    public final boolean finishActivity(IBinder token, int resultCode, Intent resultData,
-            int finishTask) {
-        // Refuse possible leaked file descriptors
-        if (resultData != null && resultData.hasFileDescriptors()) {
-            throw new IllegalArgumentException("File descriptors passed in Intent");
-        }
-
-        final ActivityRecord r;
-        synchronized (mGlobalLock) {
-            r = ActivityRecord.isInStackLocked(token);
-            if (r == null) {
-                return true;
-            }
-        }
-
-        // Carefully collect grants without holding lock
-        final NeededUriGrants resultGrants = collectGrants(resultData, r.resultTo);
-
-        synchronized (mGlobalLock) {
-            // Sanity check in case activity was removed before entering global lock.
-            if (!r.isInHistory()) {
-                return true;
-            }
-
-            // Keep track of the root activity of the task before we finish it
-            final Task tr = r.getTask();
-            final ActivityRecord rootR = tr.getRootActivity();
-            if (rootR == null) {
-                Slog.w(TAG, "Finishing task with all activities already finished");
-            }
-            // Do not allow task to finish if last task in lockTask mode. Launchable priv-apps can
-            // finish.
-            if (getLockTaskController().activityBlockedFromFinish(r)) {
-                return false;
-            }
-
-            // TODO: There is a dup. of this block of code in ActivityStack.navigateUpToLocked
-            // We should consolidate.
-            if (mController != null) {
-                // Find the first activity that is not finishing.
-                final ActivityRecord next =
-                        r.getRootTask().topRunningActivity(token, INVALID_TASK_ID);
-                if (next != null) {
-                    // ask watcher if this is allowed
-                    boolean resumeOK = true;
-                    try {
-                        resumeOK = mController.activityResuming(next.packageName);
-                    } catch (RemoteException e) {
-                        mController = null;
-                        Watchdog.getInstance().setActivityController(null);
-                    }
-
-                    if (!resumeOK) {
-                        Slog.i(TAG, "Not finishing activity because controller resumed");
-                        return false;
-                    }
-                }
-            }
-
-            // note down that the process has finished an activity and is in background activity
-            // starts grace period
-            if (r.app != null) {
-                r.app.setLastActivityFinishTimeIfNeeded(SystemClock.uptimeMillis());
-            }
-
-            final long origId = Binder.clearCallingIdentity();
-            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "finishActivity");
-            try {
-                boolean res;
-                final boolean finishWithRootActivity =
-                        finishTask == Activity.FINISH_TASK_WITH_ROOT_ACTIVITY;
-                if (finishTask == Activity.FINISH_TASK_WITH_ACTIVITY
-                        || (finishWithRootActivity && r == rootR)) {
-                    // If requested, remove the task that is associated to this activity only if it
-                    // was the root activity in the task. The result code and data is ignored
-                    // because we don't support returning them across task boundaries. Also, to
-                    // keep backwards compatibility we remove the task from recents when finishing
-                    // task with root activity.
-                    mTaskSupervisor.removeTask(tr, false /*killProcess*/,
-                            finishWithRootActivity, "finish-activity");
-                    res = true;
-                    // Explicitly dismissing the activity so reset its relaunch flag.
-                    r.mRelaunchReason = RELAUNCH_REASON_NONE;
-                } else {
-                    r.finishIfPossible(resultCode, resultData, resultGrants,
-                            "app-request", true /* oomAdj */);
-                    res = r.finishing;
-                    if (!res) {
-                        Slog.i(TAG, "Failed to finish by app-request");
-                    }
-                }
-                return res;
-            } finally {
-                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
-                Binder.restoreCallingIdentity(origId);
-            }
-        }
-    }
-
-    @Override
-    public boolean finishActivityAffinity(IBinder token) {
-        synchronized (mGlobalLock) {
-            final long origId = Binder.clearCallingIdentity();
-            try {
-                ActivityRecord r = ActivityRecord.isInStackLocked(token);
-                if (r == null) {
-                    return false;
-                }
-
-                // Do not allow task to finish if last task in lockTask mode. Launchable priv-apps
-                // can finish.
-                if (getLockTaskController().activityBlockedFromFinish(r)) {
-                    return false;
-                }
-
-                final PooledFunction p = PooledLambda.obtainFunction(
-                        ActivityRecord::finishIfSameAffinity, r,
-                        PooledLambda.__(ActivityRecord.class));
-                r.getTask().forAllActivities(
-                        p, r, true /*includeBoundary*/, true /*traverseTopToBottom*/);
-                p.recycle();
-
-                return true;
-            } finally {
-                Binder.restoreCallingIdentity(origId);
-            }
-        }
-    }
-
-    @Override
-    public final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
-        final long origId = Binder.clearCallingIdentity();
-        try {
-            synchronized (mGlobalLock) {
-                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityIdle");
-                final ActivityRecord r = ActivityRecord.forTokenLocked(token);
-                if (r == null) {
-                    return;
-                }
-                mTaskSupervisor.activityIdleInternal(r, false /* fromTimeout */,
-                        false /* processPausingActivities */, config);
-                if (stopProfiling && r.hasProcess()) {
-                    r.app.clearProfilerIfNeeded();
-                }
-            }
-        } finally {
-            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
-
-    @Override
-    public final void activityResumed(IBinder token) {
-        final long origId = Binder.clearCallingIdentity();
-        synchronized (mGlobalLock) {
-            ActivityRecord.activityResumedLocked(token);
-        }
-        Binder.restoreCallingIdentity(origId);
-    }
-
-    @Override
-    public final void activityTopResumedStateLost() {
-        final long origId = Binder.clearCallingIdentity();
-        synchronized (mGlobalLock) {
-            mTaskSupervisor.handleTopResumedStateReleased(false /* timeout */);
-        }
-        Binder.restoreCallingIdentity(origId);
-    }
-
-    @Override
-    public final void activityPaused(IBinder token) {
-        final long origId = Binder.clearCallingIdentity();
-        synchronized (mGlobalLock) {
-            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityPaused");
-            final ActivityRecord r = ActivityRecord.forTokenLocked(token);
-            if (r != null) {
-                r.activityPaused(false);
-            }
-            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
-        }
-        Binder.restoreCallingIdentity(origId);
-    }
-
-    @Override
-    public final void activityStopped(IBinder token, Bundle icicle,
-            PersistableBundle persistentState, CharSequence description) {
-        if (DEBUG_ALL) Slog.v(TAG, "Activity stopped: token=" + token);
-
-        // Refuse possible leaked file descriptors
-        if (icicle != null && icicle.hasFileDescriptors()) {
-            throw new IllegalArgumentException("File descriptors passed in Bundle");
-        }
-
-        final long origId = Binder.clearCallingIdentity();
-
-        String restartingName = null;
-        int restartingUid = 0;
-        final ActivityRecord r;
-        synchronized (mGlobalLock) {
-            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityStopped");
-            r = ActivityRecord.isInStackLocked(token);
-            if (r != null) {
-                if (r.attachedToProcess()
-                        && r.isState(Task.ActivityState.RESTARTING_PROCESS)) {
-                    // The activity was requested to restart from
-                    // {@link #restartActivityProcessIfVisible}.
-                    restartingName = r.app.mName;
-                    restartingUid = r.app.mUid;
-                }
-                r.activityStopped(icicle, persistentState, description);
-            }
-            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
-        }
-
-        if (restartingName != null) {
-            // In order to let the foreground activity can be restarted with its saved state from
-            // {@link android.app.Activity#onSaveInstanceState}, the kill operation is postponed
-            // until the activity reports stopped with the state. And the activity record will be
-            // kept because the record state is restarting, then the activity will be restarted
-            // immediately if it is still the top one.
-            mTaskSupervisor.removeRestartTimeouts(r);
-            mAmInternal.killProcess(restartingName, restartingUid, "restartActivityProcess");
-        }
-        mAmInternal.trimApplications();
-
-        Binder.restoreCallingIdentity(origId);
-    }
-
-    @Override
-    public final void activityDestroyed(IBinder token) {
-        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "ACTIVITY DESTROYED: " + token);
-        synchronized (mGlobalLock) {
-            final long origId = Binder.clearCallingIdentity();
-            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityDestroyed");
-            try {
-                final ActivityRecord activity = ActivityRecord.forTokenLocked(token);
-                if (activity != null) {
-                    activity.destroyed("activityDestroyed");
-                }
-            } finally {
-                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
-                Binder.restoreCallingIdentity(origId);
-            }
-        }
-    }
-
-    @Override
-    public final void activityRelaunched(IBinder token) {
-        final long origId = Binder.clearCallingIdentity();
-        synchronized (mGlobalLock) {
-            mTaskSupervisor.activityRelaunchedLocked(token);
-        }
-        Binder.restoreCallingIdentity(origId);
-    }
-
-    @Override
-    public void setRequestedOrientation(IBinder token, int requestedOrientation) {
-        synchronized (mGlobalLock) {
-            ActivityRecord r = ActivityRecord.isInStackLocked(token);
-            if (r == null) {
-                return;
-            }
-            final long origId = Binder.clearCallingIdentity();
-            try {
-                r.setRequestedOrientation(requestedOrientation);
-            } finally {
-                Binder.restoreCallingIdentity(origId);
-            }
-        }
-    }
-
-    @Override
-    public int getRequestedOrientation(IBinder token) {
-        synchronized (mGlobalLock) {
-            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
-            return (r != null)
-                    ? r.getRequestedOrientation() : ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-        }
-    }
-
-    @Override
-    public void setImmersive(IBinder token, boolean immersive) {
-        synchronized (mGlobalLock) {
-            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
-            if (r == null) {
-                throw new IllegalArgumentException();
-            }
-            r.immersive = immersive;
-
-            // update associated state if we're frontmost
-            if (r.isFocusedActivityOnDisplay()) {
-                ProtoLog.d(WM_DEBUG_IMMERSIVE, "Frontmost changed immersion: %s", r);
-                applyUpdateLockStateLocked(r);
-            }
-        }
+    public IActivityClientController getActivityClientController() {
+        return mActivityClientController;
     }
 
     void applyUpdateLockStateLocked(ActivityRecord r) {
@@ -2025,17 +1700,6 @@
     }
 
     @Override
-    public boolean isImmersive(IBinder token) {
-        synchronized (mGlobalLock) {
-            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
-            if (r == null) {
-                throw new IllegalArgumentException();
-            }
-            return r.immersive;
-        }
-    }
-
-    @Override
     public boolean isTopActivityImmersive() {
         enforceNotIsolatedCaller("isTopActivityImmersive");
         synchronized (mGlobalLock) {
@@ -2050,27 +1714,6 @@
     }
 
     @Override
-    public void overridePendingTransition(IBinder token, String packageName,
-            int enterAnim, int exitAnim) {
-        synchronized (mGlobalLock) {
-            ActivityRecord self = ActivityRecord.isInStackLocked(token);
-            if (self == null) {
-                return;
-            }
-
-            final long origId = Binder.clearCallingIdentity();
-
-            if (self.isState(
-                    Task.ActivityState.RESUMED, Task.ActivityState.PAUSING)) {
-                self.mDisplayContent.mAppTransition.overridePendingAppTransition(
-                        packageName, enterAnim, exitAnim, null, null);
-            }
-
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
-
-    @Override
     public int getFrontActivityScreenCompatMode() {
         enforceNotIsolatedCaller("getFrontActivityScreenCompatMode");
         synchronized (mGlobalLock) {
@@ -2125,77 +1768,6 @@
     }
 
     @Override
-    public boolean convertFromTranslucent(IBinder token) {
-        final long origId = Binder.clearCallingIdentity();
-        try {
-            synchronized (mGlobalLock) {
-                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
-                if (r == null) {
-                    return false;
-                }
-                return r.setOccludesParent(true);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
-
-    @Override
-    public boolean convertToTranslucent(IBinder token, Bundle options) {
-        SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle(options);
-        final long origId = Binder.clearCallingIdentity();
-        try {
-            synchronized (mGlobalLock) {
-                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
-                if (r == null) {
-                    return false;
-                }
-                final ActivityRecord under = r.getTask().getActivityBelow(r);
-                if (under != null) {
-                    under.returningOptions = safeOptions != null ? safeOptions.getOptions(r) : null;
-                }
-                return r.setOccludesParent(false);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
-
-    @Override
-    public void notifyActivityDrawn(IBinder token) {
-        if (DEBUG_VISIBILITY) Slog.d(TAG_VISIBILITY, "notifyActivityDrawn: token=" + token);
-        synchronized (mGlobalLock) {
-            ActivityRecord r = mRootWindowContainer.isInAnyTask(token);
-            if (r != null) {
-                r.getRootTask().notifyActivityDrawnLocked(r);
-            }
-        }
-    }
-
-    @Override
-    public void reportActivityFullyDrawn(IBinder token, boolean restoredFromBundle) {
-        synchronized (mGlobalLock) {
-            ActivityRecord r = ActivityRecord.isInStackLocked(token);
-            if (r == null) {
-                return;
-            }
-            r.reportFullyDrawnLocked(restoredFromBundle);
-        }
-    }
-
-    @Override
-    public int getDisplayId(IBinder activityToken) throws RemoteException {
-        synchronized (mGlobalLock) {
-            final Task stack = ActivityRecord.getStackLocked(activityToken);
-            if (stack != null) {
-                final int displayId = stack.getDisplayId();
-                return displayId != INVALID_DISPLAY ? displayId : DEFAULT_DISPLAY;
-            }
-            return DEFAULT_DISPLAY;
-        }
-    }
-
-    @Override
     public RootTaskInfo getFocusedRootTaskInfo() throws RemoteException {
         enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "getFocusedRootTaskInfo()");
         final long ident = Binder.clearCallingIdentity();
@@ -2312,75 +1884,6 @@
     }
 
     @Override
-    public boolean shouldUpRecreateTask(IBinder token, String destAffinity) {
-        synchronized (mGlobalLock) {
-            final ActivityRecord srec = ActivityRecord.forTokenLocked(token);
-            if (srec != null) {
-                return srec.getRootTask().shouldUpRecreateTaskLocked(srec, destAffinity);
-            }
-        }
-        return false;
-    }
-
-    @Override
-    public boolean navigateUpTo(IBinder token, Intent destIntent, int resultCode,
-            Intent resultData) {
-        final ActivityRecord r;
-        synchronized (mGlobalLock) {
-            r = ActivityRecord.isInStackLocked(token);
-            if (r == null) {
-                return false;
-            }
-        }
-
-        // Carefully collect grants without holding lock
-        final NeededUriGrants destGrants = collectGrants(destIntent, r);
-        final NeededUriGrants resultGrants = collectGrants(resultData, r.resultTo);
-
-        synchronized (mGlobalLock) {
-            return r.getRootTask().navigateUpTo(
-                    r, destIntent, destGrants, resultCode, resultData, resultGrants);
-        }
-    }
-
-    /**
-     * Attempts to move a task backwards in z-order (the order of activities within the task is
-     * unchanged).
-     *
-     * There are several possible results of this call:
-     * - if the task is locked, then we will show the lock toast
-     * - if there is a task behind the provided task, then that task is made visible and resumed as
-     * this task is moved to the back
-     * - otherwise, if there are no other tasks in the stack:
-     * - if this task is in the pinned stack, then we remove the stack completely, which will
-     * have the effect of moving the task to the top or bottom of the fullscreen stack
-     * (depending on whether it is visible)
-     * - otherwise, we simply return home and hide this task
-     *
-     * @param token   A reference to the activity we wish to move
-     * @param nonRoot If false then this only works if the activity is the root
-     *                of a task; if true it will work for any activity in a task.
-     * @return Returns true if the move completed, false if not.
-     */
-    @Override
-    public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
-        enforceNotIsolatedCaller("moveActivityTaskToBack");
-        synchronized (mGlobalLock) {
-            final long origId = Binder.clearCallingIdentity();
-            try {
-                int taskId = ActivityRecord.getTaskForActivityLocked(token, !nonRoot);
-                final Task task = mRootWindowContainer.anyTaskForId(taskId);
-                if (task != null) {
-                    return ActivityRecord.getStackLocked(token).moveTaskToBack(task);
-                }
-            } finally {
-                Binder.restoreCallingIdentity(origId);
-            }
-        }
-        return false;
-    }
-
-    @Override
     public Rect getTaskBounds(int taskId) {
         enforceTaskPermission("getTaskBounds()");
         final long ident = Binder.clearCallingIdentity();
@@ -2467,31 +1970,7 @@
         }
     }
 
-    @Override
-    public String getCallingPackage(IBinder token) {
-        synchronized (mGlobalLock) {
-            ActivityRecord r = getCallingRecordLocked(token);
-            return r != null ? r.info.packageName : null;
-        }
-    }
-
-    @Override
-    public ComponentName getCallingActivity(IBinder token) {
-        synchronized (mGlobalLock) {
-            ActivityRecord r = getCallingRecordLocked(token);
-            return r != null ? r.intent.getComponent() : null;
-        }
-    }
-
-    private ActivityRecord getCallingRecordLocked(IBinder token) {
-        ActivityRecord r = ActivityRecord.isInStackLocked(token);
-        if (r == null) {
-            return null;
-        }
-        return r.resultTo;
-    }
-
-    private NeededUriGrants collectGrants(Intent intent, ActivityRecord target) {
+    NeededUriGrants collectGrants(Intent intent, ActivityRecord target) {
         if (target != null) {
             return mUgmInternal.checkGrantUriPermissionFromIntent(intent,
                     Binder.getCallingUid(), target.packageName, target.mUserId);
@@ -2518,25 +1997,6 @@
         }
     }
 
-    @Override
-    public void onBackPressedOnTaskRoot(IBinder token) {
-        synchronized (mGlobalLock) {
-            ActivityRecord r = ActivityRecord.isInStackLocked(token);
-            if (r == null) {
-                return;
-            }
-            Task stack = r.getRootTask();
-            final TaskOrganizerController taskOrgController =
-                    mWindowOrganizerController.mTaskOrganizerController;
-            if (taskOrgController.handleInterceptBackPressedOnTaskRoot(stack)) {
-                // This task is handled by a task organizer that has requested the back pressed
-                // callback
-            } else {
-                moveActivityTaskToBack(token, false /* nonRoot */);
-            }
-        }
-    }
-
     /**
      * TODO: Add mController hook
      */
@@ -2731,13 +2191,6 @@
         }
     }
 
-    @Override
-    public int getTaskForActivity(IBinder token, boolean onlyRoot) {
-        synchronized (mGlobalLock) {
-            return ActivityRecord.getTaskForActivityLocked(token, onlyRoot);
-        }
-    }
-
     List<ActivityManager.RunningTaskInfo> getTasks(int maxNum) {
         return getTasks(maxNum, false /* filterForVisibleRecents */);
     }
@@ -2772,40 +2225,6 @@
     }
 
     @Override
-    public final void finishSubActivity(IBinder token, String resultWho, int requestCode) {
-        synchronized (mGlobalLock) {
-            final long origId = Binder.clearCallingIdentity();
-            try {
-                ActivityRecord r = ActivityRecord.isInStackLocked(token);
-                if (r == null) return;
-
-                final PooledConsumer c = PooledLambda.obtainConsumer(
-                        ActivityRecord::finishIfSubActivity, PooledLambda.__(ActivityRecord.class),
-                        r, resultWho, requestCode);
-                // TODO: This should probably only loop over the task since you need to be in the
-                // same task to return results.
-                r.getRootTask().forAllActivities(c);
-                c.recycle();
-
-                updateOomAdj();
-            } finally {
-                Binder.restoreCallingIdentity(origId);
-            }
-        }
-    }
-
-    @Override
-    public boolean willActivityBeVisible(IBinder token) {
-        synchronized (mGlobalLock) {
-            Task stack = ActivityRecord.getStackLocked(token);
-            if (stack != null) {
-                return stack.willActivityBeVisible(token);
-            }
-            return false;
-        }
-    }
-
-    @Override
     public void moveTaskToRootTask(int taskId, int rootTaskId, boolean toTop) {
         enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "moveTaskToRootTask()");
         synchronized (mGlobalLock) {
@@ -3035,17 +2454,6 @@
     }
 
     @Override
-    public void startLockTaskModeByToken(IBinder token) {
-        synchronized (mGlobalLock) {
-            final ActivityRecord r = ActivityRecord.forTokenLocked(token);
-            if (r == null) {
-                return;
-            }
-            startLockTaskModeLocked(r.getTask(), false /* isSystemCaller */);
-        }
-    }
-
-    @Override
     public void startSystemLockTaskMode(int taskId) {
         enforceTaskPermission("startSystemLockTaskMode");
         // This makes inner call to look as if it was initiated by system.
@@ -3060,18 +2468,13 @@
 
                 // When starting lock task mode the stack must be in front and focused
                 task.getRootTask().moveToFront("startSystemLockTaskMode");
-                startLockTaskModeLocked(task, true /* isSystemCaller */);
+                startLockTaskMode(task, true /* isSystemCaller */);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
     }
 
-    @Override
-    public void stopLockTaskModeByToken(IBinder token) {
-        stopLockTaskModeInternal(token, false /* isSystemCaller */);
-    }
-
     /**
      * This API should be called by SystemUI only when user perform certain action to dismiss
      * lock task mode. We should only dismiss pinned lock task mode in this case.
@@ -3082,8 +2485,8 @@
         stopLockTaskModeInternal(null, true /* isSystemCaller */);
     }
 
-    private void startLockTaskModeLocked(@Nullable Task task, boolean isSystemCaller) {
-        ProtoLog.w(WM_DEBUG_LOCKTASK, "startLockTaskModeLocked: %s", task);
+    void startLockTaskMode(@Nullable Task task, boolean isSystemCaller) {
+        ProtoLog.w(WM_DEBUG_LOCKTASK, "startLockTaskMode: %s", task);
         if (task == null || task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) {
             return;
         }
@@ -3111,7 +2514,7 @@
         }
     }
 
-    private void stopLockTaskModeInternal(@Nullable IBinder token, boolean isSystemCaller) {
+    void stopLockTaskModeInternal(@Nullable IBinder token, boolean isSystemCaller) {
         final int callingUid = Binder.getCallingUid();
         final long ident = Binder.clearCallingIdentity();
         try {
@@ -3163,34 +2566,6 @@
     }
 
     @Override
-    public void setTaskDescription(IBinder token, ActivityManager.TaskDescription td) {
-        synchronized (mGlobalLock) {
-            ActivityRecord r = ActivityRecord.isInStackLocked(token);
-            if (r != null) {
-                r.setTaskDescription(td);
-            }
-        }
-    }
-
-    @Override
-    public Bundle getActivityOptions(IBinder token) {
-        final long origId = Binder.clearCallingIdentity();
-        try {
-            synchronized (mGlobalLock) {
-                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
-                if (r != null) {
-                    final ActivityOptions activityOptions = r.takeOptionsLocked(
-                            true /* fromClient */);
-                    return activityOptions == null ? null : activityOptions.toBundle();
-                }
-                return null;
-            }
-        } finally {
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
-
-    @Override
     public List<IBinder> getAppTasks(String callingPackage) {
         int callingUid = Binder.getCallingUid();
         assertPackageMatchesCallingUid(callingPackage);
@@ -3220,39 +2595,9 @@
     }
 
     @Override
-    public boolean isTopOfTask(IBinder token) {
-        synchronized (mGlobalLock) {
-            ActivityRecord r = ActivityRecord.isInStackLocked(token);
-            return r != null && r.getTask().getTopNonFinishingActivity() == r;
-        }
-    }
-
-    @Override
-    public void notifyLaunchTaskBehindComplete(IBinder token) {
-        mTaskSupervisor.scheduleLaunchTaskBehindComplete(token);
-    }
-
-    @Override
-    public void notifyEnterAnimationComplete(IBinder token) {
-        mH.post(() -> {
-            synchronized (mGlobalLock) {
-                ActivityRecord r = ActivityRecord.forTokenLocked(token);
-                if (r != null && r.attachedToProcess()) {
-                    try {
-                        r.app.getThread().scheduleEnterAnimationComplete(r.appToken);
-                    } catch (RemoteException e) {
-                    }
-                }
-            }
-
-        });
-    }
-
-    /** Called from an app when assist data is ready. */
-    @Override
-    public void reportAssistContextExtras(IBinder token, Bundle extras, AssistStructure structure,
-            AssistContent content, Uri referrer) {
-        PendingAssistExtras pae = (PendingAssistExtras) token;
+    public void reportAssistContextExtras(IBinder assistToken, Bundle extras,
+            AssistStructure structure, AssistContent content, Uri referrer) {
+        final PendingAssistExtras pae = (PendingAssistExtras) assistToken;
         synchronized (pae) {
             pae.result = extras;
             pae.structure = structure;
@@ -3440,23 +2785,6 @@
     }
 
     @Override
-    public boolean releaseActivityInstance(IBinder token) {
-        synchronized (mGlobalLock) {
-            final long origId = Binder.clearCallingIdentity();
-            try {
-                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
-                if (r == null || !r.isDestroyable()) {
-                    return false;
-                }
-                r.destroyImmediately("app-req");
-                return r.isState(DESTROYING, DESTROYED);
-            } finally {
-                Binder.restoreCallingIdentity(origId);
-            }
-        }
-    }
-
-    @Override
     public void releaseSomeActivities(IApplicationThread appInt) {
         synchronized (mGlobalLock) {
             final long origId = Binder.clearCallingIdentity();
@@ -3540,49 +2868,6 @@
         }
     }
 
-    @Override
-    public void toggleFreeformWindowingMode(IBinder token) {
-        synchronized (mGlobalLock) {
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                final ActivityRecord r = ActivityRecord.forTokenLocked(token);
-                if (r == null) {
-                    throw new IllegalArgumentException(
-                            "toggleFreeformWindowingMode: No activity record matching token="
-                                    + token);
-                }
-
-                final Task stack = r.getRootTask();
-                if (stack == null) {
-                    throw new IllegalStateException("toggleFreeformWindowingMode: the activity "
-                            + "doesn't have a stack");
-                }
-
-                if (!stack.inFreeformWindowingMode()
-                        && stack.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
-                    throw new IllegalStateException("toggleFreeformWindowingMode: You can only "
-                            + "toggle between fullscreen and freeform.");
-                }
-
-                if (stack.inFreeformWindowingMode()) {
-                    stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
-                } else if (!mSizeCompatFreeform && r.inSizeCompatMode()) {
-                    throw new IllegalStateException("Size-compat windows are currently not"
-                            + "freeform-enabled");
-                } else if (stack.getParent().inFreeformWindowingMode()) {
-                    // If the window is on a freeform display, set it to undefined. It will be
-                    // resolved to freeform and it can adjust windowing mode when the display mode
-                    // changes in runtime.
-                    stack.setWindowingMode(WINDOWING_MODE_UNDEFINED);
-                } else {
-                    stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
-                }
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
-        }
-    }
-
     /** Sets the task stack listener that gets callbacks when a task stack changes. */
     @Override
     public void registerTaskStackListener(ITaskStackListener listener) {
@@ -3884,42 +3169,6 @@
         return DevicePolicyCache.getInstance().isScreenCaptureAllowed(userId, false);
     }
 
-    @Override
-    public boolean showAssistFromActivity(IBinder token, Bundle args) {
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            synchronized (mGlobalLock) {
-                ActivityRecord caller = ActivityRecord.forTokenLocked(token);
-                ActivityRecord top = getTopDisplayFocusedRootTask().getTopNonFinishingActivity();
-                if (top != caller) {
-                    Slog.w(TAG, "showAssistFromActivity failed: caller " + caller
-                            + " is not current top " + top);
-                    return false;
-                }
-                if (!top.nowVisible) {
-                    Slog.w(TAG, "showAssistFromActivity failed: caller " + caller
-                            + " is not visible");
-                    return false;
-                }
-            }
-            return mAssistUtils.showSessionForActiveService(args, SHOW_SOURCE_APPLICATION, null,
-                    token);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    @Override
-    public boolean isRootVoiceInteraction(IBinder token) {
-        synchronized (mGlobalLock) {
-            ActivityRecord r = ActivityRecord.isInStackLocked(token);
-            if (r == null) {
-                return false;
-            }
-            return r.rootVoiceInteraction;
-        }
-    }
-
     private void onLocalVoiceInteractionStartedLocked(IBinder activity,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) {
         ActivityRecord activityToCallback = ActivityRecord.forTokenLocked(activity);
@@ -4001,17 +3250,6 @@
     }
 
     @Override
-    public void showLockTaskEscapeMessage(IBinder token) {
-        synchronized (mGlobalLock) {
-            final ActivityRecord r = ActivityRecord.forTokenLocked(token);
-            if (r == null) {
-                return;
-            }
-            getLockTaskController().showLockTaskToast();
-        }
-    }
-
-    @Override
     public void keyguardGoingAway(int flags) {
         enforceNotIsolatedCaller("keyguardGoingAway");
         final long token = Binder.clearCallingIdentity();
@@ -4025,22 +3263,6 @@
     }
 
     @Override
-    public void reportSizeConfigurations(IBinder token, int[] horizontalSizeConfiguration,
-            int[] verticalSizeConfigurations, int[] smallestSizeConfigurations) {
-        ProtoLog.v(WM_DEBUG_CONFIGURATION, "Report configuration: %s %s %s",
-                token, Arrays.toString(horizontalSizeConfiguration),
-                Arrays.toString(verticalSizeConfigurations));
-        synchronized (mGlobalLock) {
-            ActivityRecord record = ActivityRecord.isInStackLocked(token);
-            if (record == null) {
-                return;
-            }
-            record.setSizeConfigurations(horizontalSizeConfiguration,
-                    verticalSizeConfigurations, smallestSizeConfigurations);
-        }
-    }
-
-    @Override
     public void suppressResizeConfigChanges(boolean suppress) throws RemoteException {
         mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_TASKS,
                 "suppressResizeConfigChanges()");
@@ -4138,100 +3360,6 @@
         return true;
     }
 
-    @Override
-    public boolean enterPictureInPictureMode(IBinder token, final PictureInPictureParams params) {
-        final long origId = Binder.clearCallingIdentity();
-        try {
-            synchronized (mGlobalLock) {
-                final ActivityRecord r = ensureValidPictureInPictureActivityParamsLocked(
-                        "enterPictureInPictureMode", token, params);
-                return enterPictureInPictureMode(r, params);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
-
-    @Override
-    public void setPictureInPictureParams(IBinder token, final PictureInPictureParams params) {
-        final long origId = Binder.clearCallingIdentity();
-        try {
-            synchronized (mGlobalLock) {
-                final ActivityRecord r = ensureValidPictureInPictureActivityParamsLocked(
-                        "setPictureInPictureParams", token, params);
-
-                // Only update the saved args from the args that are set
-                r.setPictureInPictureParams(params);
-                if (r.inPinnedWindowingMode()) {
-                    // If the activity is already in picture-in-picture, update the pinned stack now
-                    // if it is not already expanding to fullscreen. Otherwise, the arguments will
-                    // be used the next time the activity enters PiP
-                    final Task stack = r.getRootTask();
-                    stack.setPictureInPictureAspectRatio(
-                            r.pictureInPictureArgs.getAspectRatio());
-                    stack.setPictureInPictureActions(r.pictureInPictureArgs.getActions());
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(origId);
-        }
-    }
-
-    /**
-     * Checks the state of the system and the activity associated with the given {@param token} to
-     * verify that picture-in-picture is supported for that activity.
-     *
-     * @return the activity record for the given {@param token} if all the checks pass.
-     */
-    private ActivityRecord ensureValidPictureInPictureActivityParamsLocked(String caller,
-            IBinder token, PictureInPictureParams params) {
-        if (!mSupportsPictureInPicture) {
-            throw new IllegalStateException(caller
-                    + ": Device doesn't support picture-in-picture mode.");
-        }
-
-        final ActivityRecord r = ActivityRecord.forTokenLocked(token);
-        if (r == null) {
-            throw new IllegalStateException(caller
-                    + ": Can't find activity for token=" + token);
-        }
-
-        if (!r.supportsPictureInPicture()) {
-            throw new IllegalStateException(caller
-                    + ": Current activity does not support picture-in-picture.");
-        }
-
-        if (params.hasSetAspectRatio()
-                && !mWindowManager.isValidPictureInPictureAspectRatio(
-                r.mDisplayContent, params.getAspectRatio())) {
-            final float minAspectRatio = mContext.getResources().getFloat(
-                    com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
-            final float maxAspectRatio = mContext.getResources().getFloat(
-                    com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio);
-            throw new IllegalArgumentException(String.format(caller
-                            + ": Aspect ratio is too extreme (must be between %f and %f).",
-                    minAspectRatio, maxAspectRatio));
-        }
-
-        // Truncate the number of actions if necessary
-        params.truncateActions(ActivityTaskManager.getMaxNumPictureInPictureActions(mContext));
-
-        return r;
-    }
-
-    @Override
-    public IBinder getUriPermissionOwnerForActivity(IBinder activityToken) {
-        enforceNotIsolatedCaller("getUriPermissionOwnerForActivity");
-        synchronized (mGlobalLock) {
-            ActivityRecord r = ActivityRecord.isInStackLocked(activityToken);
-            if (r == null) {
-                throw new IllegalArgumentException("Activity does not exist; token="
-                        + activityToken);
-            }
-            return r.getUriPermissionsLocked().getExternalToken();
-        }
-    }
-
     // TODO(b/149338177): remove when CTS no-longer requires it
     @Override
     public void resizePrimarySplitScreen(Rect dockedBounds, Rect tempDockedTaskBounds,
@@ -4304,73 +3432,6 @@
     }
 
     @Override
-    public int setVrMode(IBinder token, boolean enabled, ComponentName packageName) {
-        enforceSystemHasVrFeature();
-
-        final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
-
-        ActivityRecord r;
-        synchronized (mGlobalLock) {
-            r = ActivityRecord.isInStackLocked(token);
-        }
-
-        if (r == null) {
-            throw new IllegalArgumentException();
-        }
-
-        int err;
-        if ((err = vrService.hasVrPackage(packageName, r.mUserId)) !=
-                VrManagerInternal.NO_ERROR) {
-            return err;
-        }
-
-        // Clear the binder calling uid since this path may call moveToTask().
-        final long callingId = Binder.clearCallingIdentity();
-        try {
-            synchronized (mGlobalLock) {
-                r.requestedVrComponent = (enabled) ? packageName : null;
-
-                // Update associated state if this activity is currently focused
-                if (r.isFocusedActivityOnDisplay()) {
-                    applyUpdateVrModeLocked(r);
-                }
-                return 0;
-            }
-        } finally {
-            Binder.restoreCallingIdentity(callingId);
-        }
-    }
-
-    @Override
-    public void startLocalVoiceInteraction(IBinder callingActivity, Bundle options) {
-        Slog.i(TAG, "Activity tried to startLocalVoiceInteraction");
-        synchronized (mGlobalLock) {
-            ActivityRecord activity = getTopDisplayFocusedRootTask().getTopNonFinishingActivity();
-            if (ActivityRecord.forTokenLocked(callingActivity) != activity) {
-                throw new SecurityException("Only focused activity can call startVoiceInteraction");
-            }
-            if (mRunningVoice != null || activity.getTask().voiceSession != null
-                    || activity.voiceSession != null) {
-                Slog.w(TAG, "Already in a voice interaction, cannot start new voice interaction");
-                return;
-            }
-            if (activity.pendingVoiceInteractionStart) {
-                Slog.w(TAG, "Pending start of voice interaction already.");
-                return;
-            }
-            activity.pendingVoiceInteractionStart = true;
-        }
-        LocalServices.getService(VoiceInteractionManagerInternal.class)
-                .startLocalVoiceInteraction(callingActivity, options);
-    }
-
-    @Override
-    public void stopLocalVoiceInteraction(IBinder callingActivity) {
-        LocalServices.getService(VoiceInteractionManagerInternal.class)
-                .stopLocalVoiceInteraction(callingActivity);
-    }
-
-    @Override
     public boolean supportsLocalVoiceInteraction() {
         return LocalServices.getService(VoiceInteractionManagerInternal.class)
                 .supportsLocalVoiceInteraction();
@@ -4474,24 +3535,6 @@
     }
 
     @Override
-    public void setDisablePreviewScreenshots(IBinder token, boolean disable) {
-        synchronized (mGlobalLock) {
-            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
-            if (r == null) {
-                Slog.w(TAG, "setDisablePreviewScreenshots: Unable to find activity for token="
-                        + token);
-                return;
-            }
-            final long origId = Binder.clearCallingIdentity();
-            try {
-                r.setDisablePreviewScreenshots(disable);
-            } finally {
-                Binder.restoreCallingIdentity(origId);
-            }
-        }
-    }
-
-    @Override
     public void invalidateHomeTaskSnapshot(IBinder token) {
         synchronized (mGlobalLock) {
             final ActivityRecord r = ActivityRecord.isInStackLocked(token);
@@ -4532,91 +3575,6 @@
     }
 
     @Override
-    public void setShowWhenLocked(IBinder token, boolean showWhenLocked) {
-        synchronized (mGlobalLock) {
-            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
-            if (r == null) {
-                return;
-            }
-            final long origId = Binder.clearCallingIdentity();
-            try {
-                r.setShowWhenLocked(showWhenLocked);
-            } finally {
-                Binder.restoreCallingIdentity(origId);
-            }
-        }
-    }
-
-    @Override
-    public void setInheritShowWhenLocked(IBinder token, boolean inheritShowWhenLocked) {
-        synchronized (mGlobalLock) {
-            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
-            if (r == null) {
-                return;
-            }
-            final long origId = Binder.clearCallingIdentity();
-            try {
-                r.setInheritShowWhenLocked(inheritShowWhenLocked);
-            } finally {
-                Binder.restoreCallingIdentity(origId);
-            }
-        }
-    }
-
-    @Override
-    public void setTurnScreenOn(IBinder token, boolean turnScreenOn) {
-        synchronized (mGlobalLock) {
-            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
-            if (r == null) {
-                return;
-            }
-            final long origId = Binder.clearCallingIdentity();
-            try {
-                r.setTurnScreenOn(turnScreenOn);
-            } finally {
-                Binder.restoreCallingIdentity(origId);
-            }
-        }
-    }
-
-    @Override
-    public void registerRemoteAnimations(IBinder token, RemoteAnimationDefinition definition) {
-        mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
-                "registerRemoteAnimations");
-        definition.setCallingPidUid(Binder.getCallingPid(), Binder.getCallingUid());
-        synchronized (mGlobalLock) {
-            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
-            if (r == null) {
-                return;
-            }
-            final long origId = Binder.clearCallingIdentity();
-            try {
-                r.registerRemoteAnimations(definition);
-            } finally {
-                Binder.restoreCallingIdentity(origId);
-            }
-        }
-    }
-
-    @Override
-    public void unregisterRemoteAnimations(IBinder token) {
-        mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
-                "unregisterRemoteAnimations");
-        synchronized (mGlobalLock) {
-            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
-            if (r == null) {
-                return;
-            }
-            final long origId = Binder.clearCallingIdentity();
-            try {
-                r.unregisterRemoteAnimations();
-            } finally {
-                Binder.restoreCallingIdentity(origId);
-            }
-        }
-    }
-
-    @Override
     public void registerRemoteAnimationForNextActivityStart(String packageName,
             RemoteAnimationAdapter adapter) {
         mAmInternal.enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
@@ -4743,7 +3701,7 @@
         return mVrController.shouldDisableNonVrUiLocked();
     }
 
-    private void applyUpdateVrModeLocked(ActivityRecord r) {
+    void applyUpdateVrModeLocked(ActivityRecord r) {
         // VR apps are expected to run in a main display. If an app is turning on VR for
         // itself, but isn't on the main display, then move it there before enabling VR Mode.
         if (r.requestedVrComponent != null && r.getDisplayId() != DEFAULT_DISPLAY) {
@@ -5097,7 +4055,7 @@
         return mAmInternal.getCurrentUserId();
     }
 
-    private void enforceNotIsolatedCaller(String caller) {
+    static void enforceNotIsolatedCaller(String caller) {
         if (UserHandle.isIsolated(Binder.getCallingUid())) {
             throw new SecurityException("Isolated process not allowed to call " + caller);
         }
diff --git a/services/core/java/com/android/server/wm/AppWarnings.java b/services/core/java/com/android/server/wm/AppWarnings.java
index 55200b5..994f079 100644
--- a/services/core/java/com/android/server/wm/AppWarnings.java
+++ b/services/core/java/com/android/server/wm/AppWarnings.java
@@ -31,16 +31,12 @@
 import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
-import com.android.internal.util.FastXmlSerializer;
-
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
-import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -541,15 +537,7 @@
                             if ("package".equals(tagName)) {
                                 final String name = parser.getAttributeValue(null, "name");
                                 if (name != null) {
-                                    final String flags = parser.getAttributeValue(
-                                            null, "flags");
-                                    int flagsInt = 0;
-                                    if (flags != null) {
-                                        try {
-                                            flagsInt = Integer.parseInt(flags);
-                                        } catch (NumberFormatException e) {
-                                        }
-                                    }
+                                    int flagsInt = parser.getAttributeInt(null, "flags", 0);
                                     mPackageFlags.put(name, flagsInt);
                                 }
                             }
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainerListener.java b/services/core/java/com/android/server/wm/ConfigurationContainerListener.java
index 3d84e17..ce6b7f9 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainerListener.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainerListener.java
@@ -23,7 +23,7 @@
  */
 public interface ConfigurationContainerListener {
 
-    /** {@see ConfigurationContainer#onRequestedOverrideConfigurationChanged} */
+    /** @see ConfigurationContainer#onRequestedOverrideConfigurationChanged */
     default void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {}
 
     /** Called when new merged override configuration is reported. */
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index cd3f322..15483cb 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -174,6 +174,13 @@
             return false;
         }
 
+        if (mDisplayContent.mFocusedApp != null) {
+            // We record the last focused TDA that respects orientation request, check if this
+            // change may affect it.
+            mDisplayContent.onLastFocusedTaskDisplayAreaChanged(
+                    mDisplayContent.mFocusedApp.getDisplayArea());
+        }
+
         // The orientation request from this DA may now be respected.
         if (!ignoreOrientationRequest) {
             return mDisplayContent.updateOrientation();
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
index 7573e92..d4b319a 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
@@ -35,6 +35,7 @@
 import static com.android.server.wm.DisplayAreaPolicyBuilder.HierarchyBuilder;
 
 import android.content.res.Resources;
+import android.os.Bundle;
 import android.text.TextUtils;
 
 import java.util.ArrayList;
@@ -71,6 +72,10 @@
      */
     public abstract void addWindow(WindowToken token);
 
+    /** Gets the {@link DisplayArea} which a {@link WindowToken} is about to be attached to. */
+    public abstract DisplayArea.Tokens getDisplayAreaForWindowToken(int type, Bundle options,
+            boolean ownerCanManageAppTokens, boolean roundedCornerOverlay);
+
     /**
      * Gets the set of {@link DisplayArea} that are created for the given feature to apply to.
      */
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
index bc32206..c8fadf6 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
@@ -24,6 +24,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
 import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER;
 import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
+import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_LAST;
 
 import android.annotation.Nullable;
 import android.os.Bundle;
@@ -136,12 +137,12 @@
     private ArrayList<HierarchyBuilder> mDisplayAreaGroupHierarchyBuilders = new ArrayList<>();
 
     /**
-     * When a window is created, the policy will use this function to select the
-     * {@link RootDisplayArea} to place that window in. The selected root can be either the one of
-     * the {@link #mRootHierarchyBuilder} or the one of any of the
+     * When a window is created, the policy will use this function, which takes window type and
+     * options, to select the {@link RootDisplayArea} to place that window in. The selected root
+     * can be either the one of the {@link #mRootHierarchyBuilder} or the one of any of the
      * {@link #mDisplayAreaGroupHierarchyBuilders}.
      **/
-    @Nullable private BiFunction<WindowToken, Bundle, RootDisplayArea> mSelectRootForWindowFunc;
+    @Nullable private BiFunction<Integer, Bundle, RootDisplayArea> mSelectRootForWindowFunc;
 
     /** Defines the root hierarchy for the whole logical display. */
     DisplayAreaPolicyBuilder setRootHierarchy(HierarchyBuilder rootHierarchyBuilder) {
@@ -161,37 +162,53 @@
 
     /** The policy will use this function to find the root to place windows in. */
     DisplayAreaPolicyBuilder setSelectRootForWindowFunc(
-            BiFunction<WindowToken, Bundle, RootDisplayArea> selectRootForWindowFunc) {
+            BiFunction<Integer, Bundle, RootDisplayArea> selectRootForWindowFunc) {
         mSelectRootForWindowFunc = selectRootForWindowFunc;
         return this;
     }
 
-    /** Makes sure the setting meets the requirement. */
+    /**
+     * Makes sure the setting meets the requirement:
+     * 1. {@link mRootHierarchyBuilder} must be set.
+     * 2. {@link RootDisplayArea} and {@link TaskDisplayArea} must have unique ids.
+     * 3. {@link Feature} below the same {@link RootDisplayArea} must have unique ids.
+     * 4. There must be exactly one {@link HierarchyBuilder} that contains the IME container.
+     * 5. There must be exactly one {@link HierarchyBuilder} that contains the default
+     *    {@link TaskDisplayArea} with id {@link FEATURE_DEFAULT_TASK_CONTAINER}.
+     * 6. None of the ids is greater than {@link FEATURE_VENDOR_LAST}.
+     */
     private void validate() {
         if (mRootHierarchyBuilder == null) {
             throw new IllegalStateException("Root must be set for the display area policy.");
         }
 
-        final Set<Integer> rootIdSet = new ArraySet<>();
-        rootIdSet.add(mRootHierarchyBuilder.mRoot.mFeatureId);
+        final Set<Integer> uniqueIdSet = new ArraySet<>();
+        final Set<Integer> allIdSet = new ArraySet<>();
+        validateIds(mRootHierarchyBuilder, uniqueIdSet, allIdSet);
         boolean containsImeContainer = mRootHierarchyBuilder.mImeContainer != null;
         boolean containsDefaultTda = containsDefaultTaskDisplayArea(mRootHierarchyBuilder);
         for (int i = 0; i < mDisplayAreaGroupHierarchyBuilders.size(); i++) {
             HierarchyBuilder hierarchyBuilder = mDisplayAreaGroupHierarchyBuilders.get(i);
-            if (!rootIdSet.add(hierarchyBuilder.mRoot.mFeatureId)) {
-                throw new IllegalStateException("There should not be two RootDisplayAreas with id "
-                        + hierarchyBuilder.mRoot.mFeatureId);
-            }
+            validateIds(hierarchyBuilder, uniqueIdSet, allIdSet);
+
             if (hierarchyBuilder.mTaskDisplayAreas.isEmpty()) {
                 throw new IllegalStateException(
                         "DisplayAreaGroup must contain at least one TaskDisplayArea.");
             }
 
-            containsImeContainer = containsImeContainer || hierarchyBuilder.mImeContainer != null;
+            if (containsImeContainer) {
+                if (hierarchyBuilder.mImeContainer != null) {
+                    throw new IllegalStateException(
+                            "Only one DisplayArea hierarchy can contain the IME container");
+                }
+            } else {
+                containsImeContainer = hierarchyBuilder.mImeContainer != null;
+            }
+
             if (containsDefaultTda) {
                 if (containsDefaultTaskDisplayArea(hierarchyBuilder)) {
                     throw new IllegalStateException("Only one TaskDisplayArea can have the feature "
-                            + "of FEATURE_DEFAULT_TASK_CONTAINER");
+                            + "id of FEATURE_DEFAULT_TASK_CONTAINER");
                 }
             } else {
                 containsDefaultTda = containsDefaultTaskDisplayArea(hierarchyBuilder);
@@ -203,7 +220,8 @@
         }
 
         if (!containsDefaultTda) {
-            throw new IllegalStateException("There must be a default TaskDisplayArea.");
+            throw new IllegalStateException("There must be a default TaskDisplayArea with id of "
+                    + "FEATURE_DEFAULT_TASK_CONTAINER.");
         }
     }
 
@@ -218,6 +236,67 @@
         return false;
     }
 
+    /**
+     * Makes sure that ids meet requirement.
+     * {@link RootDisplayArea} and {@link TaskDisplayArea} must have unique ids.
+     * {@link Feature} below the same {@link RootDisplayArea} must have unique ids, but
+     * {@link Feature} below different {@link RootDisplayArea} can have the same id so that we can
+     * organize them together.
+     * None of the ids is greater than {@link FEATURE_VENDOR_LAST}
+     *
+     * @param uniqueIdSet ids of {@link RootDisplayArea} and {@link TaskDisplayArea} that must be
+     *                    unique,
+     * @param allIdSet ids of {@link RootDisplayArea}, {@link TaskDisplayArea} and {@link Feature}.
+     */
+    private static void validateIds(HierarchyBuilder displayAreaHierarchy,
+            Set<Integer> uniqueIdSet, Set<Integer> allIdSet) {
+        // Root must have unique id.
+        final int rootId = displayAreaHierarchy.mRoot.mFeatureId;
+        if (!allIdSet.add(rootId) || !uniqueIdSet.add(rootId)) {
+            throw new IllegalStateException(
+                    "RootDisplayArea must have unique id, but id=" + rootId + " is not unique.");
+        }
+        if (rootId > FEATURE_VENDOR_LAST) {
+            throw new IllegalStateException(
+                    "RootDisplayArea should not have an id greater than FEATURE_VENDOR_LAST.");
+        }
+
+        // TDAs must have unique id.
+        for (int i = 0; i < displayAreaHierarchy.mTaskDisplayAreas.size(); i++) {
+            final int taskDisplayAreaId = displayAreaHierarchy.mTaskDisplayAreas.get(i).mFeatureId;
+            if (!allIdSet.add(taskDisplayAreaId) || !uniqueIdSet.add(taskDisplayAreaId)) {
+                throw new IllegalStateException("TaskDisplayArea must have unique id, but id="
+                        + taskDisplayAreaId + " is not unique.");
+            }
+            if (taskDisplayAreaId > FEATURE_VENDOR_LAST) {
+                throw new IllegalStateException("TaskDisplayArea declared in the policy should not"
+                        + "have an id greater than FEATURE_VENDOR_LAST.");
+            }
+        }
+
+        // Features below the same root must have unique ids.
+        final Set<Integer> featureIdSet = new ArraySet<>();
+        for (int i = 0; i < displayAreaHierarchy.mFeatures.size(); i++) {
+            final int featureId = displayAreaHierarchy.mFeatures.get(i).getId();
+            if (uniqueIdSet.contains(featureId)) {
+                throw new IllegalStateException("Feature must not have same id with any "
+                        + "RootDisplayArea or TaskDisplayArea, but id=" + featureId + " is used");
+            }
+            if (!featureIdSet.add(featureId)) {
+                throw new IllegalStateException("Feature below the same root must have unique id, "
+                        + "but id=" + featureId + " is not unique.");
+            }
+            if (featureId > FEATURE_VENDOR_LAST) {
+                throw new IllegalStateException(
+                        "Feature should not have an id greater than FEATURE_VENDOR_LAST.");
+            }
+        }
+
+        // Features below different roots can have the same id so that we can organize them
+        // together.
+        allIdSet.addAll(featureIdSet);
+    }
+
     Result build(WindowManagerService wmService) {
         validate();
 
@@ -576,19 +655,19 @@
 
     static class Result extends DisplayAreaPolicy {
         final List<RootDisplayArea> mDisplayAreaGroupRoots;
-        final BiFunction<WindowToken, Bundle, RootDisplayArea> mSelectRootForWindowFunc;
+        final BiFunction<Integer, Bundle, RootDisplayArea> mSelectRootForWindowFunc;
         private final TaskDisplayArea mDefaultTaskDisplayArea;
 
         Result(WindowManagerService wmService, RootDisplayArea root,
                 List<RootDisplayArea> displayAreaGroupRoots,
-                @Nullable BiFunction<WindowToken, Bundle, RootDisplayArea>
+                @Nullable BiFunction<Integer, Bundle, RootDisplayArea>
                         selectRootForWindowFunc) {
             super(wmService, root);
             mDisplayAreaGroupRoots = Collections.unmodifiableList(displayAreaGroupRoots);
             mSelectRootForWindowFunc = selectRootForWindowFunc == null
                     // Always return the highest level root of the logical display when the func is
                     // not specified.
-                    ? (window, options) -> mRoot
+                    ? (type, options) -> mRoot
                     : selectRootForWindowFunc;
 
             // Cache the default TaskDisplayArea for quick access.
@@ -610,7 +689,8 @@
 
         @VisibleForTesting
         DisplayArea.Tokens findAreaForToken(WindowToken token) {
-            return mSelectRootForWindowFunc.apply(token, token.mOptions).findAreaForToken(token);
+            return mSelectRootForWindowFunc.apply(token.windowType, token.mOptions)
+                    .findAreaForToken(token);
         }
 
         @VisibleForTesting
@@ -648,6 +728,13 @@
         public TaskDisplayArea getDefaultTaskDisplayArea() {
             return mDefaultTaskDisplayArea;
         }
+
+        @Override
+        public DisplayArea.Tokens getDisplayAreaForWindowToken(int type, Bundle options,
+                boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) {
+            return mSelectRootForWindowFunc.apply(type, options).findAreaForToken(type,
+                    ownerCanManageAppTokens, roundedCornerOverlay);
+        }
     }
 
     static class PendingArea {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 1d2cd0a..e88f8e3 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -165,6 +165,7 @@
 import android.hardware.display.DisplayManagerInternal;
 import android.metrics.LogMaker;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.Debug;
 import android.os.Handler;
 import android.os.IBinder;
@@ -488,8 +489,13 @@
      */
     ActivityRecord mFocusedApp = null;
 
-    /** The last focused {@link TaskDisplayArea} on this display. */
-    private TaskDisplayArea mLastFocusedTaskDisplayArea = null;
+    /**
+     * We only respect the orientation request from apps below this {@link TaskDisplayArea}.
+     * It is the last focused {@link TaskDisplayArea} on this display that handles orientation
+     * request.
+     */
+    @Nullable
+    private TaskDisplayArea mOrientationRequestingTaskDisplayArea = null;
 
     /**
      * The launching activity which is using fixed rotation transformation.
@@ -995,7 +1001,7 @@
         getPendingTransaction().apply();
 
         // Setup the policy and build the display area hierarchy.
-        mDisplayAreaPolicy = mWmService.mDisplayAreaPolicyProvider.instantiate(
+        mDisplayAreaPolicy = mWmService.getDisplayAreaPolicyProvider().instantiate(
                 mWmService, this /* content */, this /* root */, mImeWindowsContainers);
 
         // Sets the display content for the children.
@@ -3325,7 +3331,7 @@
 
             // Called even if the focused app is not changed in case the app is moved to a different
             // TaskDisplayArea.
-            setLastFocusedTaskDisplayArea(newFocus.getDisplayArea());
+            onLastFocusedTaskDisplayAreaChanged(newFocus.getDisplayArea());
         }
         if (mFocusedApp == newFocus) {
             return false;
@@ -3339,16 +3345,27 @@
     }
 
     /** Called when the focused {@link TaskDisplayArea} on this display may have changed. */
-    @VisibleForTesting
-    void setLastFocusedTaskDisplayArea(@Nullable TaskDisplayArea taskDisplayArea) {
-        if (taskDisplayArea != null) {
-            mLastFocusedTaskDisplayArea = taskDisplayArea;
+    void onLastFocusedTaskDisplayAreaChanged(@Nullable TaskDisplayArea taskDisplayArea) {
+        // Only record the TaskDisplayArea that handles orientation request.
+        if (taskDisplayArea != null && taskDisplayArea.handlesOrientationChangeFromDescendant()) {
+            mOrientationRequestingTaskDisplayArea = taskDisplayArea;
+            return;
+        }
+
+        // If the previous TDA no longer handles orientation request, clear it.
+        if (mOrientationRequestingTaskDisplayArea != null
+                && !mOrientationRequestingTaskDisplayArea
+                .handlesOrientationChangeFromDescendant()) {
+            mOrientationRequestingTaskDisplayArea = null;
         }
     }
 
-    /** Gets the last focused {@link TaskDisplayArea} on this display. */
-    TaskDisplayArea getLastFocusedTaskDisplayArea() {
-        return mLastFocusedTaskDisplayArea;
+    /**
+     * Gets the {@link TaskDisplayArea} that we respect orientation requests from apps below it.
+     */
+    @Nullable
+    TaskDisplayArea getOrientationRequestingTaskDisplayArea() {
+        return mOrientationRequestingTaskDisplayArea;
     }
 
     /** Updates the layer assignment of windows on this display. */
@@ -4775,7 +4792,6 @@
         return getWindowContainers().getSurfaceControl();
     }
 
-    @VisibleForTesting
     DisplayArea.Tokens getImeContainer() {
         return mImeWindowsContainers;
     }
@@ -5683,6 +5699,9 @@
 
         @Override
         public boolean getRequestedVisibility(@InternalInsetsType int type) {
+            if (type == ITYPE_IME) {
+                return getInsetsStateController().getImeSourceProvider().isImeShowing();
+            }
             return mRequestedInsetsState.getSourceOrDefaultVisibility(type);
         }
 
@@ -5728,4 +5747,20 @@
     MagnificationSpec getMagnificationSpec() {
         return mMagnificationSpec;
     }
+
+    DisplayArea getAreaForWindowToken(int windowType, Bundle options,
+            boolean ownerCanManageAppToken, boolean roundedCornerOverlay) {
+        // TODO(b/159767464): figure out how to find an appropriate TDA.
+        if (windowType >= FIRST_APPLICATION_WINDOW && windowType <= LAST_APPLICATION_WINDOW) {
+            return getDefaultTaskDisplayArea();
+        }
+        // Return IME container here because it could be in one of sub RootDisplayAreas depending on
+        // the focused edit text. Also, the RootDisplayArea choosing strategy is implemented by
+        // the server side, but not mSelectRootForWindowFunc customized by OEM.
+        if (windowType == TYPE_INPUT_METHOD || windowType == TYPE_INPUT_METHOD_DIALOG) {
+            return getImeContainer();
+        }
+        return mDisplayAreaPolicy.getDisplayAreaForWindowToken(windowType, options,
+                ownerCanManageAppToken, roundedCornerOverlay);
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 2ddd001..cd02e00 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1427,7 +1427,7 @@
                 : (task != null ? task.getBounds() : null);
         final InsetsState state =
                 mDisplayContent.getInsetsPolicy().getInsetsForWindowMetrics(attrs);
-        computeWindowBounds(attrs, state, outFrame);
+        computeWindowBounds(attrs, state, windowToken, outFrame);
         if (taskBounds != null) {
             outFrame.intersect(taskBounds);
         }
@@ -1714,11 +1714,11 @@
     }
 
     private void computeWindowBounds(WindowManager.LayoutParams attrs, InsetsState state,
-            Rect outBounds) {
+            @Nullable WindowToken windowToken, Rect outBounds) {
         final @InsetsType int typesToFit = attrs.getFitInsetsTypes();
         final @InsetsSide int sidesToFit = attrs.getFitInsetsSides();
         final ArraySet<Integer> types = InsetsState.toInternalType(typesToFit);
-        final Rect dfu = state.getDisplayFrame();
+        final Rect df = windowToken != null ? windowToken.getBounds() : state.getDisplayFrame();
         Insets insets = Insets.of(0, 0, 0, 0);
         for (int i = types.size() - 1; i >= 0; i--) {
             final InsetsSource source = state.peekSource(types.valueAt(i));
@@ -1726,13 +1726,13 @@
                 continue;
             }
             insets = Insets.max(insets, source.calculateInsets(
-                    dfu, attrs.isFitInsetsIgnoringVisibility()));
+                    df, attrs.isFitInsetsIgnoringVisibility()));
         }
         final int left = (sidesToFit & Side.LEFT) != 0 ? insets.left : 0;
         final int top = (sidesToFit & Side.TOP) != 0 ? insets.top : 0;
         final int right = (sidesToFit & Side.RIGHT) != 0 ? insets.right : 0;
         final int bottom = (sidesToFit & Side.BOTTOM) != 0 ? insets.bottom : 0;
-        outBounds.set(dfu.left + left, dfu.top + top, dfu.right - right, dfu.bottom - bottom);
+        outBounds.set(df.left + left, df.top + top, df.right - right, df.bottom - bottom);
     }
 
     /**
@@ -1772,7 +1772,7 @@
         final boolean layoutInsetDecor = (fl & FLAG_LAYOUT_INSET_DECOR) == FLAG_LAYOUT_INSET_DECOR;
 
         final InsetsState state = win.getInsetsState();
-        computeWindowBounds(attrs, state, df);
+        computeWindowBounds(attrs, state, win.mToken, df);
         if (attached == null) {
             pf.set(df);
             if ((pfl & PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME) != 0) {
@@ -1845,7 +1845,6 @@
             // They will later be cropped or shifted using the displayFrame in WindowState,
             // which prevents overlap with the DisplayCutout.
             if (!attachedInParent && !floatingInScreenWindow) {
-                getRotatedWindowBounds(displayFrames, win, sTmpRect);
                 sTmpRect.set(pf);
                 pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
                 windowFrames.setParentFrameWasClippedByDisplayCutout(!sTmpRect.equals(pf));
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
index f4fdd73..57c947f 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
@@ -450,12 +450,12 @@
                     out.attributeInt(null, "windowingMode", settingsEntry.mWindowingMode);
                 }
                 if (settingsEntry.mUserRotationMode != null) {
-                    out.attribute(null, "userRotationMode",
-                            settingsEntry.mUserRotationMode.toString());
+                    out.attributeInt(null, "userRotationMode",
+                            settingsEntry.mUserRotationMode);
                 }
                 if (settingsEntry.mUserRotation != null) {
-                    out.attribute(null, "userRotation",
-                            settingsEntry.mUserRotation.toString());
+                    out.attributeInt(null, "userRotation",
+                            settingsEntry.mUserRotation);
                 }
                 if (settingsEntry.mForcedWidth != 0 && settingsEntry.mForcedHeight != 0) {
                     out.attributeInt(null, "forcedWidth", settingsEntry.mForcedWidth);
@@ -465,30 +465,30 @@
                     out.attributeInt(null, "forcedDensity", settingsEntry.mForcedDensity);
                 }
                 if (settingsEntry.mForcedScalingMode != null) {
-                    out.attribute(null, "forcedScalingMode",
-                            settingsEntry.mForcedScalingMode.toString());
+                    out.attributeInt(null, "forcedScalingMode",
+                            settingsEntry.mForcedScalingMode);
                 }
                 if (settingsEntry.mRemoveContentMode != REMOVE_CONTENT_MODE_UNDEFINED) {
                     out.attributeInt(null, "removeContentMode", settingsEntry.mRemoveContentMode);
                 }
                 if (settingsEntry.mShouldShowWithInsecureKeyguard != null) {
-                    out.attribute(null, "shouldShowWithInsecureKeyguard",
-                            settingsEntry.mShouldShowWithInsecureKeyguard.toString());
+                    out.attributeBoolean(null, "shouldShowWithInsecureKeyguard",
+                            settingsEntry.mShouldShowWithInsecureKeyguard);
                 }
                 if (settingsEntry.mShouldShowSystemDecors != null) {
-                    out.attribute(null, "shouldShowSystemDecors",
-                            settingsEntry.mShouldShowSystemDecors.toString());
+                    out.attributeBoolean(null, "shouldShowSystemDecors",
+                            settingsEntry.mShouldShowSystemDecors);
                 }
                 if (settingsEntry.mImePolicy != null) {
                     out.attributeInt(null, "imePolicy", settingsEntry.mImePolicy);
                 }
                 if (settingsEntry.mFixedToUserRotation != null) {
-                    out.attribute(null, "fixedToUserRotation",
-                            settingsEntry.mFixedToUserRotation.toString());
+                    out.attributeInt(null, "fixedToUserRotation",
+                            settingsEntry.mFixedToUserRotation);
                 }
                 if (settingsEntry.mIgnoreOrientationRequest != null) {
-                    out.attribute(null, "ignoreOrientationRequest",
-                            settingsEntry.mIgnoreOrientationRequest.toString());
+                    out.attributeBoolean(null, "ignoreOrientationRequest",
+                            settingsEntry.mIgnoreOrientationRequest);
                 }
                 out.endTag(null, "display");
             }
diff --git a/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java b/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java
index 14880ed..9602880 100644
--- a/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java
+++ b/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import android.app.ActivityTaskManager;
 import android.app.UriGrantsManager;
 import android.content.ClipData;
 import android.net.Uri;
@@ -33,6 +32,7 @@
 class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub
         implements IBinder.DeathRecipient {
 
+    private final WindowManagerGlobalLock mGlobalLock;
     private final int mSourceUid;
     private final String mTargetPackage;
     private final int mMode;
@@ -45,8 +45,9 @@
     private IBinder mPermissionOwnerToken = null;
     private IBinder mTransientToken = null;
 
-    DragAndDropPermissionsHandler(ClipData clipData, int sourceUid, String targetPackage, int mode,
-                                  int sourceUserId, int targetUserId) {
+    DragAndDropPermissionsHandler(WindowManagerGlobalLock lock, ClipData clipData, int sourceUid,
+            String targetPackage, int mode, int sourceUserId, int targetUserId) {
+        mGlobalLock = lock;
         mSourceUid = sourceUid;
         mTargetPackage = targetPackage;
         mMode = mode;
@@ -64,8 +65,7 @@
         mActivityToken = activityToken;
 
         // Will throw if Activity is not found.
-        IBinder permissionOwner = ActivityTaskManager.getService().
-                getUriPermissionOwnerForActivity(mActivityToken);
+        IBinder permissionOwner = getUriPermissionOwnerForActivity(mActivityToken);
 
         doTake(permissionOwner);
     }
@@ -105,8 +105,7 @@
         IBinder permissionOwner = null;
         if (mActivityToken != null) {
             try {
-                permissionOwner = ActivityTaskManager.getService().
-                        getUriPermissionOwnerForActivity(mActivityToken);
+                permissionOwner = getUriPermissionOwnerForActivity(mActivityToken);
             } catch (Exception e) {
                 // Activity is destroyed, permissions already revoked.
                 return;
@@ -126,6 +125,18 @@
         }
     }
 
+    private IBinder getUriPermissionOwnerForActivity(IBinder activityToken) {
+        ActivityTaskManagerService.enforceNotIsolatedCaller("getUriPermissionOwnerForActivity");
+        synchronized (mGlobalLock) {
+            ActivityRecord r = ActivityRecord.isInStackLocked(activityToken);
+            if (r == null) {
+                throw new IllegalArgumentException("Activity does not exist; token="
+                        + activityToken);
+            }
+            return r.getUriPermissionsLocked().getExternalToken();
+        }
+    }
+
     @Override
     public void binderDied() {
         try {
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index ad4e64a..86518ea 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -59,7 +59,6 @@
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 
-import com.android.internal.os.SomeArgs;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.view.IDragAndDropPermissions;
 import com.android.server.LocalServices;
@@ -590,7 +589,7 @@
         final DragAndDropPermissionsHandler dragAndDropPermissions;
         if ((mFlags & View.DRAG_FLAG_GLOBAL) != 0 && (mFlags & DRAG_FLAGS_URI_ACCESS) != 0
                 && mData != null) {
-            dragAndDropPermissions = new DragAndDropPermissionsHandler(
+            dragAndDropPermissions = new DragAndDropPermissionsHandler(mService.mGlobalLock,
                     mData,
                     mUid,
                     touchedWin.getOwningPackage(),
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 818d96c..91106ef 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -42,6 +42,7 @@
     private InsetsControlTarget mImeTargetFromIme;
     private Runnable mShowImeRunner;
     private boolean mIsImeLayoutDrawn;
+    private boolean mImeShowing;
 
     ImeInsetsSourceProvider(InsetsSource source,
             InsetsStateController stateController, DisplayContent displayContent) {
@@ -81,6 +82,7 @@
 
                 ProtoLog.i(WM_DEBUG_IME, "call showInsets(ime) on %s",
                         target.getWindow() != null ? target.getWindow().getName() : "");
+                setImeShowing(true);
                 target.showInsets(WindowInsets.Type.ime(), true /* fromIme */);
                 Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, "WMS.showImePostLayout", 0);
                 if (target != mImeTargetFromIme && mImeTargetFromIme != null) {
@@ -155,12 +157,14 @@
     @Override
     public void dump(PrintWriter pw, String prefix) {
         super.dump(pw, prefix);
+        pw.print(prefix);
+        pw.print("mImeShowing=");
+        pw.print(mImeShowing);
         if (mImeTargetFromIme != null) {
-            pw.print(prefix);
-            pw.print("showImePostLayout pending for mImeTargetFromIme=");
+            pw.print(" showImePostLayout pending for mImeTargetFromIme=");
             pw.print(mImeTargetFromIme);
-            pw.println();
         }
+        pw.println();
     }
 
     @Override
@@ -173,4 +177,20 @@
         proto.write(IS_IME_LAYOUT_DRAWN, mIsImeLayoutDrawn);
         proto.end(token);
     }
+
+    /**
+     * Sets whether the IME is currently supposed to be showing according to
+     * InputMethodManagerService.
+     */
+    public void setImeShowing(boolean imeShowing) {
+        mImeShowing = imeShowing;
+    }
+
+    /**
+     * Returns whether the IME is currently supposed to be showing according to
+     * InputMethodManagerService.
+     */
+    public boolean isImeShowing() {
+        return mImeShowing;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 0605ed8..28a99825 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -328,7 +328,7 @@
         final Point surfacePosition = getWindowFrameSurfacePosition();
         mAdapter = new ControlAdapter(surfacePosition);
         if (getSource().getType() == ITYPE_IME) {
-            setClientVisible(InsetsState.getDefaultVisibility(mSource.getType()));
+            setClientVisible(target.getRequestedVisibility(mSource.getType()));
         }
         final Transaction t = mDisplayContent.getPendingTransaction();
         mWin.startAnimation(t, mAdapter, !mClientVisible /* hidden */,
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 52ada47..fd42b24 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -29,7 +29,6 @@
 import android.util.Log;
 import android.util.Slog;
 import android.view.DisplayInfo;
-import android.view.IPinnedStackController;
 import android.view.IPinnedStackListener;
 
 import java.io.PrintWriter;
@@ -63,8 +62,6 @@
     private final PinnedStackListenerDeathHandler mPinnedStackListenerDeathHandler =
             new PinnedStackListenerDeathHandler();
 
-    private final PinnedStackControllerCallback mCallbacks = new PinnedStackControllerCallback();
-
     /** Whether the PiP is entering or leaving. */
     private boolean mIsPipWindowingModeChanging;
 
@@ -86,18 +83,6 @@
     private final DisplayMetrics mTmpMetrics = new DisplayMetrics();
 
     /**
-     * The callback object passed to listeners for them to notify the controller of state changes.
-     */
-    private class PinnedStackControllerCallback extends IPinnedStackController.Stub {
-        @Override
-        public int getDisplayRotation() {
-            synchronized (mService.mGlobalLock) {
-                return mDisplayInfo.rotation;
-            }
-        }
-    }
-
-    /**
      * Handler for the case where the listener dies.
      */
     private class PinnedStackListenerDeathHandler implements IBinder.DeathRecipient {
@@ -141,7 +126,6 @@
     void registerPinnedStackListener(IPinnedStackListener listener) {
         try {
             listener.asBinder().linkToDeath(mPinnedStackListenerDeathHandler, 0);
-            listener.onListenerRegistered(mCallbacks);
             mPinnedStackListener = listener;
             notifyDisplayInfoChanged(mDisplayInfo);
             notifyImeVisibilityChanged(mIsImeShowing, mImeHeight);
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 5da668c..16c7226 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -850,7 +850,7 @@
         return w != null && w.mAttrs.type == TYPE_BASE_APPLICATION &&
                 ((w.mActivityRecord != null && mTargetActivityRecord == w.mActivityRecord)
                         || isAnimatingTask(w.getTask()))
-                && isTargetOverWallpaper();
+                && isTargetOverWallpaper() && w.isOnScreen();
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/RootDisplayArea.java b/services/core/java/com/android/server/wm/RootDisplayArea.java
index c4fcea6..393055e 100644
--- a/services/core/java/com/android/server/wm/RootDisplayArea.java
+++ b/services/core/java/com/android/server/wm/RootDisplayArea.java
@@ -106,12 +106,23 @@
     }
 
     /** Finds the {@link DisplayArea.Tokens} that this type of window should be attached to. */
+    @Nullable
     DisplayArea.Tokens findAreaForToken(WindowToken token) {
-        int windowLayerFromType = token.getWindowLayerFromType();
+        return findAreaForToken(token.windowType, token.mOwnerCanManageAppTokens,
+                token.mRoundedCornerOverlay);
+    }
+
+    @Nullable
+    DisplayArea.Tokens findAreaForToken(int windowType, boolean ownerCanManageAppTokens,
+            boolean roundedCornerOverlay) {
+        // TODO(b/159767464): cover TYPE_INPUT_METHOD(_DIALOG) case here. mAreaForLayer doesn't
+        // contain IME container.
+        int windowLayerFromType = mWmService.mPolicy.getWindowLayerFromTypeLw(windowType,
+                ownerCanManageAppTokens);
         if (windowLayerFromType == APPLICATION_LAYER) {
             throw new IllegalArgumentException(
                     "There shouldn't be WindowToken on APPLICATION_LAYER");
-        } else if (token.mRoundedCornerOverlay) {
+        } else if (roundedCornerOverlay) {
             windowLayerFromType = mAreaForLayer.length - 1;
         }
         return mAreaForLayer[windowLayerFromType];
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 7df2b40..6e0efbf 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -26,7 +26,6 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.util.DebugUtils;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 import android.view.SurfaceControl;
@@ -388,7 +387,7 @@
         if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to leash");
         final SurfaceControl.Builder builder = animatable.makeAnimationLeash()
                 .setParent(animatable.getAnimationLeashParent())
-                .setName(surface + " - animation-leash")
+                .setName(surface + " - animation-leash of " + animationTypeToString(type))
                 // TODO(b/151665759) Defer reparent calls
                 // We want the leash to be visible immediately because the transaction which shows
                 // the leash may be deferred but the reparent will not. This will cause the leashed
@@ -430,8 +429,7 @@
 
     void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("mLeash="); pw.print(mLeash);
-        pw.print(" mAnimationType=" + DebugUtils.valueToString(SurfaceAnimator.class,
-                "ANIMATION_TYPE_", mAnimationType));
+        pw.print(" mAnimationType=" + animationTypeToString(mAnimationType));
         pw.println(mAnimationStartDelayed ? " mAnimationStartDelayed=true" : "");
         pw.print(prefix); pw.print("Animation: "); pw.println(mAnimation);
         if (mAnimation != null) {
@@ -513,6 +511,23 @@
     @interface AnimationType {}
 
     /**
+     * Converts {@link AnimationType} to String.
+     */
+    private static String animationTypeToString(@AnimationType int type) {
+        switch (type) {
+            case ANIMATION_TYPE_NONE: return "none";
+            case ANIMATION_TYPE_APP_TRANSITION: return "app_transition";
+            case ANIMATION_TYPE_SCREEN_ROTATION: return "screen_rotation";
+            case ANIMATION_TYPE_DIMMER: return "dimmer";
+            case ANIMATION_TYPE_RECENTS: return "recents_animation";
+            case ANIMATION_TYPE_WINDOW_ANIMATION: return "window_animation";
+            case ANIMATION_TYPE_INSETS_CONTROL: return "insets_animation";
+            case ANIMATION_TYPE_FIXED_TRANSFORM: return "fixed_rotation";
+            default: return "unknown type:" + type;
+        }
+    }
+
+    /**
      * Callback to be passed into {@link AnimationAdapter#startAnimation} to be invoked by the
      * component that is running the animation when the animation is finished.
      */
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 4b65ce0f..00f545c 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -224,7 +224,6 @@
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
@@ -4108,7 +4107,7 @@
         if (top == null) return null;
         final ActivityRecord rootActivity = top.getRootActivity();
         return (rootActivity == null || rootActivity.pictureInPictureArgs.empty())
-                ? null : rootActivity.pictureInPictureArgs;
+                ? null : new PictureInPictureParams(rootActivity.pictureInPictureArgs);
     }
 
     void maybeUpdateLetterboxBounds(
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 4498a8c..9425602 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -641,9 +641,7 @@
     @Override
     int getOrientation(int candidate) {
         mLastOrientationSource = null;
-        // Only allow to specify orientation if this TDA is not set to ignore orientation request,
-        // and it has the focus.
-        if (mIgnoreOrientationRequest || !isLastFocused()) {
+        if (!canSpecifyOrientation()) {
             return SCREEN_ORIENTATION_UNSET;
         }
 
@@ -1918,10 +1916,14 @@
         return lastReparentedStack;
     }
 
-    /** Whether this task display area is the last focused one on this logical display. */
+    /** Whether this task display area can request orientation. */
     @VisibleForTesting
-    boolean isLastFocused() {
-        return mDisplayContent.getLastFocusedTaskDisplayArea() == this;
+    boolean canSpecifyOrientation() {
+        // Only allow to specify orientation if this TDA is not set to ignore orientation request,
+        // and it is the last focused one on this logical display that can request orientation
+        // request.
+        return !mIgnoreOrientationRequest
+                && mDisplayContent.getOrientationRequestingTaskDisplayArea() == this;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index cf6468d..adc7a22 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -98,6 +98,7 @@
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.LinkedList;
+import java.util.List;
 import java.util.function.BiFunction;
 import java.util.function.Consumer;
 import java.util.function.Function;
@@ -314,6 +315,8 @@
     final SurfaceControl.Transaction mSyncTransaction;
     @SyncState int mSyncState = SYNC_STATE_NONE;
 
+    private final List<WindowContainerListener> mListeners = new ArrayList<>();
+
     WindowContainer(WindowManagerService wms) {
         mWmService = wms;
         mPendingTransaction = wms.mTransactionFactory.get();
@@ -637,6 +640,10 @@
         if (mParent != null) {
             mParent.removeChild(this);
         }
+
+        for (int i = mListeners.size() - 1; i >= 0; --i) {
+            mListeners.get(i).onRemoved();
+        }
     }
 
     /**
@@ -819,6 +826,9 @@
             final WindowContainer child = mChildren.get(i);
             child.onDisplayChanged(dc);
         }
+        for (int i = mListeners.size() - 1; i >= 0; --i) {
+            mListeners.get(i).onDisplayChanged(dc);
+        }
     }
 
     DisplayContent getDisplayContent() {
@@ -1152,10 +1162,10 @@
 
     /**
      * Check if this container or its parent will handle orientation changes from descendants. It's
-     * different from the return value of {@link #onDescendantOrientationChanged(IBinder,
-     * WindowContainer)} in the sense that the return value of this method tells if this
-     * container or its parent will handle the request eventually, while the return value of the
-     * other method is if it handled the request synchronously.
+     * different from the return value of {@link #onDescendantOrientationChanged(WindowContainer)}
+     * in the sense that the return value of this method tells if this container or its parent will
+     * handle the request eventually, while the return value of the other method is if it handled
+     * the request synchronously.
      *
      * @return {@code true} if it handles or will handle orientation change in the future; {@code
      *         false} if it won't handle the change at anytime.
@@ -1221,7 +1231,7 @@
     }
 
     /**
-     * Calls {@link #setOrientation(int, IBinder, WindowContainer)} with {@code null} to the last 2
+     * Calls {@link #setOrientation(int, WindowContainer)} with {@code null} to the last 2
      * parameters.
      *
      * @param orientation the specified orientation.
@@ -3106,4 +3116,19 @@
         mSyncState = SYNC_STATE_NONE;
         prepareSync();
     }
+
+    void registerWindowContainerListener(WindowContainerListener listener) {
+        if (mListeners.contains(listener)) {
+            return;
+        }
+        mListeners.add(listener);
+        // Also register to ConfigurationChangeListener to receive configuration changes.
+        registerConfigurationChangeListener(listener);
+        listener.onDisplayChanged(getDisplayContent());
+    }
+
+    void unregisterWindowContainerListener(WindowContainerListener listener) {
+        mListeners.remove(listener);
+        unregisterConfigurationChangeListener(listener);
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowContainerListener.java b/services/core/java/com/android/server/wm/WindowContainerListener.java
new file mode 100644
index 0000000..ac1fe17
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowContainerListener.java
@@ -0,0 +1,30 @@
+/*
+ * 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.wm;
+
+/**
+ * Interface for listening to changes in a {@link WindowContainer}. A usage of this listener is
+ * to receive the changes and propagate them to the client side.
+ */
+interface WindowContainerListener extends ConfigurationContainerListener {
+
+    /** @see WindowContainer#onDisplayChanged(DisplayContent) */
+    default void onDisplayChanged(DisplayContent dc) {}
+
+    /** Called when {@link WindowContainer#removeImmediately()} is invoked. */
+    default void onRemoved() {}
+}
diff --git a/services/core/java/com/android/server/wm/WindowContextListenerController.java b/services/core/java/com/android/server/wm/WindowContextListenerController.java
new file mode 100644
index 0000000..051ece3
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowContextListenerController.java
@@ -0,0 +1,248 @@
+/*
+ * 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.wm;
+
+import static android.view.Display.INVALID_DISPLAY;
+
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
+import static com.android.internal.protolog.ProtoLogGroup.WM_ERROR;
+
+import android.annotation.NonNull;
+import android.app.IWindowToken;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
+
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * A controller to register/unregister {@link WindowContainerListener} for
+ * {@link android.app.WindowContext}.
+ *
+ * <ul>
+ *   <li>When a {@link android.app.WindowContext} is created, it registers the listener via
+ *     {@link WindowManagerService#registerWindowContextListener(IBinder, int, int, Bundle)}
+ *     automatically.</li>
+ *   <li>When the {@link android.app.WindowContext} adds the first window to the screen via
+ *     {@link android.view.WindowManager#addView(View, ViewGroup.LayoutParams)},
+ *     {@link WindowManagerService} then updates the {@link WindowContextListenerImpl} to listen
+ *     to corresponding {@link WindowToken} via this controller.</li>
+ *   <li>When the {@link android.app.WindowContext} is GCed, it unregisters the previously
+ *     registered listener via
+ *     {@link WindowManagerService#unregisterWindowContextListener(IBinder)}.
+ *     {@link WindowManagerService} is also responsible for removing the
+ *     {@link android.app.WindowContext} created {@link WindowToken}.</li>
+ * </ul>
+ * <p>Note that the listener may be removed earlier than the
+ * {@link #unregisterWindowContainerListener(IBinder)} if the listened {@link WindowContainer} was
+ * removed. An example is that the {@link DisplayArea} is removed when users unfold the
+ * foldable devices. Another example is that the associated external display is detached.</p>
+ */
+class WindowContextListenerController {
+    @VisibleForTesting
+    final Map<IBinder, WindowContextListenerImpl> mListeners = new ArrayMap<>();
+
+    /**
+     * Registers the listener to a {@code container} which is associated with
+     * a {@code clientToken}, which is a {@link android.app.WindowContext} representation. If the
+     * listener associated with {@code clientToken} hasn't been initialized yet, create one
+     * {@link WindowContextListenerImpl}. Otherwise, the listener associated with
+     * {@code clientToken} switches to listen to the {@code container}.
+     *
+     * @param clientToken the token to associate with the listener
+     * @param container the {@link WindowContainer} which the listener is going to listen to.
+     * @param ownerUid the caller UID
+     */
+    void registerWindowContainerListener(@NonNull IBinder clientToken,
+            @NonNull WindowContainer container, int ownerUid) {
+        WindowContextListenerImpl listener = mListeners.get(clientToken);
+        if (listener == null) {
+            listener = new WindowContextListenerImpl(clientToken, container, ownerUid);
+            listener.register();
+        } else {
+            listener.updateContainer(container);
+        }
+    }
+
+    void unregisterWindowContainerListener(IBinder clientToken) {
+        final WindowContextListenerImpl listener = mListeners.get(clientToken);
+        // Listeners may be removed earlier. An example is the display where the listener is
+        // located is detached. In this case, all window containers on the display, as well as
+        // their listeners will be removed before their listeners are unregistered.
+        if (listener == null) {
+            return;
+        }
+        listener.unregister();
+    }
+
+    boolean assertCallerCanRemoveListener(IBinder clientToken, boolean callerCanManageAppTokens,
+            int callingUid) {
+        final WindowContextListenerImpl listener = mListeners.get(clientToken);
+        if (listener == null) {
+            ProtoLog.i(WM_DEBUG_ADD_REMOVE, "The listener does not exist.");
+            return false;
+        }
+        if (callerCanManageAppTokens) {
+            return true;
+        }
+        if (callingUid != listener.mOwnerUid) {
+            throw new UnsupportedOperationException("Uid mismatch. Caller uid is " + callingUid
+                    + ", while the listener's owner is from " + listener.mOwnerUid);
+        }
+        return true;
+    }
+
+    @VisibleForTesting
+    class WindowContextListenerImpl implements WindowContainerListener {
+        @NonNull private final IBinder mClientToken;
+        private final int mOwnerUid;
+        @NonNull private WindowContainer mContainer;
+
+        private DeathRecipient mDeathRecipient;
+
+        private int mLastReportedDisplay = INVALID_DISPLAY;
+        private Configuration mLastReportedConfig;
+
+        private WindowContextListenerImpl(IBinder clientToken, WindowContainer container,
+                int ownerUid) {
+            mClientToken = clientToken;
+            mContainer = Objects.requireNonNull(container);
+            mOwnerUid = ownerUid;
+
+            final DeathRecipient deathRecipient = new DeathRecipient();
+            try {
+                deathRecipient.linkToDeath();
+                mDeathRecipient = deathRecipient;
+            } catch (RemoteException e) {
+                ProtoLog.e(WM_ERROR, "Could not register window container listener token=%s, "
+                        + "container=%s", mClientToken, mContainer);
+            }
+        }
+
+        /** TEST ONLY: returns the {@link WindowContainer} of the listener */
+        @VisibleForTesting
+        WindowContainer getWindowContainer() {
+            return mContainer;
+        }
+
+        private void updateContainer(WindowContainer newContainer) {
+            if (mContainer.equals(newContainer)) {
+                return;
+            }
+            mContainer.unregisterWindowContainerListener(this);
+            mContainer = newContainer;
+            clear();
+            register();
+        }
+
+        private void register() {
+            if (mDeathRecipient == null) {
+                throw new IllegalStateException("Invalid client token: " + mClientToken);
+            }
+            mListeners.putIfAbsent(mClientToken, this);
+            mContainer.registerWindowContainerListener(this);
+            reportConfigToWindowTokenClient();
+        }
+
+        private void unregister() {
+            mContainer.unregisterWindowContainerListener(this);
+            mListeners.remove(mClientToken);
+        }
+
+        private void clear() {
+            mLastReportedConfig = null;
+            mLastReportedDisplay = INVALID_DISPLAY;
+        }
+
+        @Override
+        public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
+            reportConfigToWindowTokenClient();
+        }
+
+        @Override
+        public void onDisplayChanged(DisplayContent dc) {
+            reportConfigToWindowTokenClient();
+        }
+
+        private void reportConfigToWindowTokenClient() {
+            if (mDeathRecipient == null) {
+                throw new IllegalStateException("Invalid client token: " + mClientToken);
+            }
+
+            if (mLastReportedConfig == null) {
+                mLastReportedConfig = new Configuration();
+            }
+            final Configuration config = mContainer.getConfiguration();
+            final int displayId = mContainer.getDisplayContent().getDisplayId();
+            if (config.equals(mLastReportedConfig) && displayId == mLastReportedDisplay) {
+                // No changes since last reported time.
+                return;
+            }
+
+            mLastReportedConfig.setTo(config);
+            mLastReportedDisplay = displayId;
+
+            IWindowToken windowTokenClient = IWindowToken.Stub.asInterface(mClientToken);
+            try {
+                windowTokenClient.onConfigurationChanged(config, displayId);
+            } catch (RemoteException e) {
+                ProtoLog.w(WM_ERROR, "Could not report config changes to the window token client.");
+            }
+        }
+
+        @Override
+        public void onRemoved() {
+            if (mDeathRecipient == null) {
+                throw new IllegalStateException("Invalid client token: " + mClientToken);
+            }
+            mDeathRecipient.unlinkToDeath();
+            IWindowToken windowTokenClient = IWindowToken.Stub.asInterface(mClientToken);
+            try {
+                windowTokenClient.onWindowTokenRemoved();
+            } catch (RemoteException e) {
+                ProtoLog.w(WM_ERROR, "Could not report token removal to the window token client.");
+            }
+            unregister();
+        }
+
+        private class DeathRecipient implements IBinder.DeathRecipient {
+            @Override
+            public void binderDied() {
+                synchronized (mContainer.mWmService.mGlobalLock) {
+                    mDeathRecipient = null;
+                    unregister();
+                }
+            }
+
+            void linkToDeath() throws RemoteException {
+                mClientToken.linkToDeath(this, 0);
+            }
+
+            void unlinkToDeath() {
+                mClientToken.unlinkToDeath(this, 0);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d4efa8a..8fd342c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -459,7 +459,7 @@
 
     final WindowTracing mWindowTracing;
 
-    final DisplayAreaPolicy.Provider mDisplayAreaPolicyProvider;
+    private final DisplayAreaPolicy.Provider mDisplayAreaPolicyProvider;
 
     final private KeyguardDisableHandler mKeyguardDisableHandler;
     // TODO: eventually unify all keyguard state in a common place instead of having it spread over
@@ -769,6 +769,8 @@
     final AnrController mAnrController;
 
     private final ImpressionAttestationController mImpressionAttestationController;
+    private final WindowContextListenerController mWindowContextListenerController =
+            new WindowContextListenerController();
 
     @VisibleForTesting
     final class SettingsObserver extends ContentObserver {
@@ -1121,10 +1123,7 @@
             final boolean isRecentsAnimationTarget = getRecentsAnimationController() != null
                     && getRecentsAnimationController().isTargetApp(atoken);
             if (atoken.mLaunchTaskBehind && !isRecentsAnimationTarget) {
-                try {
-                    mActivityTaskManager.notifyLaunchTaskBehindComplete(atoken.token);
-                } catch (RemoteException e) {
-                }
+                mAtmService.mTaskSupervisor.scheduleLaunchTaskBehindComplete(atoken.token);
                 atoken.mLaunchTaskBehind = false;
             } else {
                 atoken.updateReportedVisibilityLocked();
@@ -1132,9 +1131,11 @@
                 // successfully finishes.
                 if (atoken.mEnteringAnimation && !isRecentsAnimationTarget) {
                     atoken.mEnteringAnimation = false;
-                    try {
-                        mActivityTaskManager.notifyEnterAnimationComplete(atoken.token);
-                    } catch (RemoteException e) {
+                    if (atoken != null && atoken.attachedToProcess()) {
+                        try {
+                            atoken.app.getThread().scheduleEnterAnimationComplete(atoken.appToken);
+                        } catch (RemoteException e) {
+                        }
                     }
                 }
             }
@@ -1378,6 +1379,10 @@
         mStartingSurfaceController = new StartingSurfaceController(this);
     }
 
+    DisplayAreaPolicy.Provider getDisplayAreaPolicyProvider() {
+        return mDisplayAreaPolicyProvider;
+    }
+
     private void setGlobalShadowSettings() {
         final TypedArray a = mContext.obtainStyledAttributes(null, R.styleable.Lighting, 0, 0);
         float lightY = a.getDimension(R.styleable.Lighting_lightY, 0);
@@ -2624,6 +2629,10 @@
     }
 
     boolean checkCallingPermission(String permission, String func) {
+        return checkCallingPermission(permission, func, true /* printLog */);
+    }
+
+    boolean checkCallingPermission(String permission, String func, boolean printLog) {
         // Quick check: if the calling permission is me, it's all okay.
         if (Binder.getCallingPid() == myPid()) {
             return true;
@@ -2633,8 +2642,10 @@
                 == PackageManager.PERMISSION_GRANTED) {
             return true;
         }
-        ProtoLog.w(WM_ERROR, "Permission Denial: %s from pid=%d, uid=%d requires %s",
-                func, Binder.getCallingPid(), Binder.getCallingUid(), permission);
+        if (printLog) {
+            ProtoLog.w(WM_ERROR, "Permission Denial: %s from pid=%d, uid=%d requires %s",
+                    func, Binder.getCallingPid(), Binder.getCallingUid(), permission);
+        }
         return false;
     }
 
@@ -2727,6 +2738,52 @@
     }
 
     @Override
+    public boolean registerWindowContextListener(IBinder clientToken, int type, int displayId,
+            Bundle options) {
+        final boolean callerCanManageAppTokens = checkCallingPermission(MANAGE_APP_TOKENS,
+                "registerWindowContextListener", false /* printLog */);
+        final int callingUid = Binder.getCallingUid();
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                final DisplayContent dc = mRoot.getDisplayContentOrCreate(displayId);
+                if (dc == null) {
+                    ProtoLog.w(WM_ERROR, "registerWindowContextListener: trying to add listener to"
+                            + " a non-existing display:%d", displayId);
+                    return false;
+                }
+                // TODO(b/155340867): Investigate if we still need roundedCornerOverlay after
+                // the feature b/155340867 is completed.
+                final DisplayArea da = dc.getAreaForWindowToken(type, options,
+                        callerCanManageAppTokens, false /* roundedCornerOverlay */);
+                mWindowContextListenerController.registerWindowContainerListener(clientToken, da,
+                        callingUid);
+                return true;
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
+    public void unregisterWindowContextListener(IBinder clientToken) {
+        final boolean callerCanManageAppTokens = checkCallingPermission(MANAGE_APP_TOKENS,
+                "unregisterWindowContextListener", false /* printLog */);
+        final int callingUid = Binder.getCallingUid();
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                if (mWindowContextListenerController.assertCallerCanRemoveListener(clientToken,
+                        callerCanManageAppTokens, callingUid)) {
+                    mWindowContextListenerController.unregisterWindowContainerListener(clientToken);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    @Override
     public boolean isWindowToken(IBinder binder) {
         synchronized (mGlobalLock) {
             final WindowToken windowToken = mRoot.getWindowToken(binder);
@@ -5108,9 +5165,11 @@
                 }
 
                 case NOTIFY_ACTIVITY_DRAWN: {
-                    try {
-                        mActivityTaskManager.notifyActivityDrawn((IBinder) msg.obj);
-                    } catch (RemoteException e) {
+                    final ActivityRecord activity = (ActivityRecord) msg.obj;
+                    synchronized (mGlobalLock) {
+                        if (activity.isAttached()) {
+                            activity.getRootTask().notifyActivityDrawnLocked(activity);
+                        }
                     }
                     break;
                 }
@@ -7719,6 +7778,9 @@
                     dc.mInputMethodControlTarget.hideInsets(
                             WindowInsets.Type.ime(), true /* fromIme */);
                 }
+                if (dc != null) {
+                    dc.getInsetsStateController().getImeSourceProvider().setImeShowing(false);
+                }
             }
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c318fad..bc8699e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -770,6 +770,9 @@
             }
             mPendingSeamlessRotate = new SeamlessRotator(oldRotation, rotation, getDisplayInfo(),
                     false /* applyFixedTransformationHint */);
+            // The surface position is going to be unrotated according to the last position.
+            // Make sure the source position is up-to-date.
+            mLastSurfacePosition.set(mSurfacePosition.x, mSurfacePosition.y);
             mPendingSeamlessRotate.unrotate(transaction, this);
             getDisplayContent().getDisplayRotation().markForSeamlessRotation(this,
                     true /* seamlesslyRotated */);
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 5ced6a5..34875ed 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -419,6 +419,7 @@
         reportWindowTokenRemovedToClient();
     }
 
+    // TODO(b/159767464): Remove after we migrate to listener approach.
     private void reportWindowTokenRemovedToClient() {
         if (!shouldReportToClient()) {
             return;
diff --git a/services/core/jni/OWNERS b/services/core/jni/OWNERS
index 6f74885..7fc5565 100644
--- a/services/core/jni/OWNERS
+++ b/services/core/jni/OWNERS
@@ -12,3 +12,18 @@
 per-file com_android_server_HardwarePropertiesManagerService.cpp = michaelwr@google.com, santoscordon@google.com
 per-file com_android_server_power_PowerManagerService.* = michaelwr@google.com, santoscordon@google.com
 
+per-file Android.bp = file:platform/build/soong:/OWNERS
+per-file com_android_server_Usb* = file:/services/usb/OWNERS
+per-file com_android_server_Vibrator* = file:/services/core/java/com/android/server/vibrator/OWNERS
+per-file com_android_server_hdmi_* = file:/core/java/android/hardware/hdmi/OWNERS
+per-file com_android_server_input_* = file:/core/java/android/hardware/input/OWNERS
+per-file com_android_server_lights_* = file:/services/core/java/com/android/server/lights/OWNERS
+per-file com_android_server_location_* = file:/location/java/android/location/OWNERS
+per-file com_android_server_locksettings_* = file:/services/core/java/com/android/server/locksettings/OWNERS
+per-file com_android_server_net_* = file:/services/core/java/com/android/server/net/OWNERS
+per-file com_android_server_pm_* = file:/services/core/java/com/android/server/pm/OWNERS
+per-file com_android_server_power_* = file:/services/core/java/com/android/server/power/OWNERS
+per-file com_android_server_se_* = file:/core/java/android/se/OWNERS
+per-file com_android_server_security_* = file:/core/java/android/security/OWNERS
+per-file com_android_server_tv_* = file:/media/java/android/media/tv/OWNERS
+per-file com_android_server_vibrator_* = file:/services/core/java/com/android/server/vibrator/OWNERS
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 13450be..404b182 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -149,6 +149,14 @@
     jmethodID getAffineTransform;
 } gTouchCalibrationClassInfo;
 
+static struct {
+    jclass clazz;
+    jmethodID constructor;
+    jmethodID keyAt;
+    jmethodID valueAt;
+    jmethodID size;
+} gSparseArrayClassInfo;
+
 // --- Global functions ---
 
 template<typename T>
@@ -1705,19 +1713,73 @@
             patternObj, nullptr));
     jint* amplitudes = static_cast<jint*>(env->GetPrimitiveArrayCritical(amplitudesObj, nullptr));
 
-    std::vector<VibrationElement> elements(patternSize);
+    VibrationSequence sequence(patternSize);
+    std::vector<int32_t> vibrators = im->getInputManager()->getReader()->getVibratorIds(deviceId);
     for (size_t i = 0; i < patternSize; i++) {
         // VibrationEffect.validate guarantees duration > 0.
         std::chrono::milliseconds duration(patternMillis[i]);
-        elements[i].duration = std::min(duration, MAX_VIBRATE_PATTERN_DELAY_MILLIS);
-        // TODO: (b/161629089) apply channel specific amplitudes from development API.
-        elements[i].channels = {static_cast<uint8_t>(amplitudes[i]),
-                                static_cast<uint8_t>(amplitudes[i])};
+        VibrationElement element(CHANNEL_SIZE);
+        element.duration = std::min(duration, MAX_VIBRATE_PATTERN_DELAY_MILLIS);
+        // Vibrate on both channels
+        for (int32_t channel = 0; channel < vibrators.size(); channel++) {
+            element.addChannel(vibrators[channel], static_cast<uint8_t>(amplitudes[i]));
+        }
+        sequence.addElement(element);
     }
     env->ReleasePrimitiveArrayCritical(patternObj, patternMillis, JNI_ABORT);
     env->ReleasePrimitiveArrayCritical(amplitudesObj, amplitudes, JNI_ABORT);
 
-    im->getInputManager()->getReader()->vibrate(deviceId, elements, repeat, token);
+    im->getInputManager()->getReader()->vibrate(deviceId, sequence, repeat, token);
+}
+
+static void nativeVibrateCombined(JNIEnv* env, jclass /* clazz */, jlong ptr, jint deviceId,
+                                  jlongArray patternObj, jobject amplitudesObj, jint repeat,
+                                  jint token) {
+    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+    size_t patternSize = env->GetArrayLength(patternObj);
+
+    if (patternSize > MAX_VIBRATE_PATTERN_SIZE) {
+        ALOGI("Skipped requested vibration because the pattern size is %zu "
+              "which is more than the maximum supported size of %d.",
+              patternSize, MAX_VIBRATE_PATTERN_SIZE);
+        return; // limit to reasonable size
+    }
+    const jlong* patternMillis = env->GetLongArrayElements(patternObj, nullptr);
+
+    std::array<jint*, CHANNEL_SIZE> amplitudesArray;
+    std::array<jint, CHANNEL_SIZE> vibratorIdArray;
+    jint amplSize = env->CallIntMethod(amplitudesObj, gSparseArrayClassInfo.size);
+    if (amplSize > CHANNEL_SIZE) {
+        ALOGE("Can not fit into input device vibration element.");
+        return;
+    }
+
+    for (int i = 0; i < amplSize; i++) {
+        vibratorIdArray[i] = env->CallIntMethod(amplitudesObj, gSparseArrayClassInfo.keyAt, i);
+        jintArray arr = static_cast<jintArray>(
+                env->CallObjectMethod(amplitudesObj, gSparseArrayClassInfo.valueAt, i));
+        amplitudesArray[i] = env->GetIntArrayElements(arr, nullptr);
+        if (env->GetArrayLength(arr) != patternSize) {
+            ALOGE("Amplitude length not equal to pattern length!");
+            return;
+        }
+    }
+
+    VibrationSequence sequence(patternSize);
+    for (size_t i = 0; i < patternSize; i++) {
+        VibrationElement element(CHANNEL_SIZE);
+        // VibrationEffect.validate guarantees duration > 0.
+        std::chrono::milliseconds duration(patternMillis[i]);
+        element.duration = std::min(duration, MAX_VIBRATE_PATTERN_DELAY_MILLIS);
+        for (int32_t channel = 0; channel < CHANNEL_SIZE; channel++) {
+            element.addChannel(vibratorIdArray[channel],
+                               static_cast<uint8_t>(amplitudesArray[channel][i]));
+        }
+        sequence.addElement(element);
+    }
+
+    im->getInputManager()->getReader()->vibrate(deviceId, sequence, repeat, token);
 }
 
 static void nativeCancelVibrate(JNIEnv* /* env */,
@@ -1727,6 +1789,23 @@
     im->getInputManager()->getReader()->cancelVibrate(deviceId, token);
 }
 
+static bool nativeIsVibrating(JNIEnv* /* env */, jclass /* clazz */, jlong ptr, jint deviceId) {
+    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+    return im->getInputManager()->getReader()->isVibrating(deviceId);
+}
+
+static jintArray nativeGetVibratorIds(JNIEnv* env, jclass clazz, jlong ptr, jint deviceId) {
+    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+    std::vector<int32_t> vibrators = im->getInputManager()->getReader()->getVibratorIds(deviceId);
+
+    jintArray vibIdArray = env->NewIntArray(vibrators.size());
+    if (vibIdArray != nullptr) {
+        env->SetIntArrayRegion(vibIdArray, 0, vibrators.size(), vibrators.data());
+    }
+    return vibIdArray;
+}
+
 static void nativeReloadKeyboardLayouts(JNIEnv* /* env */,
         jclass /* clazz */, jlong ptr) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
@@ -1872,7 +1951,11 @@
         {"nativeSetInteractive", "(JZ)V", (void*)nativeSetInteractive},
         {"nativeReloadCalibration", "(J)V", (void*)nativeReloadCalibration},
         {"nativeVibrate", "(JI[J[III)V", (void*)nativeVibrate},
+        {"nativeVibrateCombined", "(JI[JLandroid/util/SparseArray;II)V",
+         (void*)nativeVibrateCombined},
         {"nativeCancelVibrate", "(JII)V", (void*)nativeCancelVibrate},
+        {"nativeIsVibrating", "(JI)Z", (void*)nativeIsVibrating},
+        {"nativeGetVibratorIds", "(JI)[I", (void*)nativeGetVibratorIds},
         {"nativeReloadKeyboardLayouts", "(J)V", (void*)nativeReloadKeyboardLayouts},
         {"nativeReloadDeviceAliases", "(J)V", (void*)nativeReloadDeviceAliases},
         {"nativeDump", "(J)Ljava/lang/String;", (void*)nativeDump},
@@ -2048,6 +2131,15 @@
     GET_METHOD_ID(gTouchCalibrationClassInfo.getAffineTransform, gTouchCalibrationClassInfo.clazz,
             "getAffineTransform", "()[F");
 
+    // SparseArray
+    FIND_CLASS(gSparseArrayClassInfo.clazz, "android/util/SparseArray");
+    gSparseArrayClassInfo.clazz = jclass(env->NewGlobalRef(gSparseArrayClassInfo.clazz));
+    GET_METHOD_ID(gSparseArrayClassInfo.constructor, gSparseArrayClassInfo.clazz, "<init>", "()V");
+    GET_METHOD_ID(gSparseArrayClassInfo.keyAt, gSparseArrayClassInfo.clazz, "keyAt", "(I)I");
+    GET_METHOD_ID(gSparseArrayClassInfo.valueAt, gSparseArrayClassInfo.clazz, "valueAt",
+                  "(I)Ljava/lang/Object;");
+    GET_METHOD_ID(gSparseArrayClassInfo.size, gSparseArrayClassInfo.clazz, "size", "()I");
+
     return 0;
 }
 
diff --git a/services/core/jni/gnss/OWNERS b/services/core/jni/gnss/OWNERS
new file mode 100644
index 0000000..5ac6028
--- /dev/null
+++ b/services/core/jni/gnss/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/location/OWNERS
diff --git a/services/core/xsd/device-state-config/device-state-config.xsd b/services/core/xsd/device-state-config/device-state-config.xsd
index 0d8c08c..5014503 100644
--- a/services/core/xsd/device-state-config/device-state-config.xsd
+++ b/services/core/xsd/device-state-config/device-state-config.xsd
@@ -57,8 +57,8 @@
 
     <xs:complexType name="sensorCondition">
         <xs:sequence>
+            <xs:element name="type" type="xs:string" />
             <xs:element name="name" type="xs:string" />
-            <xs:element name="type" type="xs:positiveInteger" />
             <xs:element name="value" type="numericRange" maxOccurs="unbounded" />
         </xs:sequence>
     </xs:complexType>
diff --git a/services/core/xsd/device-state-config/schema/current.txt b/services/core/xsd/device-state-config/schema/current.txt
index 667d1ad..b396af0 100644
--- a/services/core/xsd/device-state-config/schema/current.txt
+++ b/services/core/xsd/device-state-config/schema/current.txt
@@ -44,10 +44,10 @@
   public class SensorCondition {
     ctor public SensorCondition();
     method public String getName();
-    method public java.math.BigInteger getType();
+    method public String getType();
     method public java.util.List<com.android.server.policy.devicestate.config.NumericRange> getValue();
     method public void setName(String);
-    method public void setType(java.math.BigInteger);
+    method public void setType(String);
   }
 
   public class XmlParser {
diff --git a/services/core/xsd/platform-compat-schema/OWNERS b/services/core/xsd/platform-compat-schema/OWNERS
new file mode 100644
index 0000000..f8c3520
--- /dev/null
+++ b/services/core/xsd/platform-compat-schema/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/compat/OWNERS
diff --git a/services/devicepolicy/OWNERS b/services/devicepolicy/OWNERS
new file mode 100644
index 0000000..e95633a
--- /dev/null
+++ b/services/devicepolicy/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/app/admin/OWNERS
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index 1a147b9..a281180 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -40,14 +40,14 @@
 import android.util.IndentingPrintWriter;
 import android.util.Log;
 import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 import com.android.server.pm.UserRestrictionsUtils;
 
-import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -300,7 +300,7 @@
         return UserHandle.of(UserHandle.getUserId(info.getActivityInfo().applicationInfo.uid));
     }
 
-    void writeToXml(XmlSerializer out)
+    void writeToXml(TypedXmlSerializer out)
             throws IllegalArgumentException, IllegalStateException, IOException {
         out.startTag(null, TAG_POLICIES);
         info.writePoliciesToXml(out);
@@ -413,11 +413,11 @@
         }
         if (isNetworkLoggingEnabled) {
             out.startTag(null, TAG_IS_NETWORK_LOGGING_ENABLED);
-            out.attribute(null, ATTR_VALUE, Boolean.toString(isNetworkLoggingEnabled));
-            out.attribute(null, ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS,
-                    Integer.toString(numNetworkLoggingNotifications));
-            out.attribute(null, ATTR_LAST_NETWORK_LOGGING_NOTIFICATION,
-                    Long.toString(lastNetworkLoggingNotificationTimeMs));
+            out.attributeBoolean(null, ATTR_VALUE, isNetworkLoggingEnabled);
+            out.attributeInt(null, ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS,
+                    numNetworkLoggingNotifications);
+            out.attributeLong(null, ATTR_LAST_NETWORK_LOGGING_NOTIFICATION,
+                    lastNetworkLoggingNotificationTimeMs);
             out.endTag(null, TAG_IS_NETWORK_LOGGING_ENABLED);
         }
         if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) {
@@ -535,13 +535,13 @@
         }
     }
 
-    void writeTextToXml(XmlSerializer out, String tag, String text) throws IOException {
+    void writeTextToXml(TypedXmlSerializer out, String tag, String text) throws IOException {
         out.startTag(null, tag);
         out.text(text);
         out.endTag(null, tag);
     }
 
-    void writePackageListToXml(XmlSerializer out, String outerTag,
+    void writePackageListToXml(TypedXmlSerializer out, String outerTag,
             List<String> packageList)
             throws IllegalArgumentException, IllegalStateException, IOException {
         if (packageList == null) {
@@ -550,35 +550,35 @@
         writeAttributeValuesToXml(out, outerTag, TAG_PACKAGE_LIST_ITEM, packageList);
     }
 
-    void writeAttributeValueToXml(XmlSerializer out, String tag, String value)
+    void writeAttributeValueToXml(TypedXmlSerializer out, String tag, String value)
             throws IOException {
         out.startTag(null, tag);
         out.attribute(null, ATTR_VALUE, value);
         out.endTag(null, tag);
     }
 
-    void writeAttributeValueToXml(XmlSerializer out, String tag, int value)
+    void writeAttributeValueToXml(TypedXmlSerializer out, String tag, int value)
             throws IOException {
         out.startTag(null, tag);
-        out.attribute(null, ATTR_VALUE, Integer.toString(value));
+        out.attributeInt(null, ATTR_VALUE, value);
         out.endTag(null, tag);
     }
 
-    void writeAttributeValueToXml(XmlSerializer out, String tag, long value)
+    void writeAttributeValueToXml(TypedXmlSerializer out, String tag, long value)
             throws IOException {
         out.startTag(null, tag);
-        out.attribute(null, ATTR_VALUE, Long.toString(value));
+        out.attributeLong(null, ATTR_VALUE, value);
         out.endTag(null, tag);
     }
 
-    void writeAttributeValueToXml(XmlSerializer out, String tag, boolean value)
+    void writeAttributeValueToXml(TypedXmlSerializer out, String tag, boolean value)
             throws IOException {
         out.startTag(null, tag);
-        out.attribute(null, ATTR_VALUE, Boolean.toString(value));
+        out.attributeBoolean(null, ATTR_VALUE, value);
         out.endTag(null, tag);
     }
 
-    void writeAttributeValuesToXml(XmlSerializer out, String outerTag, String innerTag,
+    void writeAttributeValuesToXml(TypedXmlSerializer out, String outerTag, String innerTag,
             @NonNull Collection<String> values) throws IOException {
         out.startTag(null, outerTag);
         for (String value : values) {
@@ -589,7 +589,7 @@
         out.endTag(null, outerTag);
     }
 
-    void readFromXml(XmlPullParser parser, boolean shouldOverridePolicies)
+    void readFromXml(TypedXmlPullParser parser, boolean shouldOverridePolicies)
             throws XmlPullParserException, IOException {
         int outerDepth = parser.getDepth();
         int type;
@@ -606,47 +606,33 @@
                     info.readPoliciesFromXml(parser);
                 }
             } else if (TAG_PASSWORD_QUALITY.equals(tag)) {
-                mPasswordPolicy.quality = Integer.parseInt(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                mPasswordPolicy.quality = parser.getAttributeInt(null, ATTR_VALUE);
             } else if (TAG_MIN_PASSWORD_LENGTH.equals(tag)) {
-                mPasswordPolicy.length = Integer.parseInt(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                mPasswordPolicy.length = parser.getAttributeInt(null, ATTR_VALUE);
             } else if (TAG_PASSWORD_HISTORY_LENGTH.equals(tag)) {
-                passwordHistoryLength = Integer.parseInt(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                passwordHistoryLength = parser.getAttributeInt(null, ATTR_VALUE);
             } else if (TAG_MIN_PASSWORD_UPPERCASE.equals(tag)) {
-                mPasswordPolicy.upperCase = Integer.parseInt(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                mPasswordPolicy.upperCase = parser.getAttributeInt(null, ATTR_VALUE);
             } else if (TAG_MIN_PASSWORD_LOWERCASE.equals(tag)) {
-                mPasswordPolicy.lowerCase = Integer.parseInt(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                mPasswordPolicy.lowerCase = parser.getAttributeInt(null, ATTR_VALUE);
             } else if (TAG_MIN_PASSWORD_LETTERS.equals(tag)) {
-                mPasswordPolicy.letters = Integer.parseInt(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                mPasswordPolicy.letters = parser.getAttributeInt(null, ATTR_VALUE);
             } else if (TAG_MIN_PASSWORD_NUMERIC.equals(tag)) {
-                mPasswordPolicy.numeric = Integer.parseInt(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                mPasswordPolicy.numeric = parser.getAttributeInt(null, ATTR_VALUE);
             } else if (TAG_MIN_PASSWORD_SYMBOLS.equals(tag)) {
-                mPasswordPolicy.symbols = Integer.parseInt(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                mPasswordPolicy.symbols = parser.getAttributeInt(null, ATTR_VALUE);
             } else if (TAG_MIN_PASSWORD_NONLETTER.equals(tag)) {
-                mPasswordPolicy.nonLetter = Integer.parseInt(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                mPasswordPolicy.nonLetter = parser.getAttributeInt(null, ATTR_VALUE);
             } else if (TAG_PASSWORD_QUALITY_APPLIES_TO_PARENT.equals(tag)) {
-                mPasswordPolicyAppliesToParent = Boolean.parseBoolean(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                mPasswordPolicyAppliesToParent = parser.getAttributeBoolean(null, ATTR_VALUE);
             } else if (TAG_MAX_TIME_TO_UNLOCK.equals(tag)) {
-                maximumTimeToUnlock = Long.parseLong(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                maximumTimeToUnlock = parser.getAttributeLong(null, ATTR_VALUE);
             } else if (TAG_STRONG_AUTH_UNLOCK_TIMEOUT.equals(tag)) {
-                strongAuthUnlockTimeout = Long.parseLong(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                strongAuthUnlockTimeout = parser.getAttributeLong(null, ATTR_VALUE);
             } else if (TAG_MAX_FAILED_PASSWORD_WIPE.equals(tag)) {
-                maximumFailedPasswordsForWipe = Integer.parseInt(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                maximumFailedPasswordsForWipe = parser.getAttributeInt(null, ATTR_VALUE);
             } else if (TAG_SPECIFIES_GLOBAL_PROXY.equals(tag)) {
-                specifiesGlobalProxy = Boolean.parseBoolean(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                specifiesGlobalProxy = parser.getAttributeBoolean(null, ATTR_VALUE, false);
             } else if (TAG_GLOBAL_PROXY_SPEC.equals(tag)) {
                 globalProxySpec =
                     parser.getAttributeValue(null, ATTR_VALUE);
@@ -654,48 +640,36 @@
                 globalProxyExclusionList =
                     parser.getAttributeValue(null, ATTR_VALUE);
             } else if (TAG_PASSWORD_EXPIRATION_TIMEOUT.equals(tag)) {
-                passwordExpirationTimeout = Long.parseLong(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                passwordExpirationTimeout = parser.getAttributeLong(null, ATTR_VALUE);
             } else if (TAG_PASSWORD_EXPIRATION_DATE.equals(tag)) {
-                passwordExpirationDate = Long.parseLong(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                passwordExpirationDate = parser.getAttributeLong(null, ATTR_VALUE);
             } else if (TAG_ENCRYPTION_REQUESTED.equals(tag)) {
-                encryptionRequested = Boolean.parseBoolean(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                encryptionRequested = parser.getAttributeBoolean(null, ATTR_VALUE, false);
             } else if (TAG_TEST_ONLY_ADMIN.equals(tag)) {
-                testOnlyAdmin = Boolean.parseBoolean(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                testOnlyAdmin = parser.getAttributeBoolean(null, ATTR_VALUE, false);
             } else if (TAG_DISABLE_CAMERA.equals(tag)) {
-                disableCamera = Boolean.parseBoolean(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                disableCamera = parser.getAttributeBoolean(null, ATTR_VALUE, false);
             } else if (TAG_DISABLE_CALLER_ID.equals(tag)) {
-                disableCallerId = Boolean.parseBoolean(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                disableCallerId = parser.getAttributeBoolean(null, ATTR_VALUE, false);
             } else if (TAG_DISABLE_CONTACTS_SEARCH.equals(tag)) {
-                disableContactsSearch = Boolean.parseBoolean(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                disableContactsSearch = parser.getAttributeBoolean(null, ATTR_VALUE, false);
             } else if (TAG_DISABLE_BLUETOOTH_CONTACT_SHARING.equals(tag)) {
-                disableBluetoothContactSharing = Boolean.parseBoolean(parser
-                        .getAttributeValue(null, ATTR_VALUE));
+                disableBluetoothContactSharing =
+                        parser.getAttributeBoolean(null, ATTR_VALUE, false);
             } else if (TAG_DISABLE_SCREEN_CAPTURE.equals(tag)) {
-                disableScreenCapture = Boolean.parseBoolean(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                disableScreenCapture = parser.getAttributeBoolean(null, ATTR_VALUE, false);
             } else if (TAG_REQUIRE_AUTO_TIME.equals(tag)) {
-                requireAutoTime = Boolean.parseBoolean(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                requireAutoTime = parser.getAttributeBoolean(null, ATTR_VALUE, false);
             } else if (TAG_FORCE_EPHEMERAL_USERS.equals(tag)) {
-                forceEphemeralUsers = Boolean.parseBoolean(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                forceEphemeralUsers = parser.getAttributeBoolean(null, ATTR_VALUE, false);
             } else if (TAG_IS_NETWORK_LOGGING_ENABLED.equals(tag)) {
-                isNetworkLoggingEnabled = Boolean.parseBoolean(
-                        parser.getAttributeValue(null, ATTR_VALUE));
-                lastNetworkLoggingNotificationTimeMs = Long.parseLong(
-                        parser.getAttributeValue(null, ATTR_LAST_NETWORK_LOGGING_NOTIFICATION));
-                numNetworkLoggingNotifications = Integer.parseInt(
-                        parser.getAttributeValue(null, ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS));
+                isNetworkLoggingEnabled = parser.getAttributeBoolean(null, ATTR_VALUE, false);
+                lastNetworkLoggingNotificationTimeMs = parser.getAttributeLong(null,
+                        ATTR_LAST_NETWORK_LOGGING_NOTIFICATION);
+                numNetworkLoggingNotifications = parser.getAttributeInt(null,
+                        ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS);
             } else if (TAG_DISABLE_KEYGUARD_FEATURES.equals(tag)) {
-                disabledKeyguardFeatures = Integer.parseInt(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                disabledKeyguardFeatures = parser.getAttributeInt(null, ATTR_VALUE);
             } else if (TAG_DISABLE_ACCOUNT_MANAGEMENT.equals(tag)) {
                 readAttributeValues(
                         parser, TAG_ACCOUNT_TYPE, accountTypesWithManagementDisabled);
@@ -721,7 +695,7 @@
                         parser, TAG_RESTRICTION, defaultEnabledRestrictionsAlreadySet);
             } else if (TAG_SHORT_SUPPORT_MESSAGE.equals(tag)) {
                 type = parser.next();
-                if (type == XmlPullParser.TEXT) {
+                if (type == TypedXmlPullParser.TEXT) {
                     shortSupportMessage = parser.getText();
                 } else {
                     Log.w(DevicePolicyManagerService.LOG_TAG,
@@ -729,7 +703,7 @@
                 }
             } else if (TAG_LONG_SUPPORT_MESSAGE.equals(tag)) {
                 type = parser.next();
-                if (type == XmlPullParser.TEXT) {
+                if (type == TypedXmlPullParser.TEXT) {
                     longSupportMessage = parser.getText();
                 } else {
                     Log.w(DevicePolicyManagerService.LOG_TAG,
@@ -740,22 +714,20 @@
                 parentAdmin = new ActiveAdmin(info, /* parent */ true);
                 parentAdmin.readFromXml(parser, shouldOverridePolicies);
             } else if (TAG_ORGANIZATION_COLOR.equals(tag)) {
-                organizationColor = Integer.parseInt(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                organizationColor = parser.getAttributeInt(null, ATTR_VALUE);
             } else if (TAG_ORGANIZATION_NAME.equals(tag)) {
                 type = parser.next();
-                if (type == XmlPullParser.TEXT) {
+                if (type == TypedXmlPullParser.TEXT) {
                     organizationName = parser.getText();
                 } else {
                     Log.w(DevicePolicyManagerService.LOG_TAG,
                             "Missing text when loading organization name");
                 }
             } else if (TAG_IS_LOGOUT_ENABLED.equals(tag)) {
-                isLogoutEnabled = Boolean.parseBoolean(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                isLogoutEnabled = parser.getAttributeBoolean(null, ATTR_VALUE, false);
             } else if (TAG_START_USER_SESSION_MESSAGE.equals(tag)) {
                 type = parser.next();
-                if (type == XmlPullParser.TEXT) {
+                if (type == TypedXmlPullParser.TEXT) {
                     startUserSessionMessage = parser.getText();
                 } else {
                     Log.w(DevicePolicyManagerService.LOG_TAG,
@@ -763,7 +735,7 @@
                 }
             } else if (TAG_END_USER_SESSION_MESSAGE.equals(tag)) {
                 type = parser.next();
-                if (type == XmlPullParser.TEXT) {
+                if (type == TypedXmlPullParser.TEXT) {
                     endUserSessionMessage = parser.getText();
                 } else {
                     Log.w(DevicePolicyManagerService.LOG_TAG,
@@ -779,24 +751,21 @@
                 mFactoryResetProtectionPolicy = FactoryResetProtectionPolicy.readFromXml(
                             parser);
             } else if (TAG_SUSPEND_PERSONAL_APPS.equals(tag)) {
-                mSuspendPersonalApps = Boolean.parseBoolean(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                mSuspendPersonalApps = parser.getAttributeBoolean(null, ATTR_VALUE, false);
             } else if (TAG_PROFILE_MAXIMUM_TIME_OFF.equals(tag)) {
                 mProfileMaximumTimeOffMillis =
-                        Long.parseLong(parser.getAttributeValue(null, ATTR_VALUE));
+                        parser.getAttributeLong(null, ATTR_VALUE);
             } else if (TAG_PROFILE_OFF_DEADLINE.equals(tag)) {
                 mProfileOffDeadline =
-                        Long.parseLong(parser.getAttributeValue(null, ATTR_VALUE));
+                        parser.getAttributeLong(null, ATTR_VALUE);
             } else if (TAG_ALWAYS_ON_VPN_PACKAGE.equals(tag)) {
                 mAlwaysOnVpnPackage = parser.getAttributeValue(null, ATTR_VALUE);
             } else if (TAG_ALWAYS_ON_VPN_LOCKDOWN.equals(tag)) {
-                mAlwaysOnVpnLockdown = Boolean.parseBoolean(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                mAlwaysOnVpnLockdown = parser.getAttributeBoolean(null, ATTR_VALUE, false);
             } else if (TAG_COMMON_CRITERIA_MODE.equals(tag)) {
-                mCommonCriteriaMode = Boolean.parseBoolean(
-                        parser.getAttributeValue(null, ATTR_VALUE));
+                mCommonCriteriaMode = parser.getAttributeBoolean(null, ATTR_VALUE, false);
             } else if (TAG_PASSWORD_COMPLEXITY.equals(tag)) {
-                mPasswordComplexity = Integer.parseInt(parser.getAttributeValue(null, ATTR_VALUE));
+                mPasswordComplexity = parser.getAttributeInt(null, ATTR_VALUE);
             } else {
                 Slog.w(DevicePolicyManagerService.LOG_TAG, "Unknown admin tag: " + tag);
                 XmlUtils.skipCurrentTag(parser);
@@ -804,14 +773,14 @@
         }
     }
 
-    private List<String> readPackageList(XmlPullParser parser,
+    private List<String> readPackageList(TypedXmlPullParser parser,
             String tag) throws XmlPullParserException, IOException {
         List<String> result = new ArrayList<String>();
         int outerDepth = parser.getDepth();
         int outerType;
-        while ((outerType = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (outerType != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (outerType == XmlPullParser.END_TAG || outerType == XmlPullParser.TEXT) {
+        while ((outerType = parser.next()) != TypedXmlPullParser.END_DOCUMENT
+                && (outerType != TypedXmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (outerType == TypedXmlPullParser.END_TAG || outerType == TypedXmlPullParser.TEXT) {
                 continue;
             }
             String outerTag = parser.getName();
@@ -832,7 +801,7 @@
     }
 
     private void readAttributeValues(
-            XmlPullParser parser, String tag, Collection<String> result)
+            TypedXmlPullParser parser, String tag, Collection<String> result)
             throws XmlPullParserException, IOException {
         result.clear();
         int outerDepthDAM = parser.getDepth();
@@ -854,7 +823,7 @@
 
     @NonNull
     private ArrayMap<String, TrustAgentInfo> getAllTrustAgentInfos(
-            XmlPullParser parser, String tag) throws XmlPullParserException, IOException {
+            TypedXmlPullParser parser, String tag) throws XmlPullParserException, IOException {
         int outerDepthDAM = parser.getDepth();
         int typeDAM;
         final ArrayMap<String, TrustAgentInfo> result = new ArrayMap<>();
@@ -876,7 +845,7 @@
         return result;
     }
 
-    private TrustAgentInfo getTrustAgentInfo(XmlPullParser parser, String tag)
+    private TrustAgentInfo getTrustAgentInfo(TypedXmlPullParser parser, String tag)
             throws XmlPullParserException, IOException  {
         int outerDepthDAM = parser.getDepth();
         int typeDAM;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
index 8a585ec..31ba199 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
@@ -170,24 +170,19 @@
             }
             if (policyData.mUserSetupComplete) {
                 if (VERBOSE_LOG) Slog.v(TAG, "setting " + ATTR_SETUP_COMPLETE + " to true");
-                out.attribute(null, ATTR_SETUP_COMPLETE,
-                        Boolean.toString(true));
+                out.attributeBoolean(null, ATTR_SETUP_COMPLETE, true);
             }
             if (policyData.mPaired) {
-                out.attribute(null, ATTR_DEVICE_PAIRED,
-                        Boolean.toString(true));
+                out.attributeBoolean(null, ATTR_DEVICE_PAIRED, true);
             }
             if (policyData.mDeviceProvisioningConfigApplied) {
-                out.attribute(null, ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED,
-                        Boolean.toString(true));
+                out.attributeBoolean(null, ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED, true);
             }
             if (policyData.mUserProvisioningState != DevicePolicyManager.STATE_USER_UNMANAGED) {
-                out.attribute(null, ATTR_PROVISIONING_STATE,
-                        Integer.toString(policyData.mUserProvisioningState));
+                out.attributeInt(null, ATTR_PROVISIONING_STATE, policyData.mUserProvisioningState);
             }
             if (policyData.mPermissionPolicy != DevicePolicyManager.PERMISSION_POLICY_PROMPT) {
-                out.attribute(null, ATTR_PERMISSION_POLICY,
-                        Integer.toString(policyData.mPermissionPolicy));
+                out.attributeInt(null, ATTR_PERMISSION_POLICY, policyData.mPermissionPolicy);
             }
 
             // Serialize delegations.
@@ -217,13 +212,13 @@
 
             if (policyData.mPasswordOwner >= 0) {
                 out.startTag(null, "password-owner");
-                out.attribute(null, "value", Integer.toString(policyData.mPasswordOwner));
+                out.attributeInt(null, "value", policyData.mPasswordOwner);
                 out.endTag(null, "password-owner");
             }
 
             if (policyData.mFailedPasswordAttempts != 0) {
                 out.startTag(null, "failed-password-attempts");
-                out.attribute(null, "value", Integer.toString(policyData.mFailedPasswordAttempts));
+                out.attributeInt(null, "value", policyData.mFailedPasswordAttempts);
                 out.endTag(null, "failed-password-attempts");
             }
 
@@ -232,8 +227,7 @@
             // security reasons, we don't want to store the full set of active password metrics.
             if (isFdeDevice) {
                 out.startTag(null, TAG_PASSWORD_VALIDITY);
-                out.attribute(null, ATTR_VALUE,
-                        Boolean.toString(policyData.mPasswordValidAtLastCheckpoint));
+                out.attributeBoolean(null, ATTR_VALUE, policyData.mPasswordValidAtLastCheckpoint);
                 out.endTag(null, TAG_PASSWORD_VALIDITY);
             }
 
@@ -252,19 +246,19 @@
 
             if (policyData.mLockTaskFeatures != DevicePolicyManager.LOCK_TASK_FEATURE_NONE) {
                 out.startTag(null, TAG_LOCK_TASK_FEATURES);
-                out.attribute(null, ATTR_VALUE, Integer.toString(policyData.mLockTaskFeatures));
+                out.attributeInt(null, ATTR_VALUE, policyData.mLockTaskFeatures);
                 out.endTag(null, TAG_LOCK_TASK_FEATURES);
             }
 
             if (policyData.mSecondaryLockscreenEnabled) {
                 out.startTag(null, TAG_SECONDARY_LOCK_SCREEN);
-                out.attribute(null, ATTR_VALUE, Boolean.toString(true));
+                out.attributeBoolean(null, ATTR_VALUE, true);
                 out.endTag(null, TAG_SECONDARY_LOCK_SCREEN);
             }
 
             if (policyData.mStatusBarDisabled) {
                 out.startTag(null, TAG_STATUS_BAR);
-                out.attribute(null, ATTR_DISABLED, Boolean.toString(policyData.mStatusBarDisabled));
+                out.attributeBoolean(null, ATTR_DISABLED, policyData.mStatusBarDisabled);
                 out.endTag(null, TAG_STATUS_BAR);
             }
 
@@ -281,29 +275,25 @@
 
             if (policyData.mLastSecurityLogRetrievalTime >= 0) {
                 out.startTag(null, TAG_LAST_SECURITY_LOG_RETRIEVAL);
-                out.attribute(null, ATTR_VALUE,
-                        Long.toString(policyData.mLastSecurityLogRetrievalTime));
+                out.attributeLong(null, ATTR_VALUE, policyData.mLastSecurityLogRetrievalTime);
                 out.endTag(null, TAG_LAST_SECURITY_LOG_RETRIEVAL);
             }
 
             if (policyData.mLastBugReportRequestTime >= 0) {
                 out.startTag(null, TAG_LAST_BUG_REPORT_REQUEST);
-                out.attribute(null, ATTR_VALUE,
-                        Long.toString(policyData.mLastBugReportRequestTime));
+                out.attributeLong(null, ATTR_VALUE, policyData.mLastBugReportRequestTime);
                 out.endTag(null, TAG_LAST_BUG_REPORT_REQUEST);
             }
 
             if (policyData.mLastNetworkLogsRetrievalTime >= 0) {
                 out.startTag(null, TAG_LAST_NETWORK_LOG_RETRIEVAL);
-                out.attribute(null, ATTR_VALUE,
-                        Long.toString(policyData.mLastNetworkLogsRetrievalTime));
+                out.attributeLong(null, ATTR_VALUE, policyData.mLastNetworkLogsRetrievalTime);
                 out.endTag(null, TAG_LAST_NETWORK_LOG_RETRIEVAL);
             }
 
             if (policyData.mAdminBroadcastPending) {
                 out.startTag(null, TAG_ADMIN_BROADCAST_PENDING);
-                out.attribute(null, ATTR_VALUE,
-                        Boolean.toString(policyData.mAdminBroadcastPending));
+                out.attributeBoolean(null, ATTR_VALUE, policyData.mAdminBroadcastPending);
                 out.endTag(null, TAG_ADMIN_BROADCAST_PENDING);
             }
 
@@ -315,8 +305,7 @@
 
             if (policyData.mPasswordTokenHandle != 0) {
                 out.startTag(null, TAG_PASSWORD_TOKEN_HANDLE);
-                out.attribute(null, ATTR_VALUE,
-                        Long.toString(policyData.mPasswordTokenHandle));
+                out.attributeLong(null, ATTR_VALUE, policyData.mPasswordTokenHandle);
                 out.endTag(null, TAG_PASSWORD_TOKEN_HANDLE);
             }
 
@@ -340,7 +329,7 @@
 
             if (policyData.mAppsSuspended) {
                 out.startTag(null, TAG_APPS_SUSPENDED);
-                out.attribute(null, ATTR_VALUE, Boolean.toString(policyData.mAppsSuspended));
+                out.attributeBoolean(null, ATTR_VALUE, policyData.mAppsSuspended);
                 out.endTag(null, TAG_APPS_SUSPENDED);
             }
 
@@ -413,13 +402,13 @@
             if (Boolean.toString(true).equals(deviceProvisioningConfigApplied)) {
                 policy.mDeviceProvisioningConfigApplied = true;
             }
-            String provisioningState = parser.getAttributeValue(null, ATTR_PROVISIONING_STATE);
-            if (!TextUtils.isEmpty(provisioningState)) {
-                policy.mUserProvisioningState = Integer.parseInt(provisioningState);
+            int provisioningState = parser.getAttributeInt(null, ATTR_PROVISIONING_STATE, -1);
+            if (provisioningState != -1) {
+                policy.mUserProvisioningState = provisioningState;
             }
-            String permissionPolicy = parser.getAttributeValue(null, ATTR_PERMISSION_POLICY);
-            if (!TextUtils.isEmpty(permissionPolicy)) {
-                policy.mPermissionPolicy = Integer.parseInt(permissionPolicy);
+            int permissionPolicy = parser.getAttributeInt(null, ATTR_PERMISSION_POLICY, -1);
+            if (permissionPolicy != -1) {
+                policy.mPermissionPolicy = permissionPolicy;
             }
 
             parser.next();
@@ -472,37 +461,34 @@
                         scopes.add(scope);
                     }
                 } else if ("failed-password-attempts".equals(tag)) {
-                    policy.mFailedPasswordAttempts = Integer.parseInt(
-                            parser.getAttributeValue(null, "value"));
+                    policy.mFailedPasswordAttempts = parser.getAttributeInt(null, "value");
                 } else if ("password-owner".equals(tag)) {
-                    policy.mPasswordOwner = Integer.parseInt(
-                            parser.getAttributeValue(null, "value"));
+                    policy.mPasswordOwner = parser.getAttributeInt(null, "value");
                 } else if (TAG_ACCEPTED_CA_CERTIFICATES.equals(tag)) {
                     policy.mAcceptedCaCertificates.add(parser.getAttributeValue(null, ATTR_NAME));
                 } else if (TAG_LOCK_TASK_COMPONENTS.equals(tag)) {
                     policy.mLockTaskPackages.add(parser.getAttributeValue(null, "name"));
                 } else if (TAG_LOCK_TASK_FEATURES.equals(tag)) {
-                    policy.mLockTaskFeatures = Integer.parseInt(
-                            parser.getAttributeValue(null, ATTR_VALUE));
+                    policy.mLockTaskFeatures = parser.getAttributeInt(null, ATTR_VALUE);
                 } else if (TAG_SECONDARY_LOCK_SCREEN.equals(tag)) {
-                    policy.mSecondaryLockscreenEnabled = Boolean.parseBoolean(
-                            parser.getAttributeValue(null, ATTR_VALUE));
+                    policy.mSecondaryLockscreenEnabled =
+                            parser.getAttributeBoolean(null, ATTR_VALUE, false);
                 } else if (TAG_STATUS_BAR.equals(tag)) {
-                    policy.mStatusBarDisabled = Boolean.parseBoolean(
-                            parser.getAttributeValue(null, ATTR_DISABLED));
+                    policy.mStatusBarDisabled =
+                            parser.getAttributeBoolean(null, ATTR_DISABLED, false);
                 } else if (TAG_DO_NOT_ASK_CREDENTIALS_ON_BOOT.equals(tag)) {
                     policy.mDoNotAskCredentialsOnBoot = true;
                 } else if (TAG_AFFILIATION_ID.equals(tag)) {
                     policy.mAffiliationIds.add(parser.getAttributeValue(null, ATTR_ID));
                 } else if (TAG_LAST_SECURITY_LOG_RETRIEVAL.equals(tag)) {
-                    policy.mLastSecurityLogRetrievalTime = Long.parseLong(
-                            parser.getAttributeValue(null, ATTR_VALUE));
+                    policy.mLastSecurityLogRetrievalTime =
+                            parser.getAttributeLong(null, ATTR_VALUE);
                 } else if (TAG_LAST_BUG_REPORT_REQUEST.equals(tag)) {
-                    policy.mLastBugReportRequestTime = Long.parseLong(
-                            parser.getAttributeValue(null, ATTR_VALUE));
+                    policy.mLastBugReportRequestTime =
+                            parser.getAttributeLong(null, ATTR_VALUE);
                 } else if (TAG_LAST_NETWORK_LOG_RETRIEVAL.equals(tag)) {
-                    policy.mLastNetworkLogsRetrievalTime = Long.parseLong(
-                            parser.getAttributeValue(null, ATTR_VALUE));
+                    policy.mLastNetworkLogsRetrievalTime =
+                            parser.getAttributeLong(null, ATTR_VALUE);
                 } else if (TAG_ADMIN_BROADCAST_PENDING.equals(tag)) {
                     String pending = parser.getAttributeValue(null, ATTR_VALUE);
                     policy.mAdminBroadcastPending = Boolean.toString(true).equals(pending);
@@ -515,12 +501,11 @@
                 } else if (TAG_PASSWORD_VALIDITY.equals(tag)) {
                     if (isFdeDevice) {
                         // This flag is only used for FDE devices
-                        policy.mPasswordValidAtLastCheckpoint = Boolean.parseBoolean(
-                                parser.getAttributeValue(null, ATTR_VALUE));
+                        policy.mPasswordValidAtLastCheckpoint =
+                                parser.getAttributeBoolean(null, ATTR_VALUE, false);
                     }
                 } else if (TAG_PASSWORD_TOKEN_HANDLE.equals(tag)) {
-                    policy.mPasswordTokenHandle = Long.parseLong(
-                            parser.getAttributeValue(null, ATTR_VALUE));
+                    policy.mPasswordTokenHandle = parser.getAttributeLong(null, ATTR_VALUE);
                 } else if (TAG_CURRENT_INPUT_METHOD_SET.equals(tag)) {
                     policy.mCurrentInputMethodSet = true;
                 } else if (TAG_OWNER_INSTALLED_CA_CERT.equals(tag)) {
@@ -530,7 +515,7 @@
                             parser.getAttributeValue(null, ATTR_NAME));
                 } else if (TAG_APPS_SUSPENDED.equals(tag)) {
                     policy.mAppsSuspended =
-                            Boolean.parseBoolean(parser.getAttributeValue(null, ATTR_VALUE));
+                            parser.getAttributeBoolean(null, ATTR_VALUE, false);
                 } else {
                     Slog.w(TAG, "Unknown tag: " + tag);
                     XmlUtils.skipCurrentTag(parser);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 513543e..c7dbf95 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -983,17 +983,29 @@
 
     @Override
     public void setDevicePolicySafetyChecker(DevicePolicySafetyChecker safetyChecker) {
-        Slog.i(LOG_TAG, "Setting DevicePolicySafetyChecker as " + safetyChecker.getClass());
+        Slog.i(LOG_TAG, "Setting DevicePolicySafetyChecker as " + safetyChecker);
         mSafetyChecker = safetyChecker;
     }
 
     /**
+     * Used by {@link OneTimeSafetyChecker} only.
+     */
+    DevicePolicySafetyChecker getDevicePolicySafetyChecker() {
+        return mSafetyChecker;
+    }
+
+    /**
      * Checks if it's safe to execute the given {@code operation}.
      *
      * @throws UnsafeStateException if it's not safe to execute the operation.
      */
     private void checkCanExecuteOrThrowUnsafe(@DevicePolicyOperation int operation) {
         if (!canExecute(operation)) {
+            if (mSafetyChecker == null) {
+                // Happens on CTS after it's set just once (by OneTimeSafetyChecker)
+                throw new UnsafeStateException(operation);
+            }
+            // Let mSafetyChecker customize it (for example, by explaining how to retry)
             throw mSafetyChecker.newUnsafeStateException(operation);
         }
     }
@@ -1005,6 +1017,15 @@
         return mSafetyChecker == null || mSafetyChecker.isDevicePolicyOperationSafe(operation);
     }
 
+    @Override
+    public void setNextOperationSafety(@DevicePolicyOperation int operation, boolean safe) {
+        Preconditions.checkCallAuthorization(
+                hasCallingOrSelfPermission(permission.MANAGE_DEVICE_ADMINS));
+        Slog.i(LOG_TAG, "setNextOperationSafety(" + DevicePolicyManager.operationToString(operation)
+                + ", " + safe + ")");
+        mSafetyChecker = new OneTimeSafetyChecker(this, operation, safe);
+    }
+
     /**
      * Unit test will subclass it to inject mocks.
      */
@@ -2307,7 +2328,8 @@
                     + admin.info.getTagForPolicy(reqPolicy));
         } else {
             throw new SecurityException("No active admin owned by uid "
-                    + callingUid + " for policy #" + reqPolicy);
+                    + callingUid + " for policy #" + reqPolicy + (permission == null ? ""
+                    : ", which doesn't have " + permission));
         }
     }
 
@@ -2367,6 +2389,7 @@
      * If not provided, iterate over all of the active admins in the DevicePolicyData for that user
      * and return the one with the uid specified as parameter, and has the policy specified.
      */
+    @Nullable
     private ActiveAdmin getActiveAdminWithPolicyForUidLocked(ComponentName who, int reqPolicy,
             int uid) {
         ensureLocked();
@@ -5847,7 +5870,11 @@
         // Should include alias in authentication policy
         try (KeyChainConnection connection = KeyChain.bindAsUser(mContext,
                 caller.getUserHandle())) {
-            if (!containsAlias(connection.getService().getCredentialManagementAppPolicy(), alias)) {
+            // The policy will be null if there is no credential management app
+            AppUriAuthenticationPolicy policy =
+                    connection.getService().getCredentialManagementAppPolicy();
+            if (policy == null || policy.getAppAndUriMappings().isEmpty()
+                    || !containsAlias(policy, alias)) {
                 return false;
             }
         } catch (RemoteException | InterruptedException e) {
@@ -6071,10 +6098,14 @@
 
         final ActiveAdmin admin;
         synchronized (getLockObject()) {
-            admin = getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_WIPE_DATA);
+            admin = getActiveAdminWithPolicyForUidLocked(/* who= */ null,
+                    DeviceAdminInfo.USES_POLICY_WIPE_DATA, caller.getUid());
         }
-        Preconditions.checkCallAuthorization(admin != null,
-                "No active admin for user %d", caller.getUserId());
+
+        Preconditions.checkCallAuthorization(
+                (admin != null) || hasCallingOrSelfPermission(permission.MASTER_CLEAR),
+                "No active admin for user %d and caller %d does not hold MASTER_CLEAR permission",
+                caller.getUserId(), caller.getUid());
 
         if (TextUtils.isEmpty(wipeReasonForUser)) {
             if (calledByProfileOwnerOnOrgOwnedDevice && !calledOnParentInstance) {
@@ -6085,7 +6116,10 @@
             }
         }
 
-        int userId = admin.getUserHandle().getIdentifier();
+        int userId = admin != null ? admin.getUserHandle().getIdentifier()
+                : caller.getUserId();
+        Slog.i(LOG_TAG, "wipeDataWithReason(" + wipeReasonForUser + "): admin=" + admin + ", user="
+                + userId);
         if (calledByProfileOwnerOnOrgOwnedDevice) {
             // When wipeData is called on the parent instance, it implies wiping the entire device.
             if (calledOnParentInstance) {
@@ -6108,20 +6142,35 @@
                 });
             }
         }
-
-        DevicePolicyEventLogger
+        DevicePolicyEventLogger event = DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.WIPE_DATA_WITH_REASON)
-                .setAdmin(admin.info.getComponent())
                 .setInt(flags)
                 .setStrings(calledOnParentInstance ? CALLED_FROM_PARENT : NOT_CALLED_FROM_PARENT)
-                .write();
+                ;
+        final String adminName;
+        final ComponentName adminComp;
+        if (admin != null) {
+            adminComp = admin.info.getComponent();
+            adminName = adminComp.flattenToShortString();
+            event.setAdmin(adminComp);
+        } else {
+            adminComp = null;
+            adminName = mInjector.getPackageManager().getPackagesForUid(caller.getUid())[0];
+            Slog.i(LOG_TAG, "Logging wipeData() event admin as " + adminName);
+            event.setAdmin(adminName);
+            if (mInjector.userManagerIsHeadlessSystemUserMode()) {
+                // On headless system user mode, the call is meant to factory reset the whole
+                // device, otherwise the caller could simply remove the current user.
+                userId = UserHandle.USER_SYSTEM;
+            }
+        }
+        event.write();
+
         String internalReason = String.format(
                 "DevicePolicyManager.wipeDataWithReason() from %s, organization-owned? %s",
-                admin.info.getComponent().flattenToShortString(),
-                calledByProfileOwnerOnOrgOwnedDevice);
+                adminName, calledByProfileOwnerOnOrgOwnedDevice);
 
-        wipeDataNoLock(
-                admin.info.getComponent(), flags, internalReason, wipeReasonForUser, userId);
+        wipeDataNoLock(adminComp, flags, internalReason, wipeReasonForUser, userId);
     }
 
     private void wipeDataNoLock(ComponentName admin, int flags, String internalReason,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
index 0b0aee9..22866b4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
@@ -24,6 +24,7 @@
 final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
 
     private static final String CMD_IS_SAFE_OPERATION = "is-operation-safe";
+    private static final String CMD_SET_SAFE_OPERATION = "set-operation-safe";
 
     private final DevicePolicyManagerService mService;
 
@@ -48,6 +49,8 @@
             switch (cmd) {
                 case CMD_IS_SAFE_OPERATION:
                     return runIsSafeOperation(pw);
+                case CMD_SET_SAFE_OPERATION:
+                    return runSetSafeOperation(pw);
                 default:
                     return onInvalidCommand(pw, cmd);
             }
@@ -70,6 +73,9 @@
         pw.printf("    Prints this help text.\n\n");
         pw.printf("  %s <OPERATION_ID>\n", CMD_IS_SAFE_OPERATION);
         pw.printf("    Checks if the give operation is safe \n\n");
+        pw.printf("  %s <OPERATION_ID> <true|false>\n", CMD_SET_SAFE_OPERATION);
+        pw.printf("    Emulates the result of the next call to check if the given operation is safe"
+                + " \n\n");
     }
 
     private int runIsSafeOperation(PrintWriter pw) {
@@ -79,4 +85,13 @@
                 safe ? "SAFE" : "UNSAFE");
         return 0;
     }
+
+    private int runSetSafeOperation(PrintWriter pw) {
+        int operation = Integer.parseInt(getNextArgRequired());
+        boolean safe = getNextArg().equals("true");
+        mService.setNextOperationSafety(operation, safe);
+        pw.printf("Next call to check operation %s will return %s\n",
+                DevicePolicyManager.operationToString(operation), safe ? "SAFE" : "UNSAFE");
+        return 0;
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java b/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java
new file mode 100644
index 0000000..b0f8bfb
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java
@@ -0,0 +1,67 @@
+/*
+ * 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.devicepolicy;
+
+import static android.app.admin.DevicePolicyManager.operationToString;
+
+import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
+import android.app.admin.DevicePolicySafetyChecker;
+import android.util.Slog;
+
+import java.util.Objects;
+
+//TODO(b/172376923): add unit tests
+
+/**
+ * {@code DevicePolicySafetyChecker} implementation that overrides the real checker for just
+ * one command.
+ *
+ * <p>Used only for debugging and CTS tests.
+ */
+final class OneTimeSafetyChecker implements DevicePolicySafetyChecker {
+
+    private static final String TAG = OneTimeSafetyChecker.class.getSimpleName();
+
+    private final DevicePolicyManagerService mService;
+    private final DevicePolicySafetyChecker mRealSafetyChecker;
+    private final @DevicePolicyOperation int mOperation;
+    private final boolean mSafe;
+
+    OneTimeSafetyChecker(DevicePolicyManagerService service,
+            @DevicePolicyOperation int operation, boolean safe) {
+        mService = Objects.requireNonNull(service);
+        mOperation = operation;
+        mSafe = safe;
+        mRealSafetyChecker = service.getDevicePolicySafetyChecker();
+        Slog.i(TAG, "Saving real DevicePolicySafetyChecker as " + mRealSafetyChecker);
+    }
+
+    @Override
+    public boolean isDevicePolicyOperationSafe(@DevicePolicyOperation int operation) {
+        String name = operationToString(operation);
+        boolean safe = true;
+        if (operation == mOperation) {
+            safe = mSafe;
+        } else {
+            Slog.wtf(TAG, "invalid call to isDevicePolicyOperationSafe(): asked for " + name
+                    + ", should be " + operationToString(mOperation));
+        }
+        Slog.i(TAG, "isDevicePolicyOperationSafe(" + name + "): returning " + safe
+                + " and restoring DevicePolicySafetyChecker to " + mRealSafetyChecker);
+        mService.setDevicePolicySafetyChecker(mRealSafetyChecker);
+        return safe;
+    }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 8ef6982..79a82b8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -43,22 +43,18 @@
 import android.util.Xml;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FastXmlSerializer;
 import com.android.server.LocalServices;
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
 import libcore.io.IoUtils;
 
-import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
 import java.time.LocalDate;
 import java.util.List;
 import java.util.Map;
@@ -558,11 +554,10 @@
         }
         try {
             InputStream input = new AtomicFile(file).openRead();
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(input, StandardCharsets.UTF_8.name());
+            TypedXmlPullParser parser = Xml.resolvePullParser(input);
             int type;
-            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT) {
-                if (type!=XmlPullParser.START_TAG) {
+            while ((type=parser.next()) != TypedXmlPullParser.END_DOCUMENT) {
+                if (type!=TypedXmlPullParser.START_TAG) {
                     continue;
                 }
 
@@ -581,7 +576,7 @@
                     String profileOwnerName = parser.getAttributeValue(null, ATTR_NAME);
                     String profileOwnerComponentStr =
                             parser.getAttributeValue(null, ATTR_COMPONENT_NAME);
-                    int userId = Integer.parseInt(parser.getAttributeValue(null, ATTR_USERID));
+                    int userId = parser.getAttributeInt(null, ATTR_USERID);
                     OwnerInfo profileOwnerInfo = null;
                     if (profileOwnerComponentStr != null) {
                         ComponentName admin = ComponentName.unflattenFromString(
@@ -781,12 +776,12 @@
 
                 int type;
                 int depth = 0;
-                while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+                while ((type = parser.next()) != TypedXmlPullParser.END_DOCUMENT) {
                     switch (type) {
-                        case XmlPullParser.START_TAG:
+                        case TypedXmlPullParser.START_TAG:
                             depth++;
                             break;
-                        case XmlPullParser.END_TAG:
+                        case TypedXmlPullParser.END_TAG:
                             depth--;
                             // fallthrough
                         default:
@@ -813,9 +808,9 @@
             }
         }
 
-        abstract void writeInner(XmlSerializer out) throws IOException;
+        abstract void writeInner(TypedXmlSerializer out) throws IOException;
 
-        abstract boolean readInner(XmlPullParser parser, int depth, String tag);
+        abstract boolean readInner(TypedXmlPullParser parser, int depth, String tag);
     }
 
     private class DeviceOwnerReadWriter extends FileReadWriter {
@@ -831,11 +826,11 @@
         }
 
         @Override
-        void writeInner(XmlSerializer out) throws IOException {
+        void writeInner(TypedXmlSerializer out) throws IOException {
             if (mDeviceOwner != null) {
                 mDeviceOwner.writeToXml(out, TAG_DEVICE_OWNER);
                 out.startTag(null, TAG_DEVICE_OWNER_CONTEXT);
-                out.attribute(null, ATTR_USERID, String.valueOf(mDeviceOwnerUserId));
+                out.attributeInt(null, ATTR_USERID, mDeviceOwnerUserId);
                 out.endTag(null, TAG_DEVICE_OWNER_CONTEXT);
             }
 
@@ -863,7 +858,7 @@
         }
 
         @Override
-        boolean readInner(XmlPullParser parser, int depth, String tag) {
+        boolean readInner(TypedXmlPullParser parser, int depth, String tag) {
             if (depth > 2) {
                 return true; // Ignore
             }
@@ -873,13 +868,8 @@
                     mDeviceOwnerUserId = UserHandle.USER_SYSTEM; // Set default
                     break;
                 case TAG_DEVICE_OWNER_CONTEXT: {
-                    final String userIdString =
-                            parser.getAttributeValue(null, ATTR_USERID);
-                    try {
-                        mDeviceOwnerUserId = Integer.parseInt(userIdString);
-                    } catch (NumberFormatException e) {
-                        Slog.e(TAG, "Error parsing user-id " + userIdString);
-                    }
+                    mDeviceOwnerUserId = parser.getAttributeInt(null, ATTR_USERID,
+                            mDeviceOwnerUserId);
                     break;
                 }
                 case TAG_DEVICE_INITIALIZER:
@@ -927,7 +917,7 @@
         }
 
         @Override
-        void writeInner(XmlSerializer out) throws IOException {
+        void writeInner(TypedXmlSerializer out) throws IOException {
             final OwnerInfo profileOwner = mProfileOwners.get(mUserId);
             if (profileOwner != null) {
                 profileOwner.writeToXml(out, TAG_PROFILE_OWNER);
@@ -935,7 +925,7 @@
         }
 
         @Override
-        boolean readInner(XmlPullParser parser, int depth, String tag) {
+        boolean readInner(TypedXmlPullParser parser, int depth, String tag) {
             if (depth > 2) {
                 return true; // Ignore
             }
@@ -985,7 +975,7 @@
             this.isOrganizationOwnedDevice = isOrganizationOwnedDevice;
         }
 
-        public void writeToXml(XmlSerializer out, String tag) throws IOException {
+        public void writeToXml(TypedXmlSerializer out, String tag) throws IOException {
             out.startTag(null, tag);
             out.attribute(null, ATTR_PACKAGE, packageName);
             if (name != null) {
@@ -994,8 +984,7 @@
             if (admin != null) {
                 out.attribute(null, ATTR_COMPONENT_NAME, admin.flattenToString());
             }
-            out.attribute(null, ATTR_USER_RESTRICTIONS_MIGRATED,
-                    String.valueOf(userRestrictionsMigrated));
+            out.attributeBoolean(null, ATTR_USER_RESTRICTIONS_MIGRATED, userRestrictionsMigrated);
             if (remoteBugreportUri != null) {
                 out.attribute(null, ATTR_REMOTE_BUGREPORT_URI, remoteBugreportUri);
             }
@@ -1003,13 +992,13 @@
                 out.attribute(null, ATTR_REMOTE_BUGREPORT_HASH, remoteBugreportHash);
             }
             if (isOrganizationOwnedDevice) {
-                out.attribute(null, ATTR_PROFILE_OWNER_OF_ORG_OWNED_DEVICE,
-                        String.valueOf(isOrganizationOwnedDevice));
+                out.attributeBoolean(null, ATTR_PROFILE_OWNER_OF_ORG_OWNED_DEVICE,
+                        isOrganizationOwnedDevice);
             }
             out.endTag(null, tag);
         }
 
-        public static OwnerInfo readFromXml(XmlPullParser parser) {
+        public static OwnerInfo readFromXml(TypedXmlPullParser parser) {
             final String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
             final String name = parser.getAttributeValue(null, ATTR_NAME);
             final String componentName =
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/TransferOwnershipMetadataManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/TransferOwnershipMetadataManager.java
index 58ece07..289ed36 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/TransferOwnershipMetadataManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/TransferOwnershipMetadataManager.java
@@ -29,18 +29,15 @@
 import android.util.Xml;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.Preconditions;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.nio.charset.StandardCharsets;
 import java.util.Objects;
 
 /**
@@ -106,7 +103,7 @@
         return false;
     }
 
-    private void insertSimpleTag(XmlSerializer serializer, String tagName, String value)
+    private void insertSimpleTag(TypedXmlSerializer serializer, String tagName, String value)
             throws IOException {
         serializer.startTag(null, tagName);
         serializer.text(value);
@@ -132,7 +129,7 @@
         return null;
     }
 
-    private Metadata parseMetadataFile(XmlPullParser parser)
+    private Metadata parseMetadataFile(TypedXmlPullParser parser)
             throws XmlPullParserException, IOException {
         int type;
         final int outerDepth = parser.getDepth();
diff --git a/services/incremental/OWNERS b/services/incremental/OWNERS
new file mode 100644
index 0000000..d825dfd
--- /dev/null
+++ b/services/incremental/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/OWNERS
diff --git a/services/people/OWNERS b/services/people/OWNERS
new file mode 100644
index 0000000..7ac9b73
--- /dev/null
+++ b/services/people/OWNERS
@@ -0,0 +1,2 @@
+danningc@google.com
+juliacr@google.com
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index 3e06194..b5e595a 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -554,7 +554,7 @@
             @Nullable List<String> shortcutIds) {
         @ShortcutQuery.QueryFlags int queryFlags = ShortcutQuery.FLAG_MATCH_DYNAMIC
                 | ShortcutQuery.FLAG_MATCH_PINNED | ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER
-                | ShortcutQuery.FLAG_MATCH_CACHED;
+                | ShortcutQuery.FLAG_MATCH_CACHED | ShortcutQuery.FLAG_GET_PERSONS_DATA;
         return mShortcutServiceInternal.getShortcuts(
                 UserHandle.USER_SYSTEM, mContext.getPackageName(),
                 /*changedSince=*/ 0, packageName, shortcutIds, /*locusIds=*/ null,
diff --git a/services/print/OWNERS b/services/print/OWNERS
new file mode 100644
index 0000000..2c7b881
--- /dev/null
+++ b/services/print/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/print/OWNERS
diff --git a/services/restrictions/OWNERS b/services/restrictions/OWNERS
new file mode 100644
index 0000000..95e614c
--- /dev/null
+++ b/services/restrictions/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/restrictions/OWNERS
diff --git a/services/robotests/backup/OWNERS b/services/robotests/backup/OWNERS
new file mode 100644
index 0000000..d99779e
--- /dev/null
+++ b/services/robotests/backup/OWNERS
@@ -0,0 +1 @@
+include /services/backup/OWNERS
diff --git a/services/robotests/src/com/android/server/backup/OWNERS b/services/robotests/src/com/android/server/backup/OWNERS
new file mode 100644
index 0000000..d99779e
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/OWNERS
@@ -0,0 +1 @@
+include /services/backup/OWNERS
diff --git a/services/robotests/src/com/android/server/pm/OWNERS b/services/robotests/src/com/android/server/pm/OWNERS
new file mode 100644
index 0000000..d825dfd
--- /dev/null
+++ b/services/robotests/src/com/android/server/pm/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/OWNERS
diff --git a/services/startop/OWNERS b/services/startop/OWNERS
new file mode 100644
index 0000000..bd3d829
--- /dev/null
+++ b/services/startop/OWNERS
@@ -0,0 +1 @@
+include /startop/OWNERS
diff --git a/services/tests/PackageManager/OWNERS b/services/tests/PackageManager/OWNERS
new file mode 100644
index 0000000..d825dfd
--- /dev/null
+++ b/services/tests/PackageManager/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/OWNERS
diff --git a/services/tests/PackageManagerComponentOverrideTests/OWNERS b/services/tests/PackageManagerComponentOverrideTests/OWNERS
new file mode 100644
index 0000000..d825dfd
--- /dev/null
+++ b/services/tests/PackageManagerComponentOverrideTests/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/OWNERS
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 8fc5c08..03083c1 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -15,7 +15,7 @@
 android_test {
     name: "FrameworksMockingServicesTests",
 
-    srcs: ["src/**/*.java"],
+    srcs: ["src/**/*.java", "src/**/*.kt"],
 
     static_libs: [
         "services.core",
@@ -29,6 +29,10 @@
         "mockito-target-extended-minus-junit4",
         "platform-test-annotations",
         "truth-prebuilt",
+        "hamcrest-library",
+        "servicestests-utils-mockito-extended",
+        "mockingservicestests-utils-mockito",
+        "servicestests-core-utils",
         "testables",
         // TODO: remove once Android migrates to JUnit 4.12, which provides assertThrows
         "testng",
@@ -54,3 +58,17 @@
         enabled: false,
     },
 }
+
+java_library {
+    name: "mockingservicestests-utils-mockito",
+    srcs: [
+        "utils-mockito/**/*.kt",
+    ],
+    static_libs: [
+        "junit",
+        "mockito-target-extended-minus-junit4",
+    ],
+    libs: [
+        "android.test.runner",
+    ],
+}
\ No newline at end of file
diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml
index 182fe9a..fbde1d2 100644
--- a/services/tests/mockingservicestests/AndroidManifest.xml
+++ b/services/tests/mockingservicestests/AndroidManifest.xml
@@ -27,6 +27,9 @@
     <uses-permission android:name="android.permission.MANAGE_APPOPS"/>
     <uses-permission android:name="android.permission.MONITOR_DEVICE_CONFIG_ACCESS"/>
 
+    <!-- needed by MasterClearReceiverTest to display a system dialog -->
+    <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/>
+
     <application android:testOnly="true"
                  android:debuggable="true">
         <uses-library android:name="android.test.runner" />
diff --git a/services/tests/mockingservicestests/assets/AppOpsUpgradeTest/OWNERS b/services/tests/mockingservicestests/assets/AppOpsUpgradeTest/OWNERS
new file mode 100644
index 0000000..999ea0e
--- /dev/null
+++ b/services/tests/mockingservicestests/assets/AppOpsUpgradeTest/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/permission/OWNERS
diff --git a/services/tests/mockingservicestests/src/com/android/server/MasterClearReceiverTest.java b/services/tests/mockingservicestests/src/com/android/server/MasterClearReceiverTest.java
new file mode 100644
index 0000000..f01120e
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/MasterClearReceiverTest.java
@@ -0,0 +1,210 @@
+/*
+ * 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;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.never;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.os.Looper;
+import android.os.RecoverySystem;
+import android.os.storage.StorageManager;
+import android.platform.test.annotations.Presubmit;
+import android.util.Log;
+import android.view.WindowManager;
+
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Run it as {@code FrameworksMockingServicesTests:MasterClearReceiverTest}.
+ */
+@Presubmit
+public final class MasterClearReceiverTest {
+
+    private static final String TAG = MasterClearReceiverTest.class.getSimpleName();
+
+    private MockitoSession mSession;
+
+    // Cannot @Mock context because MasterClearReceiver shows an AlertDialog, which relies
+    // on resources - we'd need to mock them as well.
+    private final Context mContext = new ContextWrapper(
+            InstrumentationRegistry.getInstrumentation().getTargetContext()) {
+
+        @Override
+        public Object getSystemService(String name) {
+            Log.v(TAG, "getSystemService(): " + name);
+            return name.equals(Context.STORAGE_SERVICE) ? mSm : super.getSystemService(name);
+        }
+    };
+
+    private final MasterClearReceiver mReceiver = new MasterClearReceiver();
+
+    // Used to make sure that wipeAdoptableDisks() is called before rebootWipeUserData()
+    private boolean mWipeExternalDataCalled;
+
+    // Uset to block test until rebootWipeUserData() is called, as it might be asynchronous called
+    // in a different thread
+    private final CountDownLatch mRebootWipeUserDataLatch = new CountDownLatch(1);
+
+    @Mock
+    private StorageManager mSm;
+
+    @Mock
+    private WindowManager mWm;
+
+    @Before
+    public void startSession() {
+        mSession = mockitoSession()
+                .initMocks(this)
+                .mockStatic(RecoverySystem.class)
+                .strictness(Strictness.LENIENT)
+                .startMocking();
+    }
+
+    @After
+    public void finishSession() {
+        if (mSession == null) {
+            Log.w(TAG, "finishSession(): no session");
+            return;
+        }
+        mSession.finishMocking();
+    }
+
+    @Test
+    public void testNoExtras() throws Exception {
+        expectNoWipeExternalData();
+        expectRebootWipeUserData();
+
+        Intent intent = new Intent(Intent.ACTION_FACTORY_RESET);
+        mReceiver.onReceive(mContext, intent);
+
+        verifyRebootWipeUserData();
+        verifyNoWipeExternalData();
+    }
+
+    @Test
+    public void testWipeExternalDirectory() throws Exception {
+        expectWipeExternalData();
+        expectRebootWipeUserData();
+
+        Intent intent = new Intent(Intent.ACTION_FACTORY_RESET);
+        intent.putExtra(Intent.EXTRA_WIPE_EXTERNAL_STORAGE, true);
+        mReceiver.onReceive(mContext, intent);
+
+        verifyRebootWipeUserData();
+        verifyWipeExternalData();
+    }
+
+    @Test
+    public void testAllExtras() throws Exception {
+        expectWipeExternalData();
+        expectRebootWipeUserData();
+
+        Intent intent = new Intent(Intent.ACTION_FACTORY_RESET);
+        intent.putExtra(Intent.EXTRA_WIPE_EXTERNAL_STORAGE, true);
+        intent.putExtra("shutdown", true);
+        intent.putExtra(Intent.EXTRA_REASON, "Self destruct");
+        intent.putExtra(Intent.EXTRA_FORCE_FACTORY_RESET, true);
+        intent.putExtra(Intent.EXTRA_WIPE_ESIMS, true);
+        mReceiver.onReceive(mContext, intent);
+
+        verifyRebootWipeUserData(/* shutdown= */ true, /* reason= */ "Self destruct",
+                /* force= */ true, /* wipeEuicc= */ true);
+        verifyWipeExternalData();
+    }
+
+
+    private void expectNoWipeExternalData() {
+        // This is a trick to simplify how the order of methods are called: as wipeAdoptableDisks()
+        // should be called before rebootWipeUserData(), expectRebootWipeUserData() throws an
+        // exception if it's not called, so this method "emulates" a call when it's not neeeded.
+        //
+        // A more robust solution would be using internal counters for expected and actual mocked
+        // calls, so the expectXXX() methods would increment expected counter and the Answer
+        // implementations would increment the actual counter and check if they match, but that
+        // would be an overkill (and make the test logic more complicated).
+        mWipeExternalDataCalled = true;
+    }
+
+    private void expectRebootWipeUserData() {
+        doAnswer((inv) -> {
+            Log.i(TAG, inv.toString());
+            if (!mWipeExternalDataCalled) {
+                String error = "rebootWipeUserData() called before wipeAdoptableDisks()";
+                Log.e(TAG, error);
+                throw new IllegalStateException(error);
+            }
+            mRebootWipeUserDataLatch.countDown();
+            return null;
+        }).when(() -> RecoverySystem
+                .rebootWipeUserData(any(), anyBoolean(), any(), anyBoolean(), anyBoolean()));
+    }
+
+    private void expectWipeExternalData() {
+        Looper.prepare(); // needed by Dialog
+
+        doAnswer((inv) -> {
+            Log.i(TAG, inv.toString());
+            mWipeExternalDataCalled = true;
+            return null;
+        }).when(mSm).wipeAdoptableDisks();
+    }
+
+    private void verifyRebootWipeUserData() throws Exception  {
+        verifyRebootWipeUserData(/* shutdown= */ false, /* reason= */ null, /* force= */ false,
+                /* wipeEuicc= */ false);
+
+    }
+
+    private void verifyRebootWipeUserData(boolean shutdown, String reason, boolean force,
+            boolean wipeEuicc) throws Exception {
+        boolean called = mRebootWipeUserDataLatch.await(5, TimeUnit.SECONDS);
+        assertWithMessage("rebootWipeUserData not called in 5s").that(called).isTrue();
+
+        verify(()-> RecoverySystem.rebootWipeUserData(same(mContext), eq(shutdown), eq(reason),
+                eq(force), eq(wipeEuicc)));
+    }
+
+    private void verifyWipeExternalData() {
+        verify(mSm).wipeAdoptableDisks();
+    }
+
+    private void verifyNoWipeExternalData() {
+        verify(mSm, never()).wipeAdoptableDisks();
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/OWNERS b/services/tests/mockingservicestests/src/com/android/server/OWNERS
new file mode 100644
index 0000000..e779e21
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/OWNERS
@@ -0,0 +1 @@
+per-file *Alarm* = file:/apex/jobscheduler/OWNERS
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/OWNERS b/services/tests/mockingservicestests/src/com/android/server/alarm/OWNERS
new file mode 100644
index 0000000..6f207fb1
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/OWNERS
@@ -0,0 +1 @@
+include /apex/jobscheduler/OWNERS
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/OWNERS b/services/tests/mockingservicestests/src/com/android/server/am/OWNERS
new file mode 100644
index 0000000..72c0a9e
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/am/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/am/OWNERS
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/OWNERS b/services/tests/mockingservicestests/src/com/android/server/appop/OWNERS
new file mode 100644
index 0000000..999ea0e
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/permission/OWNERS
diff --git a/services/tests/mockingservicestests/src/com/android/server/blob/OWNERS b/services/tests/mockingservicestests/src/com/android/server/blob/OWNERS
new file mode 100644
index 0000000..65bb6b8
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/blob/OWNERS
@@ -0,0 +1 @@
+include /apex/blobstore/OWNERS
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/OWNERS b/services/tests/mockingservicestests/src/com/android/server/display/OWNERS
new file mode 100644
index 0000000..6ce1ee4
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/display/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/display/OWNERS
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/OWNERS b/services/tests/mockingservicestests/src/com/android/server/job/OWNERS
new file mode 100644
index 0000000..6f207fb1
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/job/OWNERS
@@ -0,0 +1 @@
+include /apex/jobscheduler/OWNERS
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
index 7f86faa..78bcc13 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -145,7 +145,7 @@
 
         final ConnectivityController controller = new ConnectivityController(mService);
         when(mService.getMaxJobExecutionTimeMs(any()))
-                .thenReturn(JobServiceContext.EXECUTING_TIMESLICE_MILLIS);
+                .thenReturn(JobServiceContext.DEFAULT_EXECUTING_TIMESLICE_MILLIS);
 
         // Slow network is too slow
         assertFalse(controller.isSatisfied(createJobStatus(job), net,
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 8795d77..4f3564d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -35,6 +35,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -42,6 +43,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.never;
@@ -76,6 +78,7 @@
 
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.server.LocalServices;
 import com.android.server.job.JobSchedulerService;
 import com.android.server.job.JobSchedulerService.Constants;
@@ -269,8 +272,9 @@
                 verify(foregroundUids, timeout(2 * SECOND_IN_MILLIS).times(1)).delete(eq(uid));
                 assertFalse(foregroundUids.get(uid));
             }
-        } catch (RemoteException e) {
-            fail("registerUidObserver threw exception: " + e.getMessage());
+            waitForQuietBackground();
+        } catch (Exception e) {
+            fail("exception encountered: " + e.getMessage());
         }
     }
 
@@ -323,6 +327,14 @@
         return createJobStatus(testTag, SOURCE_PACKAGE, CALLING_UID, jobInfo);
     }
 
+    private JobStatus createHpjJobStatus(String testTag, int jobId) {
+        JobInfo jobInfo = new JobInfo.Builder(jobId,
+                new ComponentName(mContext, "TestQuotaHpjJobService"))
+                .setForeground(true)
+                .build();
+        return createJobStatus(testTag, SOURCE_PACKAGE, CALLING_UID, jobInfo);
+    }
+
     private JobStatus createJobStatus(String testTag, String packageName, int callingUid,
             JobInfo jobInfo) {
         JobStatus js = JobStatus.createFromJobInfo(
@@ -356,26 +368,49 @@
         }
     }
 
+    private void waitForQuietBackground() throws Exception {
+        for (int i = 0; i < 5; ++i) {
+            if (!mQuotaController.isActiveBackgroundProcessing()) {
+                break;
+            }
+            Thread.sleep(500);
+        }
+    }
+
     @Test
     public void testSaveTimingSession() {
         assertNull(mQuotaController.getTimingSessions(0, "com.android.test"));
 
-        List<TimingSession> expected = new ArrayList<>();
+        List<TimingSession> expectedRegular = new ArrayList<>();
+        List<TimingSession> expectedHpj = new ArrayList<>();
         TimingSession one = new TimingSession(1, 10, 1);
         TimingSession two = new TimingSession(11, 20, 2);
         TimingSession thr = new TimingSession(21, 30, 3);
+        TimingSession fou = new TimingSession(31, 40, 4);
 
-        mQuotaController.saveTimingSession(0, "com.android.test", one);
-        expected.add(one);
-        assertEquals(expected, mQuotaController.getTimingSessions(0, "com.android.test"));
+        mQuotaController.saveTimingSession(0, "com.android.test", one, false);
+        expectedRegular.add(one);
+        assertEquals(expectedRegular, mQuotaController.getTimingSessions(0, "com.android.test"));
+        assertTrue(
+                ArrayUtils.isEmpty(mQuotaController.getHpjTimingSessions(0, "com.android.test")));
 
-        mQuotaController.saveTimingSession(0, "com.android.test", two);
-        expected.add(two);
-        assertEquals(expected, mQuotaController.getTimingSessions(0, "com.android.test"));
+        mQuotaController.saveTimingSession(0, "com.android.test", two, false);
+        expectedRegular.add(two);
+        assertEquals(expectedRegular, mQuotaController.getTimingSessions(0, "com.android.test"));
+        assertTrue(
+                ArrayUtils.isEmpty(mQuotaController.getHpjTimingSessions(0, "com.android.test")));
 
-        mQuotaController.saveTimingSession(0, "com.android.test", thr);
-        expected.add(thr);
-        assertEquals(expected, mQuotaController.getTimingSessions(0, "com.android.test"));
+        mQuotaController.saveTimingSession(0, "com.android.test", thr, true);
+        expectedHpj.add(thr);
+        assertEquals(expectedRegular, mQuotaController.getTimingSessions(0, "com.android.test"));
+        assertEquals(expectedHpj, mQuotaController.getHpjTimingSessions(0, "com.android.test"));
+
+        mQuotaController.saveTimingSession(0, "com.android.test", fou, false);
+        mQuotaController.saveTimingSession(0, "com.android.test", fou, true);
+        expectedRegular.add(fou);
+        expectedHpj.add(fou);
+        assertEquals(expectedRegular, mQuotaController.getTimingSessions(0, "com.android.test"));
+        assertEquals(expectedHpj, mQuotaController.getHpjTimingSessions(0, "com.android.test"));
     }
 
     @Test
@@ -393,35 +428,48 @@
         // Way past the 24 hour boundary.
         TimingSession fiv = createTimingSession(
                 now - (25 * HOUR_IN_MILLIS), 5 * MINUTE_IN_MILLIS, 4);
-        List<TimingSession> expected = new ArrayList<>();
+        List<TimingSession> expectedRegular = new ArrayList<>();
+        List<TimingSession> expectedHpj = new ArrayList<>();
         // Added in correct (chronological) order.
-        expected.add(fou);
-        expected.add(thr);
-        expected.add(two);
-        expected.add(one);
-        mQuotaController.saveTimingSession(0, "com.android.test", fiv);
-        mQuotaController.saveTimingSession(0, "com.android.test", fou);
-        mQuotaController.saveTimingSession(0, "com.android.test", thr);
-        mQuotaController.saveTimingSession(0, "com.android.test", two);
-        mQuotaController.saveTimingSession(0, "com.android.test", one);
+        expectedRegular.add(fou);
+        expectedRegular.add(thr);
+        expectedRegular.add(two);
+        expectedRegular.add(one);
+        expectedHpj.add(fiv); // HPJ list should be unaffected
+        expectedHpj.add(fou);
+        expectedHpj.add(one);
+        mQuotaController.saveTimingSession(0, "com.android.test", fiv, false);
+        mQuotaController.saveTimingSession(0, "com.android.test", fou, false);
+        mQuotaController.saveTimingSession(0, "com.android.test", thr, false);
+        mQuotaController.saveTimingSession(0, "com.android.test", two, false);
+        mQuotaController.saveTimingSession(0, "com.android.test", one, false);
+        mQuotaController.saveTimingSession(0, "com.android.test", fiv, true);
+        mQuotaController.saveTimingSession(0, "com.android.test", fou, true);
+        mQuotaController.saveTimingSession(0, "com.android.test", one, true);
 
         synchronized (mQuotaController.mLock) {
             mQuotaController.deleteObsoleteSessionsLocked();
         }
 
-        assertEquals(expected, mQuotaController.getTimingSessions(0, "com.android.test"));
+        assertEquals(expectedRegular, mQuotaController.getTimingSessions(0, "com.android.test"));
+        assertEquals(expectedHpj, mQuotaController.getHpjTimingSessions(0, "com.android.test"));
     }
 
     @Test
     public void testOnAppRemovedLocked() {
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
         mQuotaController.saveTimingSession(0, "com.android.test.remove",
-                createTimingSession(now - (6 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5));
+                createTimingSession(now - (6 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5), false);
         mQuotaController.saveTimingSession(0, "com.android.test.remove",
                 createTimingSession(
-                        now - (2 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 6 * MINUTE_IN_MILLIS, 5));
+                        now - (2 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 6 * MINUTE_IN_MILLIS, 5),
+                false);
         mQuotaController.saveTimingSession(0, "com.android.test.remove",
-                createTimingSession(now - (HOUR_IN_MILLIS), MINUTE_IN_MILLIS, 1));
+                createTimingSession(now - (HOUR_IN_MILLIS), MINUTE_IN_MILLIS, 1), false);
+        mQuotaController.saveTimingSession(0, "com.android.test.remove",
+                createTimingSession(now - (30 * MINUTE_IN_MILLIS), MINUTE_IN_MILLIS, 1), true);
+        mQuotaController.saveTimingSession(0, "com.android.test.remove",
+                createTimingSession(now - (15 * MINUTE_IN_MILLIS), MINUTE_IN_MILLIS, 1), true);
         // Test that another app isn't affected.
         TimingSession one = createTimingSession(
                 now - 10 * MINUTE_IN_MILLIS, 9 * MINUTE_IN_MILLIS, 3);
@@ -431,8 +479,14 @@
         // Added in correct (chronological) order.
         expected.add(two);
         expected.add(one);
-        mQuotaController.saveTimingSession(0, "com.android.test.stay", two);
-        mQuotaController.saveTimingSession(0, "com.android.test.stay", one);
+        mQuotaController.saveTimingSession(0, "com.android.test.stay", two, false);
+        mQuotaController.saveTimingSession(0, "com.android.test.stay", one, false);
+        mQuotaController.saveTimingSession(0, "com.android.test.stay", one, true);
+
+        assertNotNull(mQuotaController.getTimingSessions(0, "com.android.test.remove"));
+        assertNotNull(mQuotaController.getHpjTimingSessions(0, "com.android.test.remove"));
+        assertNotNull(mQuotaController.getTimingSessions(0, "com.android.test.stay"));
+        assertNotNull(mQuotaController.getHpjTimingSessions(0, "com.android.test.stay"));
 
         ExecutionStats expectedStats = new ExecutionStats();
         expectedStats.expirationTimeElapsed = now + 24 * HOUR_IN_MILLIS;
@@ -445,6 +499,7 @@
             mQuotaController.onAppRemovedLocked("com.android.test.remove", uid);
         }
         assertNull(mQuotaController.getTimingSessions(0, "com.android.test.remove"));
+        assertNull(mQuotaController.getHpjTimingSessions(0, "com.android.test.remove"));
         assertEquals(expected, mQuotaController.getTimingSessions(0, "com.android.test.stay"));
         synchronized (mQuotaController.mLock) {
             assertEquals(expectedStats,
@@ -462,23 +517,36 @@
     public void testOnUserRemovedLocked() {
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - (6 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5));
+                createTimingSession(now - (6 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5), false);
         mQuotaController.saveTimingSession(0, "com.android.test",
                 createTimingSession(
-                        now - (2 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 6 * MINUTE_IN_MILLIS, 5));
+                        now - (2 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 6 * MINUTE_IN_MILLIS, 5),
+                false);
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - (HOUR_IN_MILLIS), MINUTE_IN_MILLIS, 1));
+                createTimingSession(now - (HOUR_IN_MILLIS), MINUTE_IN_MILLIS, 1), false);
+        mQuotaController.saveTimingSession(0, "com.android.test",
+                createTimingSession(now - (30 * MINUTE_IN_MILLIS), MINUTE_IN_MILLIS, 1), true);
+        mQuotaController.saveTimingSession(0, "com.android.test",
+                createTimingSession(now - (15 * MINUTE_IN_MILLIS), MINUTE_IN_MILLIS, 1), true);
         // Test that another user isn't affected.
         TimingSession one = createTimingSession(
                 now - 10 * MINUTE_IN_MILLIS, 9 * MINUTE_IN_MILLIS, 3);
         TimingSession two = createTimingSession(
                 now - (70 * MINUTE_IN_MILLIS), 9 * MINUTE_IN_MILLIS, 1);
-        List<TimingSession> expected = new ArrayList<>();
+        List<TimingSession> expectedRegular = new ArrayList<>();
+        List<TimingSession> expectedHpj = new ArrayList<>();
         // Added in correct (chronological) order.
-        expected.add(two);
-        expected.add(one);
-        mQuotaController.saveTimingSession(10, "com.android.test", two);
-        mQuotaController.saveTimingSession(10, "com.android.test", one);
+        expectedRegular.add(two);
+        expectedRegular.add(one);
+        expectedHpj.add(one);
+        mQuotaController.saveTimingSession(10, "com.android.test", two, false);
+        mQuotaController.saveTimingSession(10, "com.android.test", one, false);
+        mQuotaController.saveTimingSession(10, "com.android.test", one, true);
+
+        assertNotNull(mQuotaController.getTimingSessions(0, "com.android.test"));
+        assertNotNull(mQuotaController.getHpjTimingSessions(0, "com.android.test"));
+        assertNotNull(mQuotaController.getTimingSessions(10, "com.android.test"));
+        assertNotNull(mQuotaController.getHpjTimingSessions(10, "com.android.test"));
 
         ExecutionStats expectedStats = new ExecutionStats();
         expectedStats.expirationTimeElapsed = now + 24 * HOUR_IN_MILLIS;
@@ -489,7 +557,11 @@
         synchronized (mQuotaController.mLock) {
             mQuotaController.onUserRemovedLocked(0);
             assertNull(mQuotaController.getTimingSessions(0, "com.android.test"));
-            assertEquals(expected, mQuotaController.getTimingSessions(10, "com.android.test"));
+            assertNull(mQuotaController.getHpjTimingSessions(0, "com.android.test"));
+            assertEquals(expectedRegular,
+                    mQuotaController.getTimingSessions(10, "com.android.test"));
+            assertEquals(expectedHpj,
+                    mQuotaController.getHpjTimingSessions(10, "com.android.test"));
             assertEquals(expectedStats,
                     mQuotaController.getExecutionStatsLocked(0, "com.android.test", RARE_INDEX));
             assertNotEquals(expectedStats,
@@ -502,17 +574,19 @@
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
         // Added in chronological order.
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - (6 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5));
+                createTimingSession(now - (6 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5), false);
         mQuotaController.saveTimingSession(0, "com.android.test",
                 createTimingSession(
-                        now - (2 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 6 * MINUTE_IN_MILLIS, 5));
+                        now - (2 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 6 * MINUTE_IN_MILLIS, 5),
+                false);
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - (HOUR_IN_MILLIS), MINUTE_IN_MILLIS, 1));
+                createTimingSession(now - (HOUR_IN_MILLIS), MINUTE_IN_MILLIS, 1), false);
         mQuotaController.saveTimingSession(0, "com.android.test",
                 createTimingSession(
-                        now - (HOUR_IN_MILLIS - 10 * MINUTE_IN_MILLIS), MINUTE_IN_MILLIS, 1));
+                        now - (HOUR_IN_MILLIS - 10 * MINUTE_IN_MILLIS), MINUTE_IN_MILLIS, 1),
+                false);
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - 5 * MINUTE_IN_MILLIS, 4 * MINUTE_IN_MILLIS, 3));
+                createTimingSession(now - 5 * MINUTE_IN_MILLIS, 4 * MINUTE_IN_MILLIS, 3), false);
 
         // Test an app that hasn't had any activity.
         ExecutionStats expectedStats = new ExecutionStats();
@@ -703,7 +777,6 @@
 
     @Test
     public void testUpdateExecutionStatsLocked_WithTimer() {
-        final long now = sElapsedRealtimeClock.millis();
         setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
 
         ExecutionStats expectedStats = new ExecutionStats();
@@ -741,7 +814,7 @@
         // Add old session. Make sure values are combined correctly.
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(sElapsedRealtimeClock.millis() - (6 * HOUR_IN_MILLIS),
-                        10 * MINUTE_IN_MILLIS, 5));
+                        10 * MINUTE_IN_MILLIS, 5), false);
         expectedStats.sessionCountInWindow = 1;
 
         expectedStats.expirationTimeElapsed = sElapsedRealtimeClock.millis() + 18 * HOUR_IN_MILLIS;
@@ -794,13 +867,13 @@
     public void testGetExecutionStatsLocked_Values() {
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - (23 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5));
+                createTimingSession(now - (23 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5), false);
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - (7 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5));
+                createTimingSession(now - (7 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5), false);
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - (2 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5));
+                createTimingSession(now - (2 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5), false);
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - (6 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+                createTimingSession(now - (6 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), false);
 
         ExecutionStats expectedStats = new ExecutionStats();
 
@@ -882,7 +955,7 @@
         advanceElapsedClock(3 * MINUTE_IN_MILLIS);
 
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 2));
+                createTimingSession(MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 2), false);
 
         ExecutionStats expectedStats = new ExecutionStats();
 
@@ -942,24 +1015,24 @@
             mQuotaController.saveTimingSession(0, "com.android.test",
                     createTimingSession(
                             JobSchedulerService.sElapsedRealtimeClock.millis(),
-                            5 * MINUTE_IN_MILLIS, 5));
+                            5 * MINUTE_IN_MILLIS, 5), false);
             advanceElapsedClock(5 * MINUTE_IN_MILLIS);
             advanceElapsedClock(5 * MINUTE_IN_MILLIS);
             for (int j = 0; j < 5; ++j) {
                 mQuotaController.saveTimingSession(0, "com.android.test",
                         createTimingSession(
                                 JobSchedulerService.sElapsedRealtimeClock.millis(),
-                                MINUTE_IN_MILLIS, 2));
+                                MINUTE_IN_MILLIS, 2), false);
                 advanceElapsedClock(MINUTE_IN_MILLIS);
                 advanceElapsedClock(54 * SECOND_IN_MILLIS);
                 mQuotaController.saveTimingSession(0, "com.android.test",
                         createTimingSession(
-                                JobSchedulerService.sElapsedRealtimeClock.millis(), 500, 1));
+                                JobSchedulerService.sElapsedRealtimeClock.millis(), 500, 1), false);
                 advanceElapsedClock(500);
                 advanceElapsedClock(400);
                 mQuotaController.saveTimingSession(0, "com.android.test",
                         createTimingSession(
-                                JobSchedulerService.sElapsedRealtimeClock.millis(), 100, 1));
+                                JobSchedulerService.sElapsedRealtimeClock.millis(), 100, 1), false);
                 advanceElapsedClock(100);
                 advanceElapsedClock(5 * SECOND_IN_MILLIS);
             }
@@ -1095,13 +1168,13 @@
 
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - (23 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5));
+                createTimingSession(now - (23 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5), false);
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - (7 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5));
+                createTimingSession(now - (7 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5), false);
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - (2 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5));
+                createTimingSession(now - (2 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5), false);
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - (6 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+                createTimingSession(now - (6 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), false);
         final ExecutionStats originalStatsActive;
         final ExecutionStats originalStatsWorking;
         final ExecutionStats originalStatsFrequent;
@@ -1195,20 +1268,20 @@
     public void testGetMaxJobExecutionTimeLocked() {
         mQuotaController.saveTimingSession(0, SOURCE_PACKAGE,
                 createTimingSession(sElapsedRealtimeClock.millis() - (6 * MINUTE_IN_MILLIS),
-                        3 * MINUTE_IN_MILLIS, 5));
+                        3 * MINUTE_IN_MILLIS, 5), false);
         JobStatus job = createJobStatus("testGetMaxJobExecutionTimeLocked", 0);
         job.setStandbyBucket(RARE_INDEX);
 
         setCharging();
         synchronized (mQuotaController.mLock) {
-            assertEquals(JobServiceContext.EXECUTING_TIMESLICE_MILLIS,
+            assertEquals(JobServiceContext.DEFAULT_EXECUTING_TIMESLICE_MILLIS,
                     mQuotaController.getMaxJobExecutionTimeMsLocked((job)));
         }
 
         setDischarging();
         setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
         synchronized (mQuotaController.mLock) {
-            assertEquals(JobServiceContext.EXECUTING_TIMESLICE_MILLIS,
+            assertEquals(JobServiceContext.DEFAULT_EXECUTING_TIMESLICE_MILLIS,
                     mQuotaController.getMaxJobExecutionTimeMsLocked((job)));
         }
 
@@ -1220,7 +1293,7 @@
         }
         setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
         synchronized (mQuotaController.mLock) {
-            assertEquals(JobServiceContext.EXECUTING_TIMESLICE_MILLIS,
+            assertEquals(JobServiceContext.DEFAULT_EXECUTING_TIMESLICE_MILLIS,
                     mQuotaController.getMaxJobExecutionTimeMsLocked((job)));
             mQuotaController.maybeStopTrackingJobLocked(job, null, false);
         }
@@ -1242,17 +1315,17 @@
         // Close to RARE boundary.
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(now - (24 * HOUR_IN_MILLIS - 30 * SECOND_IN_MILLIS),
-                        30 * SECOND_IN_MILLIS, 5));
+                        30 * SECOND_IN_MILLIS, 5), false);
         // Far away from FREQUENT boundary.
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - (7 * HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+                createTimingSession(now - (7 * HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), false);
         // Overlap WORKING_SET boundary.
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(now - (2 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS),
-                        3 * MINUTE_IN_MILLIS, 5));
+                        3 * MINUTE_IN_MILLIS, 5), false);
         // Close to ACTIVE boundary.
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - (9 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+                createTimingSession(now - (9 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), false);
 
         setStandbyBucket(RARE_INDEX);
         synchronized (mQuotaController.mLock) {
@@ -1306,7 +1379,8 @@
         // Overlap boundary.
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(
-                        now - (24 * HOUR_IN_MILLIS + 8 * MINUTE_IN_MILLIS), 4 * HOUR_IN_MILLIS, 5));
+                        now - (24 * HOUR_IN_MILLIS + 8 * MINUTE_IN_MILLIS), 4 * HOUR_IN_MILLIS, 5),
+                false);
 
         setStandbyBucket(WORKING_INDEX);
         synchronized (mQuotaController.mLock) {
@@ -1323,7 +1397,7 @@
         // Close to boundary.
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(now - (24 * HOUR_IN_MILLIS - MINUTE_IN_MILLIS),
-                        4 * HOUR_IN_MILLIS - 5 * MINUTE_IN_MILLIS, 5));
+                        4 * HOUR_IN_MILLIS - 5 * MINUTE_IN_MILLIS, 5), false);
 
         setStandbyBucket(WORKING_INDEX);
         synchronized (mQuotaController.mLock) {
@@ -1339,7 +1413,8 @@
         // Far from boundary.
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(
-                        now - (20 * HOUR_IN_MILLIS), 4 * HOUR_IN_MILLIS - 3 * MINUTE_IN_MILLIS, 5));
+                        now - (20 * HOUR_IN_MILLIS), 4 * HOUR_IN_MILLIS - 3 * MINUTE_IN_MILLIS, 5),
+                false);
 
         setStandbyBucket(WORKING_INDEX);
         synchronized (mQuotaController.mLock) {
@@ -1366,10 +1441,11 @@
                 createTimingSession(
                         now - (24 * HOUR_IN_MILLIS + 11 * MINUTE_IN_MILLIS),
                         4 * HOUR_IN_MILLIS,
-                        5));
+                        5), false);
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(
-                        now - (8 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+                        now - (8 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5),
+                false);
 
         synchronized (mQuotaController.mLock) {
             // Both max and bucket time have 8 minutes left.
@@ -1387,15 +1463,17 @@
         // Overlap boundary.
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(
-                        now - (24 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 2 * MINUTE_IN_MILLIS, 5));
+                        now - (24 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 2 * MINUTE_IN_MILLIS, 5),
+                false);
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(
                         now - (20 * HOUR_IN_MILLIS),
                         3 * HOUR_IN_MILLIS + 48 * MINUTE_IN_MILLIS,
-                        5));
+                        5), false);
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(
-                        now - (8 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+                        now - (8 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5),
+                false);
 
         synchronized (mQuotaController.mLock) {
             // Both max and bucket time have 8 minutes left.
@@ -1430,9 +1508,9 @@
         setDischarging();
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - (HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+                createTimingSession(now - (HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), false);
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - (5 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+                createTimingSession(now - (5 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), false);
         synchronized (mQuotaController.mLock) {
             mQuotaController.incrementJobCountLocked(0, "com.android.test", 5);
             assertTrue(mQuotaController.isWithinQuotaLocked(0, "com.android.test", WORKING_INDEX));
@@ -1445,9 +1523,10 @@
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
         final int jobCount = mQcConstants.MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW;
         mQuotaController.saveTimingSession(0, "com.android.test.spam",
-                createTimingSession(now - (HOUR_IN_MILLIS), 15 * MINUTE_IN_MILLIS, 25));
+                createTimingSession(now - (HOUR_IN_MILLIS), 15 * MINUTE_IN_MILLIS, 25), false);
         mQuotaController.saveTimingSession(0, "com.android.test.spam",
-                createTimingSession(now - (5 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, jobCount));
+                createTimingSession(now - (5 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, jobCount),
+                false);
         synchronized (mQuotaController.mLock) {
             mQuotaController.incrementJobCountLocked(0, "com.android.test.spam", jobCount);
             assertFalse(mQuotaController.isWithinQuotaLocked(
@@ -1455,9 +1534,10 @@
         }
 
         mQuotaController.saveTimingSession(0, "com.android.test.frequent",
-                createTimingSession(now - (2 * HOUR_IN_MILLIS), 15 * MINUTE_IN_MILLIS, 2000));
+                createTimingSession(now - (2 * HOUR_IN_MILLIS), 15 * MINUTE_IN_MILLIS, 2000),
+                false);
         mQuotaController.saveTimingSession(0, "com.android.test.frequent",
-                createTimingSession(now - (HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 500));
+                createTimingSession(now - (HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 500), false);
         synchronized (mQuotaController.mLock) {
             assertFalse(mQuotaController.isWithinQuotaLocked(
                     0, "com.android.test.frequent", FREQUENT_INDEX));
@@ -1469,11 +1549,11 @@
         setDischarging();
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - (HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+                createTimingSession(now - (HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), false);
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - (30 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+                createTimingSession(now - (30 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5), false);
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - (5 * MINUTE_IN_MILLIS), 4 * MINUTE_IN_MILLIS, 5));
+                createTimingSession(now - (5 * MINUTE_IN_MILLIS), 4 * MINUTE_IN_MILLIS, 5), false);
         synchronized (mQuotaController.mLock) {
             mQuotaController.incrementJobCountLocked(0, "com.android.test", 5);
             assertFalse(mQuotaController.isWithinQuotaLocked(0, "com.android.test", WORKING_INDEX));
@@ -1486,9 +1566,10 @@
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
         final int jobCount = mQcConstants.MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW;
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - (HOUR_IN_MILLIS), 15 * MINUTE_IN_MILLIS, 25));
+                createTimingSession(now - (HOUR_IN_MILLIS), 15 * MINUTE_IN_MILLIS, 25), false);
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - (5 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, jobCount));
+                createTimingSession(now - (5 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, jobCount),
+                false);
         synchronized (mQuotaController.mLock) {
             mQuotaController.incrementJobCountLocked(0, "com.android.test", jobCount);
             assertFalse(mQuotaController.isWithinQuotaLocked(0, "com.android.test", WORKING_INDEX));
@@ -1639,7 +1720,7 @@
         for (int i = 0; i < 7; ++i) {
             mQuotaController.saveTimingSession(0, "com.android.test",
                     createTimingSession(now - ((10 - i) * MINUTE_IN_MILLIS), 30 * SECOND_IN_MILLIS,
-                            2));
+                            2), false);
 
             synchronized (mQuotaController.mLock) {
                 mQuotaController.incrementJobCountLocked(0, "com.android.test", 2);
@@ -1673,7 +1754,7 @@
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
         final long end = now - (6 * HOUR_IN_MILLIS - 5 * MINUTE_IN_MILLIS);
         mQuotaController.saveTimingSession(0, "com.android.test",
-                new TimingSession(now - 6 * HOUR_IN_MILLIS, end, 1));
+                new TimingSession(now - 6 * HOUR_IN_MILLIS, end, 1), false);
         synchronized (mQuotaController.mLock) {
             mQuotaController.maybeScheduleCleanupAlarmLocked();
         }
@@ -1682,9 +1763,9 @@
 
         // Test with new (more recent) timing sessions saved. AlarmManger shouldn't be called again.
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - 3 * HOUR_IN_MILLIS, MINUTE_IN_MILLIS, 1));
+                createTimingSession(now - 3 * HOUR_IN_MILLIS, MINUTE_IN_MILLIS, 1), false);
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - HOUR_IN_MILLIS, 3 * MINUTE_IN_MILLIS, 1));
+                createTimingSession(now - HOUR_IN_MILLIS, 3 * MINUTE_IN_MILLIS, 1), false);
         synchronized (mQuotaController.mLock) {
             mQuotaController.maybeScheduleCleanupAlarmLocked();
         }
@@ -1715,11 +1796,11 @@
         final long expectedAlarmTime =
                 (now - 18 * HOUR_IN_MILLIS) + 24 * HOUR_IN_MILLIS + mQcConstants.IN_QUOTA_BUFFER_MS;
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - 18 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, 1));
+                createTimingSession(now - 18 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, 1), false);
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - 12 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, 1));
+                createTimingSession(now - 12 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, 1), false);
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - 7 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, 1));
+                createTimingSession(now - 7 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, 1), false);
         synchronized (mQuotaController.mLock) {
             mQuotaController.maybeScheduleStartAlarmLocked(
                     SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
@@ -1727,7 +1808,7 @@
         verify(mAlarmManager, never()).set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
 
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - 2 * HOUR_IN_MILLIS, 55 * MINUTE_IN_MILLIS, 1));
+                createTimingSession(now - 2 * HOUR_IN_MILLIS, 55 * MINUTE_IN_MILLIS, 1), false);
         synchronized (mQuotaController.mLock) {
             mQuotaController.maybeScheduleStartAlarmLocked(
                     SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
@@ -1772,7 +1853,7 @@
         // Test with timing sessions out of window.
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - 10 * HOUR_IN_MILLIS, 5 * MINUTE_IN_MILLIS, 1));
+                createTimingSession(now - 10 * HOUR_IN_MILLIS, 5 * MINUTE_IN_MILLIS, 1), false);
         synchronized (mQuotaController.mLock) {
             mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
         }
@@ -1784,7 +1865,7 @@
         final long expectedAlarmTime =
                 end - MINUTE_IN_MILLIS + 2 * HOUR_IN_MILLIS + mQcConstants.IN_QUOTA_BUFFER_MS;
         mQuotaController.saveTimingSession(0, "com.android.test",
-                new TimingSession(now - 2 * HOUR_IN_MILLIS, end, 1));
+                new TimingSession(now - 2 * HOUR_IN_MILLIS, end, 1), false);
         synchronized (mQuotaController.mLock) {
             mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
         }
@@ -1792,9 +1873,9 @@
 
         // Add some more sessions, but still in quota.
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - HOUR_IN_MILLIS, MINUTE_IN_MILLIS, 1));
+                createTimingSession(now - HOUR_IN_MILLIS, MINUTE_IN_MILLIS, 1), false);
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - (50 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 1));
+                createTimingSession(now - (50 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 1), false);
         synchronized (mQuotaController.mLock) {
             mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
         }
@@ -1802,7 +1883,7 @@
 
         // Test when out of quota.
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - 30 * MINUTE_IN_MILLIS, 5 * MINUTE_IN_MILLIS, 1));
+                createTimingSession(now - 30 * MINUTE_IN_MILLIS, 5 * MINUTE_IN_MILLIS, 1), false);
         synchronized (mQuotaController.mLock) {
             mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
         }
@@ -1836,7 +1917,7 @@
         // Test with timing sessions out of window.
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - 10 * HOUR_IN_MILLIS, 5 * MINUTE_IN_MILLIS, 1));
+                createTimingSession(now - 10 * HOUR_IN_MILLIS, 5 * MINUTE_IN_MILLIS, 1), false);
         synchronized (mQuotaController.mLock) {
             mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
         }
@@ -1846,7 +1927,7 @@
         final long start = now - (6 * HOUR_IN_MILLIS);
         final long expectedAlarmTime = start + 8 * HOUR_IN_MILLIS + mQcConstants.IN_QUOTA_BUFFER_MS;
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(start, 5 * MINUTE_IN_MILLIS, 1));
+                createTimingSession(start, 5 * MINUTE_IN_MILLIS, 1), false);
         synchronized (mQuotaController.mLock) {
             mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
         }
@@ -1854,9 +1935,9 @@
 
         // Add some more sessions, but still in quota.
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - 3 * HOUR_IN_MILLIS, MINUTE_IN_MILLIS, 1));
+                createTimingSession(now - 3 * HOUR_IN_MILLIS, MINUTE_IN_MILLIS, 1), false);
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - HOUR_IN_MILLIS, 3 * MINUTE_IN_MILLIS, 1));
+                createTimingSession(now - HOUR_IN_MILLIS, 3 * MINUTE_IN_MILLIS, 1), false);
         synchronized (mQuotaController.mLock) {
             mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
         }
@@ -1864,7 +1945,7 @@
 
         // Test when out of quota.
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - HOUR_IN_MILLIS, MINUTE_IN_MILLIS, 1));
+                createTimingSession(now - HOUR_IN_MILLIS, MINUTE_IN_MILLIS, 1), false);
         synchronized (mQuotaController.mLock) {
             mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
         }
@@ -1901,7 +1982,7 @@
         // Test with timing sessions out of window.
         final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - 25 * HOUR_IN_MILLIS, 5 * MINUTE_IN_MILLIS, 1));
+                createTimingSession(now - 25 * HOUR_IN_MILLIS, 5 * MINUTE_IN_MILLIS, 1), false);
         synchronized (mQuotaController.mLock) {
             mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
         }
@@ -1915,7 +1996,7 @@
                 start + MINUTE_IN_MILLIS + 24 * HOUR_IN_MILLIS
                         + mQcConstants.IN_QUOTA_BUFFER_MS;
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(start, 5 * MINUTE_IN_MILLIS, 1));
+                createTimingSession(start, 5 * MINUTE_IN_MILLIS, 1), false);
         synchronized (mQuotaController.mLock) {
             mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
         }
@@ -1923,9 +2004,9 @@
 
         // Add some more sessions, but still in quota.
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - 3 * HOUR_IN_MILLIS, MINUTE_IN_MILLIS, 1));
+                createTimingSession(now - 3 * HOUR_IN_MILLIS, MINUTE_IN_MILLIS, 1), false);
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - HOUR_IN_MILLIS, 3 * MINUTE_IN_MILLIS, 1));
+                createTimingSession(now - HOUR_IN_MILLIS, 3 * MINUTE_IN_MILLIS, 1), false);
         synchronized (mQuotaController.mLock) {
             mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
         }
@@ -1933,7 +2014,7 @@
 
         // Test when out of quota.
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - HOUR_IN_MILLIS, 2 * MINUTE_IN_MILLIS, 1));
+                createTimingSession(now - HOUR_IN_MILLIS, 2 * MINUTE_IN_MILLIS, 1), false);
         synchronized (mQuotaController.mLock) {
             mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
         }
@@ -1960,17 +2041,17 @@
 
         // Affects rare bucket
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - 12 * HOUR_IN_MILLIS, 9 * MINUTE_IN_MILLIS, 3));
+                createTimingSession(now - 12 * HOUR_IN_MILLIS, 9 * MINUTE_IN_MILLIS, 3), false);
         // Affects frequent and rare buckets
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - 4 * HOUR_IN_MILLIS, 4 * MINUTE_IN_MILLIS, 3));
+                createTimingSession(now - 4 * HOUR_IN_MILLIS, 4 * MINUTE_IN_MILLIS, 3), false);
         // Affects working, frequent, and rare buckets
         final long outOfQuotaTime = now - HOUR_IN_MILLIS;
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(outOfQuotaTime, 7 * MINUTE_IN_MILLIS, 10));
+                createTimingSession(outOfQuotaTime, 7 * MINUTE_IN_MILLIS, 10), false);
         // Affects all buckets
         mQuotaController.saveTimingSession(0, "com.android.test",
-                createTimingSession(now - 5 * MINUTE_IN_MILLIS, 3 * MINUTE_IN_MILLIS, 3));
+                createTimingSession(now - 5 * MINUTE_IN_MILLIS, 3 * MINUTE_IN_MILLIS, 3), false);
 
         InOrder inOrder = inOrder(mAlarmManager);
 
@@ -2143,9 +2224,9 @@
         // the quota.
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(now - (2 * HOUR_IN_MILLIS + 3 * MINUTE_IN_MILLIS),
-                        3 * MINUTE_IN_MILLIS + contributionMs, 3));
+                        3 * MINUTE_IN_MILLIS + contributionMs, 3), false);
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - HOUR_IN_MILLIS, remainingTimeMs, 2));
+                createTimingSession(now - HOUR_IN_MILLIS, remainingTimeMs, 2), false);
         // Expected alarm time should be when the app will have QUOTA_BUFFER_MS time of quota, which
         // is 2 hours + (QUOTA_BUFFER_MS - contributionMs) after the start of the second session.
         final long expectedAlarmTime = now - HOUR_IN_MILLIS + 2 * HOUR_IN_MILLIS
@@ -2175,9 +2256,9 @@
         // the quota.
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(now - (24 * HOUR_IN_MILLIS + 3 * MINUTE_IN_MILLIS),
-                        3 * MINUTE_IN_MILLIS + contributionMs, 3));
+                        3 * MINUTE_IN_MILLIS + contributionMs, 3), false);
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
-                createTimingSession(now - 20 * HOUR_IN_MILLIS, remainingTimeMs, 300));
+                createTimingSession(now - 20 * HOUR_IN_MILLIS, remainingTimeMs, 300), false);
         // Expected alarm time should be when the app will have QUOTA_BUFFER_MS time of quota, which
         // is 24 hours + (QUOTA_BUFFER_MS - contributionMs) after the start of the second session.
         final long expectedAlarmTime = now - 20 * HOUR_IN_MILLIS
@@ -2217,6 +2298,16 @@
         setDeviceConfigLong(QcConstants.KEY_TIMING_SESSION_COALESCING_DURATION_MS,
                 10 * SECOND_IN_MILLIS);
         setDeviceConfigLong(QcConstants.KEY_MIN_QUOTA_CHECK_DELAY_MS, 7 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_ACTIVE_MS, 2 * HOUR_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_WORKING_MS, 90 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_FREQUENT_MS, 1 * HOUR_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_RARE_MS, 30 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_RESTRICTED_MS, 27 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_WINDOW_SIZE_MS, 12 * HOUR_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_TOP_APP_TIME_CHUNK_SIZE_MS, 10 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_REWARD_TOP_APP_MS, 87 * SECOND_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_REWARD_INTERACTION_MS, 86 * SECOND_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_REWARD_NOTIFICATION_SEEN_MS, 85 * SECOND_IN_MILLIS);
 
         assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs());
         assertEquals(2 * MINUTE_IN_MILLIS, mQuotaController.getInQuotaBufferMs());
@@ -2244,6 +2335,16 @@
         assertEquals(10 * SECOND_IN_MILLIS,
                 mQuotaController.getTimingSessionCoalescingDurationMs());
         assertEquals(7 * MINUTE_IN_MILLIS, mQuotaController.getMinQuotaCheckDelayMs());
+        assertEquals(2 * HOUR_IN_MILLIS, mQuotaController.getHpjLimitsMs()[ACTIVE_INDEX]);
+        assertEquals(90 * MINUTE_IN_MILLIS, mQuotaController.getHpjLimitsMs()[WORKING_INDEX]);
+        assertEquals(HOUR_IN_MILLIS, mQuotaController.getHpjLimitsMs()[FREQUENT_INDEX]);
+        assertEquals(30 * MINUTE_IN_MILLIS, mQuotaController.getHpjLimitsMs()[RARE_INDEX]);
+        assertEquals(27 * MINUTE_IN_MILLIS, mQuotaController.getHpjLimitsMs()[RESTRICTED_INDEX]);
+        assertEquals(12 * HOUR_IN_MILLIS, mQuotaController.getHpjLimitWindowSizeMs());
+        assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getHpjTopAppTimeChunkSizeMs());
+        assertEquals(87 * SECOND_IN_MILLIS, mQuotaController.getHpjRewardTopAppMs());
+        assertEquals(86 * SECOND_IN_MILLIS, mQuotaController.getHpjRewardInteractionMs());
+        assertEquals(85 * SECOND_IN_MILLIS, mQuotaController.getHpjRewardNotificationSeenMs());
     }
 
     @Test
@@ -2272,6 +2373,16 @@
         setDeviceConfigInt(QcConstants.KEY_MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW, 0);
         setDeviceConfigLong(QcConstants.KEY_TIMING_SESSION_COALESCING_DURATION_MS, -1);
         setDeviceConfigLong(QcConstants.KEY_MIN_QUOTA_CHECK_DELAY_MS, -1);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_ACTIVE_MS, -1);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_WORKING_MS, -1);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_FREQUENT_MS, -1);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_RARE_MS, -1);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_RESTRICTED_MS, -1);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_WINDOW_SIZE_MS, -1);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_TOP_APP_TIME_CHUNK_SIZE_MS, -1);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_REWARD_TOP_APP_MS, -1);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_REWARD_INTERACTION_MS, -1);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_REWARD_NOTIFICATION_SEEN_MS, -1);
 
         assertEquals(MINUTE_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs());
         assertEquals(0, mQuotaController.getInQuotaBufferMs());
@@ -2296,6 +2407,16 @@
         assertEquals(0, mQuotaController.getBucketMaxSessionCounts()[RESTRICTED_INDEX]);
         assertEquals(0, mQuotaController.getTimingSessionCoalescingDurationMs());
         assertEquals(0, mQuotaController.getMinQuotaCheckDelayMs());
+        assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getHpjLimitsMs()[ACTIVE_INDEX]);
+        assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getHpjLimitsMs()[WORKING_INDEX]);
+        assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getHpjLimitsMs()[FREQUENT_INDEX]);
+        assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getHpjLimitsMs()[RARE_INDEX]);
+        assertEquals(0, mQuotaController.getHpjLimitsMs()[RESTRICTED_INDEX]);
+        assertEquals(HOUR_IN_MILLIS, mQuotaController.getHpjLimitWindowSizeMs());
+        assertEquals(1, mQuotaController.getHpjTopAppTimeChunkSizeMs());
+        assertEquals(10 * SECOND_IN_MILLIS, mQuotaController.getHpjRewardTopAppMs());
+        assertEquals(5 * SECOND_IN_MILLIS, mQuotaController.getHpjRewardInteractionMs());
+        assertEquals(0, mQuotaController.getHpjRewardNotificationSeenMs());
 
         // Invalid configurations.
         // In_QUOTA_BUFFER should never be greater than ALLOWED_TIME_PER_PERIOD
@@ -2318,6 +2439,16 @@
         setDeviceConfigLong(QcConstants.KEY_TIMING_SESSION_COALESCING_DURATION_MS,
                 25 * HOUR_IN_MILLIS);
         setDeviceConfigLong(QcConstants.KEY_MIN_QUOTA_CHECK_DELAY_MS, 25 * HOUR_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_ACTIVE_MS, 25 * HOUR_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_WORKING_MS, 25 * HOUR_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_FREQUENT_MS, 25 * HOUR_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_RARE_MS, 25 * HOUR_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_RESTRICTED_MS, 25 * HOUR_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_WINDOW_SIZE_MS, 25 * HOUR_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_TOP_APP_TIME_CHUNK_SIZE_MS, 25 * HOUR_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_REWARD_TOP_APP_MS, 25 * HOUR_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_REWARD_INTERACTION_MS, 25 * HOUR_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_REWARD_NOTIFICATION_SEEN_MS, 25 * HOUR_IN_MILLIS);
 
         assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getAllowedTimePerPeriodMs());
         assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getInQuotaBufferMs());
@@ -2332,6 +2463,16 @@
         assertEquals(15 * MINUTE_IN_MILLIS,
                 mQuotaController.getTimingSessionCoalescingDurationMs());
         assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getMinQuotaCheckDelayMs());
+        assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getHpjLimitsMs()[ACTIVE_INDEX]);
+        assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getHpjLimitsMs()[WORKING_INDEX]);
+        assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getHpjLimitsMs()[FREQUENT_INDEX]);
+        assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getHpjLimitsMs()[RARE_INDEX]);
+        assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getHpjLimitsMs()[RESTRICTED_INDEX]);
+        assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getHpjLimitWindowSizeMs());
+        assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getHpjTopAppTimeChunkSizeMs());
+        assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getHpjRewardTopAppMs());
+        assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getHpjRewardInteractionMs());
+        assertEquals(5 * MINUTE_IN_MILLIS, mQuotaController.getHpjRewardNotificationSeenMs());
     }
 
     /** Tests that TimingSessions aren't saved when the device is charging. */
@@ -2937,7 +3078,7 @@
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(
                         JobSchedulerService.sElapsedRealtimeClock.millis() - HOUR_IN_MILLIS,
-                        10 * MINUTE_IN_MILLIS - remainingTimeMs, 1));
+                        10 * MINUTE_IN_MILLIS - remainingTimeMs, 1), false);
 
         InOrder inOrder = inOrder(mJobSchedulerService);
 
@@ -3031,7 +3172,7 @@
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(
                         JobSchedulerService.sElapsedRealtimeClock.millis() - HOUR_IN_MILLIS,
-                        10 * MINUTE_IN_MILLIS - remainingTimeMs, 1));
+                        10 * MINUTE_IN_MILLIS - remainingTimeMs, 1), false);
 
         // Start the job.
         synchronized (mQuotaController.mLock) {
@@ -3069,10 +3210,10 @@
         // window, so as the package "reaches its quota" it will have more to keep running.
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(now - 2 * HOUR_IN_MILLIS,
-                        10 * SECOND_IN_MILLIS - remainingTimeMs, 1));
+                        10 * SECOND_IN_MILLIS - remainingTimeMs, 1), false);
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(now - HOUR_IN_MILLIS,
-                        9 * MINUTE_IN_MILLIS + 50 * SECOND_IN_MILLIS, 1));
+                        9 * MINUTE_IN_MILLIS + 50 * SECOND_IN_MILLIS, 1), false);
 
         synchronized (mQuotaController.mLock) {
             assertEquals(remainingTimeMs,
@@ -3098,7 +3239,9 @@
         }
         // Handler is told to check when the quota will be consumed, not when the initial
         // remaining time is over.
-        verify(handler, atLeast(1)).sendMessageDelayed(any(), eq(10 * SECOND_IN_MILLIS));
+        verify(handler, atLeast(1)).sendMessageDelayed(
+                argThat(msg -> msg.what == QuotaController.MSG_REACHED_QUOTA),
+                eq(10 * SECOND_IN_MILLIS));
         verify(handler, never()).sendMessageDelayed(any(), eq(remainingTimeMs));
 
         // After 10 seconds, the job should finally be out of quota.
@@ -3242,4 +3385,1337 @@
         verify(mAlarmManager, times(1))
                 .set(anyInt(), eq(expectedWorkingAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
     }
+
+    @Test
+    public void testGetRemainingHpjExecutionTimeLocked_NoHistory() {
+        final long[] limits = mQuotaController.getHpjLimitsMs();
+        for (int i = 0; i < limits.length; ++i) {
+            setStandbyBucket(i);
+            assertEquals("Got wrong remaining HPJ execution time for bucket #" + i,
+                    limits[i],
+                    mQuotaController.getRemainingHpjExecutionTimeLocked(
+                            SOURCE_USER_ID, SOURCE_PACKAGE));
+        }
+    }
+
+    @Test
+    public void testGetRemainingHpjExecutionTimeLocked_AllSessionsWithinWindow() {
+        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - mQcConstants.HPJ_WINDOW_SIZE_MS, MINUTE_IN_MILLIS, 5),
+                true);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - 40 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - 30 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - 20 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - 10 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+
+        final long[] limits = mQuotaController.getHpjLimitsMs();
+        for (int i = 0; i < limits.length; ++i) {
+            setStandbyBucket(i);
+            assertEquals("Got wrong remaining HPJ execution time for bucket #" + i,
+                    i == NEVER_INDEX ? 0 : (limits[i] - 5 * MINUTE_IN_MILLIS),
+                    mQuotaController.getRemainingHpjExecutionTimeLocked(
+                            SOURCE_USER_ID, SOURCE_PACKAGE));
+        }
+    }
+
+    @Test
+    public void testGetRemainingHpjExecutionTimeLocked_OneSessionStraddlesEdge() {
+        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+        final long[] limits = mQuotaController.getHpjLimitsMs();
+        for (int i = 0; i < limits.length; ++i) {
+            synchronized (mQuotaController.mLock) {
+                mQuotaController.onUserRemovedLocked(SOURCE_USER_ID);
+            }
+            mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                    createTimingSession(now - (mQcConstants.HPJ_WINDOW_SIZE_MS + MINUTE_IN_MILLIS),
+                            2 * MINUTE_IN_MILLIS, 5), true);
+            mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                    createTimingSession(now - 40 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+            mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                    createTimingSession(now - 30 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+            mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                    createTimingSession(now - 20 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+            mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                    createTimingSession(now - 10 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+
+            setStandbyBucket(i);
+            assertEquals("Got wrong remaining HPJ execution time for bucket #" + i,
+                    i == NEVER_INDEX ? 0 : (limits[i] - 5 * MINUTE_IN_MILLIS),
+                    mQuotaController.getRemainingHpjExecutionTimeLocked(
+                            SOURCE_USER_ID, SOURCE_PACKAGE));
+        }
+    }
+
+    @Test
+    public void testGetRemainingHpjExecutionTimeLocked_WithStaleSessions() {
+        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+
+        final long[] limits = mQuotaController.getHpjLimitsMs();
+        for (int i = 0; i < limits.length; ++i) {
+            synchronized (mQuotaController.mLock) {
+                mQuotaController.onUserRemovedLocked(SOURCE_USER_ID);
+            }
+            mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                    createTimingSession(
+                            now - (mQcConstants.HPJ_WINDOW_SIZE_MS + 10 * MINUTE_IN_MILLIS),
+                            2 * MINUTE_IN_MILLIS, 5), true);
+            mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                    createTimingSession(
+                            now - (mQcConstants.HPJ_WINDOW_SIZE_MS + 5 * MINUTE_IN_MILLIS),
+                            MINUTE_IN_MILLIS, 5), true);
+            mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                    createTimingSession(now - (mQcConstants.HPJ_WINDOW_SIZE_MS + MINUTE_IN_MILLIS),
+                            2 * MINUTE_IN_MILLIS, 5), true);
+            mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                    createTimingSession(now - 40 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+            mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                    createTimingSession(now - 30 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+            mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                    createTimingSession(now - 20 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+            mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                    createTimingSession(now - 10 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+
+            setStandbyBucket(i);
+            assertEquals("Got wrong remaining HPJ execution time for bucket #" + i,
+                    i == NEVER_INDEX ? 0 : (limits[i] - 5 * MINUTE_IN_MILLIS),
+                    mQuotaController.getRemainingHpjExecutionTimeLocked(
+                            SOURCE_USER_ID, SOURCE_PACKAGE));
+        }
+    }
+
+    /**
+     * Tests that getRemainingHpjExecutionTimeLocked returns the correct stats soon after device
+     * startup.
+     */
+    @Test
+    public void testGetRemainingHpjExecutionTimeLocked_BeginningOfTime() {
+        // Set time to 3 minutes after boot.
+        advanceElapsedClock(-JobSchedulerService.sElapsedRealtimeClock.millis());
+        advanceElapsedClock(3 * MINUTE_IN_MILLIS);
+
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 2), true);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(150 * SECOND_IN_MILLIS, 15 * SECOND_IN_MILLIS, 5), true);
+
+        final long[] limits = mQuotaController.getHpjLimitsMs();
+        for (int i = 0; i < limits.length; ++i) {
+            setStandbyBucket(i);
+            assertEquals("Got wrong remaining HPJ execution time for bucket #" + i,
+                    i == NEVER_INDEX ? 0 : (limits[i] - 75 * SECOND_IN_MILLIS),
+                    mQuotaController.getRemainingHpjExecutionTimeLocked(
+                            SOURCE_USER_ID, SOURCE_PACKAGE));
+        }
+    }
+
+    @Test
+    public void testGetTimeUntilHpjQuotaConsumedLocked_NoHistory() {
+        final long[] limits = mQuotaController.getHpjLimitsMs();
+        for (int i = 0; i < limits.length; ++i) {
+            setStandbyBucket(i);
+            assertEquals("Got wrong time until HPJ quota consumed for bucket #" + i,
+                    limits[i], mQuotaController.getTimeUntilHpjQuotaConsumedLocked(
+                            SOURCE_USER_ID, SOURCE_PACKAGE));
+        }
+    }
+
+    @Test
+    public void testGetTimeUntilHpjQuotaConsumedLocked_AllSessionsWithinWindow() {
+        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - 40 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - 30 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - 20 * MINUTE_IN_MILLIS, 2 * MINUTE_IN_MILLIS, 5), true);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - 10 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+
+        final long[] limits = mQuotaController.getHpjLimitsMs();
+        for (int i = 0; i < limits.length; ++i) {
+            setStandbyBucket(i);
+            assertEquals("Got wrong time until HPJ quota consumed for bucket #" + i,
+                    i == NEVER_INDEX ? 0 : (limits[i] - 5 * MINUTE_IN_MILLIS),
+                    mQuotaController.getTimeUntilHpjQuotaConsumedLocked(
+                            SOURCE_USER_ID, SOURCE_PACKAGE));
+        }
+    }
+
+    @Test
+    public void testGetTimeUntilHpjQuotaConsumedLocked_SessionsAtEdgeOfWindow() {
+        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - mQcConstants.HPJ_WINDOW_SIZE_MS, MINUTE_IN_MILLIS, 5),
+                true);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - (mQcConstants.HPJ_WINDOW_SIZE_MS - 2 * MINUTE_IN_MILLIS),
+                        MINUTE_IN_MILLIS, 5), true);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - (mQcConstants.HPJ_WINDOW_SIZE_MS - 10 * MINUTE_IN_MILLIS),
+                        MINUTE_IN_MILLIS, 5), true);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - 20 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - 10 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_ACTIVE_MS, 30 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_WORKING_MS, 20 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_FREQUENT_MS, 15 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_RARE_MS, 10 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_RESTRICTED_MS, 5 * MINUTE_IN_MILLIS);
+
+        setStandbyBucket(ACTIVE_INDEX);
+        assertEquals("Got wrong time until HPJ quota consumed for bucket #" + ACTIVE_INDEX,
+                28 * MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilHpjQuotaConsumedLocked(
+                        SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        setStandbyBucket(WORKING_INDEX);
+        assertEquals("Got wrong time until HPJ quota consumed for bucket #" + WORKING_INDEX,
+                18 * MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilHpjQuotaConsumedLocked(
+                        SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        setStandbyBucket(FREQUENT_INDEX);
+        assertEquals("Got wrong time until HPJ quota consumed for bucket #" + FREQUENT_INDEX,
+                13 * MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilHpjQuotaConsumedLocked(
+                        SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        setStandbyBucket(RARE_INDEX);
+        assertEquals("Got wrong time until HPJ quota consumed for bucket #" + RARE_INDEX,
+                7 * MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilHpjQuotaConsumedLocked(
+                        SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        setStandbyBucket(RESTRICTED_INDEX);
+        assertEquals("Got wrong time until HPJ quota consumed for bucket #" + RESTRICTED_INDEX,
+                MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilHpjQuotaConsumedLocked(
+                        SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
+    @Test
+    public void testGetTimeUntilHpjQuotaConsumedLocked_OneSessionStraddlesEdge() {
+        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - (mQcConstants.HPJ_WINDOW_SIZE_MS + MINUTE_IN_MILLIS),
+                        2 * MINUTE_IN_MILLIS, 5), true);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - 40 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - 30 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - 20 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - 10 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_ACTIVE_MS, 30 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_WORKING_MS, 20 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_FREQUENT_MS, 15 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_RARE_MS, 10 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_RESTRICTED_MS, 5 * MINUTE_IN_MILLIS);
+
+        setStandbyBucket(ACTIVE_INDEX);
+        assertEquals("Got wrong time until HPJ quota consumed for bucket #" + ACTIVE_INDEX,
+                26 * MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilHpjQuotaConsumedLocked(
+                        SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        setStandbyBucket(WORKING_INDEX);
+        assertEquals("Got wrong time until HPJ quota consumed for bucket #" + WORKING_INDEX,
+                16 * MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilHpjQuotaConsumedLocked(
+                        SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        setStandbyBucket(FREQUENT_INDEX);
+        assertEquals("Got wrong time until HPJ quota consumed for bucket #" + FREQUENT_INDEX,
+                11 * MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilHpjQuotaConsumedLocked(
+                        SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        setStandbyBucket(RARE_INDEX);
+        assertEquals("Got wrong time until HPJ quota consumed for bucket #" + RARE_INDEX,
+                6 * MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilHpjQuotaConsumedLocked(
+                        SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        setStandbyBucket(RESTRICTED_INDEX);
+        assertEquals("Got wrong time until HPJ quota consumed for bucket #" + RESTRICTED_INDEX,
+                MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilHpjQuotaConsumedLocked(
+                        SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
+    @Test
+    public void testGetTimeUntilHpjQuotaConsumedLocked_WithStaleSessions() {
+        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+
+        List<TimingSession> timingSessions = new ArrayList<>();
+        timingSessions.add(
+                createTimingSession(now - (mQcConstants.HPJ_WINDOW_SIZE_MS + 10 * MINUTE_IN_MILLIS),
+                        2 * MINUTE_IN_MILLIS, 5));
+        timingSessions.add(
+                createTimingSession(now - (mQcConstants.HPJ_WINDOW_SIZE_MS + 5 * MINUTE_IN_MILLIS),
+                        MINUTE_IN_MILLIS, 5));
+        timingSessions.add(
+                createTimingSession(now - (mQcConstants.HPJ_WINDOW_SIZE_MS + MINUTE_IN_MILLIS),
+                        2 * MINUTE_IN_MILLIS, 5));
+        timingSessions.add(
+                createTimingSession(now - 40 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5));
+        timingSessions.add(
+                createTimingSession(now - 30 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5));
+        timingSessions.add(
+                createTimingSession(now - 20 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5));
+        timingSessions.add(
+                createTimingSession(now - 10 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5));
+
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_ACTIVE_MS, 30 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_WORKING_MS, 20 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_FREQUENT_MS, 15 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_RARE_MS, 10 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_RESTRICTED_MS, 5 * MINUTE_IN_MILLIS);
+
+        runTestGetTimeUntilHpjQuotaConsumedLocked(
+                timingSessions, ACTIVE_INDEX, 26 * MINUTE_IN_MILLIS);
+        runTestGetTimeUntilHpjQuotaConsumedLocked(
+                timingSessions, WORKING_INDEX, 16 * MINUTE_IN_MILLIS);
+        runTestGetTimeUntilHpjQuotaConsumedLocked(
+                timingSessions, FREQUENT_INDEX, 11 * MINUTE_IN_MILLIS);
+        runTestGetTimeUntilHpjQuotaConsumedLocked(timingSessions, RARE_INDEX, 6 * MINUTE_IN_MILLIS);
+        runTestGetTimeUntilHpjQuotaConsumedLocked(
+                timingSessions, RESTRICTED_INDEX, MINUTE_IN_MILLIS);
+    }
+
+    /**
+     * Tests that getTimeUntilHpjQuotaConsumedLocked returns the correct stats soon after device
+     * startup.
+     */
+    @Test
+    public void testGetTimeUntilHpjQuotaConsumedLocked_BeginningOfTime() {
+        // Set time to 3 minutes after boot.
+        advanceElapsedClock(-JobSchedulerService.sElapsedRealtimeClock.millis());
+        advanceElapsedClock(3 * MINUTE_IN_MILLIS);
+
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 2), true);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(150 * SECOND_IN_MILLIS, 15 * SECOND_IN_MILLIS, 5), true);
+
+        final long[] limits = mQuotaController.getHpjLimitsMs();
+        for (int i = 0; i < limits.length; ++i) {
+            setStandbyBucket(i);
+            assertEquals("Got wrong time until HPJ quota consumed for bucket #" + i,
+                    limits[i], // All existing sessions will phase out
+                    mQuotaController.getTimeUntilHpjQuotaConsumedLocked(
+                            SOURCE_USER_ID, SOURCE_PACKAGE));
+        }
+    }
+
+    private void runTestGetTimeUntilHpjQuotaConsumedLocked(
+            List<TimingSession> timingSessions, int bucketIndex, long expectedValue) {
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.onUserRemovedLocked(SOURCE_USER_ID);
+        }
+        if (timingSessions != null) {
+            for (TimingSession session : timingSessions) {
+                mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE, session, true);
+            }
+        }
+
+        setStandbyBucket(bucketIndex);
+        assertEquals("Got wrong time until HPJ quota consumed for bucket #" + bucketIndex,
+                expectedValue,
+                mQuotaController.getTimeUntilHpjQuotaConsumedLocked(
+                        SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
+    @Test
+    public void testMaybeScheduleStartAlarmLocked_Hpj() {
+        // saveTimingSession calls maybeScheduleCleanupAlarmLocked which interferes with these tests
+        // because it schedules an alarm too. Prevent it from doing so.
+        spyOn(mQuotaController);
+        doNothing().when(mQuotaController).maybeScheduleCleanupAlarmLocked();
+
+        final int standbyBucket = WORKING_INDEX;
+        setStandbyBucket(standbyBucket);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_WORKING_MS, 20 * MINUTE_IN_MILLIS);
+
+        InOrder inOrder = inOrder(mAlarmManager);
+
+        synchronized (mQuotaController.mLock) {
+            // No sessions saved yet.
+            mQuotaController.maybeScheduleStartAlarmLocked(
+                    SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
+        }
+        inOrder.verify(mAlarmManager, never())
+                .set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+
+        // Test with timing sessions out of window.
+        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - 25 * HOUR_IN_MILLIS, 30 * MINUTE_IN_MILLIS, 1), true);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeScheduleStartAlarmLocked(
+                    SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
+        }
+        inOrder.verify(mAlarmManager, never())
+                .set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+
+        // Test with timing sessions in window but still in quota.
+        final long end = now - (22 * HOUR_IN_MILLIS - 5 * MINUTE_IN_MILLIS);
+        final long expectedAlarmTime = now + 2 * HOUR_IN_MILLIS + mQcConstants.IN_QUOTA_BUFFER_MS;
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                new TimingSession(now - 22 * HOUR_IN_MILLIS, end, 1), true);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeScheduleStartAlarmLocked(
+                    SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
+        }
+        inOrder.verify(mAlarmManager, never())
+                .set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+
+        // Add some more sessions, but still in quota.
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - HOUR_IN_MILLIS, 5 * MINUTE_IN_MILLIS, 1), true);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - (50 * MINUTE_IN_MILLIS), 4 * MINUTE_IN_MILLIS, 1), true);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeScheduleStartAlarmLocked(
+                    SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
+        }
+        inOrder.verify(mAlarmManager, never())
+                .set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+
+        // Test when out of quota.
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - 30 * MINUTE_IN_MILLIS, 6 * MINUTE_IN_MILLIS, 1), true);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeScheduleStartAlarmLocked(
+                    SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
+        }
+        inOrder.verify(mAlarmManager, times(1))
+                .set(anyInt(), eq(expectedAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
+
+        // Alarm already scheduled, so make sure it's not scheduled again.
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeScheduleStartAlarmLocked(
+                    SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
+        }
+        inOrder.verify(mAlarmManager, never())
+                .set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+    }
+
+    /** Tests that the start alarm is properly rescheduled if the app's bucket is changed. */
+    @Test
+    public void testMaybeScheduleStartAlarmLocked_Hpj_BucketChange() {
+        // saveTimingSession calls maybeScheduleCleanupAlarmLocked which interferes with these tests
+        // because it schedules an alarm too. Prevent it from doing so.
+        spyOn(mQuotaController);
+        doNothing().when(mQuotaController).maybeScheduleCleanupAlarmLocked();
+
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_ACTIVE_MS, 30 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_WORKING_MS, 20 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_FREQUENT_MS, 15 * MINUTE_IN_MILLIS);
+        setDeviceConfigLong(QcConstants.KEY_HPJ_LIMIT_RARE_MS, 10 * MINUTE_IN_MILLIS);
+
+        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+        // Affects active bucket
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - 12 * HOUR_IN_MILLIS, 9 * MINUTE_IN_MILLIS, 3), true);
+        // Affects active and working buckets
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - 4 * HOUR_IN_MILLIS, 5 * MINUTE_IN_MILLIS, 3), true);
+        // Affects active, working, and frequent buckets
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - HOUR_IN_MILLIS, 5 * MINUTE_IN_MILLIS, 10), true);
+        // Affects all buckets
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - 5 * MINUTE_IN_MILLIS, 10 * MINUTE_IN_MILLIS, 3), true);
+
+        InOrder inOrder = inOrder(mAlarmManager);
+
+        // Start in ACTIVE bucket.
+        setStandbyBucket(ACTIVE_INDEX);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeScheduleStartAlarmLocked(
+                    SOURCE_USER_ID, SOURCE_PACKAGE, ACTIVE_INDEX);
+        }
+        inOrder.verify(mAlarmManager, never())
+                .set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+        inOrder.verify(mAlarmManager, never()).cancel(any(AlarmManager.OnAlarmListener.class));
+
+        // And down from there.
+        setStandbyBucket(WORKING_INDEX);
+        final long expectedWorkingAlarmTime =
+                (now - 4 * HOUR_IN_MILLIS) + (24 * HOUR_IN_MILLIS)
+                        + mQcConstants.IN_QUOTA_BUFFER_MS;
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeScheduleStartAlarmLocked(
+                    SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX);
+        }
+        inOrder.verify(mAlarmManager, times(1))
+                .set(anyInt(), eq(expectedWorkingAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
+
+        setStandbyBucket(FREQUENT_INDEX);
+        final long expectedFrequentAlarmTime =
+                (now - HOUR_IN_MILLIS) + (24 * HOUR_IN_MILLIS) + mQcConstants.IN_QUOTA_BUFFER_MS;
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeScheduleStartAlarmLocked(
+                    SOURCE_USER_ID, SOURCE_PACKAGE, FREQUENT_INDEX);
+        }
+        inOrder.verify(mAlarmManager, times(1))
+                .set(anyInt(), eq(expectedFrequentAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
+
+        setStandbyBucket(RARE_INDEX);
+        final long expectedRareAlarmTime =
+                (now - 5 * MINUTE_IN_MILLIS) + (24 * HOUR_IN_MILLIS)
+                        + mQcConstants.IN_QUOTA_BUFFER_MS;
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeScheduleStartAlarmLocked(
+                    SOURCE_USER_ID, SOURCE_PACKAGE, RARE_INDEX);
+        }
+        inOrder.verify(mAlarmManager, times(1))
+                .set(anyInt(), eq(expectedRareAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
+
+        // And back up again.
+        setStandbyBucket(FREQUENT_INDEX);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeScheduleStartAlarmLocked(
+                    SOURCE_USER_ID, SOURCE_PACKAGE, FREQUENT_INDEX);
+        }
+        inOrder.verify(mAlarmManager, times(1))
+                .set(anyInt(), eq(expectedFrequentAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
+
+        setStandbyBucket(WORKING_INDEX);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeScheduleStartAlarmLocked(
+                    SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX);
+        }
+        inOrder.verify(mAlarmManager, times(1))
+                .set(anyInt(), eq(expectedWorkingAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
+
+        setStandbyBucket(ACTIVE_INDEX);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeScheduleStartAlarmLocked(
+                    SOURCE_USER_ID, SOURCE_PACKAGE, ACTIVE_INDEX);
+        }
+        inOrder.verify(mAlarmManager, never())
+                .set(anyInt(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+        inOrder.verify(mAlarmManager, times(1)).cancel(any(AlarmManager.OnAlarmListener.class));
+    }
+
+    /**
+     * Tests that the start alarm is properly rescheduled if the earliest session that contributes
+     * to the app being out of quota contributes less than the quota buffer time.
+     */
+    @Test
+    public void testMaybeScheduleStartAlarmLocked_Hpj_SmallRollingQuota() {
+        // saveTimingSession calls maybeScheduleCleanupAlarmLocked which interferes with these tests
+        // because it schedules an alarm too. Prevent it from doing so.
+        spyOn(mQuotaController);
+        doNothing().when(mQuotaController).maybeScheduleCleanupAlarmLocked();
+
+        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+        setStandbyBucket(WORKING_INDEX);
+        final long contributionMs = mQcConstants.IN_QUOTA_BUFFER_MS / 2;
+        final long remainingTimeMs = mQcConstants.HPJ_LIMIT_WORKING_MS - contributionMs;
+
+        // Session straddles edge of bucket window. Only the contribution should be counted towards
+        // the quota.
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - (24 * HOUR_IN_MILLIS + 3 * MINUTE_IN_MILLIS),
+                        3 * MINUTE_IN_MILLIS + contributionMs, 3), true);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - 23 * HOUR_IN_MILLIS, remainingTimeMs, 2), true);
+        // Expected alarm time should be when the app will have QUOTA_BUFFER_MS time of quota, which
+        // is 24 hours + (QUOTA_BUFFER_MS - contributionMs) after the start of the second session.
+        final long expectedAlarmTime =
+                now + HOUR_IN_MILLIS + (mQcConstants.IN_QUOTA_BUFFER_MS - contributionMs);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeScheduleStartAlarmLocked(
+                    SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX);
+        }
+        verify(mAlarmManager, times(1))
+                .set(anyInt(), eq(expectedAlarmTime), eq(TAG_QUOTA_CHECK), any(), any());
+    }
+
+    /** Tests that TimingSessions aren't saved when the device is charging. */
+    @Test
+    public void testHpjTimerTracking_Charging() {
+        setCharging();
+
+        JobStatus jobStatus = createHpjJobStatus("testHpjTimerTracking_Charging", 1);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
+        }
+
+        assertNull(mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobStatus);
+        }
+        advanceElapsedClock(5 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+        }
+        assertNull(mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
+    /** Tests that TimingSessions are saved properly when the device is discharging. */
+    @Test
+    public void testHpjTimerTracking_Discharging() {
+        setDischarging();
+        setProcessState(ActivityManager.PROCESS_STATE_BACKUP);
+
+        JobStatus jobStatus = createHpjJobStatus("testHpjTimerTracking_Discharging", 1);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
+        }
+
+        assertNull(mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        List<TimingSession> expected = new ArrayList<>();
+
+        long start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobStatus);
+        }
+        advanceElapsedClock(5 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+        }
+        expected.add(createTimingSession(start, 5 * SECOND_IN_MILLIS, 1));
+        assertEquals(expected,
+                mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        // Test overlapping jobs.
+        JobStatus jobStatus2 = createHpjJobStatus("testHpjTimerTracking_Discharging", 2);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(jobStatus2, null);
+        }
+
+        JobStatus jobStatus3 = createHpjJobStatus("testHpjTimerTracking_Discharging", 3);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(jobStatus3, null);
+        }
+
+        advanceElapsedClock(SECOND_IN_MILLIS);
+
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
+            mQuotaController.prepareForExecutionLocked(jobStatus);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobStatus2);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobStatus3);
+        }
+        advanceElapsedClock(20 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobStatus3, null, false);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null, false);
+        }
+        expected.add(createTimingSession(start, MINUTE_IN_MILLIS, 3));
+        assertEquals(expected,
+                mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
+    /**
+     * Tests that TimingSessions are saved properly when the device alternates between
+     * charging and discharging.
+     */
+    @Test
+    public void testHpjTimerTracking_ChargingAndDischarging() {
+        setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+
+        JobStatus jobStatus = createHpjJobStatus("testHpjTimerTracking_ChargingAndDischarging", 1);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
+        }
+        JobStatus jobStatus2 = createHpjJobStatus("testHpjTimerTracking_ChargingAndDischarging", 2);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(jobStatus2, null);
+        }
+        JobStatus jobStatus3 = createHpjJobStatus("testHpjTimerTracking_ChargingAndDischarging", 3);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(jobStatus3, null);
+        }
+        assertNull(mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+        List<TimingSession> expected = new ArrayList<>();
+
+        // A job starting while charging. Only the portion that runs during the discharging period
+        // should be counted.
+        setCharging();
+
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobStatus);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        setDischarging();
+        long start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobStatus, jobStatus, true);
+        }
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        assertEquals(expected,
+                mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(SECOND_IN_MILLIS);
+
+        // One job starts while discharging, spans a charging session, and ends after the charging
+        // session. Only the portions during the discharging periods should be counted. This should
+        // result in two TimingSessions. A second job starts while discharging and ends within the
+        // charging session. Only the portion during the first discharging portion should be
+        // counted. A third job starts and ends within the charging session. The third job
+        // shouldn't be included in either job count.
+        setDischarging();
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
+            mQuotaController.prepareForExecutionLocked(jobStatus);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobStatus2);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        setCharging();
+        expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 2));
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobStatus3);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobStatus3, null, false);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null, false);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        setDischarging();
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        advanceElapsedClock(20 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+        }
+        expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 1));
+        assertEquals(expected,
+                mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        // A job starting while discharging and ending while charging. Only the portion that runs
+        // during the discharging period should be counted.
+        setDischarging();
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(jobStatus2, null);
+            mQuotaController.prepareForExecutionLocked(jobStatus2);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        setCharging();
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null, false);
+        }
+        assertEquals(expected,
+                mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
+    /** Tests that TimingSessions are saved properly when all the jobs are background jobs. */
+    @Test
+    public void testHpjTimerTracking_AllBackground() {
+        setDischarging();
+        setProcessState(ActivityManager.PROCESS_STATE_RECEIVER);
+
+        JobStatus jobStatus = createHpjJobStatus("testHpjTimerTracking_AllBackground", 1);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
+        }
+        assertNull(mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        List<TimingSession> expected = new ArrayList<>();
+
+        // Test single job.
+        long start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobStatus);
+        }
+        advanceElapsedClock(5 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+        }
+        expected.add(createTimingSession(start, 5 * SECOND_IN_MILLIS, 1));
+        assertEquals(expected,
+                mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        // Test overlapping jobs.
+        JobStatus jobStatus2 = createHpjJobStatus("testHpjTimerTracking_AllBackground", 2);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(jobStatus2, null);
+        }
+
+        JobStatus jobStatus3 = createHpjJobStatus("testHpjTimerTracking_AllBackground", 3);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(jobStatus3, null);
+        }
+
+        advanceElapsedClock(SECOND_IN_MILLIS);
+
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
+            mQuotaController.prepareForExecutionLocked(jobStatus);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobStatus2);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobStatus3);
+        }
+        advanceElapsedClock(20 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobStatus3, null, false);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null, false);
+        }
+        expected.add(createTimingSession(start, MINUTE_IN_MILLIS, 3));
+        assertEquals(expected,
+                mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
+    /** Tests that Timers don't count foreground jobs. */
+    @Test
+    public void testHpjTimerTracking_AllForeground() {
+        setDischarging();
+
+        JobStatus jobStatus = createHpjJobStatus("testHpjTimerTracking_AllForeground", 1);
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
+        }
+
+        assertNull(mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobStatus);
+        }
+        advanceElapsedClock(5 * SECOND_IN_MILLIS);
+        // Change to a state that should still be considered foreground.
+        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        advanceElapsedClock(5 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+        }
+        assertNull(mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
+    /**
+     * Tests that Timers properly track sessions when switching between foreground and background
+     * states.
+     */
+    @Test
+    public void testHpjTimerTracking_ForegroundAndBackground() {
+        setDischarging();
+
+        JobStatus jobBg1 = createHpjJobStatus("testHpjTimerTracking_ForegroundAndBackground", 1);
+        JobStatus jobBg2 = createHpjJobStatus("testHpjTimerTracking_ForegroundAndBackground", 2);
+        JobStatus jobFg3 = createHpjJobStatus("testHpjTimerTracking_ForegroundAndBackground", 3);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(jobBg1, null);
+            mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
+            mQuotaController.maybeStartTrackingJobLocked(jobFg3, null);
+        }
+        assertNull(mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+        List<TimingSession> expected = new ArrayList<>();
+
+        // UID starts out inactive.
+        setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+        long start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobBg1);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true);
+        }
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        assertEquals(expected,
+                mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(SECOND_IN_MILLIS);
+
+        // Bg job starts while inactive, spans an entire active session, and ends after the
+        // active session.
+        // App switching to foreground state then fg job starts.
+        // App remains in foreground state after coming to foreground, so there should only be one
+        // session.
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
+            mQuotaController.prepareForExecutionLocked(jobBg2);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobFg3);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobFg3, null, false);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
+        }
+        assertEquals(expected,
+                mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(SECOND_IN_MILLIS);
+
+        // Bg job 1 starts, then fg job starts. Bg job 1 job ends. Shortly after, uid goes
+        // "inactive" and then bg job 2 starts. Then fg job ends.
+        // This should result in two TimingSessions:
+        //  * The first should have a count of 1
+        //  * The second should have a count of 2 since it will include both jobs
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(jobBg1, null);
+            mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
+            mQuotaController.maybeStartTrackingJobLocked(jobFg3, null);
+        }
+        setProcessState(ActivityManager.PROCESS_STATE_LAST_ACTIVITY);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobBg1);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobFg3);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS); // UID "inactive" now
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobBg2);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobFg3, null, false);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
+        }
+        expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 2));
+        assertEquals(expected,
+                mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
+    /**
+     * Tests that Timers properly track overlapping top and background jobs.
+     */
+    @Test
+    public void testHpjTimerTracking_TopAndNonTop() {
+        setDischarging();
+
+        JobStatus jobBg1 = createHpjJobStatus("testHpjTimerTracking_TopAndNonTop", 1);
+        JobStatus jobBg2 = createHpjJobStatus("testHpjTimerTracking_TopAndNonTop", 2);
+        JobStatus jobFg1 = createHpjJobStatus("testHpjTimerTracking_TopAndNonTop", 3);
+        JobStatus jobTop = createHpjJobStatus("testHpjTimerTracking_TopAndNonTop", 4);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(jobBg1, null);
+            mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
+            mQuotaController.maybeStartTrackingJobLocked(jobFg1, null);
+            mQuotaController.maybeStartTrackingJobLocked(jobTop, null);
+        }
+        assertNull(mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+        List<TimingSession> expected = new ArrayList<>();
+
+        // UID starts out inactive.
+        setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+        long start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobBg1);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true);
+        }
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        assertEquals(expected,
+                mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(SECOND_IN_MILLIS);
+
+        // Bg job starts while inactive, spans an entire active session, and ends after the
+        // active session.
+        // App switching to top state then fg job starts.
+        // App remains in top state after coming to top, so there should only be one
+        // session.
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
+            mQuotaController.prepareForExecutionLocked(jobBg2);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobTop);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobTop, null, false);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
+        }
+        assertEquals(expected,
+                mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(SECOND_IN_MILLIS);
+
+        // Bg job 1 starts, then top job starts. Bg job 1 job ends. Then app goes to
+        // foreground_service and a new job starts. Shortly after, uid goes
+        // "inactive" and then bg job 2 starts. Then top job ends, followed by bg and fg jobs.
+        // This should result in two TimingSessions:
+        //  * The first should have a count of 1
+        //  * The second should have a count of 2, which accounts for the bg2 and fg, but not top
+        //    jobs.
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(jobBg1, null);
+            mQuotaController.maybeStartTrackingJobLocked(jobBg2, null);
+            mQuotaController.maybeStartTrackingJobLocked(jobTop, null);
+        }
+        setProcessState(ActivityManager.PROCESS_STATE_LAST_ACTIVITY);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobBg1);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobTop);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true);
+        }
+        advanceElapsedClock(5 * SECOND_IN_MILLIS);
+        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobFg1);
+        }
+        advanceElapsedClock(5 * SECOND_IN_MILLIS);
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        advanceElapsedClock(10 * SECOND_IN_MILLIS); // UID "inactive" now
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobBg2);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobTop, null, false);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
+            mQuotaController.maybeStopTrackingJobLocked(jobFg1, null, false);
+        }
+        expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 2));
+        assertEquals(expected,
+                mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
+    /**
+     * Tests that HPJs aren't stopped when an app runs out of quota.
+     */
+    @Test
+    public void testHpjTracking_OutOfQuota_ForegroundAndBackground() {
+        setDischarging();
+
+        JobStatus jobBg =
+                createHpjJobStatus("testHpjTracking_OutOfQuota_ForegroundAndBackground", 1);
+        JobStatus jobTop =
+                createHpjJobStatus("testHpjTracking_OutOfQuota_ForegroundAndBackground", 2);
+        JobStatus jobUnstarted =
+                createHpjJobStatus("testHpjTracking_OutOfQuota_ForegroundAndBackground", 3);
+        trackJobs(jobBg, jobTop, jobUnstarted);
+        setStandbyBucket(WORKING_INDEX, jobTop, jobBg, jobUnstarted);
+        // Now the package only has 20 seconds to run.
+        final long remainingTimeMs = 20 * SECOND_IN_MILLIS;
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(
+                        JobSchedulerService.sElapsedRealtimeClock.millis() - HOUR_IN_MILLIS,
+                        mQcConstants.HPJ_LIMIT_WORKING_MS - remainingTimeMs, 1), true);
+
+        InOrder inOrder = inOrder(mJobSchedulerService);
+
+        // UID starts out inactive.
+        setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
+        // Start the job.
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobBg);
+        }
+        advanceElapsedClock(remainingTimeMs / 2);
+        // New job starts after UID is in the foreground. Since the app is now in the foreground, it
+        // should continue to have remainingTimeMs / 2 time remaining.
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobTop);
+        }
+        advanceElapsedClock(remainingTimeMs);
+
+        // Wait for some extra time to allow for job processing.
+        inOrder.verify(mJobSchedulerService,
+                timeout(remainingTimeMs + 2 * SECOND_IN_MILLIS).times(0))
+                .onControllerStateChanged();
+        synchronized (mQuotaController.mLock) {
+            assertEquals(remainingTimeMs / 2,
+                    mQuotaController.getRemainingHpjExecutionTimeLocked(
+                            SOURCE_USER_ID, SOURCE_PACKAGE));
+        }
+        // Go to a background state.
+        setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING);
+        advanceElapsedClock(remainingTimeMs / 2 + 1);
+        inOrder.verify(mJobSchedulerService,
+                timeout(remainingTimeMs / 2 + 2 * SECOND_IN_MILLIS).times(1))
+                .onControllerStateChanged();
+        // Top and bg HPJs should still be allowed to run since they started before the app ran
+        // out of quota.
+        assertTrue(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_HPJ_QUOTA));
+        assertTrue(jobTop.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_HPJ_QUOTA));
+        assertFalse(jobUnstarted.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_HPJ_QUOTA));
+        synchronized (mQuotaController.mLock) {
+            assertTrue(
+                    0 >= mQuotaController
+                            .getRemainingHpjExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+        }
+
+        // New jobs to run.
+        JobStatus jobBg2 =
+                createHpjJobStatus("testHpjTracking_OutOfQuota_ForegroundAndBackground", 4);
+        JobStatus jobTop2 =
+                createHpjJobStatus("testHpjTracking_OutOfQuota_ForegroundAndBackground", 5);
+        JobStatus jobFg =
+                createHpjJobStatus("testHpjTracking_OutOfQuota_ForegroundAndBackground", 6);
+        setStandbyBucket(WORKING_INDEX, jobBg2, jobTop2, jobFg);
+
+        advanceElapsedClock(20 * SECOND_IN_MILLIS);
+        setProcessState(ActivityManager.PROCESS_STATE_TOP);
+        // Confirm QC recognizes that jobUnstarted has changed from out-of-quota to in-quota.
+        inOrder.verify(mJobSchedulerService, timeout(SECOND_IN_MILLIS).times(1))
+                .onControllerStateChanged();
+        trackJobs(jobTop2, jobFg);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobTop2);
+        }
+        assertTrue(jobTop2.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_HPJ_QUOTA));
+        assertTrue(jobFg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_HPJ_QUOTA));
+        assertTrue(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_HPJ_QUOTA));
+        assertTrue(jobUnstarted.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_HPJ_QUOTA));
+
+        // App still in foreground so everything should be in quota.
+        advanceElapsedClock(20 * SECOND_IN_MILLIS);
+        setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        assertTrue(jobTop2.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_HPJ_QUOTA));
+        assertTrue(jobFg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_HPJ_QUOTA));
+        assertTrue(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_HPJ_QUOTA));
+        assertTrue(jobUnstarted.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_HPJ_QUOTA));
+
+        advanceElapsedClock(20 * SECOND_IN_MILLIS);
+        setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
+        inOrder.verify(mJobSchedulerService, timeout(SECOND_IN_MILLIS).times(1))
+                .onControllerStateChanged();
+        // App is now in background and out of quota. Fg should now change to out of quota since it
+        // wasn't started. Top should remain in quota since it started when the app was in TOP.
+        assertTrue(jobTop2.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_HPJ_QUOTA));
+        assertFalse(jobFg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_HPJ_QUOTA));
+        assertTrue(jobBg.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_HPJ_QUOTA));
+        trackJobs(jobBg2);
+        assertFalse(jobBg2.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_HPJ_QUOTA));
+        assertFalse(jobUnstarted.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_HPJ_QUOTA));
+        synchronized (mQuotaController.mLock) {
+            assertTrue(
+                    0 >= mQuotaController
+                            .getRemainingHpjExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+        }
+    }
+
+    /**
+     * Tests that Timers properly track overlapping top and background jobs.
+     */
+    @Test
+    public void testHpjTimerTrackingSeparateFromRegularTracking() {
+        setDischarging();
+        setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+
+        JobStatus jobReg1 = createJobStatus("testHpjTimerTrackingSeparateFromRegularTracking", 1);
+        JobStatus jobHpj1 =
+                createHpjJobStatus("testHpjTimerTrackingSeparateFromRegularTracking", 2);
+        JobStatus jobReg2 = createJobStatus("testHpjTimerTrackingSeparateFromRegularTracking", 3);
+        JobStatus jobHpj2 =
+                createHpjJobStatus("testHpjTimerTrackingSeparateFromRegularTracking", 4);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(jobReg1, null);
+            mQuotaController.maybeStartTrackingJobLocked(jobHpj1, null);
+            mQuotaController.maybeStartTrackingJobLocked(jobReg2, null);
+            mQuotaController.maybeStartTrackingJobLocked(jobHpj2, null);
+        }
+        assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+        assertNull(mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+        List<TimingSession> expectedRegular = new ArrayList<>();
+        List<TimingSession> expectedHpj = new ArrayList<>();
+
+        // First, regular job runs by itself.
+        long start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobReg1);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobReg1, jobReg1, true);
+        }
+        expectedRegular.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        assertEquals(expectedRegular,
+                mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+        assertNull(mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(SECOND_IN_MILLIS);
+
+        // Next, HPJ runs by itself.
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobHpj1);
+        }
+        advanceElapsedClock(10 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobHpj1, null, false);
+        }
+        expectedHpj.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        assertEquals(expectedRegular,
+                mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+        assertEquals(expectedHpj,
+                mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        advanceElapsedClock(SECOND_IN_MILLIS);
+
+        // Finally, a regular job and HPJ happen to overlap runs.
+        start = JobSchedulerService.sElapsedRealtimeClock.millis();
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobHpj2);
+        }
+        advanceElapsedClock(5 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.prepareForExecutionLocked(jobReg2);
+        }
+        advanceElapsedClock(5 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobHpj2, null, false);
+        }
+        expectedHpj.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
+        advanceElapsedClock(5 * SECOND_IN_MILLIS);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStopTrackingJobLocked(jobReg2, null, false);
+        }
+        expectedRegular.add(
+                createTimingSession(start + 5 * SECOND_IN_MILLIS, 10 * SECOND_IN_MILLIS, 1));
+        assertEquals(expectedRegular,
+                mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+        assertEquals(expectedHpj,
+                mQuotaController.getHpjTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
+    /**
+     * Tests that a job is properly handled when it's at the edge of its quota and the old quota is
+     * being phased out.
+     */
+    @Test
+    public void testHpjTracking_RollingQuota() {
+        JobStatus jobStatus = createHpjJobStatus("testHpjTracking_RollingQuota", 1);
+        synchronized (mQuotaController.mLock) {
+            mQuotaController.maybeStartTrackingJobLocked(jobStatus, null);
+        }
+        setStandbyBucket(WORKING_INDEX, jobStatus);
+        setProcessState(ActivityManager.PROCESS_STATE_SERVICE);
+        Handler handler = mQuotaController.getHandler();
+        spyOn(handler);
+
+        long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+        final long remainingTimeMs = SECOND_IN_MILLIS;
+        // The package only has one second to run, but this session is at the edge of the rolling
+        // window, so as the package "reaches its quota" it will have more to keep running.
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - mQcConstants.HPJ_WINDOW_SIZE_MS,
+                        10 * SECOND_IN_MILLIS - remainingTimeMs, 1), true);
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - HOUR_IN_MILLIS,
+                        mQcConstants.HPJ_LIMIT_WORKING_MS - 10 * SECOND_IN_MILLIS, 1), true);
+
+        synchronized (mQuotaController.mLock) {
+            assertEquals(remainingTimeMs,
+                    mQuotaController.getRemainingHpjExecutionTimeLocked(
+                            SOURCE_USER_ID, SOURCE_PACKAGE));
+
+            // Start the job.
+            mQuotaController.prepareForExecutionLocked(jobStatus);
+        }
+        advanceElapsedClock(remainingTimeMs);
+
+        // Wait for some extra time to allow for job processing.
+        verify(mJobSchedulerService,
+                timeout(remainingTimeMs + 2 * SECOND_IN_MILLIS).times(0))
+                .onControllerStateChanged();
+        assertTrue(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_HPJ_QUOTA));
+        // The job used up the remaining quota, but in that time, the same amount of time in the
+        // old TimingSession also fell out of the quota window, so it should still have the same
+        // amount of remaining time left its quota.
+        synchronized (mQuotaController.mLock) {
+            assertEquals(remainingTimeMs,
+                    mQuotaController.getRemainingHpjExecutionTimeLocked(
+                            SOURCE_USER_ID, SOURCE_PACKAGE));
+        }
+        // Handler is told to check when the quota will be consumed, not when the initial
+        // remaining time is over.
+        verify(handler, atLeast(1)).sendMessageDelayed(
+                argThat(msg -> msg.what == QuotaController.MSG_REACHED_HPJ_QUOTA),
+                eq(10 * SECOND_IN_MILLIS));
+        verify(handler, never()).sendMessageDelayed(any(), eq(remainingTimeMs));
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
index e331507..63b36fc 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
@@ -60,6 +60,7 @@
 import android.content.Context;
 import android.location.ILocationCallback;
 import android.location.ILocationListener;
+import android.location.LastLocationRequest;
 import android.location.Location;
 import android.location.LocationManagerInternal;
 import android.location.LocationManagerInternal.ProviderEnabledListener;
@@ -260,55 +261,77 @@
 
     @Test
     public void testGetLastLocation_Fine() {
-        assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull();
+        assertThat(mManager.getLastLocation(new LastLocationRequest.Builder().build(), IDENTITY,
+                PERMISSION_FINE)).isNull();
 
         Location loc = createLocation(NAME, mRandom);
         mProvider.setProviderLocation(loc);
-        assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc);
+        assertThat(mManager.getLastLocation(new LastLocationRequest.Builder().build(), IDENTITY,
+                PERMISSION_FINE)).isEqualTo(loc);
     }
 
     @Test
     public void testGetLastLocation_Coarse() {
-        assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull();
+        assertThat(mManager.getLastLocation(new LastLocationRequest.Builder().build(), IDENTITY,
+                PERMISSION_FINE)).isNull();
 
         Location loc = createLocation(NAME, mRandom);
         mProvider.setProviderLocation(loc);
-        Location coarse = mManager.getLastLocation(IDENTITY, PERMISSION_COARSE, false);
+        Location coarse = mManager.getLastLocation(new LastLocationRequest.Builder().build(),
+                IDENTITY, PERMISSION_COARSE);
         assertThat(coarse).isNotEqualTo(loc);
         assertThat(coarse).isNearby(loc, 5000);
     }
 
     @Test
     public void testGetLastLocation_Bypass() {
-        assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull();
-        assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, true)).isNull();
+        assertThat(mManager.getLastLocation(new LastLocationRequest.Builder().build(), IDENTITY,
+                PERMISSION_FINE)).isNull();
+        assertThat(mManager.getLastLocation(
+                new LastLocationRequest.Builder().setLocationSettingsIgnored(true).build(),
+                IDENTITY, PERMISSION_FINE)).isNull();
 
         Location loc = createLocation(NAME, mRandom);
         mProvider.setProviderLocation(loc);
-        assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc);
-        assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, true)).isEqualTo(
+        assertThat(mManager.getLastLocation(new LastLocationRequest.Builder().build(), IDENTITY,
+                PERMISSION_FINE)).isEqualTo(loc);
+        assertThat(mManager.getLastLocation(
+                new LastLocationRequest.Builder().setLocationSettingsIgnored(true).build(),
+                IDENTITY, PERMISSION_FINE)).isEqualTo(
                 loc);
 
         mProvider.setProviderAllowed(false);
-        assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull();
-        assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, true)).isEqualTo(
+        assertThat(mManager.getLastLocation(new LastLocationRequest.Builder().build(), IDENTITY,
+                PERMISSION_FINE)).isNull();
+        assertThat(mManager.getLastLocation(
+                new LastLocationRequest.Builder().setLocationSettingsIgnored(true).build(),
+                IDENTITY, PERMISSION_FINE)).isEqualTo(
                 loc);
 
         loc = createLocation(NAME, mRandom);
         mProvider.setProviderLocation(loc);
-        assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull();
-        assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, true)).isEqualTo(
+        assertThat(mManager.getLastLocation(new LastLocationRequest.Builder().build(), IDENTITY,
+                PERMISSION_FINE)).isNull();
+        assertThat(mManager.getLastLocation(
+                new LastLocationRequest.Builder().setLocationSettingsIgnored(true).build(),
+                IDENTITY, PERMISSION_FINE)).isEqualTo(
                 loc);
 
         mProvider.setProviderAllowed(true);
-        assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull();
-        assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, true)).isEqualTo(
+        assertThat(mManager.getLastLocation(new LastLocationRequest.Builder().build(), IDENTITY,
+                PERMISSION_FINE)).isNull();
+        assertThat(mManager.getLastLocation(
+                new LastLocationRequest.Builder().setLocationSettingsIgnored(true).build(),
+                IDENTITY, PERMISSION_FINE)).isEqualTo(
                 loc);
 
         loc = createLocation(NAME, mRandom);
         mProvider.setProviderLocation(loc);
-        assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc);
-        assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, true)).isEqualTo(
+        assertThat(mManager.getLastLocation(new LastLocationRequest.Builder().build(), IDENTITY,
+                PERMISSION_FINE)).isEqualTo(loc);
+        assertThat(mManager.getLastLocation(
+                new LastLocationRequest.Builder().setLocationSettingsIgnored(true).build(),
+                IDENTITY, PERMISSION_FINE)).isEqualTo(
                 loc);
     }
 
@@ -320,10 +343,12 @@
 
         Location loc = createLocation(NAME, mRandom);
         mockProvider.setProviderLocation(loc);
-        assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc);
+        assertThat(mManager.getLastLocation(new LastLocationRequest.Builder().build(), IDENTITY,
+                PERMISSION_FINE)).isEqualTo(loc);
 
         mManager.setMockProvider(null);
-        assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isNull();
+        assertThat(mManager.getLastLocation(new LastLocationRequest.Builder().build(), IDENTITY,
+                PERMISSION_FINE)).isNull();
     }
 
     @Test
@@ -331,12 +356,14 @@
         Location loc1 = createLocation(NAME, mRandom);
         mManager.injectLastLocation(loc1, CURRENT_USER);
 
-        assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc1);
+        assertThat(mManager.getLastLocation(new LastLocationRequest.Builder().build(), IDENTITY,
+                PERMISSION_FINE)).isEqualTo(loc1);
 
         Location loc2 = createLocation(NAME, mRandom);
         mManager.injectLastLocation(loc2, CURRENT_USER);
 
-        assertThat(mManager.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc1);
+        assertThat(mManager.getLastLocation(new LastLocationRequest.Builder().build(), IDENTITY,
+                PERMISSION_FINE)).isEqualTo(loc1);
     }
 
     @Test
@@ -355,7 +382,8 @@
         Location loc = createLocation(NAME, mRandom);
         mProvider.setProviderLocation(loc);
 
-        assertThat(mPassive.getLastLocation(IDENTITY, PERMISSION_FINE, false)).isEqualTo(loc);
+        assertThat(mPassive.getLastLocation(new LastLocationRequest.Builder().build(), IDENTITY,
+                PERMISSION_FINE)).isEqualTo(loc);
     }
 
     @Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
new file mode 100644
index 0000000..edae08a3
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -0,0 +1,662 @@
+/*
+ * 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.pm
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.ActivityInfo
+import android.content.pm.ApplicationInfo
+import android.content.pm.FallbackCategoryProvider
+import android.content.pm.FeatureInfo
+import android.content.pm.PackageParser.SigningDetails
+import android.content.pm.ResolveInfo
+import android.content.pm.ServiceInfo
+import android.content.pm.Signature
+import android.content.pm.UserInfo
+import android.content.pm.parsing.ParsingPackage
+import android.content.pm.parsing.ParsingPackageUtils
+import android.content.res.Resources
+import android.hardware.display.DisplayManager
+import android.os.Build
+import android.os.Environment
+import android.os.SystemProperties
+import android.os.UserHandle
+import android.os.UserManager
+import android.os.incremental.IncrementalManager
+import android.permission.IPermissionManager
+import android.util.ArrayMap
+import android.util.DisplayMetrics
+import android.util.EventLog
+import android.view.Display
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.dx.mockito.inline.extended.ExtendedMockito.any
+import com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean
+import com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt
+import com.android.dx.mockito.inline.extended.ExtendedMockito.anyString
+import com.android.dx.mockito.inline.extended.ExtendedMockito.argThat
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
+import com.android.dx.mockito.inline.extended.ExtendedMockito.eq
+import com.android.dx.mockito.inline.extended.ExtendedMockito.spy
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
+import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder
+import com.android.internal.R
+import com.android.server.LocalServices
+import com.android.server.LockGuard
+import com.android.server.SystemConfig
+import com.android.server.SystemServerInitThreadPool
+import com.android.server.compat.PlatformCompat
+import com.android.server.extendedtestutils.wheneverStatic
+import com.android.server.pm.dex.DexManager
+import com.android.server.pm.parsing.PackageParser2
+import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.pm.parsing.pkg.PackageImpl
+import com.android.server.pm.parsing.pkg.ParsedPackage
+import com.android.server.pm.permission.PermissionManagerServiceInternal
+import com.android.server.testutils.mock
+import com.android.server.testutils.nullable
+import com.android.server.testutils.whenever
+import org.junit.Assert
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+import org.mockito.AdditionalMatchers.or
+import org.mockito.invocation.InvocationOnMock
+import org.mockito.quality.Strictness
+import java.io.File
+import java.io.IOException
+import java.nio.file.Files
+import java.security.PublicKey
+import java.security.cert.CertificateException
+import java.util.Arrays
+import java.util.Random
+import java.util.concurrent.FutureTask
+
+/**
+ * A utility for mocking behavior of the system and dependencies when testing PackageManagerService
+ *
+ * Create one of these and call [stageNominalSystemState] as a basis for additional behavior in most
+ * tests.
+ */
+class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
+    private val random = Random()
+    val mocks = Mocks()
+    val packageCacheDirectory: File =
+            Files.createTempDirectory("packageCache").toFile()
+    val rootDirectory: File =
+            Files.createTempDirectory("root").toFile()
+    val dataAppDirectory: File =
+            File(Files.createTempDirectory("data").toFile(), "app")
+    val frameworkSignature: SigningDetails = SigningDetails(arrayOf(generateSpySignature()), 3)
+    val systemPartitions: List<PackageManagerService.ScanPartition> =
+            redirectScanPartitions(PackageManagerService.SYSTEM_PARTITIONS)
+    val session: StaticMockitoSession
+
+    /** Tracks temporary files created by this class during the running of a test.  */
+    private val createdFiles = ArrayList<File>()
+
+    /** Settings that are expected to be added as part of the test  */
+    private val mPendingPackageAdds: MutableList<Pair<String, PackageSetting>> = ArrayList()
+
+    /** Settings simulated to be stored on disk  */
+    private val mPreExistingSettings = ArrayMap<String, PackageSetting>()
+
+    /** The active map simulating the in memory storage of Settings  */
+    private val mSettingsMap = ArrayMap<String, PackageSetting>()
+
+    init {
+        val apply = ExtendedMockito.mockitoSession()
+                .strictness(Strictness.LENIENT)
+                .mockStatic(SystemProperties::class.java)
+                .mockStatic(SystemConfig::class.java)
+                .mockStatic(SELinuxMMAC::class.java)
+                .mockStatic(FallbackCategoryProvider::class.java)
+                .mockStatic(PackageManagerServiceUtils::class.java)
+                .mockStatic(Environment::class.java)
+                .mockStatic(SystemServerInitThreadPool::class.java)
+                .mockStatic(ParsingPackageUtils::class.java)
+                .mockStatic(LockGuard::class.java)
+                .mockStatic(EventLog::class.java)
+                .mockStatic(LocalServices::class.java)
+                .apply(withSession)
+        session = apply.startMocking()
+        whenever(mocks.settings.insertPackageSettingLPw(
+                any(PackageSetting::class.java), any(AndroidPackage::class.java))) {
+            val name: String = (getArgument<Any>(0) as PackageSetting).name
+            val pendingAdd =
+                    mPendingPackageAdds.firstOrNull { it.first == name } ?: return@whenever null
+            mPendingPackageAdds.remove(pendingAdd)
+            mSettingsMap[name] = pendingAdd.second
+            null
+        }
+        whenever(mocks.settings.addPackageLPw(nullable(), nullable(), nullable(), nullable(),
+                nullable(), nullable(), nullable(), nullable(), nullable(), nullable(), nullable(),
+                nullable(), nullable(), nullable())) {
+            val name: String = getArgument(0)
+            val pendingAdd = mPendingPackageAdds.firstOrNull { it.first == name }
+                    ?: return@whenever null
+            mPendingPackageAdds.remove(pendingAdd)
+            mSettingsMap[name] = pendingAdd.second
+            pendingAdd.second
+        }
+        whenever(mocks.settings.packagesLocked).thenReturn(mSettingsMap)
+        whenever(mocks.settings.getPackageLPr(anyString())) { mSettingsMap[getArgument<Any>(0)] }
+        whenever(mocks.settings.readLPw(nullable())) {
+            mSettingsMap.putAll(mPreExistingSettings)
+            !mPreExistingSettings.isEmpty()
+        }
+    }
+
+    /** Collection of mocks used for PackageManagerService tests. */
+
+    class Mocks {
+        val lock = Any()
+        val installLock = Any()
+        val injector: PackageManagerService.Injector = mock()
+        val systemWrapper: PackageManagerService.SystemWrapper = mock()
+        val context: Context = mock()
+        val userManagerService: UserManagerService = mock()
+        val componentResolver: ComponentResolver = mock()
+        val permissionManagerInternal: PermissionManagerServiceInternal = mock()
+        val incrementalManager: IncrementalManager = mock()
+        val platformCompat: PlatformCompat = mock()
+        val settings: Settings = mock()
+        val resources: Resources = mock()
+        val systemConfig: SystemConfig = mock()
+        val apexManager: ApexManager = mock()
+        val userManagerInternal: UserManagerInternal = mock()
+        val packageParser: PackageParser2 = mock()
+        val keySetManagerService: KeySetManagerService = mock()
+        val packageAbiHelper: PackageAbiHelper = mock()
+        val appsFilter: AppsFilter = mock()
+        val dexManager: DexManager = mock()
+        val installer: Installer = mock()
+        val displayMetrics: DisplayMetrics = mock()
+        val permissionManager: IPermissionManager = mock()
+    }
+
+    companion object {
+        private const val DEVICE_PROVISIONING_PACKAGE_NAME =
+                "com.example.android.device.provisioning"
+        private val DEFAULT_AVAILABLE_FEATURES_MAP = ArrayMap<String, FeatureInfo>()
+        private val DEFAULT_ACTIVE_APEX_INFO_LIST = emptyList<ApexManager.ActiveApexInfo>()
+        private val DEFAULT_SHARED_LIBRARIES_LIST =
+                ArrayMap<String, SystemConfig.SharedLibraryEntry>()
+        private val DEFAULT_USERS = Arrays.asList(
+                UserInfo(UserHandle.USER_SYSTEM, "primary", "",
+                        UserInfo.FLAG_PRIMARY or UserInfo.FLAG_SYSTEM or UserInfo.FLAG_FULL,
+                        UserManager.USER_TYPE_FULL_SYSTEM))
+        public val DEFAULT_VERSION_INFO = Settings.VersionInfo()
+
+        init {
+            DEFAULT_VERSION_INFO.fingerprint = "abcdef"
+            DEFAULT_VERSION_INFO.sdkVersion = Build.VERSION_CODES.R
+            DEFAULT_VERSION_INFO.databaseVersion = Settings.CURRENT_DATABASE_VERSION
+        }
+    }
+
+    /**
+     * Clean up any potentially dangling state. This should be run at the end of every test to
+     * account for changes to static memory, such as [LocalServices]
+     */
+    fun cleanup() {
+        createdFiles.forEach(File::delete)
+        createdFiles.clear()
+        mSettingsMap.clear()
+        mPendingPackageAdds.clear()
+        mPreExistingSettings.clear()
+        session.finishMocking()
+    }
+
+    /**
+     * Run this method to ensure that all expected actions were executed, such as pending
+     * [Settings] adds.
+     */
+    fun validateFinalState() {
+        if (mPendingPackageAdds.isNotEmpty()) {
+            Assert.fail(
+                    "Not all expected settings were added: ${mPendingPackageAdds.map { it.first }}")
+        }
+    }
+
+    /**
+     * This method stages enough of system startup to execute the PackageManagerService constructor
+     * successfullly.
+     */
+    @Throws(Exception::class)
+    fun stageNominalSystemState() {
+        whenever(mocks.injector.context).thenReturn(mocks.context)
+        whenever(mocks.injector.lock).thenReturn(mocks.lock)
+        whenever(mocks.injector.installLock).thenReturn(mocks.installLock)
+        whenever(mocks.injector.systemWrapper).thenReturn(mocks.systemWrapper)
+        whenever(mocks.injector.userManagerService).thenReturn(mocks.userManagerService)
+        whenever(mocks.injector.componentResolver).thenReturn(mocks.componentResolver)
+        whenever(mocks.injector.permissionManagerServiceInternal) {
+            mocks.permissionManagerInternal
+        }
+        whenever(mocks.injector.permissionManagerService).thenReturn(mocks.permissionManager)
+        whenever(mocks.injector.incrementalManager).thenReturn(mocks.incrementalManager)
+        whenever(mocks.injector.compatibility).thenReturn(mocks.platformCompat)
+        whenever(mocks.injector.settings).thenReturn(mocks.settings)
+        whenever(mocks.injector.dexManager).thenReturn(mocks.dexManager)
+        whenever(mocks.injector.systemConfig).thenReturn(mocks.systemConfig)
+        whenever(mocks.injector.apexManager).thenReturn(mocks.apexManager)
+        whenever(mocks.injector.scanningCachingPackageParser).thenReturn(mocks.packageParser)
+        whenever(mocks.injector.scanningPackageParser).thenReturn(mocks.packageParser)
+        whenever(mocks.injector.systemPartitions).thenReturn(systemPartitions)
+        whenever(mocks.injector.appsFilter).thenReturn(mocks.appsFilter)
+        whenever(mocks.injector.abiHelper).thenReturn(mocks.packageAbiHelper)
+        whenever(mocks.injector.userManagerInternal).thenReturn(mocks.userManagerInternal)
+        whenever(mocks.injector.installer).thenReturn(mocks.installer)
+        whenever(mocks.injector.displayMetrics).thenReturn(mocks.displayMetrics)
+        wheneverStatic { SystemConfig.getInstance() }.thenReturn(mocks.systemConfig)
+        whenever(mocks.systemConfig.availableFeatures).thenReturn(DEFAULT_AVAILABLE_FEATURES_MAP)
+        whenever(mocks.systemConfig.sharedLibraries).thenReturn(DEFAULT_SHARED_LIBRARIES_LIST)
+        wheneverStatic { SystemProperties.getBoolean("fw.free_cache_v2", true) }.thenReturn(true)
+        wheneverStatic { Environment.getPackageCacheDirectory() }.thenReturn(packageCacheDirectory)
+        wheneverStatic { SystemProperties.digestOf("ro.build.fingerprint") }.thenReturn("cacheName")
+        wheneverStatic { Environment.getRootDirectory() }.thenReturn(rootDirectory)
+        wheneverStatic { SystemServerInitThreadPool.submit(any(Runnable::class.java), anyString())}
+                .thenAnswer { FutureTask<Any?>(it.getArgument(0), null) }
+
+        wheneverStatic { Environment.getDataDirectory() }.thenReturn(dataAppDirectory.parentFile)
+        wheneverStatic { Environment.getDataSystemDirectory() }
+                .thenReturn(File(dataAppDirectory.parentFile, "system"))
+        whenever(mocks.context.resources).thenReturn(mocks.resources)
+        whenever(mocks.resources.getString(R.string.config_deviceProvisioningPackage)) {
+            DEVICE_PROVISIONING_PACKAGE_NAME
+        }
+        whenever(mocks.apexManager.activeApexInfos).thenReturn(DEFAULT_ACTIVE_APEX_INFO_LIST)
+        whenever(mocks.settings.packagesLocked).thenReturn(mSettingsMap)
+        whenever(mocks.settings.internalVersion).thenReturn(DEFAULT_VERSION_INFO)
+        whenever(mocks.settings.keySetManagerService).thenReturn(mocks.keySetManagerService)
+        whenever(mocks.settings.keySetManagerService).thenReturn(mocks.keySetManagerService)
+        whenever(mocks.packageAbiHelper.derivePackageAbi(
+                any(AndroidPackage::class.java), anyBoolean(), nullable(), any(File::class.java))) {
+            android.util.Pair(PackageAbiHelper.Abis("", ""),
+                    PackageAbiHelper.NativeLibraryPaths("", false, "", ""))
+        }
+        whenever(mocks.userManagerInternal.getUsers(true, false, false)).thenReturn(DEFAULT_USERS)
+        whenever(mocks.userManagerService.userIds).thenReturn(intArrayOf(0))
+        whenever(mocks.userManagerService.exists(0)).thenReturn(true)
+        whenever(mocks.packageAbiHelper.deriveNativeLibraryPaths(
+                any(AndroidPackage::class.java), anyBoolean(), any(File::class.java))) {
+            PackageAbiHelper.NativeLibraryPaths("", false, "", "")
+        }
+        // everything visible by default
+        whenever(mocks.appsFilter.shouldFilterApplication(
+                anyInt(), nullable(), nullable(), anyInt())) { false }
+
+        val displayManager: DisplayManager = mock()
+        whenever(mocks.context.getSystemService(DisplayManager::class.java))
+                .thenReturn(displayManager)
+        val display: Display = mock()
+        whenever(displayManager.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(display)
+
+        stageFrameworkScan()
+        stageInstallerScan()
+        stageServicesExtensionScan()
+        stageSystemSharedLibraryScan()
+        stagePermissionsControllerScan()
+        stageInstantAppResolverScan()
+    }
+
+    /**
+     * This method will stage the parsing and scanning of a package as well as add it to the
+     * [PackageSetting]s read from disk.
+     */
+    @Throws(Exception::class)
+    fun stageScanExistingPackage(
+        packageName: String,
+        versionCode: Long,
+        parent: File?,
+        withPackage: (PackageImpl) -> PackageImpl = { it },
+        withSetting:
+        (PackageSettingBuilder) -> PackageSettingBuilder = { it },
+        withExistingSetting:
+        (PackageSettingBuilder) -> PackageSettingBuilder = { it }
+    ) {
+        val existingSettingBuilderRef = arrayOfNulls<PackageSettingBuilder>(1)
+        stageScanNewPackage(packageName, versionCode, parent, withPackage,
+                withSetting = { settingBuilder ->
+                    withSetting(settingBuilder)
+                    existingSettingBuilderRef[0] = settingBuilder
+                    settingBuilder
+                })
+        existingSettingBuilderRef[0]?.setPackage(null)
+        val packageSetting = existingSettingBuilderRef[0]?.let { withExistingSetting(it) }!!.build()
+        addPreExistingSetting(packageName, packageSetting)
+    }
+
+    /**
+     * This method will stage a [PackageSetting] read from disk, but does not stage any scanning
+     * or parsing of the package.
+     */
+    fun addPreExistingSetting(packageName: String, packageSetting: PackageSetting) {
+        mPreExistingSettings[packageName] = packageSetting
+    }
+
+    /**
+     * This method will stage the parsing and scanning of a package but will not add it to the set
+     * of [PackageSetting]s read from disk.
+     */
+    @Throws(Exception::class)
+    fun stageScanNewPackage(
+        packageName: String,
+        versionCode: Long,
+        parent: File?,
+        withPackage: (PackageImpl) -> PackageImpl = { it },
+        withSetting: (PackageSettingBuilder) -> PackageSettingBuilder = { it }
+    ) {
+        val pair = createBasicAndroidPackage(parent, packageName, versionCode)
+        val apkPath = pair.first
+        val pkg = withPackage(pair.second)
+        stageParse(apkPath, pkg)
+        val parentFile = apkPath.parentFile
+        val settingBuilder = withSetting(createBasicSettingBuilder(parentFile, pkg))
+        stageSettingInsert(packageName, settingBuilder.build())
+    }
+
+    /**
+     * Creates a simple package that should reasonably parse for scan operations. This can be used
+     * as a basis for more complicated packages.
+     */
+    fun createBasicAndroidPackage(
+        parent: File?,
+        packageName: String,
+        versionCode: Long,
+        signingDetails: SigningDetails =
+                createRandomSigningDetails()
+    ): Pair<File, PackageImpl> {
+        val apkPath = File(File(parent, packageName), "base.apk")
+        val pkg = PackageImpl.forTesting(packageName, apkPath.parentFile.path) as PackageImpl
+        pkg.signingDetails = signingDetails
+        wheneverStatic { ParsingPackageUtils.getSigningDetails(eq(pkg), anyBoolean()) }
+                .thenReturn(signingDetails)
+        pkg.versionCode = versionCode.toInt()
+        pkg.versionCodeMajor = (versionCode shr 32).toInt()
+        pkg.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT
+        return Pair(apkPath, pkg)
+    }
+
+    /**
+     * This method will create a spy of a [SigningDetails] object to be used when simulating the
+     * collection of signatures.
+     */
+    fun createRandomSigningDetails(): SigningDetails {
+        val signingDetails = spy(SigningDetails(arrayOf(generateSpySignature()),
+                SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3))
+        doReturn(true).whenever(signingDetails).checkCapability(
+                anyString(), anyInt())
+        doReturn(true).whenever(signingDetails).checkCapability(
+                any(SigningDetails::class.java), anyInt())
+        return signingDetails
+    }
+
+    /**
+     * This method will create a basic [PackageSettingBuilder] from an [AndroidPackage] with all of
+     * the necessary parameters to be returned by a simple scan. This can be used as a basis for
+     * more complicated settings.
+     */
+    fun createBasicSettingBuilder(parentFile: File, pkg: AndroidPackage): PackageSettingBuilder {
+        return createBasicSettingBuilder(parentFile, pkg.packageName, pkg.longVersionCode,
+                pkg.signingDetails)
+                .setPackage(pkg)
+    }
+
+    /**
+     * This method will create a basic [PackageSettingBuilder] with all of the necessary parameters
+     * to be returned by a simple scan. This can be used as a basis for more complicated settings.
+     */
+    fun createBasicSettingBuilder(
+        parentFile: File,
+        packageName: String,
+        versionCode: Long,
+        signingDetails: SigningDetails
+    ): PackageSettingBuilder {
+        return PackageSettingBuilder()
+                .setCodePath(parentFile.path)
+                .setName(packageName)
+                .setPVersionCode(versionCode)
+                .setSigningDetails(signingDetails)
+    }
+
+    fun createBasicApplicationInfo(pkg: ParsingPackage): ApplicationInfo {
+        val applicationInfo: ApplicationInfo = mock()
+        applicationInfo.packageName = pkg.packageName
+        return applicationInfo
+    }
+
+    fun createBasicActivityInfo(
+        pkg: ParsingPackage,
+        applicationInfo: ApplicationInfo?,
+        className: String?
+    ):
+            ActivityInfo {
+        val activityInfo = ActivityInfo()
+        activityInfo.applicationInfo = applicationInfo
+        activityInfo.packageName = pkg.packageName
+        activityInfo.name = className
+        return activityInfo
+    }
+
+    fun createBasicServiceInfo(
+        pkg: ParsingPackage,
+        applicationInfo: ApplicationInfo?,
+        className: String?
+    ):
+            ServiceInfo {
+        val serviceInfo = ServiceInfo()
+        serviceInfo.applicationInfo = applicationInfo
+        serviceInfo.packageName = pkg.packageName
+        serviceInfo.name = className
+        return serviceInfo
+    }
+
+    /** Finds the appropriate partition, if available, based on a scan flag unique to it.  */
+    fun getPartitionFromFlag(scanFlagMask: Int): PackageManagerService.ScanPartition =
+            systemPartitions.first { (it.scanFlag and scanFlagMask) != 0 }
+
+    @Throws(Exception::class)
+    private fun stageParse(path: File, parseResult: ParsingPackage): ParsedPackage {
+        val basePath = path.parentFile
+        basePath.mkdirs()
+        path.createNewFile()
+        createdFiles.add(path)
+        val parsedPackage = parseResult.hideAsParsed() as ParsedPackage
+        whenever(mocks.packageParser.parsePackage(
+                or(eq(path), eq(basePath)), anyInt(), anyBoolean())) { parsedPackage }
+        return parsedPackage
+    }
+
+    private fun stageSettingInsert(name: String, setting: PackageSetting): PackageSetting {
+        mPendingPackageAdds.add(Pair(name, setting))
+        return setting
+    }
+
+    @Throws(Exception::class)
+    private fun stageFrameworkScan() {
+        val apk = File(File(rootDirectory, "framework"), "framework-res.apk")
+        val frameworkPkg = PackageImpl.forTesting("android",
+                apk.parentFile.path) as PackageImpl
+        wheneverStatic { ParsingPackageUtils.getSigningDetails(frameworkPkg, true) }
+                .thenReturn(frameworkSignature)
+        stageParse(apk, frameworkPkg)
+        stageSettingInsert("android",
+                PackageSettingBuilder().setCodePath(apk.path).setName(
+                        "android").setPackage(frameworkPkg).build())
+    }
+
+    @Throws(Exception::class)
+    private fun stageInstantAppResolverScan() {
+        whenever(mocks.resources.getStringArray(R.array.config_ephemeralResolverPackage)) {
+            arrayOf("com.android.test.ephemeral.resolver")
+        }
+        stageScanNewPackage("com.android.test.ephemeral.resolver",
+                1L, getPartitionFromFlag(PackageManagerService.SCAN_AS_PRODUCT).privAppFolder,
+                withPackage = { pkg: PackageImpl ->
+                    val applicationInfo: ApplicationInfo = createBasicApplicationInfo(pkg)
+                    whenever(applicationInfo.isPrivilegedApp).thenReturn(true)
+                    mockQueryServices(Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE,
+                            createBasicServiceInfo(pkg, applicationInfo, "test.EphemeralService"))
+                    mockQueryActivities(Intent.ACTION_INSTANT_APP_RESOLVER_SETTINGS,
+                            createBasicActivityInfo(pkg, applicationInfo, "test.SettingsActivity"))
+                    pkg
+                },
+                withSetting = { setting: PackageSettingBuilder ->
+                    setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
+                })
+    }
+
+    @Throws(Exception::class)
+    private fun stagePermissionsControllerScan() {
+        stageScanNewPackage("com.android.permissions.controller",
+                1L, systemPartitions[0].privAppFolder,
+                withPackage = { pkg: PackageImpl ->
+                    val applicationInfo: ApplicationInfo = createBasicApplicationInfo(pkg)
+                    whenever(applicationInfo.isPrivilegedApp).thenReturn(true)
+                    mockQueryActivities(Intent.ACTION_MANAGE_PERMISSIONS,
+                            createBasicActivityInfo(
+                                    pkg, applicationInfo, "test.PermissionActivity"))
+                    pkg
+                },
+                withSetting = { setting: PackageSettingBuilder ->
+                    setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
+                })
+    }
+
+    @Throws(Exception::class)
+    private fun stageSystemSharedLibraryScan() {
+        stageScanNewPackage("android.ext.shared",
+                1L, systemPartitions[0].appFolder,
+                withPackage = { it.addLibraryName("android.ext.shared") as PackageImpl },
+                withSetting = { setting: PackageSettingBuilder ->
+                    setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
+                }
+        )
+    }
+
+    @Throws(Exception::class)
+    private fun stageServicesExtensionScan() {
+        whenever(mocks.context.getString(R.string.config_servicesExtensionPackage)) {
+            "com.android.test.services.extension"
+        }
+        stageScanNewPackage("com.android.test.services.extension",
+                1L, getPartitionFromFlag(PackageManagerService.SCAN_AS_SYSTEM_EXT).privAppFolder,
+                withSetting = { setting: PackageSettingBuilder ->
+                    setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
+                })
+    }
+
+    @Throws(Exception::class)
+    private fun stageInstallerScan() {
+        stageScanNewPackage(
+                "com.android.test.installer",
+                1L, getPartitionFromFlag(PackageManagerService.SCAN_AS_PRODUCT).privAppFolder,
+                withPackage = { pkg: PackageImpl ->
+                    val applicationInfo: ApplicationInfo = createBasicApplicationInfo(pkg)
+                    whenever(applicationInfo.isPrivilegedApp).thenReturn(true)
+                    val installerActivity: ActivityInfo = createBasicActivityInfo(
+                            pkg, applicationInfo, "test.InstallerActivity")
+                    mockQueryActivities(Intent.ACTION_INSTALL_PACKAGE, installerActivity)
+                    mockQueryActivities(Intent.ACTION_UNINSTALL_PACKAGE, installerActivity)
+                    mockQueryActivities(Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE,
+                            installerActivity)
+                    pkg
+                },
+                withSetting = { setting: PackageSettingBuilder ->
+                    setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM)
+                }
+        )
+    }
+
+    private fun mockQueryActivities(action: String, vararg activities: ActivityInfo) {
+        whenever(mocks.componentResolver.queryActivities(
+                argThat { intent: Intent? -> intent != null && (action == intent.action) },
+                nullable(), anyInt(), anyInt())) {
+            ArrayList(activities.asList().map { info: ActivityInfo? ->
+                ResolveInfo().apply { activityInfo = info }
+            })
+        }
+    }
+
+    private fun mockQueryServices(action: String, vararg services: ServiceInfo) {
+        whenever(mocks.componentResolver.queryServices(
+                argThat { intent: Intent? -> intent != null && (action == intent.action) },
+                nullable(), anyInt(), anyInt())) {
+            ArrayList(services.asList().map { info ->
+                ResolveInfo().apply { serviceInfo = info }
+            })
+        }
+    }
+
+    fun generateSpySignature(): Signature {
+        val bytes = ByteArray(32)
+        random.nextBytes(bytes)
+        val signature = spy(Signature(bytes))
+        try {
+            val mockPublicKey: PublicKey = mock()
+            doReturn(mockPublicKey).whenever(signature).getPublicKey()
+        } catch (e: CertificateException) {
+            throw RuntimeException(e)
+        }
+        return signature
+    }
+
+    /** Override get*Folder methods to point to temporary local directories  */
+
+    @Throws(IOException::class)
+    private fun redirectScanPartitions(partitions: List<PackageManagerService.ScanPartition>):
+            List<PackageManagerService.ScanPartition> {
+        val spiedPartitions: MutableList<PackageManagerService.ScanPartition> =
+                ArrayList(partitions.size)
+        for (partition: PackageManagerService.ScanPartition in partitions) {
+            val spy = spy(partition)
+            val newRoot = Files.createTempDirectory(partition.folder.name).toFile()
+            whenever(spy.overlayFolder).thenReturn(File(newRoot, "overlay"))
+            whenever(spy.appFolder).thenReturn(File(newRoot, "app"))
+            whenever(spy.privAppFolder).thenReturn(File(newRoot, "priv-app"))
+            whenever(spy.folder).thenReturn(newRoot)
+            spiedPartitions.add(spy)
+        }
+        return spiedPartitions
+    }
+}
+
+/**
+ * Sets up a basic [MockSystem] for use in a test method. This will create a MockSystem before the
+ * test method and any [org.junit.Before] annotated methods. It can then be used to access the
+ * MockSystem via the [system] method or the mocks directly via [mocks].
+ */
+class MockSystemRule : TestRule {
+    var mockSystem: MockSystem? = null
+    override fun apply(base: Statement?, description: Description?) = object : Statement() {
+        @Throws(Throwable::class)
+        override fun evaluate() {
+            mockSystem = MockSystem()
+            try {
+                base!!.evaluate()
+            } finally {
+                mockSystem?.cleanup()
+                mockSystem = null
+            }
+        }
+    }
+
+    /** Fetch the [MockSystem] instance prepared for this test */
+    fun system(): MockSystem = mockSystem!!
+    /** Fetch the [MockSystem.Mocks] prepared for this test */
+    fun mocks(): MockSystem.Mocks = mockSystem!!.mocks
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceBootTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceBootTest.kt
new file mode 100644
index 0000000..bd44c36
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceBootTest.kt
@@ -0,0 +1,173 @@
+/*
+ * 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.pm
+
+import android.content.pm.ApplicationInfo.FLAG_SYSTEM
+import android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
+import android.content.pm.PackageManager
+import android.content.pm.PackageParser
+import android.os.Build
+import android.os.Process
+import android.util.Log
+import com.android.server.pm.parsing.pkg.AndroidPackage
+import com.android.server.testutils.whenever
+import org.hamcrest.MatcherAssert.assertThat
+import org.hamcrest.Matchers.equalTo
+import org.hamcrest.Matchers.notNullValue
+import org.hamcrest.collection.IsMapContaining.hasKey
+import org.hamcrest.core.IsNot.not
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.argThat
+import org.mockito.Mockito
+import org.mockito.Mockito.verify
+import java.io.File
+
+@RunWith(JUnit4::class)
+class PackageManagerServiceBootTest {
+
+    @Rule
+    @JvmField
+    val rule = MockSystemRule()
+
+    @Before
+    @Throws(Exception::class)
+    fun setup() {
+        Log.i("system.out", "setup", Exception())
+        rule.system().stageNominalSystemState()
+    }
+
+    private fun createPackageManagerService(): PackageManagerService {
+        return PackageManagerService(rule.mocks().injector,
+                false /*coreOnly*/,
+                false /*factoryTest*/,
+                MockSystem.DEFAULT_VERSION_INFO.fingerprint,
+                false /*isEngBuild*/,
+                false /*isUserDebugBuild*/,
+                Build.VERSION_CODES.CUR_DEVELOPMENT,
+                Build.VERSION.INCREMENTAL)
+    }
+
+    @Test
+    @Throws(Exception::class)
+    fun simpleConstruction() {
+        val pm = createPackageManagerService()
+        verify(rule.mocks().injector).bootstrap(pm)
+        verify(rule.mocks().settings).addSharedUserLPw("android.uid.system",
+                Process.SYSTEM_UID, FLAG_SYSTEM, PRIVATE_FLAG_PRIVILEGED)
+        verify(rule.mocks().settings).addSharedUserLPw("android.uid.phone",
+                Process.PHONE_UID, FLAG_SYSTEM, PRIVATE_FLAG_PRIVILEGED)
+        verify(rule.mocks().settings).addSharedUserLPw("android.uid.log",
+                Process.LOG_UID, FLAG_SYSTEM, PRIVATE_FLAG_PRIVILEGED)
+        verify(rule.mocks().settings).addSharedUserLPw("android.uid.nfc",
+                Process.NFC_UID, FLAG_SYSTEM, PRIVATE_FLAG_PRIVILEGED)
+        verify(rule.mocks().settings).addSharedUserLPw("android.uid.bluetooth",
+                Process.BLUETOOTH_UID, FLAG_SYSTEM, PRIVATE_FLAG_PRIVILEGED)
+        verify(rule.mocks().settings).addSharedUserLPw("android.uid.shell",
+                Process.SHELL_UID, FLAG_SYSTEM, PRIVATE_FLAG_PRIVILEGED)
+        verify(rule.mocks().settings).addSharedUserLPw("android.uid.se",
+                Process.SE_UID, FLAG_SYSTEM, PRIVATE_FLAG_PRIVILEGED)
+        verify(rule.mocks().settings).addSharedUserLPw("android.uid.networkstack",
+                Process.NETWORK_STACK_UID, FLAG_SYSTEM, PRIVATE_FLAG_PRIVILEGED)
+        rule.system().validateFinalState()
+    }
+
+    @Test
+    @Throws(Exception::class)
+    fun existingDataPackage_remains() {
+        rule.system().stageScanExistingPackage("a.data.package", 1L, rule.system().dataAppDirectory)
+        val pm = createPackageManagerService()
+        rule.system().validateFinalState()
+        assertThat(pm.mPackages, hasKey("a.data.package"))
+    }
+
+    @Test
+    @Throws(Exception::class)
+    fun unexpectedDataPackage_isRemoved() {
+        rule.system().stageScanNewPackage(
+                "a.data.package", 1L, rule.system().dataAppDirectory)
+        val pm = createPackageManagerService()
+        verify(rule.mocks().settings, Mockito.never()).insertPackageSettingLPw(
+                argThat { setting: PackageSetting -> setting.name == "a.data.package" },
+                argThat { pkg: AndroidPackage -> pkg.packageName == "a.data.package" })
+        assertThat(pm.mPackages, not(hasKey("a.data.package")))
+    }
+
+    @Test
+    @Throws(Exception::class)
+    fun expectedPackageMissing_doesNotReplace() {
+        // setup existing package
+        rule.system().stageScanExistingPackage("a.data.package", 1L,
+                rule.system().dataAppDirectory)
+        // simulate parsing failure for any path containing the package name.
+        whenever(rule.mocks().packageParser.parsePackage(
+                argThat { path: File -> path.path.contains("a.data.package") },
+                anyInt(),
+                anyBoolean()))
+                .thenThrow(PackageParser.PackageParserException(
+                        PackageManager.INSTALL_FAILED_INVALID_APK, "Oh no!"))
+        val pm = createPackageManagerService()
+        verify(rule.mocks().settings, Mockito.never()).insertPackageSettingLPw(
+                argThat { setting: PackageSetting -> setting.name == "a.data.package" },
+                argThat { pkg: AndroidPackage -> pkg.packageName == "a.data.package" })
+        assertThat(pm.mPackages, not(hasKey("a.data.package")))
+    }
+
+    @Test
+    @Throws(Exception::class)
+    fun expectingBetter_updateStillBetter() {
+        // Debug.waitForDebugger()
+        val systemAppPackageName = "com.android.test.updated.system.app"
+        val systemAppSigningDetails = rule.system().createRandomSigningDetails()
+        val systemVersionParent = rule.system()
+                .getPartitionFromFlag(PackageManagerService.SCAN_AS_PRODUCT).privAppFolder
+
+        // system app v1 is disabled
+        whenever(rule.mocks().settings.isDisabledSystemPackageLPr(systemAppPackageName)) {
+            true
+        }
+        whenever(rule.mocks().settings.getDisabledSystemPkgLPr(systemAppPackageName)) {
+            rule.system().createBasicSettingBuilder(
+                    File(systemVersionParent, systemAppPackageName),
+                    systemAppPackageName, 1, systemAppSigningDetails).build()
+        }
+
+        // system app v3 is on data/app
+        rule.system().stageScanExistingPackage(
+                systemAppPackageName,
+                3,
+                rule.system().dataAppDirectory,
+                withPackage = { it.apply { signingDetails = systemAppSigningDetails } },
+                withExistingSetting = { it.setPkgFlags(FLAG_SYSTEM) })
+
+        // system app v2 is scanned from system
+        rule.system().stageScanNewPackage(systemAppPackageName, 2, systemVersionParent,
+                withPackage = { it.apply { signingDetails = systemAppSigningDetails } },
+                withSetting = { it.setPkgFlags(FLAG_SYSTEM) })
+
+        val pm = createPackageManagerService()
+
+        assertThat("system package should exist after boot",
+                pm.mPackages[systemAppPackageName], notNullValue())
+        assertThat("system package should remain at version on data/app",
+                pm.mPackages[systemAppPackageName]!!.longVersionCode, equalTo(3))
+    }
+}
\ No newline at end of file
diff --git a/services/tests/mockingservicestests/src/com/android/server/power/OWNERS b/services/tests/mockingservicestests/src/com/android/server/power/OWNERS
new file mode 100644
index 0000000..d68066b
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/power/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/power/OWNERS
diff --git a/services/tests/mockingservicestests/src/com/android/server/usage/OWNERS b/services/tests/mockingservicestests/src/com/android/server/usage/OWNERS
new file mode 100644
index 0000000..d3227de
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/usage/OWNERS
@@ -0,0 +1 @@
+include /services/usage/OWNERS
diff --git a/services/tests/mockingservicestests/src/com/android/server/utils/quota/MultiRateLimiterTest.java b/services/tests/mockingservicestests/src/com/android/server/utils/quota/MultiRateLimiterTest.java
new file mode 100644
index 0000000..df533f3
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/utils/quota/MultiRateLimiterTest.java
@@ -0,0 +1,197 @@
+/*
+ * 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.utils.quota;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.testing.TestableContext;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.time.Duration;
+
+@SmallTest
+public class MultiRateLimiterTest {
+
+    private static final int USER_ID = 1;
+    private static final String PACKAGE_NAME_1 = "com.android.package.one";
+    private static final String PACKAGE_NAME_2 = "com.android.package.two";
+    private static final String TAG = "tag";
+
+    @Rule
+    public final TestableContext mContext =
+            new TestableContext(InstrumentationRegistry.getContext(), null);
+
+    private final InjectorForTest mInjector = new InjectorForTest();
+
+    private static class InjectorForTest extends QuotaTracker.Injector {
+        Duration mElapsedTime = Duration.ZERO;
+
+        @Override
+        public long getElapsedRealtime() {
+            return mElapsedTime.toMillis();
+        }
+
+        @Override
+        public boolean isAlarmManagerReady() {
+            return true;
+        }
+    }
+
+    @Test
+    public void testSingleRateLimit_belowLimit_isWithinQuota() {
+        MultiRateLimiter multiRateLimiter =  new MultiRateLimiter.Builder(mContext, mInjector)
+                .addRateLimit(3, Duration.ofSeconds(20))
+                .build();
+
+        // Three quick events are within quota.
+        mInjector.mElapsedTime = Duration.ZERO;
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+        multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+        mInjector.mElapsedTime = Duration.ofMillis(50);
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+        multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+        mInjector.mElapsedTime = Duration.ofMillis(100);
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+    }
+
+    @Test
+    public void testSingleRateLimit_aboveLimit_isNotWithinQuota() {
+        MultiRateLimiter multiRateLimiter =  new MultiRateLimiter.Builder(mContext, mInjector)
+                .addRateLimit(3, Duration.ofSeconds(20))
+                .build();
+
+        mInjector.mElapsedTime = Duration.ZERO;
+        multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+        mInjector.mElapsedTime = Duration.ofMillis(50);
+        multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+        mInjector.mElapsedTime = Duration.ofMillis(100);
+        multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+        mInjector.mElapsedTime = Duration.ofMillis(150);
+        // We hit the limit, 4th event in under 20 seconds is not within quota.
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isFalse();
+    }
+
+    @Test
+    public void testSingleRateLimit_afterGoingAboveQuotaAndWaitingWindow_isBackWithinQuota() {
+        MultiRateLimiter multiRateLimiter =  new MultiRateLimiter.Builder(mContext, mInjector)
+                .addRateLimit(3, Duration.ofSeconds(20))
+                .build();
+
+        mInjector.mElapsedTime = Duration.ZERO;
+        multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+        mInjector.mElapsedTime = Duration.ofMillis(50);
+        multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+        mInjector.mElapsedTime = Duration.ofMillis(100);
+        multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+        mInjector.mElapsedTime = Duration.ofMillis(150);
+        // We hit the limit, 4th event in under 20 seconds is not within quota.
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isFalse();
+
+        mInjector.mElapsedTime = Duration.ofSeconds(21);
+        // 20 seconds have passed, we're again within quota.
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+    }
+
+    @Test
+    public void createMultipleRateLimits_testTheyLimitsAsExpected() {
+        MultiRateLimiter multiRateLimiter = new MultiRateLimiter.Builder(mContext, mInjector)
+                .addRateLimit(3, Duration.ofSeconds(20)) // 1st limit
+                .addRateLimit(4, Duration.ofSeconds(40)) // 2nd limit
+                .addRateLimit(5, Duration.ofSeconds(60)) // 3rd limit
+                .build();
+
+        // Testing the 1st limit
+        mInjector.mElapsedTime = Duration.ZERO;
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+        multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+        mInjector.mElapsedTime = Duration.ofMillis(50);
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+        multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+        mInjector.mElapsedTime = Duration.ofMillis(100);
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+        multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+        mInjector.mElapsedTime = Duration.ofMillis(150);
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isFalse();
+
+        mInjector.mElapsedTime = Duration.ofSeconds(21);
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+        multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+        // Testing the 2nd limit
+        mInjector.mElapsedTime = Duration.ofSeconds(35);
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isFalse();
+
+        mInjector.mElapsedTime = Duration.ofSeconds(42);
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+        multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+        // Testing the 3rd limit.
+        mInjector.mElapsedTime = Duration.ofSeconds(43);
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isFalse();
+
+        mInjector.mElapsedTime = Duration.ofSeconds(62);
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+        multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+    }
+
+    @Test
+    public void createSingleRateLimit_testItLimitsOnlyGivenUptc() {
+        MultiRateLimiter multiRateLimiter =  new MultiRateLimiter.Builder(mContext, mInjector)
+                .addRateLimit(3, Duration.ofSeconds(20))
+                .build();
+
+        mInjector.mElapsedTime = Duration.ZERO;
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_2, TAG)).isTrue();
+        multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+        mInjector.mElapsedTime = Duration.ofMillis(50);
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_2, TAG)).isTrue();
+        multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+        mInjector.mElapsedTime = Duration.ofMillis(100);
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_2, TAG)).isTrue();
+        multiRateLimiter.noteEvent(USER_ID, PACKAGE_NAME_1, TAG);
+
+        mInjector.mElapsedTime = Duration.ofMillis(150);
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isFalse();
+        // Different userId - packageName - tag combination is still allowed.
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_2, TAG)).isTrue();
+
+        mInjector.mElapsedTime = Duration.ofSeconds(21);
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_1, TAG)).isTrue();
+        assertThat(multiRateLimiter.isWithinQuota(USER_ID, PACKAGE_NAME_2, TAG)).isTrue();
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/OWNERS b/services/tests/mockingservicestests/src/com/android/server/wallpaper/OWNERS
new file mode 100644
index 0000000..8ff0f74
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/wallpaper/OWNERS
diff --git a/services/tests/mockingservicestests/utils-mockito/com/android/server/extendedtestutils/ExtendedMockitoUtils.kt b/services/tests/mockingservicestests/utils-mockito/com/android/server/extendedtestutils/ExtendedMockitoUtils.kt
new file mode 100644
index 0000000..72ae77e
--- /dev/null
+++ b/services/tests/mockingservicestests/utils-mockito/com/android/server/extendedtestutils/ExtendedMockitoUtils.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.extendedtestutils
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.dx.mockito.inline.extended.MockedMethod
+import com.android.dx.mockito.inline.extended.StaticCapableStubber
+import org.mockito.stubbing.Answer
+
+fun <T> StaticCapableStubber.wheneverStatic(methodCall: MockedMethod<T>) {
+    this.`when`(methodCall)
+}
+
+fun <T> wheneverStatic(mockedMethod: MockedMethod<T>) = object : CustomStaticStubber<T> {
+    override fun thenAnswer(answer: Answer<T>) {
+        ExtendedMockito.doAnswer(answer).wheneverStatic(mockedMethod)
+    }
+
+    override fun thenReturn(value: T) {
+        ExtendedMockito.doReturn(value).wheneverStatic(mockedMethod)
+    }
+}
+
+interface CustomStaticStubber<T> {
+    fun thenAnswer(answer: Answer<T>)
+    fun thenReturn(value: T)
+}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 343b156..6daa381 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -33,6 +33,7 @@
         "androidx.test.ext.truth",
         "androidx.test.runner",
         "androidx.test.rules",
+        "platform-compat-test-rules",
         "mockito-target-minus-junit4",
         "platform-test-annotations",
         "ShortcutManagerTestUtils",
@@ -111,6 +112,16 @@
 }
 
 java_library {
+    name: "servicestests-core-utils",
+    srcs: [
+        "src/com/android/server/pm/PackageSettingBuilder.java",
+    ],
+    static_libs: [
+        "services.core",
+    ],
+}
+
+java_library {
     name: "servicestests-utils",
     srcs: [
         "utils/**/*.java",
diff --git a/services/tests/servicestests/apks/OWNERS b/services/tests/servicestests/apks/OWNERS
new file mode 100644
index 0000000..d825dfd
--- /dev/null
+++ b/services/tests/servicestests/apks/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/OWNERS
diff --git a/services/tests/servicestests/assets/NetworkPolicy/OWNERS b/services/tests/servicestests/assets/NetworkPolicy/OWNERS
new file mode 100644
index 0000000..aa87958
--- /dev/null
+++ b/services/tests/servicestests/assets/NetworkPolicy/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/net/OWNERS
diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/OWNERS b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/OWNERS
new file mode 100644
index 0000000..aa87958
--- /dev/null
+++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/net/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementInternalTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementInternalTest.java
deleted file mode 100644
index 33ea1d6..0000000
--- a/services/tests/servicestests/src/com/android/server/NetworkManagementInternalTest.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static android.net.INetd.FIREWALL_CHAIN_DOZABLE;
-import static android.net.INetd.FIREWALL_CHAIN_POWERSAVE;
-import static android.net.INetd.FIREWALL_CHAIN_STANDBY;
-import static android.net.INetd.FIREWALL_RULE_ALLOW;
-import static android.net.INetd.FIREWALL_RULE_DENY;
-import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
-import static android.util.DebugUtils.valueToString;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.net.NetworkPolicyManager;
-import android.util.ArrayMap;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.function.BiFunction;
-
-/**
- * Test class for {@link NetworkManagementInternal}.
- *
- * To run the tests, use
- *
- * runtest -c com.android.server.NetworkManagementInternalTest frameworks-services
- *
- * or the following steps:
- *
- * Build: m FrameworksServicesTests
- * Install: adb install -r \
- *     ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
- * Run: adb shell am instrument -e class com.android.server.NetworkManagementInternalTest -w \
- *     com.android.frameworks.servicestests/androidx.test.runner.AndroidJUnitRunner
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class NetworkManagementInternalTest {
-    private static final int TEST_UID = 111;
-
-    private NetworkManagementService.Injector mInjector;
-    private NetworkManagementInternal mNmi;
-
-    @Before
-    public void setUp() {
-        final NetworkManagementService service = new NetworkManagementService();
-        mInjector = service.getInjector();
-        mNmi = service.new LocalService();
-    }
-
-    @Test
-    public void testIsNetworkRestrictedForUid() {
-        // No firewall chains enabled
-        assertFalse(mNmi.isNetworkRestrictedForUid(TEST_UID));
-
-        // Restrict usage of mobile data in background
-        mInjector.setUidOnMeteredNetworkList(true, TEST_UID, true);
-        assertTrue("Should be true since mobile data usage is restricted",
-                mNmi.isNetworkRestrictedForUid(TEST_UID));
-        mInjector.reset();
-
-        // Data saver is on and uid is not allowlisted
-        mInjector.setDataSaverMode(true);
-        mInjector.setUidOnMeteredNetworkList(false, TEST_UID, false);
-        assertTrue("Should be true since data saver is on and the uid is not whitelisted",
-                mNmi.isNetworkRestrictedForUid(TEST_UID));
-        mInjector.reset();
-
-        // Data saver is on and uid is allowlisted
-        mInjector.setDataSaverMode(true);
-        mInjector.setUidOnMeteredNetworkList(false, TEST_UID, true);
-        assertFalse("Should be false since data saver is on and the uid is whitelisted",
-                mNmi.isNetworkRestrictedForUid(TEST_UID));
-        mInjector.reset();
-
-        final ArrayMap<Integer, ArrayMap<Integer, Boolean>> expected = new ArrayMap<>();
-        // Dozable chain
-        final ArrayMap<Integer, Boolean> isRestrictedForDozable = new ArrayMap<>();
-        isRestrictedForDozable.put(FIREWALL_RULE_DEFAULT, true);
-        isRestrictedForDozable.put(FIREWALL_RULE_ALLOW, false);
-        isRestrictedForDozable.put(FIREWALL_RULE_DENY, true);
-        expected.put(FIREWALL_CHAIN_DOZABLE, isRestrictedForDozable);
-        // Powersaver chain
-        final ArrayMap<Integer, Boolean> isRestrictedForPowerSave = new ArrayMap<>();
-        isRestrictedForPowerSave.put(FIREWALL_RULE_DEFAULT, true);
-        isRestrictedForPowerSave.put(FIREWALL_RULE_ALLOW, false);
-        isRestrictedForPowerSave.put(FIREWALL_RULE_DENY, true);
-        expected.put(FIREWALL_CHAIN_POWERSAVE, isRestrictedForPowerSave);
-        // Standby chain
-        final ArrayMap<Integer, Boolean> isRestrictedForStandby = new ArrayMap<>();
-        isRestrictedForStandby.put(FIREWALL_RULE_DEFAULT, false);
-        isRestrictedForStandby.put(FIREWALL_RULE_ALLOW, false);
-        isRestrictedForStandby.put(FIREWALL_RULE_DENY, true);
-        expected.put(FIREWALL_CHAIN_STANDBY, isRestrictedForStandby);
-
-        final int[] chains = {
-                FIREWALL_CHAIN_STANDBY,
-                FIREWALL_CHAIN_POWERSAVE,
-                FIREWALL_CHAIN_DOZABLE
-        };
-        final int[] states = {
-                FIREWALL_RULE_ALLOW,
-                FIREWALL_RULE_DENY,
-                FIREWALL_RULE_DEFAULT
-        };
-        BiFunction<Integer, Integer, String> errorMsg = (chain, state) -> {
-            return String.format("Unexpected value for chain: %s and state: %s",
-                    valueToString(NetworkPolicyManager.class, "FIREWALL_CHAIN_", chain),
-                    valueToString(NetworkPolicyManager.class, "FIREWALL_RULE_", state));
-        };
-        for (int chain : chains) {
-            final ArrayMap<Integer, Boolean> expectedValues = expected.get(chain);
-            mInjector.setFirewallChainState(chain, true);
-            for (int state : states) {
-                mInjector.setFirewallRule(chain, TEST_UID, state);
-                assertEquals(errorMsg.apply(chain, state),
-                        expectedValues.get(state), mNmi.isNetworkRestrictedForUid(TEST_UID));
-            }
-            mInjector.reset();
-        }
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index e609adc..ce3751a 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -72,7 +72,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.devicepolicy.MockUtils;
-import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.permission.LegacyPermissionManagerInternal;
 
 import com.google.android.collect.Lists;
 
@@ -133,10 +133,10 @@
     @Mock private UnaryOperator<List<ScoredNetwork>> mScanResultsFilter;
     @Mock private WifiInfo mWifiInfo;
     @Mock private NetworkScoreService.ScoringServiceConnection mServiceConnection;
-    @Mock private PermissionManagerServiceInternal mPermissionManagerInternal;
+    @Mock private LegacyPermissionManagerInternal mPermissionManagerInternal;
     @Captor private ArgumentCaptor<List<ScoredNetwork>> mScoredNetworkCaptor;
-    @Captor private
-    ArgumentCaptor<PermissionManagerServiceInternal.PackagesProvider> mPackagesProviderCaptor;
+    @Captor private ArgumentCaptor<LegacyPermissionManagerInternal.PackagesProvider>
+            mPackagesProviderCaptor;
 
     private ContentResolver mContentResolver;
     private NetworkScoreService mNetworkScoreService;
@@ -165,7 +165,7 @@
         mHandlerThread = new HandlerThread("NetworkScoreServiceTest");
         mHandlerThread.start();
         LocalServices.addService(
-                PermissionManagerServiceInternal.class, mPermissionManagerInternal);
+                LegacyPermissionManagerInternal.class, mPermissionManagerInternal);
         mNetworkScoreService = new NetworkScoreService(mContext, mNetworkScorerAppManager,
                 networkScorerAppData -> mServiceConnection, mHandlerThread.getLooper());
         WifiConfiguration configuration = new WifiConfiguration();
@@ -191,7 +191,7 @@
     @After
     public void tearDown() throws Exception {
         mHandlerThread.quitSafely();
-        LocalServices.removeServiceForTest(PermissionManagerServiceInternal.class);
+        LocalServices.removeServiceForTest(LegacyPermissionManagerInternal.class);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/OWNERS b/services/tests/servicestests/src/com/android/server/OWNERS
new file mode 100644
index 0000000..6153db3
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/OWNERS
@@ -0,0 +1,6 @@
+per-file *Alarm* = file:/apex/jobscheduler/OWNERS
+per-file *AppOps* = file:/core/java/android/permission/OWNERS
+per-file *Bluetooth* = file:/core/java/android/bluetooth/OWNERS
+per-file *Gnss* = file:/services/core/java/com/android/server/location/OWNERS
+per-file *Network* = file:/services/core/java/com/android/server/net/OWNERS
+per-file *Vibrator* = file:/services/core/java/com/android/server/vibrator/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index 3f3d5e5..839bc93 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -35,6 +35,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
 import android.graphics.drawable.Icon;
 import android.os.IBinder;
 import android.os.UserHandle;
@@ -94,6 +95,8 @@
     @Mock private IAccessibilityServiceClient mMockServiceClient;
     @Mock private WindowMagnificationManager mMockWindowMagnificationMgr;
     @Mock private MagnificationController mMockMagnificationController;
+    @Mock private Resources mMockResources;
+
     private AccessibilityUserState mUserState;
 
     private MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
@@ -121,6 +124,9 @@
             mMockA11yDisplayListener,
             mMockMagnificationController);
 
+        mMockResources = mock(Resources.class);
+        when(mMockContext.getResources()).thenReturn(mMockResources);
+
         final AccessibilityUserState userState = new AccessibilityUserState(
                 mA11yms.getCurrentUserIdLocked(), mMockContext, mA11yms);
         mA11yms.mUserStates.put(mA11yms.getCurrentUserIdLocked(), userState);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
index fbfb045..81ca92c 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
@@ -42,11 +42,16 @@
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Color;
 import android.provider.Settings;
 import android.test.mock.MockContentResolver;
 import android.testing.DexmakerShareClassLoaderRule;
 import android.util.ArraySet;
 
+import androidx.test.InstrumentationRegistry;
+
+import com.android.internal.R;
 import com.android.internal.util.test.FakeSettingsProvider;
 
 import org.junit.After;
@@ -90,8 +95,13 @@
 
     private AccessibilityUserState mUserState;
 
+    private int mFocusStrokeWidthDefaultValue;
+    private int mFocusColorDefaultValue;
+
     @Before
     public void setUp() {
+        final Resources resources = InstrumentationRegistry.getContext().getResources();
+
         MockitoAnnotations.initMocks(this);
         FakeSettingsProvider.clearSettingsProvider();
         mMockResolver = new MockContentResolver();
@@ -99,6 +109,11 @@
         when(mMockContext.getContentResolver()).thenReturn(mMockResolver);
         when(mMockServiceInfo.getComponentName()).thenReturn(COMPONENT_NAME);
         when(mMockConnection.getServiceInfo()).thenReturn(mMockServiceInfo);
+        when(mMockContext.getResources()).thenReturn(resources);
+
+        mFocusStrokeWidthDefaultValue =
+                resources.getDimensionPixelSize(R.dimen.accessibility_focus_highlight_stroke_width);
+        mFocusColorDefaultValue = resources.getColor(R.color.accessibility_focus_highlight_color);
 
         mUserState = new AccessibilityUserState(USER_ID, mMockContext, mMockListener);
     }
@@ -129,6 +144,7 @@
         mUserState.setUserNonInteractiveUiTimeoutLocked(30);
         mUserState.setUserInteractiveUiTimeoutLocked(30);
         mUserState.setMagnificationModeLocked(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
+        mUserState.setFocusAppearanceLocked(20, Color.BLUE);
 
         mUserState.onSwitchToAnotherUserLocked();
 
@@ -150,6 +166,8 @@
         assertEquals(0, mUserState.getUserInteractiveUiTimeoutLocked());
         assertEquals(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN,
                 mUserState.getMagnificationModeLocked());
+        assertEquals(mFocusStrokeWidthDefaultValue, mUserState.getFocusStrokeWidthLocked());
+        assertEquals(mFocusColorDefaultValue, mUserState.getFocusColorLocked());
     }
 
     @Test
@@ -350,6 +368,21 @@
                 mUserState.getMagnificationModeLocked());
     }
 
+    @Test
+    public void setFocusAppearanceData_returnExpectedFocusAppearanceData() {
+        final int focusStrokeWidthValue = 100;
+        final int focusColorValue = Color.BLUE;
+
+        assertEquals(mFocusStrokeWidthDefaultValue, mUserState.getFocusStrokeWidthLocked());
+        assertEquals(mFocusColorDefaultValue, mUserState.getFocusColorLocked());
+
+        mUserState.setFocusAppearanceLocked(focusStrokeWidthValue, focusColorValue);
+
+        assertEquals(focusStrokeWidthValue, mUserState.getFocusStrokeWidthLocked());
+        assertEquals(focusColorValue, mUserState.getFocusColorLocked());
+
+    }
+
     private int getSecureIntForUser(String key, int userId) {
         return Settings.Secure.getIntForUser(mMockResolver, key, -1, userId);
     }
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/OWNERS b/services/tests/servicestests/src/com/android/server/accessibility/OWNERS
new file mode 100644
index 0000000..b74281e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/accessibility/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/accounts/OWNERS b/services/tests/servicestests/src/com/android/server/accounts/OWNERS
new file mode 100644
index 0000000..df1b4f4
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accounts/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/accounts/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/adb/OWNERS b/services/tests/servicestests/src/com/android/server/adb/OWNERS
new file mode 100644
index 0000000..b97f795
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/adb/OWNERS
@@ -0,0 +1 @@
+include platform/packages/modules/adb:/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/am/OWNERS b/services/tests/servicestests/src/com/android/server/am/OWNERS
new file mode 100644
index 0000000..72c0a9e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/am/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/appop/OWNERS b/services/tests/servicestests/src/com/android/server/appop/OWNERS
new file mode 100644
index 0000000..999ea0e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/appop/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/permission/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/OWNERS b/services/tests/servicestests/src/com/android/server/appsearch/OWNERS
new file mode 100644
index 0000000..ebe9e4e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/appsearch/OWNERS
@@ -0,0 +1 @@
+include /apex/appsearch/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
index b929061..f38def8 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
@@ -37,6 +37,7 @@
 import com.android.server.appsearch.proto.StringIndexingConfig;
 import com.android.server.appsearch.proto.TermMatchType;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 
 import org.junit.Before;
@@ -46,9 +47,7 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 
 public class AppSearchImplTest {
     @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
@@ -66,14 +65,15 @@
                                         + VisibilityStore.SCHEMA_TYPE)
                         .addProperty(
                                 new AppSearchSchema.PropertyConfig.Builder(
-                                                VisibilityStore.PLATFORM_HIDDEN_PROPERTY)
+                                                VisibilityStore.NOT_PLATFORM_SURFACEABLE_PROPERTY)
                                         .setDataType(
                                                 AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
                                         .setCardinality(
                                                 AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
                                         .build())
                         .build();
-        mVisibilitySchemaProto = SchemaToProtoConverter.convert(visibilityAppSearchSchema);
+        mVisibilitySchemaProto =
+                SchemaToProtoConverter.toSchemaTypeConfigProto(visibilityAppSearchSchema);
     }
 
     /**
@@ -340,9 +340,13 @@
     @Test
     public void testOptimize() throws Exception {
         // Insert schema
-        Set<AppSearchSchema> schemas =
-                Collections.singleton(new AppSearchSchema.Builder("type").build());
-        mAppSearchImpl.setSchema("database", schemas, /*forceOverride=*/ false);
+        List<AppSearchSchema> schemas =
+                Collections.singletonList(new AppSearchSchema.Builder("type").build());
+        mAppSearchImpl.setSchema(
+                "database",
+                schemas,
+                /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+                /*forceOverride=*/ false);
 
         // Insert enough documents.
         for (int i = 0;
@@ -351,7 +355,7 @@
                                 + AppSearchImpl.CHECK_OPTIMIZE_INTERVAL;
                 i++) {
             GenericDocument document =
-                    new GenericDocument.Builder("uri" + i, "type")
+                    new GenericDocument.Builder<>("uri" + i, "type")
                             .setNamespace("namespace")
                             .build();
             mAppSearchImpl.putDocument("database", document);
@@ -392,13 +396,17 @@
         SearchSpecProto.Builder searchSpecProto = SearchSpecProto.newBuilder().setQuery("");
 
         // Insert schema
-        Set<AppSearchSchema> schemas =
-                Collections.singleton(new AppSearchSchema.Builder("type").build());
-        mAppSearchImpl.setSchema("database", schemas, /*forceOverride=*/ false);
+        List<AppSearchSchema> schemas =
+                Collections.singletonList(new AppSearchSchema.Builder("type").build());
+        mAppSearchImpl.setSchema(
+                "database",
+                schemas,
+                /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+                /*forceOverride=*/ false);
 
         // Insert document
         GenericDocument document =
-                new GenericDocument.Builder("uri", "type").setNamespace("namespace").build();
+                new GenericDocument.Builder<>("uri", "type").setNamespace("namespace").build();
         mAppSearchImpl.putDocument("database", document);
 
         // Rewrite SearchSpec
@@ -413,20 +421,28 @@
         SearchSpecProto.Builder searchSpecProto = SearchSpecProto.newBuilder().setQuery("");
 
         // Insert schema
-        Set<AppSearchSchema> schemas =
-                Set.of(
+        List<AppSearchSchema> schemas =
+                ImmutableList.of(
                         new AppSearchSchema.Builder("typeA").build(),
                         new AppSearchSchema.Builder("typeB").build());
-        mAppSearchImpl.setSchema("database1", schemas, /*forceOverride=*/ false);
-        mAppSearchImpl.setSchema("database2", schemas, /*forceOverride=*/ false);
+        mAppSearchImpl.setSchema(
+                "database1",
+                schemas,
+                /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+                /*forceOverride=*/ false);
+        mAppSearchImpl.setSchema(
+                "database2",
+                schemas,
+                /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+                /*forceOverride=*/ false);
 
         // Insert documents
         GenericDocument document1 =
-                new GenericDocument.Builder("uri", "typeA").setNamespace("namespace").build();
+                new GenericDocument.Builder<>("uri", "typeA").setNamespace("namespace").build();
         mAppSearchImpl.putDocument("database1", document1);
 
         GenericDocument document2 =
-                new GenericDocument.Builder("uri", "typeB").setNamespace("namespace").build();
+                new GenericDocument.Builder<>("uri", "typeB").setNamespace("namespace").build();
         mAppSearchImpl.putDocument("database2", document2);
 
         // Rewrite SearchSpec
@@ -477,10 +493,14 @@
 
     @Test
     public void testSetSchema() throws Exception {
-        Set<AppSearchSchema> schemas =
-                Collections.singleton(new AppSearchSchema.Builder("Email").build());
+        List<AppSearchSchema> schemas =
+                Collections.singletonList(new AppSearchSchema.Builder("Email").build());
         // Set schema Email to AppSearch database1
-        mAppSearchImpl.setSchema("database1", schemas, /*forceOverride=*/ false);
+        mAppSearchImpl.setSchema(
+                "database1",
+                schemas,
+                /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+                /*forceOverride=*/ false);
 
         // Create expected schemaType proto.
         SchemaProto expectedProto =
@@ -500,35 +520,47 @@
     public void testSetSchema_existingSchemaRetainsVisibilitySetting() throws Exception {
         mAppSearchImpl.setSchema(
                 "database",
-                Collections.singleton(new AppSearchSchema.Builder("schema1").build()),
+                Collections.singletonList(new AppSearchSchema.Builder("schema1").build()),
+                /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("schema1"),
                 /*forceOverride=*/ false);
-        mAppSearchImpl.setVisibility("database", Set.of("schema1"));
 
         // "schema1" is platform hidden now
-        assertThat(mAppSearchImpl.getVisibilityStoreLocked().getPlatformHiddenSchemas("database"))
+        assertThat(
+                        mAppSearchImpl
+                                .getVisibilityStoreLocked()
+                                .getSchemasNotPlatformSurfaceable("database"))
                 .containsExactly("database/schema1");
 
         // Add a new schema, and include the already-existing "schema1"
         mAppSearchImpl.setSchema(
                 "database",
-                Set.of(
+                ImmutableList.of(
                         new AppSearchSchema.Builder("schema1").build(),
                         new AppSearchSchema.Builder("schema2").build()),
+                /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("schema1"),
                 /*forceOverride=*/ false);
 
         // Check that "schema1" is still platform hidden, but "schema2" is the default platform
         // visible.
-        assertThat(mAppSearchImpl.getVisibilityStoreLocked().getPlatformHiddenSchemas("database"))
+        assertThat(
+                        mAppSearchImpl
+                                .getVisibilityStoreLocked()
+                                .getSchemasNotPlatformSurfaceable("database"))
                 .containsExactly("database/schema1");
     }
 
     @Test
     public void testRemoveSchema() throws Exception {
-        Set<AppSearchSchema> schemas = new HashSet<>();
-        schemas.add(new AppSearchSchema.Builder("Email").build());
-        schemas.add(new AppSearchSchema.Builder("Document").build());
+        List<AppSearchSchema> schemas =
+                ImmutableList.of(
+                        new AppSearchSchema.Builder("Email").build(),
+                        new AppSearchSchema.Builder("Document").build());
         // Set schema Email and Document to AppSearch database1
-        mAppSearchImpl.setSchema("database1", schemas, /*forceOverride=*/ false);
+        mAppSearchImpl.setSchema(
+                "database1",
+                schemas,
+                /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+                /*forceOverride=*/ false);
 
         // Create expected schemaType proto.
         SchemaProto expectedProto =
@@ -547,20 +579,27 @@
         assertThat(mAppSearchImpl.getSchemaProtoLocked().getTypesList())
                 .containsExactlyElementsIn(expectedTypes);
 
-        final Set<AppSearchSchema> finalSchemas =
-                Collections.singleton(new AppSearchSchema.Builder("Email").build());
+        final List<AppSearchSchema> finalSchemas =
+                Collections.singletonList(new AppSearchSchema.Builder("Email").build());
         // Check the incompatible error has been thrown.
         AppSearchException e =
                 expectThrows(
                         AppSearchException.class,
                         () ->
                                 mAppSearchImpl.setSchema(
-                                        "database1", finalSchemas, /*forceOverride=*/ false));
+                                        "database1",
+                                        finalSchemas,
+                                        /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+                                        /*forceOverride=*/ false));
         assertThat(e).hasMessageThat().contains("Schema is incompatible");
         assertThat(e).hasMessageThat().contains("Deleted types: [database1/Document]");
 
         // ForceOverride to delete.
-        mAppSearchImpl.setSchema("database1", finalSchemas, /*forceOverride=*/ true);
+        mAppSearchImpl.setSchema(
+                "database1",
+                finalSchemas,
+                /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+                /*forceOverride=*/ true);
 
         // Check Document schema is removed.
         expectedProto =
@@ -579,13 +618,22 @@
     @Test
     public void testRemoveSchema_differentDataBase() throws Exception {
         // Create schemas
-        Set<AppSearchSchema> schemas = new HashSet<>();
-        schemas.add(new AppSearchSchema.Builder("Email").build());
-        schemas.add(new AppSearchSchema.Builder("Document").build());
+        List<AppSearchSchema> schemas =
+                ImmutableList.of(
+                        new AppSearchSchema.Builder("Email").build(),
+                        new AppSearchSchema.Builder("Document").build());
 
         // Set schema Email and Document to AppSearch database1 and 2
-        mAppSearchImpl.setSchema("database1", schemas, /*forceOverride=*/ false);
-        mAppSearchImpl.setSchema("database2", schemas, /*forceOverride=*/ false);
+        mAppSearchImpl.setSchema(
+                "database1",
+                schemas,
+                /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+                /*forceOverride=*/ false);
+        mAppSearchImpl.setSchema(
+                "database2",
+                schemas,
+                /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+                /*forceOverride=*/ false);
 
         // Create expected schemaType proto.
         SchemaProto expectedProto =
@@ -610,8 +658,12 @@
                 .containsExactlyElementsIn(expectedTypes);
 
         // Save only Email to database1 this time.
-        schemas = Collections.singleton(new AppSearchSchema.Builder("Email").build());
-        mAppSearchImpl.setSchema("database1", schemas, /*forceOverride=*/ true);
+        schemas = Collections.singletonList(new AppSearchSchema.Builder("Email").build());
+        mAppSearchImpl.setSchema(
+                "database1",
+                schemas,
+                /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+                /*forceOverride=*/ true);
 
         // Create expected schemaType list, database 1 should only contain Email but database 2
         // remains in same.
@@ -638,76 +690,82 @@
     public void testRemoveSchema_removedFromVisibilityStore() throws Exception {
         mAppSearchImpl.setSchema(
                 "database",
-                Collections.singleton(new AppSearchSchema.Builder("schema1").build()),
+                Collections.singletonList(new AppSearchSchema.Builder("schema1").build()),
+                /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("schema1"),
                 /*forceOverride=*/ false);
-        mAppSearchImpl.setVisibility("database", Set.of("schema1"));
 
         // "schema1" is platform hidden now
-        assertThat(mAppSearchImpl.getVisibilityStoreLocked().getPlatformHiddenSchemas("database"))
+        assertThat(
+                        mAppSearchImpl
+                                .getVisibilityStoreLocked()
+                                .getSchemasNotPlatformSurfaceable("database"))
                 .containsExactly("database/schema1");
 
         // Remove "schema1" by force overriding
-        mAppSearchImpl.setSchema("database", Collections.emptySet(), /*forceOverride=*/ true);
+        mAppSearchImpl.setSchema(
+                "database",
+                Collections.emptyList(),
+                /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
+                /*forceOverride=*/ true);
 
         // Check that "schema1" is no longer considered platform hidden
-        assertThat(mAppSearchImpl.getVisibilityStoreLocked().getPlatformHiddenSchemas("database"))
+        assertThat(
+                        mAppSearchImpl
+                                .getVisibilityStoreLocked()
+                                .getSchemasNotPlatformSurfaceable("database"))
                 .isEmpty();
 
         // Add "schema1" back, it gets default visibility settings which means it's not platform
         // hidden.
         mAppSearchImpl.setSchema(
                 "database",
-                Collections.singleton(new AppSearchSchema.Builder("schema1").build()),
+                Collections.singletonList(new AppSearchSchema.Builder("schema1").build()),
+                /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
                 /*forceOverride=*/ false);
-        assertThat(mAppSearchImpl.getVisibilityStoreLocked().getPlatformHiddenSchemas("database"))
+        assertThat(
+                        mAppSearchImpl
+                                .getVisibilityStoreLocked()
+                                .getSchemasNotPlatformSurfaceable("database"))
                 .isEmpty();
     }
 
     @Test
-    public void testSetVisibility_defaultPlatformVisible() throws Exception {
+    public void testSetSchema_defaultPlatformVisible() throws Exception {
         mAppSearchImpl.setSchema(
                 "database",
-                Collections.singleton(new AppSearchSchema.Builder("Schema").build()),
+                Collections.singletonList(new AppSearchSchema.Builder("Schema").build()),
+                /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
                 /*forceOverride=*/ false);
-        assertThat(mAppSearchImpl.getVisibilityStoreLocked().getPlatformHiddenSchemas("database"))
+        assertThat(
+                        mAppSearchImpl
+                                .getVisibilityStoreLocked()
+                                .getSchemasNotPlatformSurfaceable("database"))
                 .isEmpty();
     }
 
     @Test
-    public void testSetVisibility_platformHidden() throws Exception {
+    public void testSetSchema_platformHidden() throws Exception {
         mAppSearchImpl.setSchema(
                 "database",
-                Collections.singleton(new AppSearchSchema.Builder("Schema").build()),
+                Collections.singletonList(new AppSearchSchema.Builder("Schema").build()),
+                /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("Schema"),
                 /*forceOverride=*/ false);
-        mAppSearchImpl.setVisibility("database", Set.of("Schema"));
-        assertThat(mAppSearchImpl.getVisibilityStoreLocked().getPlatformHiddenSchemas("database"))
+        assertThat(
+                        mAppSearchImpl
+                                .getVisibilityStoreLocked()
+                                .getSchemasNotPlatformSurfaceable("database"))
                 .containsExactly("database/Schema");
     }
 
     @Test
-    public void testSetVisibility_unknownSchema() throws Exception {
-        mAppSearchImpl.setSchema(
-                "database",
-                Collections.singleton(new AppSearchSchema.Builder("Schema").build()),
-                /*forceOverride=*/ false);
-
-        // We'll throw an exception if a client tries to set visibility on a schema we don't know
-        // about.
-        AppSearchException e =
-                expectThrows(
-                        AppSearchException.class,
-                        () -> mAppSearchImpl.setVisibility("database", Set.of("UnknownSchema")));
-        assertThat(e).hasMessageThat().contains("Unknown schema(s)");
-    }
-
-    @Test
     public void testHasSchemaType() throws Exception {
         // Nothing exists yet
         assertThat(mAppSearchImpl.hasSchemaTypeLocked("database", "Schema")).isFalse();
 
         mAppSearchImpl.setSchema(
                 "database",
-                Collections.singleton(new AppSearchSchema.Builder("Schema").build()),
+                Collections.singletonList(new AppSearchSchema.Builder("Schema").build()),
+                /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
                 /*forceOverride=*/ false);
         assertThat(mAppSearchImpl.hasSchemaTypeLocked("database", "Schema")).isTrue();
 
@@ -723,7 +781,8 @@
         // Has database1
         mAppSearchImpl.setSchema(
                 "database1",
-                Collections.singleton(new AppSearchSchema.Builder("schema").build()),
+                Collections.singletonList(new AppSearchSchema.Builder("schema").build()),
+                /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
                 /*forceOverride=*/ false);
         assertThat(mAppSearchImpl.getDatabasesLocked())
                 .containsExactly(VisibilityStore.DATABASE_NAME, "database1");
@@ -731,7 +790,8 @@
         // Has both databases
         mAppSearchImpl.setSchema(
                 "database2",
-                Collections.singleton(new AppSearchSchema.Builder("schema").build()),
+                Collections.singletonList(new AppSearchSchema.Builder("schema").build()),
+                /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
                 /*forceOverride=*/ false);
         assertThat(mAppSearchImpl.getDatabasesLocked())
                 .containsExactly(VisibilityStore.DATABASE_NAME, "database1", "database2");
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/VisibilityStoreTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/VisibilityStoreTest.java
index dfe2de6..a1f575a 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/VisibilityStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/VisibilityStoreTest.java
@@ -41,34 +41,19 @@
     @Test
     public void testSetVisibility() throws Exception {
         mVisibilityStore.setVisibility(
-                "database", /*platformHiddenSchemas=*/ Set.of("schema1", "schema2"));
-        assertThat(mVisibilityStore.getPlatformHiddenSchemas("database"))
+                "database", /*schemasNotPlatformSurfaceable=*/ Set.of("schema1", "schema2"));
+        assertThat(mVisibilityStore.getSchemasNotPlatformSurfaceable("database"))
                 .containsExactly("schema1", "schema2");
 
         // New .setVisibility() call completely overrides previous visibility settings. So
         // "schema1" isn't preserved.
         mVisibilityStore.setVisibility(
-                "database", /*platformHiddenSchemas=*/ Set.of("schema1", "schema3"));
-        assertThat(mVisibilityStore.getPlatformHiddenSchemas("database"))
+                "database", /*schemasNotPlatformSurfaceable=*/ Set.of("schema1", "schema3"));
+        assertThat(mVisibilityStore.getSchemasNotPlatformSurfaceable("database"))
                 .containsExactly("schema1", "schema3");
 
         mVisibilityStore.setVisibility(
-                "database", /*platformHiddenSchemas=*/ Collections.emptySet());
-        assertThat(mVisibilityStore.getPlatformHiddenSchemas("database")).isEmpty();
-    }
-
-    @Test
-    public void testRemoveSchemas() throws Exception {
-        mVisibilityStore.setVisibility(
-                "database", /*platformHiddenSchemas=*/ Set.of("schema1", "schema2"));
-
-        // Removed just schema1
-        mVisibilityStore.updateSchemas("database", /*schemasToRemove=*/ Set.of("schema1"));
-        assertThat(mVisibilityStore.getPlatformHiddenSchemas("database"))
-                .containsExactly("schema2");
-
-        // Removed everything now
-        mVisibilityStore.updateSchemas("database", /*schemasToRemove=*/ Set.of("schema2"));
-        assertThat(mVisibilityStore.getPlatformHiddenSchemas("database")).isEmpty();
+                "database", /*schemasNotPlatformSurfaceable=*/ Collections.emptySet());
+        assertThat(mVisibilityStore.getSchemasNotPlatformSurfaceable("database")).isEmpty();
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverterTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverterTest.java
index 98392a7..194be37 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverterTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/GenericDocumentToProtoConverterTest.java
@@ -94,20 +94,24 @@
                 PropertyProto.newBuilder()
                         .setName("documentKey1")
                         .addDocumentValues(
-                                GenericDocumentToProtoConverter.convert(DOCUMENT_PROPERTIES_1)));
+                                GenericDocumentToProtoConverter.toDocumentProto(
+                                        DOCUMENT_PROPERTIES_1)));
         propertyProtoMap.put(
                 "documentKey2",
                 PropertyProto.newBuilder()
                         .setName("documentKey2")
                         .addDocumentValues(
-                                GenericDocumentToProtoConverter.convert(DOCUMENT_PROPERTIES_2)));
+                                GenericDocumentToProtoConverter.toDocumentProto(
+                                        DOCUMENT_PROPERTIES_2)));
         List<String> sortedKey = new ArrayList<>(propertyProtoMap.keySet());
         Collections.sort(sortedKey);
         for (String key : sortedKey) {
             documentProtoBuilder.addProperties(propertyProtoMap.get(key));
         }
         DocumentProto documentProto = documentProtoBuilder.build();
-        assertThat(GenericDocumentToProtoConverter.convert(document)).isEqualTo(documentProto);
-        assertThat(document).isEqualTo(GenericDocumentToProtoConverter.convert(documentProto));
+        assertThat(GenericDocumentToProtoConverter.toDocumentProto(document))
+                .isEqualTo(documentProto);
+        assertThat(document)
+                .isEqualTo(GenericDocumentToProtoConverter.toGenericDocument(documentProto));
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverterTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverterTest.java
index dedfca4..88edcb8 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverterTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SchemaToProtoConverterTest.java
@@ -89,7 +89,10 @@
                                                                 TermMatchType.Code.PREFIX)))
                         .build();
 
-        assertThat(SchemaToProtoConverter.convert(emailSchema)).isEqualTo(expectedEmailProto);
+        assertThat(SchemaToProtoConverter.toSchemaTypeConfigProto(emailSchema))
+                .isEqualTo(expectedEmailProto);
+        assertThat(SchemaToProtoConverter.toAppSearchSchema(expectedEmailProto))
+                .isEqualTo(emailSchema);
     }
 
     @Test
@@ -151,7 +154,9 @@
                                                                 TermMatchType.Code.UNKNOWN)))
                         .build();
 
-        assertThat(SchemaToProtoConverter.convert(musicRecordingSchema))
+        assertThat(SchemaToProtoConverter.toSchemaTypeConfigProto(musicRecordingSchema))
                 .isEqualTo(expectedMusicRecordingProto);
+        assertThat(SchemaToProtoConverter.toAppSearchSchema(expectedMusicRecordingProto))
+                .isEqualTo(musicRecordingSchema);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
index 518f532..7c68c6b 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
@@ -83,7 +83,7 @@
 
         // Making ResultReader and getting Snippet values.
         SearchResultPage searchResultPage =
-                SearchResultToProtoConverter.convertToSearchResultPage(searchResultProto);
+                SearchResultToProtoConverter.toSearchResultPage(searchResultProto);
         for (SearchResult result : searchResultPage.getResults()) {
             SearchResult.MatchInfo match = result.getMatches().get(0);
             assertThat(match.getPropertyPath()).isEqualTo(propertyKeyString);
@@ -131,7 +131,7 @@
                 SearchResultProto.newBuilder().addResults(resultProto).build();
 
         SearchResultPage searchResultPage =
-                SearchResultToProtoConverter.convertToSearchResultPage(searchResultProto);
+                SearchResultToProtoConverter.toSearchResultPage(searchResultProto);
         for (SearchResult result : searchResultPage.getResults()) {
             assertThat(result.getMatches()).isEmpty();
         }
@@ -196,7 +196,7 @@
 
         // Making ResultReader and getting Snippet values.
         SearchResultPage searchResultPage =
-                SearchResultToProtoConverter.convertToSearchResultPage(searchResultProto);
+                SearchResultToProtoConverter.toSearchResultPage(searchResultProto);
         for (SearchResult result : searchResultPage.getResults()) {
 
             SearchResult.MatchInfo match1 = result.getMatches().get(0);
diff --git a/services/tests/servicestests/src/com/android/server/attention/OWNERS b/services/tests/servicestests/src/com/android/server/attention/OWNERS
new file mode 100644
index 0000000..51fc9bd
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/attention/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/attention/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/backup/OWNERS b/services/tests/servicestests/src/com/android/server/backup/OWNERS
new file mode 100644
index 0000000..d99779e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/backup/OWNERS
@@ -0,0 +1 @@
+include /services/backup/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java
index 444155d..738527e 100644
--- a/services/tests/servicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java
@@ -18,14 +18,17 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import android.app.backup.BackupManager.OperationType;
+import android.compat.testing.PlatformCompatChangeRule;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.Property;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageParser;
 import android.content.pm.Signature;
@@ -38,9 +41,15 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.backup.UserBackupManagerService;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+
+import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
+import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -50,17 +59,19 @@
 @RunWith(AndroidJUnit4.class)
 public class BackupEligibilityRulesTest {
     private static final String CUSTOM_BACKUP_AGENT_NAME = "custom.backup.agent";
-    private static final String TEST_PACKAGE_NAME = "test_package";
+    private static final String TEST_PACKAGE_NAME = "com.android.frameworks.servicestests";
 
     private static final Signature SIGNATURE_1 = generateSignature((byte) 1);
     private static final Signature SIGNATURE_2 = generateSignature((byte) 2);
     private static final Signature SIGNATURE_3 = generateSignature((byte) 3);
     private static final Signature SIGNATURE_4 = generateSignature((byte) 4);
 
+    @Rule public TestRule compatChangeRule = new PlatformCompatChangeRule();
+
     @Mock private PackageManagerInternal mMockPackageManagerInternal;
     @Mock private PackageManager mPackageManager;
-    private BackupEligibilityRules mBackupEligibilityRules;
 
+    private BackupEligibilityRules mBackupEligibilityRules;
     private int mUserId;
 
     @Before
@@ -225,7 +236,6 @@
             throws Exception {
         ApplicationInfo applicationInfo = getApplicationInfo(Process.SYSTEM_UID,
                 /* flags */ 0, CUSTOM_BACKUP_AGENT_NAME);
-
         BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
                 OperationType.MIGRATION);
         boolean isEligible = eligibilityRules.appIsEligibleForBackup(applicationInfo);
@@ -234,6 +244,82 @@
     }
 
     @Test
+    @EnableCompatChanges({BackupEligibilityRules.RESTRICT_ADB_BACKUP})
+    public void appIsEligibleForBackup_adbBackupNotAllowed_returnsFalseForAdbBackup()
+            throws Exception {
+        ApplicationInfo applicationInfo = getApplicationInfo(Process.FIRST_APPLICATION_UID,
+                /* flags */ ApplicationInfo.PRIVATE_FLAG_PRIVILEGED, CUSTOM_BACKUP_AGENT_NAME);
+        BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
+                OperationType.ADB_BACKUP);
+        when(mPackageManager.getProperty(eq(PackageManager.PROPERTY_ALLOW_ADB_BACKUP),
+                eq(TEST_PACKAGE_NAME))).thenReturn(getAdbBackupProperty(
+                        /* allowAdbBackup */ false));
+
+        boolean isEligible = eligibilityRules.appIsEligibleForBackup(applicationInfo);
+
+        assertThat(isEligible).isFalse();
+    }
+
+    @Test
+    @EnableCompatChanges({BackupEligibilityRules.RESTRICT_ADB_BACKUP})
+    public void appIsEligibleForBackup_adbBackupAllowed_returnsTrueForAdbBackup()
+            throws Exception {
+        ApplicationInfo applicationInfo = getApplicationInfo(Process.FIRST_APPLICATION_UID,
+                /* flags */ ApplicationInfo.PRIVATE_FLAG_PRIVILEGED, CUSTOM_BACKUP_AGENT_NAME);
+        BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
+                OperationType.ADB_BACKUP);
+        when(mPackageManager.getProperty(eq(PackageManager.PROPERTY_ALLOW_ADB_BACKUP),
+                eq(TEST_PACKAGE_NAME))).thenReturn(getAdbBackupProperty(
+                /* allowAdbBackup */ true));
+
+        boolean isEligible = eligibilityRules.appIsEligibleForBackup(applicationInfo);
+
+        assertThat(isEligible).isTrue();
+    }
+
+    @Test
+    @EnableCompatChanges({BackupEligibilityRules.RESTRICT_ADB_BACKUP})
+    public void appIsEligibleForBackup_debuggableNonPrivilegedApp_returnsTrueForAdbBackup()
+            throws Exception {
+        ApplicationInfo applicationInfo = getApplicationInfo(Process.FIRST_APPLICATION_UID,
+                /* flags */ ApplicationInfo.FLAG_DEBUGGABLE, CUSTOM_BACKUP_AGENT_NAME);
+        BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
+                OperationType.ADB_BACKUP);
+
+        boolean isEligible = eligibilityRules.appIsEligibleForBackup(applicationInfo);
+
+        assertThat(isEligible).isTrue();
+    }
+
+    @Test
+    @DisableCompatChanges({BackupEligibilityRules.RESTRICT_ADB_BACKUP})
+    public void appIsEligibleForBackup_allowBackupTrueBeforeS_returnsTrueForAdbBackup()
+            throws Exception {
+        ApplicationInfo applicationInfo = getApplicationInfo(Process.FIRST_APPLICATION_UID,
+                ApplicationInfo.FLAG_ALLOW_BACKUP, CUSTOM_BACKUP_AGENT_NAME);
+        BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
+                OperationType.ADB_BACKUP);
+
+        boolean isEligible = eligibilityRules.appIsEligibleForBackup(applicationInfo);
+
+        assertThat(isEligible).isTrue();
+    }
+
+    @Test
+    @DisableCompatChanges({BackupEligibilityRules.RESTRICT_ADB_BACKUP})
+    public void appIsEligibleForBackup_allowBackupFalseBeforeS_returnsFalseForAdbBackup()
+            throws Exception {
+        ApplicationInfo applicationInfo = getApplicationInfo(Process.FIRST_APPLICATION_UID,
+                /* flags */ 0, CUSTOM_BACKUP_AGENT_NAME);
+        BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
+                OperationType.ADB_BACKUP);
+
+        boolean isEligible = eligibilityRules.appIsEligibleForBackup(applicationInfo);
+
+        assertThat(isEligible).isFalse();
+    }
+
+    @Test
     public void appIsDisabled_stateDefaultManifestEnabled_returnsFalse() throws Exception {
         ApplicationInfo applicationInfo = new ApplicationInfo();
         applicationInfo.flags = 0;
@@ -789,10 +875,15 @@
     private static ApplicationInfo getApplicationInfo(int appUid, int flags,
             String backupAgentName) {
         ApplicationInfo applicationInfo = new ApplicationInfo();
-        applicationInfo.flags = 0;
+        applicationInfo.flags = flags;
         applicationInfo.packageName = TEST_PACKAGE_NAME;
         applicationInfo.uid = appUid;
         applicationInfo.backupAgentName = backupAgentName;
         return applicationInfo;
     }
+
+    private static Property getAdbBackupProperty(boolean allowAdbBackup) {
+        return new Property(PackageManager.PROPERTY_ALLOW_ADB_BACKUP, allowAdbBackup,
+                TEST_PACKAGE_NAME, /* className */ "");
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/compat/OWNERS b/services/tests/servicestests/src/com/android/server/compat/OWNERS
new file mode 100644
index 0000000..f8c3520
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/compat/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/compat/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/OWNERS b/services/tests/servicestests/src/com/android/server/devicepolicy/OWNERS
new file mode 100644
index 0000000..e95633a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/app/admin/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/OWNERS b/services/tests/servicestests/src/com/android/server/devicestate/OWNERS
new file mode 100644
index 0000000..d9b0e2e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicestate/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/devicestate/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/display/OWNERS b/services/tests/servicestests/src/com/android/server/display/OWNERS
new file mode 100644
index 0000000..6ce1ee4
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/display/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
index 6debc89..f2254a9 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
@@ -98,17 +98,17 @@
             }
 
             @Override
-            PowerManager getPowerManager() {
+            protected PowerManager getPowerManager() {
                 return powerManager;
             }
 
             @Override
-            void writeStringSystemProperty(String key, String value) {
+            protected void writeStringSystemProperty(String key, String value) {
                 // do nothing
             }
 
             @Override
-            HdmiCecConfig getHdmiCecConfig() {
+            protected HdmiCecConfig getHdmiCecConfig() {
                 return hdmiCecConfig;
             }
         };
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
index a19336e..6e4d994 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
@@ -90,7 +90,7 @@
                     }
 
                     @Override
-                    PowerManager getPowerManager() {
+                    protected PowerManager getPowerManager() {
                         return powerManager;
                     }
 
@@ -110,7 +110,7 @@
                     }
 
                     @Override
-                    HdmiCecConfig getHdmiCecConfig() {
+                    protected HdmiCecConfig getHdmiCecConfig() {
                         return hdmiCecConfig;
                     }
                 };
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
index cd69775..bbe1156 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
@@ -86,7 +86,7 @@
                     }
 
                     @Override
-                    PowerManager getPowerManager() {
+                    protected PowerManager getPowerManager() {
                         return powerManager;
                     }
 
@@ -111,7 +111,7 @@
                     }
 
                     @Override
-                    HdmiCecConfig getHdmiCecConfig() {
+                    protected HdmiCecConfig getHdmiCecConfig() {
                         return hdmiCecConfig;
                     }
                 };
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java
new file mode 100644
index 0000000..af119c8
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.hdmi;
+
+import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
+import static com.android.server.hdmi.Constants.ADDR_TV;
+import static com.android.server.hdmi.Constants.PATH_RELATIONSHIP_ANCESTOR;
+import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
+
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.hardware.hdmi.HdmiPortInfo;
+import android.hardware.tv.cec.V1_0.SendMessageResult;
+import android.os.Handler;
+import android.os.IPowerManager;
+import android.os.IThermalService;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.test.TestLooper;
+import android.platform.test.annotations.Presubmit;
+import android.stats.hdmi.nano.HdmiStatsEnums;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
+import com.android.server.SystemService;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+
+/**
+ * Tests for the {@link HdmiCecAtomWriter} class and its usage by the HDMI-CEC framework.
+ */
+@SmallTest
+@Presubmit
+@RunWith(JUnit4.class)
+public class HdmiCecAtomLoggingTest {
+    private HdmiCecAtomWriter mHdmiCecAtomWriterSpy;
+    private HdmiControlService mHdmiControlServiceSpy;
+    private HdmiCecController mHdmiCecController;
+    private HdmiCecLocalDevicePlayback mHdmiCecLocalDevicePlayback;
+    private HdmiMhlControllerStub mHdmiMhlControllerStub;
+    private FakeNativeWrapper mNativeWrapper;
+    private HdmiCecNetwork mHdmiCecNetwork;
+    private Looper mLooper;
+    private TestLooper mTestLooper = new TestLooper();
+    private int mPhysicalAddress = 0x1110;
+    private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
+    private HdmiPortInfo[] mHdmiPortInfo;
+
+    @Mock private IPowerManager mIPowerManagerMock;
+    @Mock private IThermalService mIThermalServiceMock;
+
+    @Before
+    public void setUp() throws RemoteException {
+        MockitoAnnotations.initMocks(this);
+
+        mHdmiCecAtomWriterSpy = spy(new HdmiCecAtomWriter());
+
+        mLooper = mTestLooper.getLooper();
+
+        Context mContextSpy = spy(new ContextWrapper(
+                InstrumentationRegistry.getInstrumentation().getTargetContext()));
+
+        PowerManager powerManager = new PowerManager(
+                mContextSpy, mIPowerManagerMock, mIThermalServiceMock, new Handler(mLooper));
+        doReturn(powerManager).when(mContextSpy).getSystemService(Context.POWER_SERVICE);
+        doReturn(true).when(mIPowerManagerMock).isInteractive();
+
+        mHdmiControlServiceSpy = spy(new HdmiControlService(mContextSpy));
+        doNothing().when(mHdmiControlServiceSpy)
+                .writeStringSystemProperty(anyString(), anyString());
+        doReturn(mHdmiCecAtomWriterSpy).when(mHdmiControlServiceSpy).getAtomWriter();
+
+        HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
+        doReturn(hdmiCecConfig).when(mHdmiControlServiceSpy).getHdmiCecConfig();
+
+        mHdmiControlServiceSpy.setIoLooper(mLooper);
+        mHdmiControlServiceSpy.setMessageValidator(
+                new HdmiCecMessageValidator(mHdmiControlServiceSpy));
+        mHdmiControlServiceSpy.setCecMessageBuffer(
+                new CecMessageBuffer(mHdmiControlServiceSpy));
+
+        mNativeWrapper = new FakeNativeWrapper();
+        mNativeWrapper.setPhysicalAddress(mPhysicalAddress);
+
+        mHdmiCecController = HdmiCecController.createWithNativeWrapper(
+                mHdmiControlServiceSpy, mNativeWrapper, mHdmiCecAtomWriterSpy);
+        mHdmiControlServiceSpy.setCecController(mHdmiCecController);
+
+        mHdmiMhlControllerStub = HdmiMhlControllerStub.create(mHdmiControlServiceSpy);
+        mHdmiControlServiceSpy.setHdmiMhlController(
+                mHdmiMhlControllerStub);
+
+        mHdmiCecNetwork = new HdmiCecNetwork(mHdmiControlServiceSpy,
+                mHdmiCecController, mHdmiMhlControllerStub);
+        mHdmiControlServiceSpy.setHdmiCecNetwork(mHdmiCecNetwork);
+
+        HdmiPortInfo[] hdmiPortInfos = new HdmiPortInfo[1];
+        hdmiPortInfos[0] =
+                new HdmiPortInfo(1, HdmiPortInfo.PORT_OUTPUT, 0x0000, true, false, false);
+        mNativeWrapper.setPortInfo(hdmiPortInfos);
+        mNativeWrapper.setPortConnectionStatus(1, true);
+
+        mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlServiceSpy);
+        mHdmiCecLocalDevicePlayback.init();
+        mLocalDevices.add(mHdmiCecLocalDevicePlayback);
+
+        mHdmiControlServiceSpy.initService();
+        mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+        mHdmiControlServiceSpy.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
+
+        mTestLooper.dispatchAll();
+    }
+
+    @Test
+    public void testActiveSourceChanged_calledOnSetActiveSource() {
+        mHdmiControlServiceSpy.setActiveSource(1, 0x1111, "caller");
+        verify(mHdmiCecAtomWriterSpy, times(1))
+                .activeSourceChanged(1, 0x1111, PATH_RELATIONSHIP_ANCESTOR);
+    }
+
+    @Test
+    public void testMessageReported_calledOnOutgoingMessage() {
+        HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1,
+                mPhysicalAddress);
+
+        mHdmiCecController.sendCommand(message);
+
+        verify(mHdmiCecAtomWriterSpy, times(1)).messageReported(
+                message,
+                HdmiStatsEnums.OUTGOING,
+                SendMessageResult.SUCCESS);
+    }
+
+    @Test
+    public void testMessageReported_calledOnIncomingMessage() {
+        HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
+
+        mNativeWrapper.onCecMessage(message);
+        mTestLooper.dispatchAll();
+
+        verify(mHdmiCecAtomWriterSpy, times(1)).messageReported(
+                message,
+                HdmiStatsEnums.INCOMING);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
index d10e075..777713e 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
@@ -99,7 +99,7 @@
                 + "</cec-settings>", null);
         assertThat(hdmiCecConfig.getAllSettings())
                 .containsExactly(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
-                                 HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP);
+                                 HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE);
     }
 
     @Test
@@ -147,7 +147,7 @@
                 + "</cec-settings>", null);
         assertThat(hdmiCecConfig.getUserSettings())
                 .containsExactly(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
-                                 HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP);
+                                 HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE);
     }
 
     @Test
@@ -230,7 +230,7 @@
                 + "  </setting>"
                 + "</cec-settings>", null);
         assertTrue(hdmiCecConfig.isStringValueType(
-                    HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP));
+                    HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE));
     }
 
     @Test
@@ -330,10 +330,10 @@
                 + "  </setting>"
                 + "</cec-settings>", null);
         assertThat(hdmiCecConfig.getAllowedStringValues(
-                    HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP))
-                .containsExactly(HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV,
-                                 HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST,
-                                 HdmiControlManager.SEND_STANDBY_ON_SLEEP_NONE);
+                    HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE))
+                .containsExactly(HdmiControlManager.POWER_CONTROL_MODE_TV,
+                                 HdmiControlManager.POWER_CONTROL_MODE_BROADCAST,
+                                 HdmiControlManager.POWER_CONTROL_MODE_NONE);
     }
 
     @Test
@@ -374,7 +374,7 @@
                 + "</cec-settings>", null);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.getAllowedIntValues(
-                    HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP));
+                    HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE));
     }
 
     @Test
@@ -479,8 +479,8 @@
                 + "  </setting>"
                 + "</cec-settings>", null);
         assertThat(hdmiCecConfig.getDefaultStringValue(
-                    HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP))
-                .isEqualTo(HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV);
+                    HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE))
+                .isEqualTo(HdmiControlManager.POWER_CONTROL_MODE_TV);
     }
 
     @Test
@@ -521,7 +521,7 @@
                 + "</cec-settings>", null);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.getDefaultIntValue(
-                    HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP));
+                    HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE));
     }
 
     @Test
@@ -610,8 +610,8 @@
     public void getStringValue_GlobalSetting_BasicSanity() {
         when(mStorageAdapter.retrieveGlobalSetting(
                   Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
-                  HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV))
-            .thenReturn(HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST);
+                  HdmiControlManager.POWER_CONTROL_MODE_TV))
+            .thenReturn(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
         HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
                 mContext, mStorageAdapter,
                 "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
@@ -628,8 +628,8 @@
                 + "  </setting>"
                 + "</cec-settings>", null);
         assertThat(hdmiCecConfig.getStringValue(
-                    HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP))
-                .isEqualTo(HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST);
+                    HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE))
+                .isEqualTo(HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
     }
 
     @Test
@@ -696,7 +696,7 @@
                 + "</cec-settings>", null);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.getIntValue(
-                    HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP));
+                    HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE));
     }
 
     @Test
@@ -812,8 +812,8 @@
                 + "</cec-settings>", null);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.setStringValue(
-                        HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
-                        HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST));
+                        HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                        HdmiControlManager.POWER_CONTROL_MODE_BROADCAST));
     }
 
     @Test
@@ -835,7 +835,7 @@
                 + "</cec-settings>", null);
         assertThrows(IllegalArgumentException.class,
                 () -> hdmiCecConfig.setStringValue(
-                        HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
+                        HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
                         "bar"));
     }
 
@@ -856,11 +856,11 @@
                 + "    <default-value string-value=\"to_tv\" />"
                 + "  </setting>"
                 + "</cec-settings>", null);
-        hdmiCecConfig.setStringValue(HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
-                               HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST);
+        hdmiCecConfig.setStringValue(HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                               HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
         verify(mStorageAdapter).storeGlobalSetting(
                   Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
-                  HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST);
+                  HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index 3fd3ce3..6bb68da 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -170,7 +170,7 @@
                 }
 
                 @Override
-                void writeStringSystemProperty(String key, String value) {
+                protected void writeStringSystemProperty(String key, String value) {
                     // do nothing
                 }
 
@@ -185,12 +185,12 @@
                 }
 
                 @Override
-                PowerManager getPowerManager() {
+                protected PowerManager getPowerManager() {
                     return powerManager;
                 }
 
                 @Override
-                HdmiCecConfig getHdmiCecConfig() {
+                protected HdmiCecConfig getHdmiCecConfig() {
                     return hdmiCecConfig;
                 }
             };
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index dfeed13..f7d52b6 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -18,7 +18,6 @@
 import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
 import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
 import static com.android.server.hdmi.Constants.ADDR_INVALID;
-import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
 import static com.android.server.hdmi.Constants.ADDR_TV;
 import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
 
@@ -114,7 +113,7 @@
                     }
 
                     @Override
-                    void writeStringSystemProperty(String key, String value) {
+                    protected void writeStringSystemProperty(String key, String value) {
                         // do nothing
                     }
 
@@ -124,12 +123,12 @@
                     }
 
                     @Override
-                    PowerManager getPowerManager() {
+                    protected PowerManager getPowerManager() {
                         return powerManager;
                     }
 
                     @Override
-                    HdmiCecConfig getHdmiCecConfig() {
+                    protected HdmiCecConfig getHdmiCecConfig() {
                         return hdmiCecConfig;
                     }
                 };
@@ -557,8 +556,8 @@
     @Test
     public void handleOnStandby_ScreenOff_NotActiveSource_ToTv() {
         mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
-                HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
-                HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV);
+                HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                HdmiControlManager.POWER_CONTROL_MODE_TV);
         mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
                 "HdmiCecLocalDevicePlaybackTest");
         mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
@@ -577,8 +576,8 @@
     @Test
     public void handleOnStandby_ScreenOff_NotActiveSource_Broadcast() {
         mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
-                HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
-                HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST);
+                HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
         mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
                 "HdmiCecLocalDevicePlaybackTest");
         mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
@@ -597,8 +596,8 @@
     @Test
     public void handleOnStandby_ScreenOff_NotActiveSource_None() {
         mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
-                HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
-                HdmiControlManager.SEND_STANDBY_ON_SLEEP_NONE);
+                HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                HdmiControlManager.POWER_CONTROL_MODE_NONE);
         mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
                 "HdmiCecLocalDevicePlaybackTest");
         mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
@@ -617,8 +616,8 @@
     @Test
     public void handleOnStandby_ScreenOff_ActiveSource_ToTv() {
         mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
-                HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
-                HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV);
+                HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                HdmiControlManager.POWER_CONTROL_MODE_TV);
         mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
                 mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
         mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
@@ -637,8 +636,8 @@
     @Test
     public void handleOnStandby_ScreenOff_ActiveSource_Broadcast() {
         mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
-                HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
-                HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST);
+                HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
         mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
                 mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
         mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
@@ -657,8 +656,8 @@
     @Test
     public void handleOnStandby_ScreenOff_ActiveSource_None() {
         mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
-                HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
-                HdmiControlManager.SEND_STANDBY_ON_SLEEP_NONE);
+                HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                HdmiControlManager.POWER_CONTROL_MODE_NONE);
         mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
                 mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
         mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
@@ -828,12 +827,12 @@
                 HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
                 HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
         mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
-                HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
-                HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST);
+                HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
         mStandby = false;
         // 1. DUT is <AS>.
-        HdmiCecMessage message1 = HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1,
-                                         mPlaybackPhysicalAddress);
+        HdmiCecMessage message1 = HdmiCecMessageBuilder.buildActiveSource(
+                mHdmiCecLocalDevicePlayback.mAddress, mPlaybackPhysicalAddress);
         assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message1)).isTrue();
         assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
         assertThat(mStandby).isFalse();
@@ -1141,8 +1140,8 @@
     @Test
     public void oneTouchPlay_SendStandbyOnSleepToTv() {
         mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
-                HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
-                HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV);
+                HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                HdmiControlManager.POWER_CONTROL_MODE_TV);
         mHdmiControlService.oneTouchPlay(new IHdmiControlCallback.Stub() {
             @Override
             public void onComplete(int result) {
@@ -1164,8 +1163,8 @@
     @Test
     public void oneTouchPlay_SendStandbyOnSleepBroadcast() {
         mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
-                HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
-                HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST);
+                HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
         mHdmiControlService.oneTouchPlay(new IHdmiControlCallback.Stub() {
             @Override
             public void onComplete(int result) {
@@ -1187,8 +1186,8 @@
     @Test
     public void oneTouchPlay_SendStandbyOnSleepNone() {
         mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
-                HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
-                HdmiControlManager.SEND_STANDBY_ON_SLEEP_NONE);
+                HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                HdmiControlManager.POWER_CONTROL_MODE_NONE);
         mHdmiControlService.oneTouchPlay(new IHdmiControlCallback.Stub() {
             @Override
             public void onComplete(int result) {
@@ -1266,8 +1265,8 @@
     @Test
     public void toggleAndFollowTvPower_ToTv_TvStatusOn() {
         mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
-                HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
-                HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV);
+                HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                HdmiControlManager.POWER_CONTROL_MODE_TV);
         mStandby = false;
         mHdmiControlService.toggleAndFollowTvPower();
         HdmiCecMessage tvPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(ADDR_TV,
@@ -1284,8 +1283,8 @@
     @Test
     public void toggleAndFollowTvPower_Broadcast_TvStatusOn() {
         mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
-                HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
-                HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST);
+                HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                HdmiControlManager.POWER_CONTROL_MODE_BROADCAST);
         mStandby = false;
         mHdmiControlService.toggleAndFollowTvPower();
         HdmiCecMessage tvPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(ADDR_TV,
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index 12414d9..d24b376 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -88,17 +88,17 @@
                     }
 
                     @Override
-                    void writeStringSystemProperty(String key, String value) {
+                    protected void writeStringSystemProperty(String key, String value) {
                         // do nothing
                     }
 
                     @Override
-                    PowerManager getPowerManager() {
+                    protected PowerManager getPowerManager() {
                         return powerManager;
                     }
 
                     @Override
-                    HdmiCecConfig getHdmiCecConfig() {
+                    protected HdmiCecConfig getHdmiCecConfig() {
                         return hdmiCecConfig;
                     }
                 };
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
index a05cbb4..6285f58 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
@@ -56,6 +56,30 @@
     }
 
     @Test
+    public void isValid_unregisteredSource() {
+        // Message invokes a broadcast response
+        //   <Get Menu Language>
+        assertMessageValidity("F4:91").isEqualTo(OK);
+        //   <Request Active Source>
+        assertMessageValidity("FF:85").isEqualTo(OK);
+
+        // Message by CEC Switch
+        //   <Routing Change>
+        assertMessageValidity("FF:80:00:00:10:00").isEqualTo(OK);
+
+        //   <Routing Information>
+        assertMessageValidity("FF:81:10:00").isEqualTo(OK);
+
+        // Standby
+        assertMessageValidity("F4:36").isEqualTo(OK);
+        assertMessageValidity("FF:36").isEqualTo(OK);
+
+        // <Report Physical Address> / <Active Source>
+        assertMessageValidity("FF:84:10:00:04").isEqualTo(OK);
+        assertMessageValidity("FF:82:10:00").isEqualTo(OK);
+    }
+
+    @Test
     public void isValid_giveDevicePowerStatus() {
         assertMessageValidity("04:8F").isEqualTo(OK);
 
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
index 3cc7c6b..670d512 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
@@ -95,7 +95,7 @@
             }
 
             @Override
-            void writeStringSystemProperty(String key, String value) {
+            protected void writeStringSystemProperty(String key, String value) {
                 // do nothing
             }
 
@@ -110,7 +110,7 @@
             }
 
             @Override
-            HdmiCecConfig getHdmiCecConfig() {
+            protected HdmiCecConfig getHdmiCecConfig() {
                 return hdmiCecConfig;
             }
         };
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 819bd019..2513807 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -151,7 +151,7 @@
             }
 
             @Override
-            HdmiCecConfig getHdmiCecConfig() {
+            protected HdmiCecConfig getHdmiCecConfig() {
                 return hdmiCecConfig;
             }
         };
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/OWNERS b/services/tests/servicestests/src/com/android/server/hdmi/OWNERS
new file mode 100644
index 0000000..c3c47ed
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/hardware/hdmi/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
index 0a225a0..f80b573 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
@@ -162,7 +162,7 @@
                     }
 
                     @Override
-                    HdmiCecConfig getHdmiCecConfig() {
+                    protected HdmiCecConfig getHdmiCecConfig() {
                         return hdmiCecConfig;
                     }
                 };
diff --git a/services/tests/servicestests/src/com/android/server/input/OWNERS b/services/tests/servicestests/src/com/android/server/input/OWNERS
new file mode 100644
index 0000000..d701f23
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/input/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/hardware/input/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/inputmethod/OWNERS b/services/tests/servicestests/src/com/android/server/inputmethod/OWNERS
new file mode 100644
index 0000000..5deb2ce
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/inputmethod/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/inputmethod/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/integrity/OWNERS b/services/tests/servicestests/src/com/android/server/integrity/OWNERS
new file mode 100644
index 0000000..653d1c9
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/integrity/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/integrity/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/job/OWNERS b/services/tests/servicestests/src/com/android/server/job/OWNERS
new file mode 100644
index 0000000..6f207fb1
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/job/OWNERS
@@ -0,0 +1 @@
+include /apex/jobscheduler/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/lights/OWNERS b/services/tests/servicestests/src/com/android/server/lights/OWNERS
new file mode 100644
index 0000000..cb46a80
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/lights/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/lights/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
index 2205694..25dbc6b 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
@@ -16,6 +16,9 @@
 
 package com.android.server.locksettings;
 
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
@@ -277,6 +280,94 @@
         verify(mLockPatternUtils, never()).setLockCredential(any(), any(), anyInt());
     }
 
+    @Test
+    public void testSetPin_nonCompliantWithComplexity() throws Exception {
+        when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true);
+        when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
+        when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
+        when(mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)).thenReturn(
+                PASSWORD_QUALITY_NUMERIC);
+        when(mLockPatternUtils.checkCredential(
+                LockscreenCredential.createPin("1234"), mUserId, null)).thenReturn(true);
+        when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId))
+                .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_UNSPECIFIED));
+        when(mLockPatternUtils.getRequestedPasswordComplexity(mUserId))
+                .thenReturn(PASSWORD_COMPLEXITY_MEDIUM);
+
+        assertEquals(-1, mCommand.exec(new Binder(), in, out, err,
+                new String[] { "set-pin", "--old", "1234", "4321" },
+                mShellCallback, mResultReceiver));
+
+        verify(mLockPatternUtils, never()).setLockCredential(any(), any(), anyInt());
+    }
+
+    @Test
+    public void testSetPin_compliantWithComplexity() throws Exception {
+        when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true);
+        when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
+        when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
+        when(mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)).thenReturn(
+                PASSWORD_QUALITY_NUMERIC);
+        when(mLockPatternUtils.checkCredential(
+                LockscreenCredential.createPin("1234"), mUserId, null)).thenReturn(true);
+        when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId))
+                .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_UNSPECIFIED));
+        when(mLockPatternUtils.getRequestedPasswordComplexity(mUserId))
+                .thenReturn(PASSWORD_COMPLEXITY_MEDIUM);
+
+        assertEquals(0, mCommand.exec(new Binder(), in, out, err,
+                new String[] { "set-pin", "--old", "1234", "4231" },
+                mShellCallback, mResultReceiver));
+
+        verify(mLockPatternUtils).setLockCredential(
+                LockscreenCredential.createPin("4231"),
+                LockscreenCredential.createPin("1234"),
+                mUserId);
+    }
+
+    @Test
+    public void testSetPattern_nonCompliantWithComplexity() throws Exception {
+        when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true);
+        when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(true);
+        when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(false);
+        when(mLockPatternUtils.checkCredential(
+                LockscreenCredential.createPattern(stringToPattern("1234")),
+                mUserId, null)).thenReturn(true);
+        when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId))
+                .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_UNSPECIFIED));
+        when(mLockPatternUtils.getRequestedPasswordComplexity(mUserId))
+                .thenReturn(PASSWORD_COMPLEXITY_HIGH);
+
+        assertEquals(-1, mCommand.exec(new Binder(), in, out, err,
+                new String[] { "set-pattern", "--old", "1234", "4321" },
+                mShellCallback, mResultReceiver));
+
+        verify(mLockPatternUtils, never()).setLockCredential(any(), any(), anyInt());
+    }
+
+    @Test
+    public void testSetPattern_compliantWithComplexity() throws Exception {
+        when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true);
+        when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(true);
+        when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(false);
+        when(mLockPatternUtils.checkCredential(
+                LockscreenCredential.createPattern(stringToPattern("1234")),
+                mUserId, null)).thenReturn(true);
+        when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId))
+                .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_UNSPECIFIED));
+        when(mLockPatternUtils.getRequestedPasswordComplexity(mUserId))
+                .thenReturn(PASSWORD_COMPLEXITY_LOW);
+
+        assertEquals(0, mCommand.exec(new Binder(), in, out, err,
+                new String[] { "set-pattern", "--old", "1234", "4321" },
+                mShellCallback, mResultReceiver));
+
+        verify(mLockPatternUtils).setLockCredential(
+                LockscreenCredential.createPattern(stringToPattern("4321")),
+                LockscreenCredential.createPattern(stringToPattern("1234")),
+                mUserId);
+    }
+
     private List<LockPatternView.Cell> stringToPattern(String str) {
         return LockPatternUtils.byteArrayToPattern(str.getBytes());
     }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/OWNERS b/services/tests/servicestests/src/com/android/server/locksettings/OWNERS
new file mode 100644
index 0000000..0a8dc8c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/locksettings/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/net/OWNERS b/services/tests/servicestests/src/com/android/server/net/OWNERS
new file mode 100644
index 0000000..aa87958
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/net/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/net/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/om/OWNERS b/services/tests/servicestests/src/com/android/server/om/OWNERS
new file mode 100644
index 0000000..afb98d4
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/om/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/content/om/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/people/OWNERS b/services/tests/servicestests/src/com/android/server/people/OWNERS
new file mode 100644
index 0000000..3198a5e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/people/OWNERS
@@ -0,0 +1 @@
+include /services/people/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index f823bb9..2471210 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -22,6 +22,8 @@
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -58,6 +60,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.LauncherApps.ShortcutChangeCallback;
+import android.content.pm.LauncherApps.ShortcutQuery;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.ShortcutInfo;
@@ -136,6 +139,7 @@
 
     @Captor private ArgumentCaptor<ShortcutChangeCallback> mShortcutChangeCallbackCaptor;
     @Captor private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor;
+    @Captor private ArgumentCaptor<Integer> mQueryFlagsCaptor;
 
     private ScheduledExecutorService mExecutorService;
     private NotificationChannel mNotificationChannel;
@@ -854,6 +858,8 @@
         List<ConversationChannel> result = mDataManager.getRecentConversations(USER_ID_PRIMARY);
         assertEquals(1, result.size());
         assertEquals(shortcut.getId(), result.get(0).getShortcutInfo().getId());
+        assertEquals(1, result.get(0).getShortcutInfo().getPersons().length);
+        assertEquals(CONTACT_URI, result.get(0).getShortcutInfo().getPersons()[0].getUri());
         assertEquals(mParentNotificationChannel.getId(),
                 result.get(0).getParentNotificationChannel().getId());
         assertEquals(mStatusBarNotification.getPostTime(), result.get(0).getLastEventTimestamp());
@@ -861,6 +867,28 @@
     }
 
     @Test
+    public void testGetRecentConversationsGetsPersonsData() {
+        mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+        ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+                buildPerson());
+        shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+        mDataManager.addOrUpdateConversationInfo(shortcut);
+
+        NotificationListenerService listenerService =
+                mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+        listenerService.onNotificationPosted(mStatusBarNotification);
+
+        List<ConversationChannel> result = mDataManager.getRecentConversations(USER_ID_PRIMARY);
+
+        verify(mShortcutServiceInternal).getShortcuts(
+                anyInt(), anyString(), anyLong(), anyString(), anyList(), any(), any(),
+                mQueryFlagsCaptor.capture(), anyInt(), anyInt(), anyInt());
+        Integer queryFlags = mQueryFlagsCaptor.getValue();
+        assertThat(hasFlag(queryFlags, ShortcutQuery.FLAG_GET_PERSONS_DATA)).isTrue();
+    }
+
+    @Test
     public void testPruneOldRecentConversations() {
         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
 
@@ -1068,6 +1096,13 @@
         return new UserInfo(userId, "", 0);
     }
 
+    /**
+     * Returns {@code true} iff {@link ShortcutQuery}'s {@code queryFlags} has {@code flag} set.
+     */
+    private static boolean hasFlag(int queryFlags, int flag) {
+        return (queryFlags & flag) != 0;
+    }
+
     private class TestContactsQueryHelper extends ContactsQueryHelper {
 
         private Uri mContactUri;
diff --git a/services/tests/servicestests/src/com/android/server/pm/OWNERS b/services/tests/servicestests/src/com/android/server/pm/OWNERS
new file mode 100644
index 0000000..d825dfd
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
index f8e92ad..84551c5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
@@ -22,6 +22,7 @@
 import android.util.SparseArray;
 
 import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.PackageImpl;
 
 import java.io.File;
 import java.util.Map;
@@ -38,14 +39,14 @@
     private int mPkgFlags;
     private int mPrivateFlags;
     private int mSharedUserId;
+    private String mVolumeUuid;
+    private int mAppId;
+    private SparseArray<PackageUserState> mUserStates = new SparseArray<>();
+    private AndroidPackage mPkg;
+    private InstallSource mInstallSource;
     private String[] mUsesStaticLibraries;
     private long[] mUsesStaticLibrariesVersions;
     private Map<String, ArraySet<String>> mMimeGroups;
-    private String mVolumeUuid;
-    private SparseArray<PackageUserState> mUserStates = new SparseArray<>();
-    private AndroidPackage mPkg;
-    private int mAppId;
-    private InstallSource mInstallSource;
     private PackageParser.SigningDetails mSigningDetails;
 
     public PackageSettingBuilder setPackage(AndroidPackage pkg) {
@@ -143,6 +144,14 @@
         return this;
     }
 
+    public PackageSettingBuilder setInstallState(int userId, boolean installed) {
+        if (mUserStates.indexOfKey(userId) < 0) {
+            mUserStates.put(userId, new PackageUserState());
+        }
+        mUserStates.get(userId).installed = installed;
+        return this;
+    }
+
     public PackageSettingBuilder setInstallSource(InstallSource installSource) {
         mInstallSource = installSource;
         return this;
@@ -173,6 +182,5 @@
             packageSetting.setUserState(mUserStates.keyAt(i), mUserStates.valueAt(i));
         }
         return packageSetting;
-
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
index fcbb5ed..d8c3979 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -101,7 +101,8 @@
     @Before
     public void setupDefaultAbiBehavior() throws Exception {
         when(mMockPackageAbiHelper.derivePackageAbi(
-                any(AndroidPackage.class), anyBoolean(), nullable(String.class)))
+                any(AndroidPackage.class), anyBoolean(), nullable(String.class),
+                any(File.class)))
                 .thenReturn(new Pair<>(
                         new PackageAbiHelper.Abis("derivedPrimary", "derivedSecondary"),
                         new PackageAbiHelper.NativeLibraryPaths(
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
index 3ce7a7d..eaf62cb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
@@ -227,8 +227,8 @@
         File dm = createDexMetadataFile("install_split_base.apk");
         try (FileInputStream is = new FileInputStream(base)) {
             ApkLite baseApk = PackageParser.parseApkLite(is.getFD(), base.getAbsolutePath(), 0);
-            PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
-                    null, null);
+            PackageLite pkgLite = new PackageLite(null, baseApk.codePath, baseApk, null, null, null,
+                    null, null, null);
             Assert.assertEquals(dm.length(), DexMetadataHelper.getPackageDexMetadataSize(pkgLite));
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java b/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java
index 92942bb..e816cbe 100644
--- a/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java
@@ -23,6 +23,7 @@
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -170,16 +171,16 @@
 
     @Test
     public void create_sensor() throws Exception {
-        Sensor sensor = newSensor("sensor", Sensor.TYPE_HINGE_ANGLE);
-        when(mSensorManager.getSensorList(eq(sensor.getType()))).thenReturn(List.of(sensor));
+        Sensor sensor = newSensor("sensor", Sensor.STRING_TYPE_HINGE_ANGLE);
+        when(mSensorManager.getSensorList(anyInt())).thenReturn(List.of(sensor));
 
         String configString = "<device-state-config>\n"
                 + "    <device-state>\n"
                 + "        <identifier>1</identifier>\n"
                 + "        <conditions>\n"
                 + "            <sensor>\n"
+                + "                <type>" + sensor.getStringType() + "</type>\n"
                 + "                <name>" + sensor.getName() + "</name>\n"
-                + "                <type>" + sensor.getType() + "</type>\n"
                 + "                <value>\n"
                 + "                    <max>90</max>\n"
                 + "                </value>\n"
@@ -190,8 +191,8 @@
                 + "        <identifier>2</identifier>\n"
                 + "        <conditions>\n"
                 + "            <sensor>\n"
+                + "                <type>" + sensor.getStringType() + "</type>\n"
                 + "                <name>" + sensor.getName() + "</name>\n"
-                + "                <type>" + sensor.getType() + "</type>\n"
                 + "                <value>\n"
                 + "                    <min-inclusive>90</min-inclusive>\n"
                 + "                    <max>180</max>\n"
@@ -203,8 +204,8 @@
                 + "        <identifier>3</identifier>\n"
                 + "        <conditions>\n"
                 + "            <sensor>\n"
+                + "                <type>" + sensor.getStringType() + "</type>\n"
                 + "                <name>" + sensor.getName() + "</name>\n"
-                + "                <type>" + sensor.getType() + "</type>\n"
                 + "                <value>\n"
                 + "                    <min-inclusive>180</min-inclusive>\n"
                 + "                </value>\n"
@@ -262,13 +263,13 @@
         assertEquals(1, mIntegerCaptor.getValue().intValue());
     }
 
-    private static Sensor newSensor(String name, int type) throws Exception {
+    private static Sensor newSensor(String name, String type) throws Exception {
         Constructor<Sensor> constructor = Sensor.class.getDeclaredConstructor();
         constructor.setAccessible(true);
 
         Sensor sensor = constructor.newInstance();
         FieldSetter.setField(sensor, Sensor.class.getDeclaredField("mName"), name);
-        FieldSetter.setField(sensor, Sensor.class.getDeclaredField("mType"), type);
+        FieldSetter.setField(sensor, Sensor.class.getDeclaredField("mStringType"), type);
         return sensor;
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/policy/OWNERS b/services/tests/servicestests/src/com/android/server/policy/OWNERS
new file mode 100644
index 0000000..0862c05
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/policy/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/power/OWNERS b/services/tests/servicestests/src/com/android/server/power/OWNERS
new file mode 100644
index 0000000..d68066b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/power/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/power/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
index fb6b29e..9bd488d3 100644
--- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
@@ -25,6 +25,7 @@
 import android.os.PowerManager;
 import android.os.PowerManager.ServiceType;
 import android.os.PowerSaveState;
+import android.provider.DeviceConfig;
 import android.provider.Settings.Global;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -47,19 +48,19 @@
     private static final int GPS_MODE = 0; // LOCATION_MODE_NO_CHANGE
     private static final int DEFAULT_GPS_MODE =
             PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF;
-    private static final String BATTERY_SAVER_CONSTANTS = "vibration_disabled=true,"
+    private static final String BATTERY_SAVER_CONSTANTS = "disable_vibration=true,"
             + "advertise_is_enabled=true,"
-            + "animation_disabled=false,"
-            + "soundtrigger_disabled=true,"
-            + "firewall_disabled=false,"
-            + "datasaver_disabled=false,"
-            + "adjust_brightness_disabled=true,"
+            + "disable_animation=false,"
+            + "disable_soundtrigger=true,"
+            + "enable_firewall=true,"
+            + "enable_datasaver=true,"
+            + "enable_brightness_adjustment=false,"
             + "adjust_brightness_factor=0.7,"
-            + "fullbackup_deferred=true,"
-            + "keyvaluebackup_deferred=false,"
-            + "gps_mode=0," // LOCATION_MODE_NO_CHANGE
+            + "defer_full_backup=true,"
+            + "defer_keyvalue_backup=false,"
+            + "location_mode=0," // LOCATION_MODE_NO_CHANGE
             + "enable_night_mode=false,"
-            + "quick_doze_enabled=true";
+            + "enable_quick_doze=true";
     private static final String BATTERY_SAVER_INCORRECT_CONSTANTS = "vi*,!=,,true";
 
     private class BatterySaverPolicyForTest extends BatterySaverPolicy {
@@ -336,13 +337,15 @@
         }
 
         mBatterySaverPolicy.setAdaptivePolicyLocked(
-                Policy.fromSettings(BATTERY_SAVER_CONSTANTS, ""));
+                Policy.fromSettings(BATTERY_SAVER_CONSTANTS, "",
+                        new DeviceConfig.Properties.Builder(
+                                DeviceConfig.NAMESPACE_BATTERY_SAVER).build(), null));
         verifyBatterySaverConstantsUpdated();
     }
 
     public void testAutomotiveProjectionChanges_Full() {
         mBatterySaverPolicy.updateConstantsLocked(
-                "gps_mode=" + PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF
+                "location_mode=" + PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF
                         + ",enable_night_mode=true", "");
         mBatterySaverPolicy.setPolicyLevel(POLICY_LEVEL_FULL);
         assertThat(mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.LOCATION).locationMode)
@@ -369,8 +372,10 @@
     public void testAutomotiveProjectionChanges_Adaptive() {
         mBatterySaverPolicy.setAdaptivePolicyLocked(
                 Policy.fromSettings(
-                        "gps_mode=" + PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF
-                                + ",enable_night_mode=true", ""));
+                        "location_mode=" + PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF
+                                + ",enable_night_mode=true", "",
+                        new DeviceConfig.Properties.Builder(
+                                DeviceConfig.NAMESPACE_BATTERY_SAVER).build(), null));
         mBatterySaverPolicy.setPolicyLevel(POLICY_LEVEL_ADAPTIVE);
         assertThat(mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.LOCATION).locationMode)
                 .isEqualTo(PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF);
@@ -392,4 +397,188 @@
         assertTrue(mBatterySaverPolicy.getBatterySaverPolicy(
                 ServiceType.NIGHT_MODE).batterySaverEnabled);
     }
+
+    public void testUserSettingsOverrideDeviceConfig() {
+        Policy policy = Policy.fromSettings(
+                BatterySaverPolicy.KEY_ADJUST_BRIGHTNESS_FACTOR + "=.1"
+                        + "," + BatterySaverPolicy.KEY_ADVERTISE_IS_ENABLED + "=true"
+                        + "," + BatterySaverPolicy.KEY_DEFER_FULL_BACKUP + "=true"
+                        + "," + BatterySaverPolicy.KEY_DEFER_KEYVALUE_BACKUP + "=true"
+                        + "," + BatterySaverPolicy.KEY_DISABLE_ANIMATION + "=true"
+                        + "," + BatterySaverPolicy.KEY_DISABLE_AOD + "=true"
+                        + "," + BatterySaverPolicy.KEY_DISABLE_LAUNCH_BOOST + "=true"
+                        + "," + BatterySaverPolicy.KEY_DISABLE_OPTIONAL_SENSORS + "=true"
+                        + "," + BatterySaverPolicy.KEY_DISABLE_SOUNDTRIGGER + "=true"
+                        + "," + BatterySaverPolicy.KEY_DISABLE_VIBRATION + "=true"
+                        + "," + BatterySaverPolicy.KEY_ENABLE_BRIGHTNESS_ADJUSTMENT + "=true"
+                        + "," + BatterySaverPolicy.KEY_ENABLE_DATASAVER + "=true"
+                        + "," + BatterySaverPolicy.KEY_ENABLE_FIREWALL + "=true"
+                        + "," + BatterySaverPolicy.KEY_ENABLE_NIGHT_MODE + "=true"
+                        + "," + BatterySaverPolicy.KEY_ENABLE_QUICK_DOZE + "=true"
+                        + "," + BatterySaverPolicy.KEY_FORCE_ALL_APPS_STANDBY + "=true"
+                        + "," + BatterySaverPolicy.KEY_FORCE_BACKGROUND_CHECK + "=true"
+                        + "," + BatterySaverPolicy.KEY_LOCATION_MODE
+                        + "=" + PowerManager.LOCATION_MODE_FOREGROUND_ONLY,
+                "",
+                new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_BATTERY_SAVER)
+                        .setFloat(BatterySaverPolicy.KEY_ADJUST_BRIGHTNESS_FACTOR, .5f)
+                        .setBoolean(BatterySaverPolicy.KEY_ADVERTISE_IS_ENABLED, false)
+                        .setBoolean(BatterySaverPolicy.KEY_DEFER_FULL_BACKUP, false)
+                        .setBoolean(BatterySaverPolicy.KEY_DEFER_KEYVALUE_BACKUP, false)
+                        .setBoolean(BatterySaverPolicy.KEY_DISABLE_ANIMATION, false)
+                        .setBoolean(BatterySaverPolicy.KEY_DISABLE_AOD, false)
+                        .setBoolean(BatterySaverPolicy.KEY_DISABLE_LAUNCH_BOOST, false)
+                        .setBoolean(BatterySaverPolicy.KEY_DISABLE_OPTIONAL_SENSORS, false)
+                        .setBoolean(BatterySaverPolicy.KEY_DISABLE_SOUNDTRIGGER, false)
+                        .setBoolean(BatterySaverPolicy.KEY_DISABLE_VIBRATION, false)
+                        .setBoolean(BatterySaverPolicy.KEY_ENABLE_BRIGHTNESS_ADJUSTMENT, false)
+                        .setBoolean(BatterySaverPolicy.KEY_ENABLE_DATASAVER, false)
+                        .setBoolean(BatterySaverPolicy.KEY_ENABLE_FIREWALL, false)
+                        .setBoolean(BatterySaverPolicy.KEY_ENABLE_NIGHT_MODE, false)
+                        .setBoolean(BatterySaverPolicy.KEY_ENABLE_QUICK_DOZE, false)
+                        .setBoolean(BatterySaverPolicy.KEY_FORCE_ALL_APPS_STANDBY, false)
+                        .setBoolean(BatterySaverPolicy.KEY_FORCE_BACKGROUND_CHECK, false)
+                        .setInt(BatterySaverPolicy.KEY_LOCATION_MODE,
+                                PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF)
+                        .build(),
+                null);
+        assertEquals(.1f, policy.adjustBrightnessFactor);
+        assertTrue(policy.advertiseIsEnabled);
+        assertTrue(policy.deferFullBackup);
+        assertTrue(policy.deferKeyValueBackup);
+        assertTrue(policy.disableAnimation);
+        assertTrue(policy.disableAod);
+        assertTrue(policy.disableLaunchBoost);
+        assertTrue(policy.disableOptionalSensors);
+        assertTrue(policy.disableSoundTrigger);
+        assertTrue(policy.disableVibration);
+        assertTrue(policy.enableAdjustBrightness);
+        assertTrue(policy.enableDataSaver);
+        assertTrue(policy.enableFirewall);
+        assertTrue(policy.enableNightMode);
+        assertTrue(policy.enableQuickDoze);
+        assertTrue(policy.forceAllAppsStandby);
+        assertTrue(policy.forceBackgroundCheck);
+        assertEquals(PowerManager.LOCATION_MODE_FOREGROUND_ONLY, policy.locationMode);
+    }
+
+    public void testDeviceConfigOverridesDefaults() {
+        Policy policy = Policy.fromSettings(
+                "", "",
+                new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_BATTERY_SAVER)
+                        .setFloat(BatterySaverPolicy.KEY_ADJUST_BRIGHTNESS_FACTOR, .5f)
+                        .setBoolean(BatterySaverPolicy.KEY_ADVERTISE_IS_ENABLED, false)
+                        .setBoolean(BatterySaverPolicy.KEY_DEFER_FULL_BACKUP, false)
+                        .setBoolean(BatterySaverPolicy.KEY_DEFER_KEYVALUE_BACKUP, false)
+                        .setBoolean(BatterySaverPolicy.KEY_DISABLE_ANIMATION, false)
+                        .setBoolean(BatterySaverPolicy.KEY_DISABLE_AOD, false)
+                        .setBoolean(BatterySaverPolicy.KEY_DISABLE_LAUNCH_BOOST, false)
+                        .setBoolean(BatterySaverPolicy.KEY_DISABLE_OPTIONAL_SENSORS, false)
+                        .setBoolean(BatterySaverPolicy.KEY_DISABLE_SOUNDTRIGGER, false)
+                        .setBoolean(BatterySaverPolicy.KEY_DISABLE_VIBRATION, false)
+                        .setBoolean(BatterySaverPolicy.KEY_ENABLE_BRIGHTNESS_ADJUSTMENT, false)
+                        .setBoolean(BatterySaverPolicy.KEY_ENABLE_DATASAVER, false)
+                        .setBoolean(BatterySaverPolicy.KEY_ENABLE_FIREWALL, false)
+                        .setBoolean(BatterySaverPolicy.KEY_ENABLE_NIGHT_MODE, false)
+                        .setBoolean(BatterySaverPolicy.KEY_ENABLE_QUICK_DOZE, false)
+                        .setBoolean(BatterySaverPolicy.KEY_FORCE_ALL_APPS_STANDBY, false)
+                        .setBoolean(BatterySaverPolicy.KEY_FORCE_BACKGROUND_CHECK, false)
+                        .setInt(BatterySaverPolicy.KEY_LOCATION_MODE,
+                                PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF)
+                        .build(),
+                null);
+        assertEquals(.5f, policy.adjustBrightnessFactor);
+        assertFalse(policy.advertiseIsEnabled);
+        assertFalse(policy.deferFullBackup);
+        assertFalse(policy.deferKeyValueBackup);
+        assertFalse(policy.disableAnimation);
+        assertFalse(policy.disableAod);
+        assertFalse(policy.disableLaunchBoost);
+        assertFalse(policy.disableOptionalSensors);
+        assertFalse(policy.disableSoundTrigger);
+        assertFalse(policy.disableVibration);
+        assertFalse(policy.enableAdjustBrightness);
+        assertFalse(policy.enableDataSaver);
+        assertFalse(policy.enableFirewall);
+        assertFalse(policy.enableNightMode);
+        assertFalse(policy.enableQuickDoze);
+        assertFalse(policy.forceAllAppsStandby);
+        assertFalse(policy.forceBackgroundCheck);
+        assertEquals(PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF,
+                policy.locationMode);
+    }
+
+    public void testDeviceConfig_AdaptiveValues() {
+        final String adaptiveSuffix = "_adaptive";
+        Policy policy = Policy.fromSettings(
+                "", "",
+                new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_BATTERY_SAVER)
+                        .setFloat(BatterySaverPolicy.KEY_ADJUST_BRIGHTNESS_FACTOR, .5f)
+                        .setBoolean(BatterySaverPolicy.KEY_ADVERTISE_IS_ENABLED, false)
+                        .setBoolean(BatterySaverPolicy.KEY_DEFER_FULL_BACKUP, false)
+                        .setBoolean(BatterySaverPolicy.KEY_DEFER_KEYVALUE_BACKUP, false)
+                        .setBoolean(BatterySaverPolicy.KEY_DISABLE_ANIMATION, false)
+                        .setBoolean(BatterySaverPolicy.KEY_DISABLE_AOD, false)
+                        .setBoolean(BatterySaverPolicy.KEY_DISABLE_LAUNCH_BOOST, false)
+                        .setBoolean(BatterySaverPolicy.KEY_DISABLE_OPTIONAL_SENSORS, false)
+                        .setBoolean(BatterySaverPolicy.KEY_DISABLE_SOUNDTRIGGER, false)
+                        .setBoolean(BatterySaverPolicy.KEY_DISABLE_VIBRATION, false)
+                        .setBoolean(BatterySaverPolicy.KEY_ENABLE_BRIGHTNESS_ADJUSTMENT, false)
+                        .setBoolean(BatterySaverPolicy.KEY_ENABLE_DATASAVER, false)
+                        .setBoolean(BatterySaverPolicy.KEY_ENABLE_FIREWALL, false)
+                        .setBoolean(BatterySaverPolicy.KEY_ENABLE_NIGHT_MODE, false)
+                        .setBoolean(BatterySaverPolicy.KEY_ENABLE_QUICK_DOZE, false)
+                        .setBoolean(BatterySaverPolicy.KEY_FORCE_ALL_APPS_STANDBY, false)
+                        .setBoolean(BatterySaverPolicy.KEY_FORCE_BACKGROUND_CHECK, false)
+                        .setInt(BatterySaverPolicy.KEY_LOCATION_MODE,
+                                PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF)
+                        .setFloat(BatterySaverPolicy.KEY_ADJUST_BRIGHTNESS_FACTOR + adaptiveSuffix,
+                                .9f)
+                        .setBoolean(BatterySaverPolicy.KEY_ADVERTISE_IS_ENABLED + adaptiveSuffix,
+                                true)
+                        .setBoolean(BatterySaverPolicy.KEY_DEFER_FULL_BACKUP + adaptiveSuffix, true)
+                        .setBoolean(BatterySaverPolicy.KEY_DEFER_KEYVALUE_BACKUP + adaptiveSuffix,
+                                true)
+                        .setBoolean(BatterySaverPolicy.KEY_DISABLE_ANIMATION + adaptiveSuffix, true)
+                        .setBoolean(BatterySaverPolicy.KEY_DISABLE_AOD + adaptiveSuffix, true)
+                        .setBoolean(BatterySaverPolicy.KEY_DISABLE_LAUNCH_BOOST + adaptiveSuffix,
+                                true)
+                        .setBoolean(
+                                BatterySaverPolicy.KEY_DISABLE_OPTIONAL_SENSORS + adaptiveSuffix,
+                                true)
+                        .setBoolean(BatterySaverPolicy.KEY_DISABLE_SOUNDTRIGGER + adaptiveSuffix,
+                                true)
+                        .setBoolean(BatterySaverPolicy.KEY_DISABLE_VIBRATION + adaptiveSuffix, true)
+                        .setBoolean(BatterySaverPolicy.KEY_ENABLE_BRIGHTNESS_ADJUSTMENT
+                                        + adaptiveSuffix, true)
+                        .setBoolean(BatterySaverPolicy.KEY_ENABLE_DATASAVER + adaptiveSuffix, true)
+                        .setBoolean(BatterySaverPolicy.KEY_ENABLE_FIREWALL + adaptiveSuffix, true)
+                        .setBoolean(BatterySaverPolicy.KEY_ENABLE_NIGHT_MODE + adaptiveSuffix, true)
+                        .setBoolean(BatterySaverPolicy.KEY_ENABLE_QUICK_DOZE + adaptiveSuffix, true)
+                        .setBoolean(BatterySaverPolicy.KEY_FORCE_ALL_APPS_STANDBY + adaptiveSuffix,
+                                true)
+                        .setBoolean(BatterySaverPolicy.KEY_FORCE_BACKGROUND_CHECK + adaptiveSuffix,
+                                true)
+                        .setInt(BatterySaverPolicy.KEY_LOCATION_MODE + adaptiveSuffix,
+                                PowerManager.LOCATION_MODE_FOREGROUND_ONLY)
+                        .build(), adaptiveSuffix);
+        assertEquals(.9f, policy.adjustBrightnessFactor);
+        assertTrue(policy.advertiseIsEnabled);
+        assertTrue(policy.deferFullBackup);
+        assertTrue(policy.deferKeyValueBackup);
+        assertTrue(policy.disableAnimation);
+        assertTrue(policy.disableAod);
+        assertTrue(policy.disableLaunchBoost);
+        assertTrue(policy.disableOptionalSensors);
+        assertTrue(policy.disableSoundTrigger);
+        assertTrue(policy.disableVibration);
+        assertTrue(policy.enableAdjustBrightness);
+        assertTrue(policy.enableDataSaver);
+        assertTrue(policy.enableFirewall);
+        assertTrue(policy.enableNightMode);
+        assertTrue(policy.enableQuickDoze);
+        assertTrue(policy.forceAllAppsStandby);
+        assertTrue(policy.forceBackgroundCheck);
+        assertEquals(PowerManager.LOCATION_MODE_FOREGROUND_ONLY, policy.locationMode);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/powerstats/OWNERS b/services/tests/servicestests/src/com/android/server/powerstats/OWNERS
new file mode 100644
index 0000000..d68066b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/powerstats/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/power/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/rollback/OWNERS b/services/tests/servicestests/src/com/android/server/rollback/OWNERS
new file mode 100644
index 0000000..d04a706
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/rollback/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/rollback/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/OWNERS b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/OWNERS
new file mode 100644
index 0000000..816bc6b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/media/soundtrigger/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/stats/OWNERS b/services/tests/servicestests/src/com/android/server/stats/OWNERS
new file mode 100644
index 0000000..ee865b1
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/stats/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/stats/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/storage/OWNERS b/services/tests/servicestests/src/com/android/server/storage/OWNERS
new file mode 100644
index 0000000..6f9dbea
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/storage/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/os/storage/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/textclassifier/OWNERS b/services/tests/servicestests/src/com/android/server/textclassifier/OWNERS
new file mode 100644
index 0000000..46b3cb8
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/textclassifier/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/textclassifier/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/OWNERS b/services/tests/servicestests/src/com/android/server/timedetector/OWNERS
new file mode 100644
index 0000000..09447a9
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timedetector/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/app/timezone/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/timezone/OWNERS b/services/tests/servicestests/src/com/android/server/timezone/OWNERS
new file mode 100644
index 0000000..09447a9
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezone/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/app/timezone/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/OWNERS b/services/tests/servicestests/src/com/android/server/timezonedetector/OWNERS
new file mode 100644
index 0000000..09447a9
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/app/timezone/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/tv/OWNERS b/services/tests/servicestests/src/com/android/server/tv/OWNERS
new file mode 100644
index 0000000..305027c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/tv/OWNERS
@@ -0,0 +1 @@
+include /media/java/android/media/tv/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/tv/TvInputServiceManagerTest.java b/services/tests/servicestests/src/com/android/server/tv/TvInputServiceManagerTest.java
new file mode 100644
index 0000000..229e27b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/tv/TvInputServiceManagerTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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.tv;
+
+import static android.media.tv.TvInputManager.VIDEO_UNAVAILABLE_REASON_BUFFERING;
+import static android.media.tv.TvInputManager.VIDEO_UNAVAILABLE_REASON_CAS_UNKNOWN;
+import static android.media.tv.TvInputManager.VIDEO_UNAVAILABLE_REASON_TUNING;
+import static android.media.tv.TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+
+import com.android.internal.util.FrameworkStatsLog;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+
+/**
+ * Tests for {@link TvInputManagerService}.
+ */
+@Presubmit
+@RunWith(JUnit4.class)
+public class TvInputServiceManagerTest {
+
+    @Test
+    public void getVideoUnavailableReasonForStatsd_tuning() {
+        assertThat(TvInputManagerService.getVideoUnavailableReasonForStatsd(
+                VIDEO_UNAVAILABLE_REASON_TUNING
+        )).isEqualTo(
+                FrameworkStatsLog.TIF_TUNE_STATE_CHANGED__STATE__VIDEO_UNAVAILABLE_REASON_TUNING);
+    }
+
+    @Test
+    public void getVideoUnavailableReasonForStatsd_unknown() {
+        assertThat(TvInputManagerService.getVideoUnavailableReasonForStatsd(
+                VIDEO_UNAVAILABLE_REASON_UNKNOWN
+        )).isEqualTo(
+                FrameworkStatsLog.TIF_TUNE_STATE_CHANGED__STATE__VIDEO_UNAVAILABLE_REASON_UNKNOWN);
+    }
+
+
+    @Test
+    public void getVideoUnavailableReasonForStatsd_casBuffering() {
+        assertThat(TvInputManagerService.getVideoUnavailableReasonForStatsd(
+                VIDEO_UNAVAILABLE_REASON_BUFFERING
+        )).isEqualTo(
+                FrameworkStatsLog
+                        .TIF_TUNE_STATE_CHANGED__STATE__VIDEO_UNAVAILABLE_REASON_BUFFERING);
+    }
+
+    @Test
+    public void getVideoUnavailableReasonForStatsd_casUnknown() {
+        assertThat(TvInputManagerService.getVideoUnavailableReasonForStatsd(
+                VIDEO_UNAVAILABLE_REASON_CAS_UNKNOWN
+        )).isEqualTo(
+                FrameworkStatsLog
+                        .TIF_TUNE_STATE_CHANGED__STATE__VIDEO_UNAVAILABLE_REASON_CAS_UNKNOWN);
+    }
+
+    @Test
+    public void getVideoUnavailableReasonForStatsd_negative() {
+        assertThat(TvInputManagerService.getVideoUnavailableReasonForStatsd(
+                -1
+        )).isEqualTo(
+                FrameworkStatsLog.TIF_TUNE_STATE_CHANGED__STATE__VIDEO_UNAVAILABLE_REASON_UNKNOWN);
+    }
+
+    @Test
+    public void getVideoUnavailableReasonForStatsd_oneBelow() {
+        assertThat(TvInputManagerService.getVideoUnavailableReasonForStatsd(
+                VIDEO_UNAVAILABLE_REASON_UNKNOWN - 1
+        )).isEqualTo(
+                FrameworkStatsLog.TIF_TUNE_STATE_CHANGED__STATE__VIDEO_UNAVAILABLE_REASON_UNKNOWN);
+    }
+
+    @Test
+    public void getVideoUnavailableReasonForStatsd_oneAbove() {
+        assertThat(TvInputManagerService.getVideoUnavailableReasonForStatsd(
+                VIDEO_UNAVAILABLE_REASON_CAS_UNKNOWN + 1
+        )).isEqualTo(
+                FrameworkStatsLog.TIF_TUNE_STATE_CHANGED__STATE__VIDEO_UNAVAILABLE_REASON_UNKNOWN);
+    }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/uri/OWNERS b/services/tests/servicestests/src/com/android/server/uri/OWNERS
new file mode 100644
index 0000000..ca5d5f98
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/uri/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/uri/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/usage/OWNERS b/services/tests/servicestests/src/com/android/server/usage/OWNERS
new file mode 100644
index 0000000..d3227de
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/usage/OWNERS
@@ -0,0 +1 @@
+include /services/usage/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/OWNERS b/services/tests/servicestests/src/com/android/server/vibrator/OWNERS
new file mode 100644
index 0000000..cc63ceb
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/vibrator/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/vibrator/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/wallpaper/OWNERS b/services/tests/servicestests/src/com/android/server/wallpaper/OWNERS
new file mode 100644
index 0000000..8ff0f74
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wallpaper/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/wallpaper/OWNERS
diff --git a/services/tests/servicestests/test-apps/JobTestApp/OWNERS b/services/tests/servicestests/test-apps/JobTestApp/OWNERS
new file mode 100644
index 0000000..6f207fb1
--- /dev/null
+++ b/services/tests/servicestests/test-apps/JobTestApp/OWNERS
@@ -0,0 +1 @@
+include /apex/jobscheduler/OWNERS
diff --git a/services/tests/servicestests/test-apps/PackageParserApp/OWNERS b/services/tests/servicestests/test-apps/PackageParserApp/OWNERS
new file mode 100644
index 0000000..d825dfd
--- /dev/null
+++ b/services/tests/servicestests/test-apps/PackageParserApp/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/OWNERS
diff --git a/services/tests/servicestests/test-apps/PackageParsingTestManifests/OWNERS b/services/tests/servicestests/test-apps/PackageParsingTestManifests/OWNERS
new file mode 100644
index 0000000..d825dfd
--- /dev/null
+++ b/services/tests/servicestests/test-apps/PackageParsingTestManifests/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/OWNERS
diff --git a/services/tests/servicestests/utils-mockito/com/android/server/testutils/MockitoUtils.kt b/services/tests/servicestests/utils-mockito/com/android/server/testutils/MockitoUtils.kt
index 59cbd1c..4c82818 100644
--- a/services/tests/servicestests/utils-mockito/com/android/server/testutils/MockitoUtils.kt
+++ b/services/tests/servicestests/utils-mockito/com/android/server/testutils/MockitoUtils.kt
@@ -17,6 +17,7 @@
 package com.android.server.testutils
 
 import org.mockito.Answers
+import org.mockito.ArgumentMatchers
 import org.mockito.Mockito
 import org.mockito.invocation.InvocationOnMock
 import org.mockito.stubbing.Answer
@@ -53,7 +54,7 @@
 
 fun <T> spy(value: T, block: T.() -> Unit = {}) = Mockito.spy(value).apply(block)
 
-fun <Type> Stubber.whenever(mock: Type) = Mockito.`when`(mock)
+fun <Type> Stubber.whenever(mock: Type) = this.`when`(mock)
 fun <Type : Any?> whenever(mock: Type) = Mockito.`when`(mock)
 
 @Suppress("UNCHECKED_CAST")
@@ -81,3 +82,5 @@
 
 inline fun <reified T> mockThrowOnUnmocked(block: T.() -> Unit = {}) =
         spyThrowOnUnmocked<T>(null, block)
+
+inline fun <reified T : Any> nullable() = ArgumentMatchers.nullable(T::class.java)
\ No newline at end of file
diff --git a/services/tests/uiservicestests/src/com/android/server/OWNERS b/services/tests/uiservicestests/src/com/android/server/OWNERS
new file mode 100644
index 0000000..05944c0
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/OWNERS
@@ -0,0 +1 @@
+per-file UiModeManagerServiceTest.java = file:/packages/SystemUI/OWNERS
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 00f706b..e510b4f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -153,7 +153,8 @@
                 AccessibilityEvent.TYPES_ALL_MASK);
         when(mAccessibilityService.addClient(any(), anyInt())).thenReturn(serviceReturnValue);
         AccessibilityManager accessibilityManager =
-                new AccessibilityManager(Handler.getMain(), mAccessibilityService, 0);
+                new AccessibilityManager(getContext(), Handler.getMain(), mAccessibilityService,
+                        0, true);
         verify(mAccessibilityService).addClient(any(IAccessibilityManagerClient.class), anyInt());
         assertTrue(accessibilityManager.isEnabled());
 
@@ -1191,7 +1192,7 @@
         NotificationRecord r = getLightsNotification();
         mService.buzzBeepBlinkLocked(r);
         verifyNeverLights();
-        assertFalse(r.isInterruptive());
+        assertTrue(r.isInterruptive());
         assertEquals(-1, r.getLastAudiblyAlertedMs());
     }
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index 4a4d9bc..ec28baf 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -249,13 +249,13 @@
                         backupPrimary.get(approvalLevel).get(userId),
                         Build.VERSION_CODES.N_MR1, userId);
             }
-            verifyExpectedApprovedEntries(service, true);
 
             for (int userId : backupSecondary.get(approvalLevel).keySet()) {
                 service.onSettingRestored(service.getConfig().secondarySettingName,
                         backupSecondary.get(approvalLevel).get(userId),
                         Build.VERSION_CODES.N_MR1, userId);
             }
+            // both sets of approved entries should be allowed
             verifyExpectedApprovedEntries(service);
             verifyExpectedApprovedEntries(service, backupPrimary.get(approvalLevel));
             verifyExpectedApprovedEntries(service, backupSecondary.get(approvalLevel));
@@ -638,8 +638,8 @@
     @Test
     public void testWriteXml_writesSetting() throws Exception {
         for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
-            ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
-                    mIpm, approvalLevel);
+            ManagedServices service = new TestManagedServicesSettings(getContext(), mLock,
+                    mUserProfiles, mIpm, approvalLevel);
             loadXml(service);
 
             TypedXmlSerializer serializer = Xml.newFastSerializer();
@@ -662,6 +662,36 @@
     }
 
     @Test
+    public void testWriteXml_doesNotWriteSetting() throws Exception {
+        for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
+            ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
+                    mIpm, approvalLevel);
+
+            for (int userId : mUserProfiles.getCurrentProfileIds().toArray()) {
+                Settings.Secure.putStringForUser(
+                        getContext().getContentResolver(),
+                        service.getConfig().secureSettingName, null, userId);
+            }
+            loadXml(service);
+
+            TypedXmlSerializer serializer = Xml.newFastSerializer();
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
+            serializer.startDocument(null, true);
+            service.writeXml(serializer, false, UserHandle.USER_ALL);
+            serializer.endDocument();
+            serializer.flush();
+
+            for (int userId : mUserProfiles.getCurrentProfileIds().toArray()) {
+                String actual = Settings.Secure.getStringForUser(
+                        getContext().getContentResolver(),
+                        service.getConfig().secureSettingName, userId);
+                assertTrue(TextUtils.isEmpty(actual));
+            }
+        }
+    }
+
+    @Test
     public void testWriteXml_writesUserSet() throws Exception {
         for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
             ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
@@ -1415,11 +1445,11 @@
         xml.append("<" + ManagedServices.TAG_MANAGED_SERVICES + " "
                         + ManagedServices.ATT_USER_ID + "=\"99\" "
                         + ManagedServices.ATT_IS_PRIMARY + "=\"true\" "
-                        + ManagedServices.ATT_APPROVED_LIST + "=\"99\" />\n");
+                        + ManagedServices.ATT_APPROVED_LIST + "=\"990\" />\n");
         xml.append("<" + ManagedServices.TAG_MANAGED_SERVICES + " "
                 + ManagedServices.ATT_USER_ID + "=\"98\" "
                 + ManagedServices.ATT_IS_PRIMARY + "=\"false\" "
-                + ManagedServices.ATT_APPROVED_LIST + "=\"98\" />\n");
+                + ManagedServices.ATT_APPROVED_LIST + "=\"981\" />\n");
         xml.append("</" + xmlTag + ">");
 
         return xml.toString();
@@ -1483,7 +1513,7 @@
 
     private void assertContentsInAnyOrder(Collection<?> expected, Collection<?> actual) {
         assertNotNull(actual);
-        assertEquals(expected.size(), actual.size());
+        assertEquals(expected + " : " + actual, expected.size(), actual.size());
 
         for (Object o : expected) {
             assertTrue("Actual missing " + o, actual.contains(o));
@@ -1665,4 +1695,17 @@
             return null;
         }
     }
+
+    class TestManagedServicesSettings extends TestManagedServices {
+
+        public TestManagedServicesSettings(Context context, Object mutex, UserProfiles userProfiles,
+                IPackageManager pm, int approvedServiceType) {
+            super(context, mutex, userProfiles, pm, approvedServiceType);
+        }
+
+        @Override
+        public boolean shouldReflectToSettings() {
+            return true;
+        }
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java
index e658d17..824c05e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java
@@ -126,6 +126,7 @@
         return new Notification.Action.Builder(
                 Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
                 "action",
-                PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0)).build();
+                PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"),
+                    PendingIntent.FLAG_MUTABLE_UNAUDITED)).build();
     }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationIntrusivenessExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationIntrusivenessExtractorTest.java
index 00d93de..a9a3b2b 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationIntrusivenessExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationIntrusivenessExtractorTest.java
@@ -58,8 +58,11 @@
         NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
         final Notification.Builder builder = new Notification.Builder(getContext())
                 .setContentTitle("foo")
+                // TODO(b/174258141) Please replace FLAG_MUTABLE_UNAUDITED below
+                // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
                 .setFullScreenIntent(PendingIntent.getActivity(
-                        getContext(), 0, new Intent(""), 0), true)
+                        getContext(), 0, new Intent(""), PendingIntent.FLAG_MUTABLE_UNAUDITED),
+                        true)
                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
 
         Notification n = builder.build();
@@ -76,8 +79,11 @@
         NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
         final Notification.Builder builder = new Notification.Builder(getContext())
                 .setContentTitle("foo")
+                // TODO(b/174258141) Please replace FLAG_MUTABLE_UNAUDITED below
+                // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
                 .setFullScreenIntent(PendingIntent.getActivity(
-                        getContext(), 0, new Intent(""), 0), true)
+                        getContext(), 0, new Intent(""), PendingIntent.FLAG_MUTABLE_UNAUDITED),
+                        true)
                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
 
         Notification n = builder.build();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
index fdc089e..c634706 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
@@ -102,7 +102,7 @@
             String key = mKeys[i];
             Ranking ranking = new Ranking();
             service.getCurrentRanking().getRanking(key, ranking);
-            assertEquals(getVisibilityOverride(i), ranking.getVisibilityOverride());
+            assertEquals(getVisibilityOverride(i), ranking.getLockscreenVisibilityOverride());
             assertEquals(getOverrideGroupKey(key), ranking.getOverrideGroupKey());
             assertEquals(!isIntercepted(i), ranking.matchesInterruptionFilter());
             assertEquals(getSuppressedVisualEffects(i), ranking.getSuppressedVisualEffects());
@@ -173,7 +173,7 @@
                 tweak.getKey(),
                 tweak.getRank(),
                 !tweak.matchesInterruptionFilter(), // note the inversion here!
-                tweak.getVisibilityOverride(),
+                tweak.getLockscreenVisibilityOverride(),
                 tweak.getSuppressedVisualEffects(),
                 tweak.getImportance(),
                 tweak.getImportanceExplanation(),
@@ -357,11 +357,13 @@
     private ArrayList<Notification.Action> getSmartActions(String key, int index) {
         ArrayList<Notification.Action> actions = new ArrayList<>();
         for (int i = 0; i < index; i++) {
+            // TODO(b/174935955) Please replace FLAG_MUTABLE_UNAUDITED below
+            // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
             PendingIntent intent = PendingIntent.getBroadcast(
                     getContext(),
                     index /*requestCode*/,
                     new Intent("ACTION_" + key),
-                    0 /*flags*/);
+                    PendingIntent.FLAG_MUTABLE_UNAUDITED /*flags*/);
             actions.add(new Notification.Action.Builder(null /*icon*/, key, intent).build());
         }
         return actions;
@@ -424,7 +426,7 @@
         assertEquals(comment, a.getKey(), b.getKey());
         assertEquals(comment, a.getRank(), b.getRank());
         assertEquals(comment, a.matchesInterruptionFilter(), b.matchesInterruptionFilter());
-        assertEquals(comment, a.getVisibilityOverride(), b.getVisibilityOverride());
+        assertEquals(comment, a.getLockscreenVisibilityOverride(), b.getLockscreenVisibilityOverride());
         assertEquals(comment, a.getSuppressedVisualEffects(), b.getSuppressedVisualEffects());
         assertEquals(comment, a.getImportance(), b.getImportance());
         assertEquals(comment, a.getImportanceExplanation(), b.getImportanceExplanation());
@@ -440,7 +442,8 @@
         assertEquals(comment, a.getSmartReplies(), b.getSmartReplies());
         assertEquals(comment, a.canBubble(), b.canBubble());
         assertEquals(comment, a.isConversation(), b.isConversation());
-        assertEquals(comment, a.getConversationShortcutInfo().getId(), b.getConversationShortcutInfo().getId());
+        assertEquals(comment, a.getConversationShortcutInfo().getId(),
+                b.getConversationShortcutInfo().getId());
         assertActionsEqual(a.getSmartActions(), b.getSmartActions());
     }
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 5cf529a..849477c 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -183,6 +183,7 @@
 import com.android.server.notification.NotificationManagerService.NotificationListeners;
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.uri.UriGrantsManagerInternal;
+import com.android.server.utils.quota.MultiRateLimiter;
 import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 
@@ -295,6 +296,8 @@
     NotificationHistoryManager mHistoryManager;
     @Mock
     StatsManager mStatsManager;
+    @Mock
+    MultiRateLimiter mToastRateLimiter;
     BroadcastReceiver mPackageIntentReceiver;
     NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
     private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(
@@ -486,7 +489,7 @@
                 mGroupHelper, mAm, mAtm, mAppUsageStats,
                 mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal,
                 mAppOpsManager, mUm, mHistoryManager, mStatsManager,
-                mock(TelephonyManager.class), mAmi);
+                mock(TelephonyManager.class), mAmi, mToastRateLimiter);
         mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
 
         mService.setAudioManager(mAudioManager);
@@ -566,7 +569,7 @@
 
         try {
             mService.onDestroy();
-        } catch (IllegalStateException e) {
+        } catch (IllegalStateException | IllegalArgumentException e) {
             // can throw if a broadcast receiver was never registered
         }
 
@@ -787,7 +790,10 @@
                 .setName("bubblebot")
                 .build();
         RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build();
-        PendingIntent inputIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+        // TODO(b/174965245) Please replace FLAG_MUTABLE_UNAUDITED below
+        // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
+        PendingIntent inputIntent = PendingIntent.getActivity(mContext, 0, new Intent(),
+                PendingIntent.FLAG_MUTABLE_UNAUDITED);
         Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon);
         Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply",
                 inputIntent).addRemoteInput(remoteInput)
@@ -4888,6 +4894,7 @@
         final String testPackage = "testPackageName";
         assertEquals(0, mService.mToastQueue.size());
         mService.isSystemUid = false;
+        setToastRateIsWithinQuota(true);
 
         // package is not suspended
         when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -4910,6 +4917,7 @@
         final String testPackage = "testPackageName";
         assertEquals(0, mService.mToastQueue.size());
         mService.isSystemUid = false;
+        setToastRateIsWithinQuota(true);
 
         // package is not suspended
         when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -4928,6 +4936,7 @@
         final String testPackage = "testPackageName";
         assertEquals(0, mService.mToastQueue.size());
         mService.isSystemUid = false;
+        setToastRateIsWithinQuota(true);
 
         // package is not suspended
         when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -4950,10 +4959,32 @@
     }
 
     @Test
+    public void testToastRateLimiterCanPreventsShowCallForCustomToast() throws Exception {
+        final String testPackage = "testPackageName";
+        assertEquals(0, mService.mToastQueue.size());
+        mService.isSystemUid = false;
+        setToastRateIsWithinQuota(false); // rate limit reached
+
+        // package is not suspended
+        when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
+                .thenReturn(false);
+
+        setAppInForegroundForToasts(mUid, true);
+
+        Binder token = new Binder();
+        ITransientNotification callback = mock(ITransientNotification.class);
+        INotificationManager nmService = (INotificationManager) mService.mService;
+
+        nmService.enqueueToast(testPackage, token, callback, 2000, 0);
+        verify(callback, times(0)).show(any());
+    }
+
+    @Test
     public void testAllowForegroundTextToasts() throws Exception {
         final String testPackage = "testPackageName";
         assertEquals(0, mService.mToastQueue.size());
         mService.isSystemUid = false;
+        setToastRateIsWithinQuota(true);
 
         // package is not suspended
         when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -4972,6 +5003,7 @@
         final String testPackage = "testPackageName";
         assertEquals(0, mService.mToastQueue.size());
         mService.isSystemUid = false;
+        setToastRateIsWithinQuota(true);
 
         // package is not suspended
         when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -4990,6 +5022,7 @@
         final String testPackage = "testPackageName";
         assertEquals(0, mService.mToastQueue.size());
         mService.isSystemUid = false;
+        setToastRateIsWithinQuota(true);
 
         // package is not suspended
         when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5013,11 +5046,31 @@
     }
 
     @Test
+    public void testToastRateLimiterCanPreventsShowCallForTextToast() throws Exception {
+        final String testPackage = "testPackageName";
+        assertEquals(0, mService.mToastQueue.size());
+        mService.isSystemUid = false;
+        setToastRateIsWithinQuota(false); // rate limit reached
+
+        // package is not suspended
+        when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
+                .thenReturn(false);
+
+        Binder token = new Binder();
+        INotificationManager nmService = (INotificationManager) mService.mService;
+
+        nmService.enqueueTextToast(testPackage, token, "Text", 2000, 0, null);
+        verify(mStatusBar, times(0))
+                .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any());
+    }
+
+    @Test
     public void backgroundSystemCustomToast_callsSetProcessImportantAsForegroundForToast() throws
             Exception {
         final String testPackage = "testPackageName";
         assertEquals(0, mService.mToastQueue.size());
         mService.isSystemUid = true;
+        setToastRateIsWithinQuota(true);
 
         // package is not suspended
         when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5042,6 +5095,7 @@
         final String testPackage = "testPackageName";
         assertEquals(0, mService.mToastQueue.size());
         mService.isSystemUid = false;
+        setToastRateIsWithinQuota(true);
 
         // package is not suspended
         when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5062,6 +5116,7 @@
         final String testPackage = "testPackageName";
         assertEquals(0, mService.mToastQueue.size());
         mService.isSystemUid = false;
+        setToastRateIsWithinQuota(true);
 
         // package is not suspended
         when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5081,6 +5136,7 @@
         final String testPackage = "testPackageName";
         assertEquals(0, mService.mToastQueue.size());
         mService.isSystemUid = false;
+        setToastRateIsWithinQuota(true);
 
         // package is not suspended
         when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5097,6 +5153,7 @@
         final String testPackage = "testPackageName";
         assertEquals(0, mService.mToastQueue.size());
         mService.isSystemUid = false;
+        setToastRateIsWithinQuota(true);
 
         // package is suspended
         when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5117,6 +5174,7 @@
         final String testPackage = "testPackageName";
         assertEquals(0, mService.mToastQueue.size());
         mService.isSystemUid = false;
+        setToastRateIsWithinQuota(true);
 
         // package is not suspended
         when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5139,6 +5197,7 @@
         final String testPackage = "testPackageName";
         assertEquals(0, mService.mToastQueue.size());
         mService.isSystemUid = true;
+        setToastRateIsWithinQuota(true);
 
         // package is suspended
         when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5161,6 +5220,7 @@
         final String testPackage = "testPackageName";
         assertEquals(0, mService.mToastQueue.size());
         mService.isSystemUid = false;
+        setToastRateIsWithinQuota(true);
 
         // package is not suspended
         when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
@@ -5188,6 +5248,14 @@
         when(mAtm.hasResumedActivity(uid)).thenReturn(inForeground);
     }
 
+    private void setToastRateIsWithinQuota(boolean isWithinQuota) {
+        when(mToastRateLimiter.isWithinQuota(
+                anyInt(),
+                anyString(),
+                eq(NotificationManagerService.TOAST_QUOTA_TAG)))
+                .thenReturn(isWithinQuota);
+    }
+
     @Test
     public void testOnPanelRevealedAndHidden() {
         int items = 5;
@@ -7301,7 +7369,10 @@
         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
         ArrayList<Notification.Action> extraAction = new ArrayList<>();
         RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build();
-        PendingIntent inputIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+        // TODO(b/174965245) Please replace FLAG_MUTABLE_UNAUDITED below
+        // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
+        PendingIntent inputIntent = PendingIntent.getActivity(mContext, 0, new Intent(),
+                PendingIntent.FLAG_MUTABLE_UNAUDITED);
         Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon);
         Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply",
                 inputIntent).addRemoteInput(remoteInput)
@@ -7331,7 +7402,10 @@
         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
         ArrayList<Notification.Action> extraAction = new ArrayList<>();
         RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build();
-        PendingIntent inputIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+        // TODO(b/174965245) Please replace FLAG_MUTABLE_UNAUDITED below
+        // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
+        PendingIntent inputIntent = PendingIntent.getActivity(mContext, 0, new Intent(),
+                PendingIntent.FLAG_MUTABLE_UNAUDITED);
         Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon);
         Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply",
                 inputIntent).addRemoteInput(remoteInput)
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/OWNERS b/services/tests/uiservicestests/src/com/android/server/notification/OWNERS
new file mode 100644
index 0000000..396fd12
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/notification/OWNERS
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 98c4a2d..4d2a478 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -97,6 +97,7 @@
 import android.testing.TestableContentResolver;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.IntArray;
 import android.util.Pair;
 import android.util.StatsEvent;
 import android.util.TypedXmlPullParser;
@@ -3320,7 +3321,8 @@
         channel2.setImportantConversation(true);
         mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false);
 
-        List<ConversationChannelWrapper> convos = mHelper.getConversations(false);
+        List<ConversationChannelWrapper> convos =
+                mHelper.getConversations(IntArray.wrap(new int[] {0}), false);
 
         assertEquals(3, convos.size());
         assertTrue(conversationWrapperContainsChannel(convos, channel));
@@ -3329,6 +3331,44 @@
     }
 
     @Test
+    public void testGetConversations_multiUser() {
+        String convoId = "convo";
+        NotificationChannel messages =
+                new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
+        mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false);
+
+        NotificationChannel messagesUser10 =
+                new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
+        mHelper.createNotificationChannel(
+                PKG_O, UID_O + UserHandle.PER_USER_RANGE, messagesUser10, true, false);
+
+        NotificationChannel messagesFromB =
+                new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT);
+        messagesFromB.setConversationId(messages.getId(), "different convo");
+        mHelper.createNotificationChannel(PKG_O, UID_O, messagesFromB, true, false);
+
+        NotificationChannel messagesFromBUser10 =
+                new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT);
+        messagesFromBUser10.setConversationId(messagesUser10.getId(), "different convo");
+        mHelper.createNotificationChannel(
+                PKG_O, UID_O + UserHandle.PER_USER_RANGE, messagesFromBUser10, true, false);
+
+
+        List<ConversationChannelWrapper> convos =
+                mHelper.getConversations(IntArray.wrap(new int[] {0}), false);
+
+        assertEquals(1, convos.size());
+        assertTrue(conversationWrapperContainsChannel(convos, messagesFromB));
+
+        convos =
+                mHelper.getConversations(IntArray.wrap(new int[] {0, UserHandle.getUserId(UID_O + UserHandle.PER_USER_RANGE)}), false);
+
+        assertEquals(2, convos.size());
+        assertTrue(conversationWrapperContainsChannel(convos, messagesFromB));
+        assertTrue(conversationWrapperContainsChannel(convos, messagesFromBUser10));
+    }
+
+    @Test
     public void testGetConversations_notDemoted() {
         String convoId = "convo";
         NotificationChannel messages =
@@ -3358,7 +3398,8 @@
         channel2.setImportantConversation(true);
         mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false);
 
-        List<ConversationChannelWrapper> convos = mHelper.getConversations(false);
+        List<ConversationChannelWrapper> convos =
+                mHelper.getConversations(IntArray.wrap(new int[] {0}), false);
 
         assertEquals(2, convos.size());
         assertTrue(conversationWrapperContainsChannel(convos, channel));
@@ -3396,7 +3437,8 @@
         channel2.setConversationId(calls.getId(), convoId);
         mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false);
 
-        List<ConversationChannelWrapper> convos = mHelper.getConversations(true);
+        List<ConversationChannelWrapper> convos =
+                mHelper.getConversations(IntArray.wrap(new int[] {0}), true);
 
         assertEquals(2, convos.size());
         assertTrue(conversationWrapperContainsChannel(convos, channel));
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
index a80f62a..4ce237e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
@@ -67,6 +67,7 @@
 import com.android.server.notification.NotificationManagerService.NotificationAssistants;
 import com.android.server.notification.NotificationManagerService.NotificationListeners;
 import com.android.server.uri.UriGrantsManagerInternal;
+import com.android.server.utils.quota.MultiRateLimiter;
 import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 
@@ -156,7 +157,8 @@
                     mock(UriGrantsManagerInternal.class),
                     mock(AppOpsManager.class), mUm, mock(NotificationHistoryManager.class),
                     mock(StatsManager.class), mock(TelephonyManager.class),
-                    mock(ActivityManagerInternal.class));
+                    mock(ActivityManagerInternal.class),
+                    mock(MultiRateLimiter.class));
         } catch (SecurityException e) {
             if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
                 throw e;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
index e5ae2d3..f43e5a8 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
@@ -27,8 +27,11 @@
 import static org.mockito.Mockito.when;
 
 import android.app.Notification;
+import android.app.Person;
 import android.content.pm.LauncherApps;
+import android.content.pm.LauncherApps.ShortcutQuery;
 import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutQueryWrapper;
 import android.content.pm.ShortcutServiceInternal;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
@@ -44,6 +47,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
@@ -60,6 +64,7 @@
     private static final String SHORTCUT_ID = "shortcut";
     private static final String PKG = "pkg";
     private static final String KEY = "key";
+    private static final Person PERSON = mock(Person.class);
 
     @Mock
     LauncherApps mLauncherApps;
@@ -78,6 +83,8 @@
     @Mock
     ShortcutInfo mShortcutInfo;
 
+    @Captor private ArgumentCaptor<ShortcutQuery> mShortcutQueryCaptor;
+
     ShortcutHelper mShortcutHelper;
 
     @Before
@@ -298,6 +305,7 @@
         when(si.getUserId()).thenReturn(UserHandle.USER_SYSTEM);
         when(si.isLongLived()).thenReturn(true);
         when(si.isEnabled()).thenReturn(true);
+        when(si.getPersons()).thenReturn(new Person[]{PERSON});
         ArrayList<ShortcutInfo> shortcuts = new ArrayList<>();
         shortcuts.add(si);
         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcuts);
@@ -308,4 +316,23 @@
         assertThat(mShortcutHelper.getValidShortcutInfo("a", "p", UserHandle.SYSTEM))
                 .isSameInstanceAs(si);
     }
+
+    @Test
+    public void testGetValidShortcutInfo_hasGetPersonsDataFlag() {
+
+        ShortcutInfo info = mShortcutHelper.getValidShortcutInfo(
+                "a", "p", UserHandle.SYSTEM);
+        verify(mLauncherApps).getShortcuts(mShortcutQueryCaptor.capture(), any());
+        ShortcutQueryWrapper shortcutQuery =
+                new ShortcutQueryWrapper(mShortcutQueryCaptor.getValue());
+        assertThat(hasFlag(shortcutQuery.getQueryFlags(), ShortcutQuery.FLAG_GET_PERSONS_DATA))
+                .isTrue();
+    }
+
+    /**
+     * Returns {@code true} iff {@link ShortcutQuery}'s {@code queryFlags} has {@code flag} set.
+    */
+    private static boolean hasFlag(int queryFlags, int flag) {
+        return (queryFlags & flag) != 0;
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/VisibilityExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/VisibilityExtractorTest.java
new file mode 100644
index 0000000..3998129
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/VisibilityExtractorTest.java
@@ -0,0 +1,246 @@
+/*
+ * 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.notification;
+
+import static android.app.Notification.VISIBILITY_PRIVATE;
+import static android.app.Notification.VISIBILITY_SECRET;
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
+import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
+import static android.app.NotificationManager.VISIBILITY_NO_OVERRIDE;
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS;
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.app.Notification;
+import android.app.Notification.Builder;
+import android.app.NotificationChannel;
+import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
+import android.content.Intent;
+import android.graphics.drawable.Icon;
+import android.media.session.MediaSession;
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.UiServiceTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class VisibilityExtractorTest extends UiServiceTestCase {
+
+    @Mock RankingConfig mConfig;
+    @Mock
+    DevicePolicyManager mDpm;
+
+    private String mPkg = "com.android.server.notification";
+    private int mId = 1001;
+    private String mTag = null;
+    private int mUid = 1000;
+    private int mPid = 2000;
+    private int mUser = ActivityManager.getCurrentUser();
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext.addMockSystemService(DevicePolicyManager.class, mDpm);
+    }
+
+    private NotificationRecord getNotificationRecord(int visibility) {
+        NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
+        channel.setLockscreenVisibility(visibility);
+        when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
+
+        final Builder builder = new Builder(getContext())
+                .setContentTitle("foo")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon);
+
+        Notification n = builder.build();
+        StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, mId, mTag, mUid,
+                mPid, n, UserHandle.of(mUser), null, System.currentTimeMillis());
+        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
+        return r;
+    }
+
+    //
+    // Tests
+    //
+
+    @Test
+    public void testGlobalAllDpmAllChannelAll() {
+        VisibilityExtractor extractor = new VisibilityExtractor();
+        extractor.setConfig(mConfig);
+        extractor.initialize(mContext, null);
+
+        when(mConfig.canShowNotificationsOnLockscreen(mUser)).thenReturn(true);
+        when(mConfig.canShowPrivateNotificationsOnLockScreen(mUser)).thenReturn(true);
+
+        when(mDpm.getKeyguardDisabledFeatures(null, mUser)).thenReturn(0);
+
+        NotificationRecord r = getNotificationRecord(VISIBILITY_NO_OVERRIDE);
+
+        extractor.process(r);
+
+        assertEquals(VISIBILITY_NO_OVERRIDE, r.getPackageVisibilityOverride());
+    }
+
+    @Test
+    public void testGlobalNoneDpmAllChannelAll() {
+        VisibilityExtractor extractor = new VisibilityExtractor();
+        extractor.setConfig(mConfig);
+        extractor.initialize(mContext, null);
+
+        when(mConfig.canShowNotificationsOnLockscreen(mUser)).thenReturn(false);
+        when(mConfig.canShowPrivateNotificationsOnLockScreen(mUser)).thenReturn(true);
+
+        when(mDpm.getKeyguardDisabledFeatures(null, mUser)).thenReturn(0);
+
+        NotificationRecord r = getNotificationRecord(VISIBILITY_NO_OVERRIDE);
+
+        extractor.process(r);
+
+        assertEquals(VISIBILITY_SECRET, r.getPackageVisibilityOverride());
+    }
+
+    @Test
+    public void testGlobalSomeDpmAllChannelAll() {
+        VisibilityExtractor extractor = new VisibilityExtractor();
+        extractor.setConfig(mConfig);
+        extractor.initialize(mContext, null);
+
+        when(mConfig.canShowNotificationsOnLockscreen(mUser)).thenReturn(true);
+        when(mConfig.canShowPrivateNotificationsOnLockScreen(mUser)).thenReturn(false);
+
+        when(mDpm.getKeyguardDisabledFeatures(null, mUser)).thenReturn(0);
+
+        NotificationRecord r = getNotificationRecord(VISIBILITY_NO_OVERRIDE);
+
+        extractor.process(r);
+
+        assertEquals(VISIBILITY_PRIVATE, r.getPackageVisibilityOverride());
+    }
+
+    @Test
+    public void testGlobalAllDpmNoneChannelAll() {
+        VisibilityExtractor extractor = new VisibilityExtractor();
+        extractor.setConfig(mConfig);
+        extractor.initialize(mContext, null);
+
+        when(mConfig.canShowNotificationsOnLockscreen(mUser)).thenReturn(true);
+        when(mConfig.canShowPrivateNotificationsOnLockScreen(mUser)).thenReturn(true);
+
+        when(mDpm.getKeyguardDisabledFeatures(null, mUser)).thenReturn(
+                KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
+
+        NotificationRecord r = getNotificationRecord(VISIBILITY_NO_OVERRIDE);
+
+        extractor.process(r);
+
+        assertEquals(VISIBILITY_SECRET, r.getPackageVisibilityOverride());
+    }
+
+    @Test
+    public void testGlobalAllDpmSomeChannelAll() {
+        VisibilityExtractor extractor = new VisibilityExtractor();
+        extractor.setConfig(mConfig);
+        extractor.initialize(mContext, null);
+
+        when(mConfig.canShowNotificationsOnLockscreen(mUser)).thenReturn(true);
+        when(mConfig.canShowPrivateNotificationsOnLockScreen(mUser)).thenReturn(true);
+
+        when(mDpm.getKeyguardDisabledFeatures(null, mUser)).thenReturn(
+                KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
+
+        NotificationRecord r = getNotificationRecord(VISIBILITY_NO_OVERRIDE);
+
+        extractor.process(r);
+
+        assertEquals(VISIBILITY_PRIVATE, r.getPackageVisibilityOverride());
+    }
+
+    @Test
+    public void testGlobalAllDpmAllChannelNone() {
+        VisibilityExtractor extractor = new VisibilityExtractor();
+        extractor.setConfig(mConfig);
+        extractor.initialize(mContext, null);
+
+        when(mConfig.canShowNotificationsOnLockscreen(mUser)).thenReturn(true);
+        when(mConfig.canShowPrivateNotificationsOnLockScreen(mUser)).thenReturn(true);
+
+        when(mDpm.getKeyguardDisabledFeatures(null, mUser)).thenReturn(0);
+
+        NotificationRecord r = getNotificationRecord(VISIBILITY_SECRET);
+
+        extractor.process(r);
+
+        assertEquals(VISIBILITY_SECRET, r.getPackageVisibilityOverride());
+    }
+
+    @Test
+    public void testGlobalAllDpmAllChannelSome() {
+        VisibilityExtractor extractor = new VisibilityExtractor();
+        extractor.setConfig(mConfig);
+        extractor.initialize(mContext, null);
+
+        when(mConfig.canShowNotificationsOnLockscreen(mUser)).thenReturn(true);
+        when(mConfig.canShowPrivateNotificationsOnLockScreen(mUser)).thenReturn(true);
+
+        when(mDpm.getKeyguardDisabledFeatures(null, mUser)).thenReturn(0);
+
+        NotificationRecord r = getNotificationRecord(VISIBILITY_PRIVATE);
+
+        extractor.process(r);
+
+        assertEquals(VISIBILITY_PRIVATE, r.getPackageVisibilityOverride());
+    }
+
+    @Test
+    public void testGlobalAllDpmSomeChannelNone() {
+        VisibilityExtractor extractor = new VisibilityExtractor();
+        extractor.setConfig(mConfig);
+        extractor.initialize(mContext, null);
+
+        when(mConfig.canShowNotificationsOnLockscreen(mUser)).thenReturn(true);
+        when(mConfig.canShowPrivateNotificationsOnLockScreen(mUser)).thenReturn(true);
+
+        when(mDpm.getKeyguardDisabledFeatures(null, mUser)).thenReturn(
+                KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
+
+        NotificationRecord r = getNotificationRecord(VISIBILITY_SECRET);
+
+        extractor.process(r);
+
+        assertEquals(VISIBILITY_SECRET, r.getPackageVisibilityOverride());
+    }
+
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/OWNERS b/services/tests/uiservicestests/src/com/android/server/slice/OWNERS
new file mode 100644
index 0000000..3d0859f
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/slice/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/app/slice/OWNERS
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
index a443695..dd0c162 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java
@@ -75,7 +75,6 @@
         LocalServices.addService(UsageStatsManagerInternal.class,
                 mock(UsageStatsManagerInternal.class));
         mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class));
-        mContext.getTestablePermissions().setPermission(TEST_URI, PERMISSION_GRANTED);
 
         mContextSpy = spy(mContext);
         mService = spy(new SliceManagerService(mContextSpy, TestableLooper.get(this).getLooper()));
@@ -90,6 +89,7 @@
 
     @Test
     public void testAddPinCreatesPinned() throws RemoteException {
+        grantSlicePermission();
         doReturn("pkg").when(mService).getDefaultHome(anyInt());
 
         mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS, mToken);
@@ -99,6 +99,7 @@
 
     @Test
     public void testRemovePinDestroysPinned() throws RemoteException {
+        grantSlicePermission();
         doReturn("pkg").when(mService).getDefaultHome(anyInt());
 
         mService.pinSlice("pkg", TEST_URI, EMPTY_SPECS, mToken);
@@ -130,11 +131,13 @@
 
     @Test(expected = IllegalStateException.class)
     public void testNoPinThrow() throws Exception {
+        grantSlicePermission();
         mService.getPinnedSpecs(TEST_URI, "pkg");
     }
 
     @Test
     public void testGetPinnedSpecs() throws Exception {
+        grantSlicePermission();
         SliceSpec[] specs = new SliceSpec[] {
             new SliceSpec("Something", 1) };
         mService.pinSlice("pkg", TEST_URI, specs, mToken);
@@ -143,4 +146,10 @@
         assertEquals(specs, mService.getPinnedSpecs(TEST_URI, "pkg"));
     }
 
+    private void grantSlicePermission() {
+        doReturn(PERMISSION_GRANTED).when(mService).checkSlicePermission(
+                eq(TEST_URI), anyString(), anyString(), anyInt(), anyInt(), any());
+        doReturn(PERMISSION_GRANTED).when(mService).checkAccess(
+                anyString(), eq(TEST_URI), anyInt(), anyInt());
+    }
 }
diff --git a/services/tests/wmtests/OWNERS b/services/tests/wmtests/OWNERS
new file mode 100644
index 0000000..0862c05
--- /dev/null
+++ b/services/tests/wmtests/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/services/tests/wmtests/src/com/android/server/policy/KeyCombinationTests.java b/services/tests/wmtests/src/com/android/server/policy/KeyCombinationTests.java
new file mode 100644
index 0000000..75479de
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/policy/KeyCombinationTests.java
@@ -0,0 +1,208 @@
+/*
+ * 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.policy;
+
+import static android.view.KeyEvent.ACTION_DOWN;
+import static android.view.KeyEvent.ACTION_UP;
+import static android.view.KeyEvent.KEYCODE_BACK;
+import static android.view.KeyEvent.KEYCODE_POWER;
+import static android.view.KeyEvent.KEYCODE_VOLUME_DOWN;
+import static android.view.KeyEvent.KEYCODE_VOLUME_UP;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.view.KeyEvent;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test class for {@link KeyCombinationManager}.
+ *
+ * Build/Install/Run:
+ *  atest KeyCombinationTests
+ */
+
+@SmallTest
+public class KeyCombinationTests {
+    private KeyCombinationManager mKeyCombinationManager;
+
+    private boolean mAction1Triggered = false;
+    private boolean mAction2Triggered = false;
+    private boolean mAction3Triggered = false;
+
+    private boolean mPreCondition = true;
+    private static final long SCHEDULE_TIME = 300;
+
+    @Before
+    public void setUp() {
+        mKeyCombinationManager = new KeyCombinationManager();
+        initKeyCombinationRules();
+    }
+
+    private void initKeyCombinationRules() {
+        // Rule 1 : power + volume_down trigger action immediately.
+        mKeyCombinationManager.addRule(
+                new KeyCombinationManager.TwoKeysCombinationRule(KEYCODE_VOLUME_DOWN,
+                        KEYCODE_POWER) {
+                    @Override
+                    void execute() {
+                        mAction1Triggered = true;
+                    }
+
+                    @Override
+                    void cancel() {
+                    }
+                });
+
+        // Rule 2 : volume_up + volume_down with condition.
+        mKeyCombinationManager.addRule(
+                new KeyCombinationManager.TwoKeysCombinationRule(KEYCODE_VOLUME_DOWN,
+                        KEYCODE_VOLUME_UP) {
+                    @Override
+                    boolean preCondition() {
+                        return mPreCondition;
+                    }
+
+                    @Override
+                    void execute() {
+                        mAction2Triggered = true;
+                    }
+
+                    @Override
+                    void cancel() {
+                    }
+                });
+
+        // Rule 3 : power + volume_up schedule and trigger action after timeout.
+        mKeyCombinationManager.addRule(
+                new KeyCombinationManager.TwoKeysCombinationRule(KEYCODE_VOLUME_UP, KEYCODE_POWER) {
+                    final Runnable mAction = new Runnable() {
+                        @Override
+                        public void run() {
+                            mAction3Triggered = true;
+                        }
+                    };
+                    final Handler mHandler = new Handler(Looper.getMainLooper());
+
+                    @Override
+                    void execute() {
+                        mHandler.postDelayed(mAction, SCHEDULE_TIME);
+                    }
+
+                    @Override
+                    void cancel() {
+                        mHandler.removeCallbacks(mAction);
+                    }
+                });
+    }
+
+    private void pressKeys(long firstKeyTime, int firstKeyCode, long secondKeyTime,
+            int secondKeyCode) {
+        pressKeys(firstKeyTime, firstKeyCode, secondKeyTime, secondKeyCode, 0);
+    }
+
+    private void pressKeys(long firstKeyTime, int firstKeyCode, long secondKeyTime,
+            int secondKeyCode, long pressTime) {
+        final KeyEvent firstKeyDown = new KeyEvent(firstKeyTime, firstKeyTime, ACTION_DOWN,
+                firstKeyCode, 0 /* repeat */, 0 /* metaState */);
+        final KeyEvent secondKeyDown = new KeyEvent(secondKeyTime, secondKeyTime, ACTION_DOWN,
+                secondKeyCode, 0 /* repeat */, 0 /* metaState */);
+
+        mKeyCombinationManager.interceptKey(firstKeyDown, true);
+        mKeyCombinationManager.interceptKey(secondKeyDown, true);
+
+        // keep press down.
+        try {
+            Thread.sleep(pressTime);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+
+        final KeyEvent firstKeyUp = new KeyEvent(firstKeyTime, firstKeyTime, ACTION_UP,
+                firstKeyCode, 0 /* repeat */, 0 /* metaState */);
+        final KeyEvent secondKeyUp = new KeyEvent(secondKeyTime, secondKeyTime, ACTION_UP,
+                secondKeyCode, 0 /* repeat */, 0 /* metaState */);
+
+        mKeyCombinationManager.interceptKey(firstKeyUp, true);
+        mKeyCombinationManager.interceptKey(secondKeyUp, true);
+    }
+
+    @Test
+    public void testTriggerRule() {
+        final long eventTime = SystemClock.uptimeMillis();
+        pressKeys(eventTime, KEYCODE_POWER, eventTime, KEYCODE_VOLUME_DOWN);
+        assertTrue(mAction1Triggered);
+
+        pressKeys(eventTime, KEYCODE_VOLUME_UP, eventTime, KEYCODE_VOLUME_DOWN);
+        assertTrue(mAction2Triggered);
+
+        pressKeys(eventTime, KEYCODE_POWER, eventTime, KEYCODE_VOLUME_UP, SCHEDULE_TIME + 50);
+        assertTrue(mAction3Triggered);
+    }
+
+    /**
+     *  Nothing should happen if there is no definition.
+     */
+    @Test
+    public void testNotTrigger_NoRule() {
+        final long eventTime = SystemClock.uptimeMillis();
+        pressKeys(eventTime, KEYCODE_BACK, eventTime, KEYCODE_VOLUME_DOWN);
+        assertFalse(mAction1Triggered);
+        assertFalse(mAction2Triggered);
+        assertFalse(mAction3Triggered);
+    }
+
+    /**
+     *  Nothing should happen if the interval of press time is too long.
+     */
+    @Test
+    public void testNotTrigger_Interval() {
+        final long eventTime = SystemClock.uptimeMillis();
+        final long earlyEventTime = eventTime - 200; // COMBINE_KEY_DELAY_MILLIS = 150;
+        pressKeys(earlyEventTime, KEYCODE_POWER, eventTime, KEYCODE_VOLUME_DOWN);
+        assertFalse(mAction1Triggered);
+    }
+
+    /**
+     *  Nothing should happen if the condition is false.
+     */
+    @Test
+    public void testNotTrigger_Condition() {
+        final long eventTime = SystemClock.uptimeMillis();
+        // we won't trigger action 2 because the condition is false.
+        mPreCondition = false;
+        pressKeys(eventTime, KEYCODE_VOLUME_UP, eventTime, KEYCODE_VOLUME_DOWN);
+        assertFalse(mAction2Triggered);
+    }
+
+    /**
+     *  Nothing should happen if the keys released too early.
+     */
+    @Test
+    public void testNotTrigger_EarlyRelease() {
+        final long eventTime = SystemClock.uptimeMillis();
+        pressKeys(eventTime, KEYCODE_POWER, eventTime, KEYCODE_VOLUME_UP);
+        assertFalse(mAction3Triggered);
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index 3d31824..080f04ef 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -80,13 +80,13 @@
     public void testActivityFinish() {
         final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
         final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity();
-        assertTrue("Activity must be finished", mAtm.finishActivity(activity.appToken,
-                0 /* resultCode */, null /* resultData */,
+        assertTrue("Activity must be finished", mAtm.mActivityClientController.finishActivity(
+                activity.appToken, 0 /* resultCode */, null /* resultData */,
                 Activity.DONT_FINISH_TASK_WITH_ACTIVITY));
         assertTrue(activity.finishing);
 
         assertTrue("Duplicate activity finish request must also return 'true'",
-                mAtm.finishActivity(activity.appToken, 0 /* resultCode */,
+                mAtm.mActivityClientController.finishActivity(activity.appToken, 0 /* resultCode */,
                         null /* resultData */, Activity.DONT_FINISH_TASK_WITH_ACTIVITY));
     }
 
@@ -225,7 +225,7 @@
         //to simulate NPE
         doReturn(null).when(record).getParent();
 
-        mAtm.enterPictureInPictureMode(token, params);
+        mAtm.mActivityClientController.enterPictureInPictureMode(token, params);
         //if record's null parent is not handled gracefully, test will fail with NPE
 
         mockSession.finishMocking();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java
index bc91c70..f536cd0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java
@@ -61,7 +61,7 @@
         mTaskDisplayArea = new TaskDisplayArea(
                 mDisplayContent, mWm, "TDA1", FEATURE_VENDOR_FIRST + 1);
         mDisplayAreaGroup.addChild(mTaskDisplayArea, POSITION_TOP);
-        mDisplayContent.setLastFocusedTaskDisplayArea(mTaskDisplayArea);
+        mDisplayContent.onLastFocusedTaskDisplayAreaChanged(mTaskDisplayArea);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
index 266ce5b..e47913f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
@@ -32,6 +32,7 @@
 import static android.window.DisplayAreaOrganizer.FEATURE_ONE_HANDED;
 import static android.window.DisplayAreaOrganizer.FEATURE_ROOT;
 import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
+import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_LAST;
 import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION;
 
 import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS;
@@ -46,6 +47,7 @@
 import static java.util.stream.Collectors.toList;
 
 import android.content.res.Resources;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.platform.test.annotations.Presubmit;
@@ -114,11 +116,13 @@
         final Feature bar;
         DisplayAreaPolicyBuilder.HierarchyBuilder rootHierarchy =
                 new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
-                        .addFeature(foo = new Feature.Builder(mPolicy, "Foo", 0)
+                        .addFeature(foo = new Feature.Builder(mPolicy, "Foo",
+                                FEATURE_VENDOR_FIRST)
                                 .upTo(TYPE_STATUS_BAR)
                                 .and(TYPE_NAVIGATION_BAR)
                                 .build())
-                        .addFeature(bar = new Feature.Builder(mPolicy, "Bar", 1)
+                        .addFeature(bar = new Feature.Builder(mPolicy, "Bar",
+                                FEATURE_VENDOR_FIRST + 1)
                                 .all()
                                 .except(TYPE_STATUS_BAR)
                                 .build())
@@ -240,12 +244,14 @@
         final Feature other;
         DisplayAreaPolicyBuilder.HierarchyBuilder rootHierarchy =
                 new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
-                        .addFeature(dimmable = new Feature.Builder(mPolicy, "Dimmable", 0)
+                        .addFeature(dimmable = new Feature.Builder(mPolicy, "Dimmable",
+                                FEATURE_VENDOR_FIRST)
                                 .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
                                 .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
                                 .setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
                                 .build())
-                        .addFeature(other = new Feature.Builder(mPolicy, "Other", 1)
+                        .addFeature(other = new Feature.Builder(mPolicy, "Other",
+                                FEATURE_VENDOR_FIRST + 1)
                                 .all()
                                 .build())
                         .setImeContainer(mImeContainer)
@@ -313,9 +319,7 @@
         builder2.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
                 mGroupRoot1)
                 .setImeContainer(mImeContainer)
-                .setTaskDisplayAreas(Lists.newArrayList(
-                        new TaskDisplayArea(mDisplayContent, mWms, "testTda",
-                                FEATURE_VENDOR_FIRST + 1))));
+                .setTaskDisplayAreas(Lists.newArrayList(mTda1)));
 
         assertThrows(IllegalStateException.class, () -> builder2.build(mWms));
 
@@ -340,14 +344,147 @@
                 .setTaskDisplayAreas(mTaskDisplayAreaList));
         builder4.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
                 mGroupRoot2)
-                .setTaskDisplayAreas(Lists.newArrayList(
-                        new TaskDisplayArea(mDisplayContent, mWms, "testTda",
-                                FEATURE_VENDOR_FIRST + 1))));
+                .setTaskDisplayAreas(Lists.newArrayList(mTda1)));
 
         builder4.build(mWms);
     }
 
     @Test
+    public void testBuilder_rootHasUniqueId() {
+        // Root must have different id from all roots.
+        final DisplayAreaPolicyBuilder builder1 = new DisplayAreaPolicyBuilder();
+        builder1.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+                .setImeContainer(mImeContainer)
+                .setTaskDisplayAreas(mTaskDisplayAreaList));
+        final RootDisplayArea groupRoot1 = new SurfacelessDisplayAreaRoot(mWms, "group1",
+                mRoot.mFeatureId);
+        builder1.addDisplayAreaGroupHierarchy(
+                new DisplayAreaPolicyBuilder.HierarchyBuilder(groupRoot1)
+                        .setTaskDisplayAreas(Lists.newArrayList(mTda1)));
+
+        assertThrows(IllegalStateException.class, () -> builder1.build(mWms));
+
+        // Root must have different id from all TDAs.
+        final DisplayAreaPolicyBuilder builder2 = new DisplayAreaPolicyBuilder();
+        builder2.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+                .setImeContainer(mImeContainer)
+                .setTaskDisplayAreas(Lists.newArrayList(
+                        mDefaultTaskDisplayArea,
+                        new TaskDisplayArea(mDisplayContent, mWms, "testTda",
+                                mRoot.mFeatureId))));
+
+        assertThrows(IllegalStateException.class, () -> builder2.build(mWms));
+
+        // Root must have different id from all features.
+        final DisplayAreaPolicyBuilder builder3 = new DisplayAreaPolicyBuilder();
+        builder3.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+                .setImeContainer(mImeContainer)
+                .setTaskDisplayAreas(mTaskDisplayAreaList)
+                .addFeature(new Feature.Builder(mPolicy, "testFeature", mRoot.mFeatureId)
+                        .all()
+                        .build()));
+
+        assertThrows(IllegalStateException.class, () -> builder3.build(mWms));
+    }
+
+    @Test
+    public void testBuilder_taskDisplayAreaHasUniqueId() {
+        // TDA must have different id from all TDAs.
+        final DisplayAreaPolicyBuilder builder = new DisplayAreaPolicyBuilder();
+        final List<TaskDisplayArea> tdaList = Lists.newArrayList(
+                mDefaultTaskDisplayArea,
+                mTda1,
+                new TaskDisplayArea(mDisplayContent, mWms, "tda2", mTda1.mFeatureId));
+        builder.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+                .setImeContainer(mImeContainer)
+                .setTaskDisplayAreas(tdaList));
+
+        assertThrows(IllegalStateException.class, () -> builder.build(mWms));
+
+        // TDA must have different id from all features.
+        final DisplayAreaPolicyBuilder builder2 = new DisplayAreaPolicyBuilder();
+        builder2.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+                .setImeContainer(mImeContainer)
+                .setTaskDisplayAreas(Lists.newArrayList(
+                        mDefaultTaskDisplayArea,
+                        mTda1))
+                .addFeature(new Feature.Builder(mPolicy, "testFeature", mTda1.mFeatureId)
+                        .all()
+                        .build()));
+
+        assertThrows(IllegalStateException.class, () -> builder2.build(mWms));
+    }
+
+    @Test
+    public void testBuilder_featureHasUniqueId() {
+        // Feature must have different id from features below the same root.
+        final DisplayAreaPolicyBuilder builder = new DisplayAreaPolicyBuilder();
+        builder.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+                .setImeContainer(mImeContainer)
+                .setTaskDisplayAreas(mTaskDisplayAreaList)
+                .addFeature(new Feature.Builder(mPolicy, "feature1", FEATURE_VENDOR_FIRST + 10)
+                        .all()
+                        .build())
+                .addFeature(new Feature.Builder(mPolicy, "feature2", FEATURE_VENDOR_FIRST + 10)
+                        .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
+                        .build()));
+
+        assertThrows(IllegalStateException.class, () -> builder.build(mWms));
+
+        // Features below different root can have the same id.
+        final DisplayAreaPolicyBuilder builder2 = new DisplayAreaPolicyBuilder();
+        builder2.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+                .setImeContainer(mImeContainer)
+                .setTaskDisplayAreas(mTaskDisplayAreaList)
+                .addFeature(new Feature.Builder(mPolicy, "feature1", FEATURE_VENDOR_FIRST + 10)
+                        .all()
+                        .build()));
+        builder2.addDisplayAreaGroupHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(
+                mGroupRoot1)
+                .setTaskDisplayAreas(Lists.newArrayList(mTda1))
+                .addFeature(new Feature.Builder(mPolicy, "feature2", FEATURE_VENDOR_FIRST + 10)
+                        .all()
+                        .build()));
+
+        builder2.build(mWms);
+    }
+
+    @Test
+    public void testBuilder_idsNotGreaterThanFeatureVendorLast() {
+        // Root id should not be greater than FEATURE_VENDOR_LAST.
+        final DisplayAreaPolicyBuilder builder1 = new DisplayAreaPolicyBuilder();
+        final RootDisplayArea root = new SurfacelessDisplayAreaRoot(mWms, "testRoot",
+                FEATURE_VENDOR_LAST + 1);
+        builder1.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(root)
+                .setImeContainer(mImeContainer)
+                .setTaskDisplayAreas(mTaskDisplayAreaList));
+
+        assertThrows(IllegalStateException.class, () -> builder1.build(mWms));
+
+        // TDA id should not be greater than FEATURE_VENDOR_LAST.
+        final DisplayAreaPolicyBuilder builder2 = new DisplayAreaPolicyBuilder();
+        builder2.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(root)
+                .setImeContainer(mImeContainer)
+                .setTaskDisplayAreas(Lists.newArrayList(
+                        mDefaultTaskDisplayArea,
+                        new TaskDisplayArea(mDisplayContent, mWms, "testTda",
+                                FEATURE_VENDOR_LAST + 1))));
+
+        assertThrows(IllegalStateException.class, () -> builder2.build(mWms));
+
+        // Feature id should not be greater than FEATURE_VENDOR_LAST.
+        final DisplayAreaPolicyBuilder builder3 = new DisplayAreaPolicyBuilder();
+        builder3.setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+                .setImeContainer(mImeContainer)
+                .setTaskDisplayAreas(mTaskDisplayAreaList)
+                .addFeature(new Feature.Builder(mPolicy, "testFeature", FEATURE_VENDOR_LAST + 1)
+                        .all()
+                        .build()));
+
+        assertThrows(IllegalStateException.class, () -> builder3.build(mWms));
+    }
+
+    @Test
     public void testBuilder_displayAreaGroup_attachDisplayAreas() {
         final DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder()
                 .setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
@@ -449,8 +586,8 @@
                         .setTaskDisplayAreas(mTaskDisplayAreaList))
                 .addDisplayAreaGroupHierarchy(hierarchy1)
                 .addDisplayAreaGroupHierarchy(hierarchy2)
-                .setSelectRootForWindowFunc((token, options) -> {
-                    if (token.windowType == TYPE_STATUS_BAR) {
+                .setSelectRootForWindowFunc((type, options) -> {
+                    if (type == TYPE_STATUS_BAR) {
                         return mGroupRoot1;
                     }
                     return mGroupRoot2;
@@ -604,10 +741,9 @@
     }
 
     private WindowToken tokenOfType(int type) {
-        WindowToken m = mock(WindowToken.class);
-        when(m.getWindowLayerFromType()).thenReturn(
-                mPolicy.getWindowLayerFromTypeLw(type, false /* canAddInternalSystemWindow */));
-        return m;
+        WindowToken token = new WindowToken(mWms, new Binder(), type, false /* persistOnEmpty */,
+                mDisplayContent, false /* ownerCanManageAppTokens */);
+        return token;
     }
 
     private static void assertMatchLayerOrder(List<DisplayArea<?>> actualOrder,
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
index 025c5a6..6f5a874 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
@@ -458,8 +458,7 @@
 
     @Test
     public void testSetIgnoreOrientationRequest_notCallSuperOnDescendantOrientationChanged() {
-        final TaskDisplayArea tda =
-                mDisplayContent.getDefaultTaskDisplayArea();
+        final TaskDisplayArea tda = mDisplayContent.getDefaultTaskDisplayArea();
         final Task stack =
                 new TaskBuilder(mSupervisor).setOnTop(!ON_TOP).setCreateActivity(true).build();
         final ActivityRecord activity = stack.getTopNonFinishingActivity();
@@ -478,6 +477,27 @@
         verify(mDisplayContent).onDescendantOrientationChanged(any());
     }
 
+    @Test
+    public void testSetIgnoreOrientationRequest_updateOrientationRequestingTaskDisplayArea() {
+        final TaskDisplayArea tda = mDisplayContent.getDefaultTaskDisplayArea();
+        final Task stack =
+                new TaskBuilder(mSupervisor).setOnTop(!ON_TOP).setCreateActivity(true).build();
+        final ActivityRecord activity = stack.getTopNonFinishingActivity();
+
+        mDisplayContent.setFocusedApp(activity);
+        assertThat(mDisplayContent.getOrientationRequestingTaskDisplayArea()).isEqualTo(tda);
+
+        // TDA is no longer handling orientation request, clear the last focused TDA.
+        tda.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+        assertThat(mDisplayContent.getOrientationRequestingTaskDisplayArea()).isNull();
+
+        // TDA now handles orientation request, update last focused TDA based on the focused app.
+        tda.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
+
+        assertThat(mDisplayContent.getOrientationRequestingTaskDisplayArea()).isEqualTo(tda);
+    }
+
     private static class TestDisplayArea<T extends WindowContainer> extends DisplayArea<T> {
         private TestDisplayArea(WindowManagerService wms, Rect bounds) {
             super(wms, ANY, "half display area");
diff --git a/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
new file mode 100644
index 0000000..eebc207
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/DualDisplayAreaGroupPolicyTest.java
@@ -0,0 +1,390 @@
+/*
+ * 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.wm;
+
+import static android.content.ActivityInfoProto.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.view.Surface.ROTATION_90;
+import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
+import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
+import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
+import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.wm.SizeCompatTests.prepareUnresizable;
+import static com.android.server.wm.SizeCompatTests.rotateDisplay;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+import android.view.Display;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for the Dual DisplayAreaGroup device behavior.
+ *
+ * Build/Install/Run:
+ *  atest WmTests:DualDisplayAreaGroupPolicyTest
+ */
+@SmallTest
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class DualDisplayAreaGroupPolicyTest extends WindowTestsBase {
+    private static final int FEATURE_FIRST_ROOT = FEATURE_VENDOR_FIRST;
+    private static final int FEATURE_FIRST_TASK_CONTAINER = FEATURE_DEFAULT_TASK_CONTAINER;
+    private static final int FEATURE_SECOND_ROOT = FEATURE_VENDOR_FIRST + 1;
+    private static final int FEATURE_SECOND_TASK_CONTAINER = FEATURE_VENDOR_FIRST + 2;
+
+    private DualDisplayContent mDisplay;
+    private DisplayAreaGroup mFirstRoot;
+    private DisplayAreaGroup mSecondRoot;
+    private TaskDisplayArea mFirstTda;
+    private TaskDisplayArea mSecondTda;
+    private Task mFirstTask;
+    private Task mSecondTask;
+    private ActivityRecord mFirstActivity;
+    private ActivityRecord mSecondActivity;
+
+    @Before
+    public void setUp() {
+        // Let the Display to be created with the DualDisplay policy.
+        final DisplayAreaPolicy.Provider policyProvider = new DualDisplayTestPolicyProvider();
+        doReturn(policyProvider).when(mWm).getDisplayAreaPolicyProvider();
+
+        // Display: 1920x1200 (landscape). First and second display are both 860x1200 (portrait).
+        mDisplay = (DualDisplayContent) new DualDisplayContent.Builder(mAtm, 1920, 1200).build();
+        mFirstRoot = mDisplay.mFirstRoot;
+        mSecondRoot = mDisplay.mSecondRoot;
+        mFirstTda = mDisplay.getTaskDisplayArea(FEATURE_FIRST_TASK_CONTAINER);
+        mSecondTda = mDisplay.getTaskDisplayArea(FEATURE_SECOND_TASK_CONTAINER);
+        mFirstTask = new TaskBuilder(mSupervisor)
+                .setTaskDisplayArea(mFirstTda)
+                .setCreateActivity(true)
+                .build()
+                .getBottomMostTask();
+        mSecondTask = new TaskBuilder(mSupervisor)
+                .setTaskDisplayArea(mSecondTda)
+                .setCreateActivity(true)
+                .build()
+                .getBottomMostTask();
+        mFirstActivity = mFirstTask.getTopNonFinishingActivity();
+        mSecondActivity = mSecondTask.getTopNonFinishingActivity();
+
+        spyOn(mDisplay);
+        spyOn(mFirstRoot);
+        spyOn(mSecondRoot);
+    }
+
+    @Test
+    public void testNotIgnoreOrientationRequest_differentOrientationFromDisplay_reversesRequest() {
+        mFirstRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
+        mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
+
+        prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_LANDSCAPE);
+
+        assertThat(mDisplay.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_PORTRAIT);
+        assertThat(mFirstActivity.getConfiguration().orientation).isEqualTo(ORIENTATION_LANDSCAPE);
+
+        prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_PORTRAIT);
+
+        assertThat(mDisplay.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE);
+        assertThat(mFirstActivity.getConfiguration().orientation).isEqualTo(ORIENTATION_PORTRAIT);
+    }
+
+    @Test
+    public void testNotIgnoreOrientationRequest_onlyRespectsFocusedTaskDisplayArea() {
+        mFirstRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
+        mSecondRoot.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
+        mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
+
+        // Second TDA is not focused, so Display won't get the request
+        prepareUnresizable(mSecondActivity, SCREEN_ORIENTATION_LANDSCAPE);
+
+        assertThat(mDisplay.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSPECIFIED);
+
+        // First TDA is focused, so Display gets the request
+        prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_LANDSCAPE);
+
+        assertThat(mDisplay.getLastOrientation()).isEqualTo(SCREEN_ORIENTATION_PORTRAIT);
+    }
+
+    @Test
+    public void testIgnoreOrientationRequest_displayDoesNotReceiveOrientationChange() {
+        mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
+
+        prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_LANDSCAPE);
+
+        verify(mFirstRoot).onDescendantOrientationChanged(any());
+        verify(mDisplay, never()).onDescendantOrientationChanged(any());
+    }
+
+    @Test
+    public void testLaunchPortraitApp_fillsDisplayAreaGroup() {
+        mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
+
+        prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_PORTRAIT);
+        final Rect dagBounds = new Rect(mFirstRoot.getBounds());
+        final Rect taskBounds = new Rect(mFirstTask.getBounds());
+        final Rect activityBounds = new Rect(mFirstActivity.getBounds());
+
+        // DAG is portrait (860x1200), so Task and Activity fill DAG.
+        assertThat(mFirstTask.isTaskLetterboxed()).isFalse();
+        assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
+        assertThat(taskBounds).isEqualTo(dagBounds);
+        assertThat(activityBounds).isEqualTo(taskBounds);
+    }
+
+    @Test
+    public void testLaunchPortraitApp_sizeCompatAfterRotation() {
+        mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
+
+        prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_PORTRAIT);
+        final Rect dagBounds = new Rect(mFirstRoot.getBounds());
+        final Rect activityBounds = new Rect(mFirstActivity.getBounds());
+
+        rotateDisplay(mDisplay, ROTATION_90);
+        final Rect newDagBounds = new Rect(mFirstRoot.getBounds());
+        final Rect newTaskBounds = new Rect(mFirstTask.getBounds());
+        final Rect activitySizeCompatBounds = new Rect(mFirstActivity.getBounds());
+        final Rect activityConfigBounds =
+                new Rect(mFirstActivity.getConfiguration().windowConfiguration.getBounds());
+
+        // DAG is landscape (1200x860), Task fills parent
+        assertThat(mFirstTask.isTaskLetterboxed()).isFalse();
+        assertThat(mFirstActivity.inSizeCompatMode()).isTrue();
+        assertThat(newDagBounds.width()).isEqualTo(dagBounds.height());
+        assertThat(newDagBounds.height()).isEqualTo(dagBounds.width());
+        assertThat(newTaskBounds).isEqualTo(newDagBounds);
+
+        // Activity config bounds is unchanged, size compat bounds is (860x[860x860/1200=616])
+        assertThat(mFirstActivity.getSizeCompatScale()).isLessThan(1f);
+        assertThat(activityConfigBounds.width()).isEqualTo(activityBounds.width());
+        assertThat(activityConfigBounds.height()).isEqualTo(activityBounds.height());
+        assertThat(activitySizeCompatBounds.height()).isEqualTo(newTaskBounds.height());
+        assertThat(activitySizeCompatBounds.width()).isEqualTo(
+                newTaskBounds.height() * newTaskBounds.height() / newTaskBounds.width());
+    }
+
+    @Test
+    public void testLaunchLandscapeApp_taskIsLetterboxInDisplayAreaGroup() {
+        mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
+
+        prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_LANDSCAPE);
+        final Rect dagBounds = new Rect(mFirstRoot.getBounds());
+        final Rect taskBounds = new Rect(mFirstTask.getBounds());
+        final Rect activityBounds = new Rect(mFirstActivity.getBounds());
+
+        // DAG is portrait (860x1200), so Task is letterbox (860x[860x860/1200=616])
+        assertThat(mFirstTask.isTaskLetterboxed()).isTrue();
+        assertThat(mFirstActivity.inSizeCompatMode()).isFalse();
+        assertThat(taskBounds.width()).isEqualTo(dagBounds.width());
+        assertThat(taskBounds.height())
+                .isEqualTo(dagBounds.width() * dagBounds.width() / dagBounds.height());
+        assertThat(activityBounds).isEqualTo(taskBounds);
+    }
+
+    @Test
+    public void testLaunchLandscapeApp_taskLetterboxBecomesActivityLetterboxAfterRotation() {
+        mFirstRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        mSecondRoot.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        mDisplay.onLastFocusedTaskDisplayAreaChanged(mFirstTda);
+
+        prepareUnresizable(mFirstActivity, SCREEN_ORIENTATION_LANDSCAPE);
+        final Rect dagBounds = new Rect(mFirstRoot.getBounds());
+        final Rect activityBounds = new Rect(mFirstActivity.getBounds());
+
+        rotateDisplay(mDisplay, ROTATION_90);
+        final Rect newDagBounds = new Rect(mFirstRoot.getBounds());
+        final Rect newTaskBounds = new Rect(mFirstTask.getBounds());
+        final Rect newActivityBounds = new Rect(mFirstActivity.getBounds());
+
+        // DAG is landscape (1200x860), Task fills parent
+        // Task letterbox size
+        assertThat(mFirstTask.isTaskLetterboxed()).isFalse();
+        assertThat(mFirstActivity.inSizeCompatMode()).isTrue();
+        assertThat(newDagBounds.width()).isEqualTo(dagBounds.height());
+        assertThat(newDagBounds.height()).isEqualTo(dagBounds.width());
+        assertThat(newTaskBounds).isEqualTo(newDagBounds);
+
+        // Because we don't scale up, there is no size compat bounds and app bounds is the same as
+        // the previous bounds.
+        assertThat(mFirstActivity.hasSizeCompatBounds()).isFalse();
+        assertThat(newActivityBounds.width()).isEqualTo(activityBounds.width());
+        assertThat(newActivityBounds.height()).isEqualTo(activityBounds.height());
+    }
+
+    /** Display with two {@link DisplayAreaGroup}. Each of them take half of the screen. */
+    private static class DualDisplayContent extends TestDisplayContent {
+        final DisplayAreaGroup mFirstRoot;
+        final DisplayAreaGroup mSecondRoot;
+        final Rect mLastDisplayBounds;
+
+        /** Please use the {@link Builder} to create. */
+        DualDisplayContent(RootWindowContainer rootWindowContainer,
+                Display display) {
+            super(rootWindowContainer, display);
+
+            mFirstRoot = getGroupRoot(FEATURE_FIRST_ROOT);
+            mSecondRoot = getGroupRoot(FEATURE_SECOND_ROOT);
+            mLastDisplayBounds = new Rect(getBounds());
+            updateDisplayAreaGroupBounds();
+        }
+
+        DisplayAreaGroup getGroupRoot(int rootFeatureId) {
+            DisplayArea da = getDisplayArea(rootFeatureId);
+            assertThat(da).isInstanceOf(DisplayAreaGroup.class);
+            return (DisplayAreaGroup) da;
+        }
+
+        TaskDisplayArea getTaskDisplayArea(int tdaFeatureId) {
+            DisplayArea da = getDisplayArea(tdaFeatureId);
+            assertThat(da).isInstanceOf(TaskDisplayArea.class);
+            return (TaskDisplayArea) da;
+        }
+
+        DisplayArea getDisplayArea(int featureId) {
+            final DisplayArea displayArea =
+                    getItemFromDisplayAreas(da -> da.mFeatureId == featureId ? da : null);
+            assertThat(displayArea).isNotNull();
+            return displayArea;
+        }
+
+        @Override
+        public void onConfigurationChanged(Configuration newParentConfig) {
+            super.onConfigurationChanged(newParentConfig);
+
+            final Rect curBounds = getBounds();
+            if (mLastDisplayBounds != null && !mLastDisplayBounds.equals(curBounds)) {
+                mLastDisplayBounds.set(curBounds);
+                updateDisplayAreaGroupBounds();
+            }
+        }
+
+        /** Updates first and second {@link DisplayAreaGroup} to take half of the screen. */
+        private void updateDisplayAreaGroupBounds() {
+            if (mFirstRoot == null || mSecondRoot == null) {
+                return;
+            }
+
+            final Rect bounds = mLastDisplayBounds;
+            Rect groupBounds1, groupBounds2;
+            if (bounds.width() >= bounds.height()) {
+                groupBounds1 = new Rect(bounds.left, bounds.top,
+                        (bounds.right + bounds.left) / 2, bounds.bottom);
+
+                groupBounds2 = new Rect((bounds.right + bounds.left) / 2, bounds.top,
+                        bounds.right, bounds.bottom);
+            } else {
+                groupBounds1 = new Rect(bounds.left, bounds.top,
+                        bounds.right, (bounds.top + bounds.bottom) / 2);
+
+                groupBounds2 = new Rect(bounds.left,
+                        (bounds.top + bounds.bottom) / 2, bounds.right, bounds.bottom);
+            }
+            mFirstRoot.setBounds(groupBounds1);
+            mSecondRoot.setBounds(groupBounds2);
+        }
+
+        static class Builder extends TestDisplayContent.Builder {
+
+            Builder(ActivityTaskManagerService service, int width, int height) {
+                super(service, width, height);
+            }
+
+            @Override
+            TestDisplayContent createInternal(Display display) {
+                return new DualDisplayContent(mService.mRootWindowContainer, display);
+            }
+        }
+    }
+
+    /** Policy to create a dual {@link DisplayAreaGroup} policy in test. */
+    private static class DualDisplayTestPolicyProvider implements DisplayAreaPolicy.Provider {
+
+        @Override
+        public DisplayAreaPolicy instantiate(WindowManagerService wmService, DisplayContent content,
+                RootDisplayArea root, DisplayArea.Tokens imeContainer) {
+            // Root
+            // Include FEATURE_WINDOWED_MAGNIFICATION because it will be used as the screen rotation
+            // layer
+            DisplayAreaPolicyBuilder.HierarchyBuilder rootHierarchy =
+                    new DisplayAreaPolicyBuilder.HierarchyBuilder(root)
+                            .setImeContainer(imeContainer)
+                            .addFeature(new DisplayAreaPolicyBuilder.Feature.Builder(
+                                    wmService.mPolicy,
+                                    "WindowedMagnification", FEATURE_WINDOWED_MAGNIFICATION)
+                                    .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
+                                    .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
+                                    .setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
+                                    .build());
+
+            // First
+            final RootDisplayArea firstRoot = new DisplayAreaGroup(wmService, "FirstRoot",
+                    FEATURE_FIRST_ROOT);
+            final TaskDisplayArea firstTaskDisplayArea = new TaskDisplayArea(content, wmService,
+                    "FirstTaskDisplayArea", FEATURE_FIRST_TASK_CONTAINER);
+            final List<TaskDisplayArea> firstTdaList = new ArrayList<>();
+            firstTdaList.add(firstTaskDisplayArea);
+            DisplayAreaPolicyBuilder.HierarchyBuilder firstHierarchy =
+                    new DisplayAreaPolicyBuilder.HierarchyBuilder(firstRoot)
+                            .setTaskDisplayAreas(firstTdaList);
+
+            // Second
+            final RootDisplayArea secondRoot = new DisplayAreaGroup(wmService, "SecondRoot",
+                    FEATURE_SECOND_ROOT);
+            final TaskDisplayArea secondTaskDisplayArea = new TaskDisplayArea(content, wmService,
+                    "SecondTaskDisplayArea", FEATURE_SECOND_TASK_CONTAINER);
+            final List<TaskDisplayArea> secondTdaList = new ArrayList<>();
+            secondTdaList.add(secondTaskDisplayArea);
+            DisplayAreaPolicyBuilder.HierarchyBuilder secondHierarchy =
+                    new DisplayAreaPolicyBuilder.HierarchyBuilder(secondRoot)
+                            .setTaskDisplayAreas(secondTdaList);
+
+            return new DisplayAreaPolicyBuilder()
+                    .setRootHierarchy(rootHierarchy)
+                    .addDisplayAreaGroupHierarchy(firstHierarchy)
+                    .addDisplayAreaGroupHierarchy(secondHierarchy)
+                    .build(wmService);
+        }
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java
index 91cfd4e..59d195b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java
@@ -18,7 +18,9 @@
 
 import static android.view.InsetsState.ITYPE_IME;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import android.graphics.PixelFormat;
@@ -64,4 +66,22 @@
         mImeProvider.scheduleShowImePostLayout(target);
         assertTrue(mImeProvider.isImeTargetFromDisplayContentAndImeSame());
     }
+
+    @Test
+    public void testIsImeShowing() {
+        WindowState ime = createWindow(null, TYPE_INPUT_METHOD, "ime");
+        makeWindowVisibleAndDrawn(ime);
+        mImeProvider.setWindow(ime, null, null);
+
+        WindowState target = createWindow(null, TYPE_APPLICATION, "app");
+        mDisplayContent.mInputMethodTarget = target;
+        mDisplayContent.mInputMethodControlTarget = target;
+
+        mImeProvider.scheduleShowImePostLayout(target);
+        assertFalse(mImeProvider.isImeShowing());
+        mImeProvider.checkShowImePostLayout();
+        assertTrue(mImeProvider.isImeShowing());
+        mImeProvider.setImeShowing(false);
+        assertFalse(mImeProvider.isImeShowing());
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 5c39bd0..6dd23ba 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -423,6 +423,7 @@
 
         final WindowState homeWindow = createWindow(null, TYPE_BASE_APPLICATION, homeActivity,
                 "homeWindow");
+        makeWindowVisible(homeWindow);
         homeActivity.addWindow(homeWindow);
         homeWindow.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index da00198..dd6e490 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -92,7 +92,7 @@
         mActivity.mVisibleRequested = true;
         mActivity.setSavedState(null /* savedState */);
         mActivity.setState(Task.ActivityState.RESUMED, "testRestart");
-        prepareUnresizable(1.5f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED);
+        prepareUnresizable(mActivity, 1.5f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED);
 
         final Rect originalOverrideBounds = new Rect(mActivity.getBounds());
         resizeDisplay(mTask.mDisplayContent, 600, 1200);
@@ -115,7 +115,7 @@
         // Put app window into freeform and then make it a compat app.
         final Rect bounds = new Rect(100, 100, 400, 600);
         mTask.setBounds(bounds);
-        prepareUnresizable(-1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
+        prepareUnresizable(mActivity, -1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
         assertEquals(bounds, mActivity.getBounds());
 
         // The activity should be able to accept negative x position [-150, 100 - 150, 600].
@@ -145,7 +145,7 @@
         final Rect displayBounds = mActivity.mDisplayContent.getWindowConfiguration().getBounds();
         final float aspectRatio = 1.2f;
         mActivity.info.minAspectRatio = mActivity.info.maxAspectRatio = aspectRatio;
-        prepareUnresizable(-1f, SCREEN_ORIENTATION_UNSPECIFIED);
+        prepareUnresizable(mActivity, -1f, SCREEN_ORIENTATION_UNSPECIFIED);
         final Rect appBounds = mActivity.getWindowConfiguration().getAppBounds();
 
         // The parent configuration doesn't change since the first resolved configuration, so the
@@ -205,7 +205,7 @@
     @Test
     public void testFixedScreenBoundsWhenDisplaySizeChanged() {
         setUpDisplaySizeWithApp(1000, 2500);
-        prepareUnresizable(-1f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
+        prepareUnresizable(mActivity, -1f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
         assertFitted();
 
         final Rect origBounds = new Rect(mActivity.getBounds());
@@ -262,7 +262,7 @@
         setUpDisplaySizeWithApp(displayWidth, 1000);
 
         final float maxAspect = 1.5f;
-        prepareUnresizable(maxAspect, SCREEN_ORIENTATION_LANDSCAPE);
+        prepareUnresizable(mActivity, maxAspect, SCREEN_ORIENTATION_LANDSCAPE);
         assertFitted();
 
         final Rect bounds = mActivity.getBounds();
@@ -286,7 +286,7 @@
     public void testAspectRatioMatchParentBoundsAndImeAttachable() {
         setUpApp(new TestDisplayContent.Builder(mAtm, 1000, 2000)
                 .setSystemDecorations(true).build());
-        prepareUnresizable(2f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED);
+        prepareUnresizable(mActivity, 2f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED);
         assertFitted();
 
         rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
@@ -307,7 +307,7 @@
     @Test
     public void testMoveToDifferentOrientDisplay() {
         setUpDisplaySizeWithApp(1000, 2500);
-        prepareUnresizable(-1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
+        prepareUnresizable(mActivity, -1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
         assertFitted();
 
         final Rect configBounds = mActivity.getWindowConfiguration().getBounds();
@@ -352,7 +352,7 @@
         setUpApp(new TestDisplayContent.Builder(mAtm, 1000, 2500)
                 .setNotch(notchHeight).build());
         // Bounds=[0, 0 - 1000, 1460], AppBounds=[0, 60 - 1000, 1460].
-        prepareUnresizable(1.4f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
+        prepareUnresizable(mActivity, 1.4f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
 
         final Rect currentBounds = mActivity.getWindowConfiguration().getBounds();
         final Rect appBounds = mActivity.getWindowConfiguration().getAppBounds();
@@ -381,7 +381,7 @@
         setUpDisplaySizeWithApp(1000, 2500);
 
         final float maxAspect = 1.4f;
-        prepareUnresizable(maxAspect, SCREEN_ORIENTATION_PORTRAIT);
+        prepareUnresizable(mActivity, maxAspect, SCREEN_ORIENTATION_PORTRAIT);
         // The display aspect ratio 2.5 > 1.4 (max of activity), so the size is fitted.
         assertFitted();
 
@@ -415,7 +415,7 @@
         Configuration c = new Configuration(mTask.getRequestedOverrideConfiguration());
         c.screenLayout = fixedScreenLayout | Configuration.SCREENLAYOUT_LAYOUTDIR_LTR;
         mTask.onRequestedOverrideConfigurationChanged(c);
-        prepareUnresizable(1.5f, SCREEN_ORIENTATION_UNSPECIFIED);
+        prepareUnresizable(mActivity, 1.5f, SCREEN_ORIENTATION_UNSPECIFIED);
 
         // The initial configuration should inherit from parent.
         assertEquals(fixedScreenLayout | Configuration.SCREENLAYOUT_LAYOUTDIR_LTR,
@@ -433,7 +433,7 @@
     @Test
     public void testResetNonVisibleActivity() {
         setUpDisplaySizeWithApp(1000, 2500);
-        prepareUnresizable(1.5f, SCREEN_ORIENTATION_UNSPECIFIED);
+        prepareUnresizable(mActivity, 1.5f, SCREEN_ORIENTATION_UNSPECIFIED);
         final DisplayContent display = mTask.mDisplayContent;
         // Resize the display so the activity is in size compatibility mode.
         resizeDisplay(display, 900, 1800);
@@ -472,7 +472,7 @@
         setUpDisplaySizeWithApp(1000, 2000);
         ActivityRecord activity = mActivity;
         activity.setState(Task.ActivityState.RESUMED, "testHandleActivitySizeCompatMode");
-        prepareUnresizable(-1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
+        prepareUnresizable(mActivity, -1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT);
         assertFitted();
 
         final ArrayList<IBinder> compatTokens = new ArrayList<>();
@@ -545,7 +545,7 @@
         mActivity.mDisplayContent.prepareAppTransition(WindowManager.TRANSIT_OPEN);
         mActivity.mDisplayContent.mOpeningApps.add(mActivity);
         final float maxAspect = 1.8f;
-        prepareUnresizable(maxAspect, SCREEN_ORIENTATION_LANDSCAPE);
+        prepareUnresizable(mActivity, maxAspect, SCREEN_ORIENTATION_LANDSCAPE);
 
         assertFitted();
         assertTrue(mActivity.isFixedRotationTransforming());
@@ -576,7 +576,7 @@
         assertFalse(statusBarController.isTransparentAllowed(w));
 
         // Make the activity fill the display.
-        prepareUnresizable(10 /* maxAspect */, SCREEN_ORIENTATION_LANDSCAPE);
+        prepareUnresizable(mActivity, 10 /* maxAspect */, SCREEN_ORIENTATION_LANDSCAPE);
         w.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN;
         // Refresh the letterbox.
         mActivity.mRootWindowContainer.performSurfacePlacement();
@@ -593,11 +593,11 @@
         mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
 
         // Portrait fixed app without max aspect.
-        prepareUnresizable(0, SCREEN_ORIENTATION_PORTRAIT);
+        prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
 
-        final Rect displayBounds = mActivity.mDisplayContent.getBounds();
-        final Rect taskBounds = mTask.getBounds();
-        final Rect activityBounds = mActivity.getBounds();
+        final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds());
+        final Rect taskBounds = new Rect(mTask.getBounds());
+        final Rect activityBounds = new Rect(mActivity.getBounds());
 
         // Display shouldn't be rotated.
         assertEquals(SCREEN_ORIENTATION_UNSPECIFIED,
@@ -622,15 +622,15 @@
         mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
 
         // Portrait fixed app without max aspect.
-        prepareUnresizable(0, SCREEN_ORIENTATION_PORTRAIT);
+        prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
 
-        final Rect activityBounds = mActivity.getBounds();
+        final Rect activityBounds = new Rect(mActivity.getBounds());
 
         // Rotate display to portrait.
         rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
 
-        final Rect displayBounds = mActivity.mDisplayContent.getBounds();
-        final Rect newActivityBounds = mActivity.getBounds();
+        final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds());
+        final Rect newActivityBounds = new Rect(mActivity.getBounds());
         assertTrue(displayBounds.width() < displayBounds.height());
 
         // App should be in size compat.
@@ -647,10 +647,10 @@
         mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
 
         // Portrait fixed app without max aspect.
-        prepareUnresizable(0, SCREEN_ORIENTATION_PORTRAIT);
+        prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
 
-        Rect displayBounds = mActivity.mDisplayContent.getBounds();
-        Rect activityBounds = mActivity.getBounds();
+        Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds());
+        Rect activityBounds = new Rect(mActivity.getBounds());
 
         // App should launch in fullscreen.
         assertFalse(mTask.isTaskLetterboxed());
@@ -660,8 +660,8 @@
         // Rotate display to landscape.
         rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
 
-        displayBounds = mActivity.mDisplayContent.getBounds();
-        activityBounds = mActivity.getBounds();
+        displayBounds = new Rect(mActivity.mDisplayContent.getBounds());
+        activityBounds = new Rect(mActivity.getBounds());
         assertTrue(displayBounds.width() > displayBounds.height());
 
         // App should be in size compat.
@@ -682,7 +682,7 @@
         display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
 
         // Portrait fixed app without max aspect.
-        prepareUnresizable(0, SCREEN_ORIENTATION_PORTRAIT);
+        prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
 
         assertTrue(mTask.isTaskLetterboxed());
         assertFalse(mActivity.inSizeCompatMode());
@@ -701,9 +701,9 @@
         verify(mTask).onDescendantOrientationChanged(same(newActivity));
         verify(mTask).computeFullscreenBounds(any(), any(), any(), anyInt());
 
-        final Rect displayBounds = display.getBounds();
-        final Rect taskBounds = mTask.getBounds();
-        final Rect newActivityBounds = newActivity.getBounds();
+        final Rect displayBounds = new Rect(display.getBounds());
+        final Rect taskBounds = new Rect(mTask.getBounds());
+        final Rect newActivityBounds = new Rect(newActivity.getBounds());
 
         // Task and app bounds should be 700x1400 with the ratio as the display.
         assertTrue(mTask.isTaskLetterboxed());
@@ -722,7 +722,7 @@
         display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
 
         // Portrait fixed app without max aspect.
-        prepareUnresizable(0, SCREEN_ORIENTATION_PORTRAIT);
+        prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
 
         assertTrue(mTask.isTaskLetterboxed());
         assertFalse(mActivity.inSizeCompatMode());
@@ -742,9 +742,9 @@
         verify(mTask).onDescendantOrientationChanged(same(newActivity));
         verify(mTask).computeFullscreenBounds(any(), any(), any(), anyInt());
 
-        final Rect displayBounds = display.getBounds();
-        final Rect taskBounds = mTask.getBounds();
-        final Rect newActivityBounds = newActivity.getBounds();
+        final Rect displayBounds = new Rect(display.getBounds());
+        final Rect taskBounds = new Rect(mTask.getBounds());
+        final Rect newActivityBounds = new Rect(newActivity.getBounds());
 
         // Task bounds should be (1400 / 1.3 = 1076)x1400 with the app requested ratio.
         assertTrue(mTask.isTaskLetterboxed());
@@ -765,7 +765,7 @@
         display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
 
         // Portrait fixed app.
-        prepareUnresizable(0, SCREEN_ORIENTATION_PORTRAIT);
+        prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT);
         clearInvocations(mActivity);
 
         assertTrue(mTask.isTaskLetterboxed());
@@ -829,26 +829,31 @@
                 displayContent.getConfiguration().uiMode);
     }
 
+    static void prepareUnresizable(ActivityRecord activity, int screenOrientation) {
+        prepareUnresizable(activity, -1 /* maxAspect */, screenOrientation);
+    }
+
     /**
-     * Setup {@link #mActivity} as a size-compat-mode-able activity with fixed aspect and/or
+     * Setups {@link #mActivity} as a size-compat-mode-able activity with fixed aspect and/or
      * orientation.
      */
-    private void prepareUnresizable(float maxAspect, int screenOrientation) {
-        mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
-        mActivity.mVisibleRequested = true;
+    static void prepareUnresizable(ActivityRecord activity, float maxAspect,
+            int screenOrientation) {
+        activity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+        activity.mVisibleRequested = true;
         if (maxAspect >= 0) {
-            mActivity.info.maxAspectRatio = maxAspect;
+            activity.info.maxAspectRatio = maxAspect;
         }
         if (screenOrientation != SCREEN_ORIENTATION_UNSPECIFIED) {
-            mActivity.info.screenOrientation = screenOrientation;
-            mActivity.setRequestedOrientation(screenOrientation);
+            activity.info.screenOrientation = screenOrientation;
+            activity.setRequestedOrientation(screenOrientation);
         }
         // Make sure to use the provided configuration to construct the size compat fields.
-        mActivity.clearSizeCompatMode();
-        mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
+        activity.clearSizeCompatMode();
+        activity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
         // Make sure the display configuration reflects the change of activity.
-        if (mActivity.mDisplayContent.updateOrientation()) {
-            mActivity.mDisplayContent.sendNewConfiguration();
+        if (activity.mDisplayContent.updateOrientation()) {
+            activity.mDisplayContent.sendNewConfiguration();
         }
     }
 
@@ -869,7 +874,7 @@
         assertFalse(mActivity.hasSizeCompatBounds());
     }
 
-    private static Configuration rotateDisplay(DisplayContent display, int rotation) {
+    static Configuration rotateDisplay(DisplayContent display, int rotation) {
         final Configuration c = new Configuration();
         display.getDisplayRotation().setRotation(rotation);
         display.computeScreenConfiguration(c);
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 83e3d22..e1bc90a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -325,7 +325,7 @@
         final TaskDisplayArea taskDisplayArea = display.getDefaultTaskDisplayArea();
 
         // Set the default focused TDA.
-        display.setLastFocusedTaskDisplayArea(taskDisplayArea);
+        display.onLastFocusedTaskDisplayAreaChanged(taskDisplayArea);
         spyOn(taskDisplayArea);
         final Task homeStack = taskDisplayArea.getRootTask(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
index d80f816..1c93e0f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
@@ -262,20 +262,50 @@
         // Activity on TDA1 is focused
         mDisplayContent.setFocusedApp(firstActivity);
 
-        assertThat(firstTaskDisplayArea.isLastFocused()).isTrue();
-        assertThat(secondTaskDisplayArea.isLastFocused()).isFalse();
+        assertThat(firstTaskDisplayArea.canSpecifyOrientation()).isTrue();
+        assertThat(secondTaskDisplayArea.canSpecifyOrientation()).isFalse();
 
         // No focused app, TDA1 is still recorded as last focused.
         mDisplayContent.setFocusedApp(null);
 
-        assertThat(firstTaskDisplayArea.isLastFocused()).isTrue();
-        assertThat(secondTaskDisplayArea.isLastFocused()).isFalse();
+        assertThat(firstTaskDisplayArea.canSpecifyOrientation()).isTrue();
+        assertThat(secondTaskDisplayArea.canSpecifyOrientation()).isFalse();
 
         // Activity on TDA2 is focused
         mDisplayContent.setFocusedApp(secondActivity);
 
-        assertThat(firstTaskDisplayArea.isLastFocused()).isFalse();
-        assertThat(secondTaskDisplayArea.isLastFocused()).isTrue();
+        assertThat(firstTaskDisplayArea.canSpecifyOrientation()).isFalse();
+        assertThat(secondTaskDisplayArea.canSpecifyOrientation()).isTrue();
+    }
+
+    @Test
+    public void testIsLastFocused_onlyCountIfTaskDisplayAreaHandlesOrientationRequest() {
+        final TaskDisplayArea firstTaskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
+        final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea(
+                mDisplayContent, mRootWindowContainer.mWmService, "TestTaskDisplayArea",
+                FEATURE_VENDOR_FIRST);
+        final Task firstStack = firstTaskDisplayArea.createRootTask(
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
+        final Task secondStack = secondTaskDisplayArea.createRootTask(
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
+        final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
+                .setTask(firstStack).build();
+        final ActivityRecord secondActivity = new ActivityBuilder(mAtm)
+                .setTask(secondStack).build();
+        firstTaskDisplayArea.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        secondTaskDisplayArea.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
+
+        // Activity on TDA1 is focused, but TDA1 doesn't respect orientation request
+        mDisplayContent.setFocusedApp(firstActivity);
+
+        assertThat(firstTaskDisplayArea.canSpecifyOrientation()).isFalse();
+        assertThat(secondTaskDisplayArea.canSpecifyOrientation()).isFalse();
+
+        // Activity on TDA2 is focused, and TDA2 respects orientation request
+        mDisplayContent.setFocusedApp(secondActivity);
+
+        assertThat(firstTaskDisplayArea.canSpecifyOrientation()).isFalse();
+        assertThat(secondTaskDisplayArea.canSpecifyOrientation()).isTrue();
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
index e95efe7..ae85ceb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
@@ -37,7 +37,8 @@
 
 class TestDisplayContent extends DisplayContent {
 
-    private TestDisplayContent(RootWindowContainer rootWindowContainer, Display display) {
+    /** Please use the {@link Builder} to create, visible for use in test builder overrides only. */
+    TestDisplayContent(RootWindowContainer rootWindowContainer, Display display) {
         super(display, rootWindowContainer);
         // Normally this comes from display-properties as exposed by WM. Without that, just
         // hard-code to FULLSCREEN for tests.
@@ -72,7 +73,7 @@
         private boolean mCanRotate = true;
         private int mWindowingMode = WINDOWING_MODE_FULLSCREEN;
         private int mPosition = POSITION_BOTTOM;
-        private final ActivityTaskManagerService mService;
+        protected final ActivityTaskManagerService mService;
         private boolean mSystemDecorations = false;
 
         Builder(ActivityTaskManagerService service, int width, int height) {
@@ -125,14 +126,16 @@
             mInfo.logicalDensityDpi = dpi;
             return this;
         }
+        TestDisplayContent createInternal(Display display) {
+            return new TestDisplayContent(mService.mRootWindowContainer, display);
+        }
         TestDisplayContent build() {
             SystemServicesTestRule.checkHoldsLock(mService.mGlobalLock);
 
             final int displayId = SystemServicesTestRule.sNextDisplayId++;
             final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
                     mInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
-            final TestDisplayContent newDisplay =
-                    new TestDisplayContent(mService.mRootWindowContainer, display);
+            final TestDisplayContent newDisplay = createInternal(display);
             // disable the normal system decorations
             final DisplayPolicy displayPolicy = newDisplay.getDisplayPolicy();
             spyOn(displayPolicy);
@@ -158,7 +161,7 @@
             mService.mRootWindowContainer.addChild(newDisplay, mPosition);
 
             // Set the default focused TDA.
-            newDisplay.setLastFocusedTaskDisplayArea(newDisplay.getDefaultTaskDisplayArea());
+            newDisplay.onLastFocusedTaskDisplayAreaChanged(newDisplay.getDefaultTaskDisplayArea());
 
             return newDisplay;
         }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index c4bcfdb..b0b8afd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -948,6 +948,36 @@
         assertFalse(act.isAnimating(PARENTS));
     }
 
+    @Test
+    public void testRegisterWindowContainerListener() {
+        final WindowContainer container = new WindowContainer(mWm);
+        container.mDisplayContent = mDisplayContent;
+        final TestWindowContainerListener listener = new TestWindowContainerListener();
+        Configuration config = container.getConfiguration();
+        Rect bounds = new Rect(0, 0, 10, 10);
+        config.windowConfiguration.setBounds(bounds);
+        config.densityDpi = 100;
+        container.onRequestedOverrideConfigurationChanged(config);
+        container.registerWindowContainerListener(listener);
+
+        assertEquals(mDisplayContent, listener.mDisplayContent);
+        assertEquals(bounds, listener.mConfiguration.windowConfiguration.getBounds());
+        assertEquals(100, listener.mConfiguration.densityDpi);
+
+        container.onDisplayChanged(mDefaultDisplay);
+        assertEquals(listener.mDisplayContent, mDefaultDisplay);
+
+        config = new Configuration();
+        bounds = new Rect(0, 0, 20, 20);
+        config.windowConfiguration.setBounds(bounds);
+        config.densityDpi = 200;
+
+        container.onRequestedOverrideConfigurationChanged(config);
+
+        assertEquals(bounds, listener.mConfiguration.windowConfiguration.getBounds());
+        assertEquals(200, listener.mConfiguration.densityDpi);
+    }
+
     /* Used so we can gain access to some protected members of the {@link WindowContainer} class */
     private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
         private final int mLayer;
@@ -1131,4 +1161,19 @@
             mSession.kill();
         }
     }
+
+    private static class TestWindowContainerListener implements WindowContainerListener {
+        private Configuration mConfiguration = new Configuration();
+        private DisplayContent mDisplayContent;
+
+        @Override
+        public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
+            mConfiguration.setTo(overrideConfiguration);
+        }
+
+        @Override
+        public void onDisplayChanged(DisplayContent dc) {
+            mDisplayContent = dc;
+        }
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java
new file mode 100644
index 0000000..67067ee
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java
@@ -0,0 +1,173 @@
+/*
+ * 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.wm;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.app.IWindowToken;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Build/Install/Run:
+ *  atest WmTests:WindowContextListenerControllerTests
+ */
+@SmallTest
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class WindowContextListenerControllerTests extends WindowTestsBase {
+    private WindowContextListenerController mController;
+
+    private static final int TEST_UID = 12345;
+    private static final int ANOTHER_UID = 1000;
+
+    private final IBinder mClientToken = new Binder();
+    private WindowContainer mContainer;
+
+    @Before
+    public void setUp() {
+        mController = new WindowContextListenerController();
+        mContainer = createTestWindowToken(TYPE_APPLICATION_OVERLAY, mDisplayContent);
+    }
+
+    @Test
+    public void testRegisterWindowContextListener() {
+        mController.registerWindowContainerListener(mClientToken, mContainer, -1);
+
+        assertEquals(1, mController.mListeners.size());
+
+        final IBinder clientToken = new Binder();
+        mController.registerWindowContainerListener(clientToken, mContainer, -1);
+
+        assertEquals(2, mController.mListeners.size());
+
+        final WindowContainer container = createTestWindowToken(TYPE_APPLICATION_OVERLAY,
+                mDefaultDisplay);
+        mController.registerWindowContainerListener(mClientToken, container, -1);
+
+        // The number of listeners doesn't increase since the listener just gets updated.
+        assertEquals(2, mController.mListeners.size());
+
+        WindowContextListenerController.WindowContextListenerImpl listener =
+                mController.mListeners.get(mClientToken);
+        assertEquals(container, listener.getWindowContainer());
+    }
+
+    @Test
+    public void testRegisterWindowContextListenerClientConfigPropagation() {
+        final TestWindowTokenClient clientToken = new TestWindowTokenClient();
+
+        final Configuration config1 = mContainer.getConfiguration();
+        final Rect bounds1 = new Rect(0, 0, 10, 10);
+        config1.windowConfiguration.setBounds(bounds1);
+        config1.densityDpi = 100;
+        mContainer.onRequestedOverrideConfigurationChanged(config1);
+
+        mController.registerWindowContainerListener(clientToken, mContainer, -1);
+
+        assertEquals(bounds1, clientToken.mConfiguration.windowConfiguration.getBounds());
+        assertEquals(config1.densityDpi, clientToken.mConfiguration.densityDpi);
+        assertEquals(mDisplayContent.mDisplayId, clientToken.mDisplayId);
+
+        // Update the WindowContainer.
+        final WindowContainer container = createTestWindowToken(TYPE_APPLICATION_OVERLAY,
+                mDefaultDisplay);
+        final Configuration config2 = container.getConfiguration();
+        final Rect bounds2 = new Rect(0, 0, 20, 20);
+        config2.windowConfiguration.setBounds(bounds2);
+        config2.densityDpi = 200;
+        container.onRequestedOverrideConfigurationChanged(config2);
+
+        mController.registerWindowContainerListener(clientToken, container, -1);
+
+        assertEquals(bounds2, clientToken.mConfiguration.windowConfiguration.getBounds());
+        assertEquals(config2.densityDpi, clientToken.mConfiguration.densityDpi);
+        assertEquals(DEFAULT_DISPLAY, clientToken.mDisplayId);
+
+        // Update the configuration of WindowContainer.
+        container.onRequestedOverrideConfigurationChanged(config1);
+
+        assertEquals(bounds1, clientToken.mConfiguration.windowConfiguration.getBounds());
+        assertEquals(config1.densityDpi, clientToken.mConfiguration.densityDpi);
+
+        // Update the display of WindowContainer.
+        container.onDisplayChanged(mDisplayContent);
+
+        assertEquals(mDisplayContent.mDisplayId, clientToken.mDisplayId);
+    }
+
+    @Test
+    public void testCanCallerRemoveListener_NullListener_ReturnFalse() {
+        assertFalse(mController.assertCallerCanRemoveListener(mClientToken,
+                true /* callerCanManagerAppTokens */, TEST_UID));
+    }
+
+    @Test
+    public void testCanCallerRemoveListener_CanManageAppTokens_ReturnTrue() {
+        mController.registerWindowContainerListener(mClientToken, mContainer, TEST_UID);
+
+        assertTrue(mController.assertCallerCanRemoveListener(mClientToken,
+                true /* callerCanManagerAppTokens */, ANOTHER_UID));
+    }
+
+    @Test
+    public void testCanCallerRemoveListener_SameUid_ReturnTrue() {
+        mController.registerWindowContainerListener(mClientToken, mContainer, TEST_UID);
+
+        assertTrue(mController.assertCallerCanRemoveListener(mClientToken,
+                false /* callerCanManagerAppTokens */, TEST_UID));
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testCanCallerRemoveListener_DifferentUid_ThrowException() {
+        mController.registerWindowContainerListener(mClientToken, mContainer, TEST_UID);
+
+        mController.assertCallerCanRemoveListener(mClientToken,
+                false /* callerCanManagerAppTokens */, ANOTHER_UID);
+    }
+
+    private class TestWindowTokenClient extends IWindowToken.Stub {
+        private Configuration mConfiguration;
+        private int mDisplayId;
+        private boolean mRemoved;
+
+        @Override
+        public void onConfigurationChanged(Configuration configuration, int displayId) {
+            mConfiguration = configuration;
+            mDisplayId = displayId;
+        }
+
+        @Override
+        public void onWindowTokenRemoved() {
+            mRemoved = true;
+        }
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index dba157e..f123bc1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -824,7 +824,8 @@
 
         final PictureInPictureParams p = new PictureInPictureParams.Builder()
                 .setAspectRatio(new Rational(1, 2)).build();
-        assertTrue(mWm.mAtmService.enterPictureInPictureMode(record.token, p));
+        assertTrue(mWm.mAtmService.mActivityClientController.enterPictureInPictureMode(
+                record.token, p));
         waitUntilHandlersIdle();
         assertNotNull(o.mInfo);
         assertNotNull(o.mInfo.pictureInPictureParams);
@@ -845,14 +846,15 @@
         final ActivityRecord record = makePipableActivity();
         final PictureInPictureParams p = new PictureInPictureParams.Builder()
                 .setAspectRatio(new Rational(1, 2)).build();
-        assertTrue(mWm.mAtmService.enterPictureInPictureMode(record.token, p));
+        assertTrue(mWm.mAtmService.mActivityClientController.enterPictureInPictureMode(
+                record.token, p));
         waitUntilHandlersIdle();
         assertNotNull(o.mInfo);
         assertNotNull(o.mInfo.pictureInPictureParams);
 
         final PictureInPictureParams p2 = new PictureInPictureParams.Builder()
                 .setAspectRatio(new Rational(3, 4)).build();
-        mWm.mAtmService.setPictureInPictureParams(record.token, p2);
+        mWm.mAtmService.mActivityClientController.setPictureInPictureParams(record.token, p2);
         waitUntilHandlersIdle();
         assertNotNull(o.mChangedInfo);
         assertNotNull(o.mChangedInfo.pictureInPictureParams);
@@ -920,7 +922,7 @@
         assertTrue(stack2.isOrganized());
 
         // Verify a back pressed does not call the organizer
-        mWm.mAtmService.onBackPressedOnTaskRoot(activity.token);
+        mWm.mAtmService.mActivityClientController.onBackPressedOnTaskRoot(activity.token);
         verify(organizer, never()).onBackPressedOnTaskRoot(any());
 
         // Enable intercepting back
@@ -928,7 +930,7 @@
                 stack.mRemoteToken.toWindowContainerToken(), true);
 
         // Verify now that the back press does call the organizer
-        mWm.mAtmService.onBackPressedOnTaskRoot(activity.token);
+        mWm.mAtmService.mActivityClientController.onBackPressedOnTaskRoot(activity.token);
         verify(organizer, times(1)).onBackPressedOnTaskRoot(any());
 
         // Disable intercepting back
@@ -936,7 +938,7 @@
                 stack.mRemoteToken.toWindowContainerToken(), false);
 
         // Verify now that the back press no longer calls the organizer
-        mWm.mAtmService.onBackPressedOnTaskRoot(activity.token);
+        mWm.mAtmService.mActivityClientController.onBackPressedOnTaskRoot(activity.token);
         verify(organizer, times(1)).onBackPressedOnTaskRoot(any());
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 227eba2..a57de09 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -19,9 +19,10 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.hardware.camera2.params.OutputConfiguration.ROTATION_90;
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
 import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
@@ -480,33 +481,49 @@
         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
         final SurfaceControl.Transaction t = spy(StubTransaction.class);
 
-        app.mHasSurface = true;
+        makeWindowVisible(app);
         app.mSurfaceControl = mock(SurfaceControl.class);
-        try {
-            app.getFrame().set(10, 20, 60, 80);
-            app.updateSurfacePosition(t);
+        final Rect frame = app.getFrame();
+        frame.set(10, 20, 60, 80);
+        app.updateSurfacePosition(t);
+        assertTrue(app.mLastSurfacePosition.equals(frame.left, frame.top));
+        app.seamlesslyRotateIfAllowed(t, ROTATION_0, ROTATION_90, true /* requested */);
+        assertTrue(app.mSeamlesslyRotated);
 
-            app.seamlesslyRotateIfAllowed(t, ROTATION_0, ROTATION_90, true);
+        // Verify we un-rotate the window state surface.
+        final Matrix matrix = new Matrix();
+        // Un-rotate 90 deg.
+        matrix.setRotate(270);
+        // Translate it back to origin.
+        matrix.postTranslate(0, mDisplayInfo.logicalWidth);
+        verify(t).setMatrix(eq(app.mSurfaceControl), eq(matrix), any(float[].class));
 
-            assertTrue(app.mSeamlesslyRotated);
+        // Verify we update the position as well.
+        final float[] curSurfacePos = {app.mLastSurfacePosition.x, app.mLastSurfacePosition.y};
+        matrix.mapPoints(curSurfacePos);
+        verify(t).setPosition(eq(app.mSurfaceControl), eq(curSurfacePos[0]), eq(curSurfacePos[1]));
 
-            // Verify we un-rotate the window state surface.
-            Matrix matrix = new Matrix();
-            // Un-rotate 90 deg
-            matrix.setRotate(270);
-            // Translate it back to origin
-            matrix.postTranslate(0, mDisplayInfo.logicalWidth);
-            verify(t).setMatrix(eq(app.mSurfaceControl), eq(matrix), any(float[].class));
+        app.finishSeamlessRotation(false /* timeout */);
+        assertFalse(app.mSeamlesslyRotated);
+        assertNull(app.mPendingSeamlessRotate);
 
-            // Verify we update the position as well.
-            float[] currentSurfacePos = {app.mLastSurfacePosition.x, app.mLastSurfacePosition.y};
-            matrix.mapPoints(currentSurfacePos);
-            verify(t).setPosition(eq(app.mSurfaceControl), eq(currentSurfacePos[0]),
-                    eq(currentSurfacePos[1]));
-        } finally {
-            app.mSurfaceControl = null;
-            app.mHasSurface = false;
-        }
+        // Simulate the case with deferred layout and animation.
+        app.resetSurfacePositionForAnimationLeash(t);
+        clearInvocations(t);
+        mWm.mWindowPlacerLocked.deferLayout();
+        app.updateSurfacePosition(t);
+        // Because layout is deferred, the position should keep the reset value.
+        assertTrue(app.mLastSurfacePosition.equals(0, 0));
+
+        app.seamlesslyRotateIfAllowed(t, ROTATION_0, ROTATION_270, true /* requested */);
+        // The last position must be updated so the surface can be unrotated properly.
+        assertTrue(app.mLastSurfacePosition.equals(frame.left, frame.top));
+        matrix.setRotate(90);
+        matrix.postTranslate(mDisplayInfo.logicalHeight, 0);
+        curSurfacePos[0] = frame.left;
+        curSurfacePos[1] = frame.top;
+        matrix.mapPoints(curSurfacePos);
+        verify(t).setPosition(eq(app.mSurfaceControl), eq(curSurfacePos[0]), eq(curSurfacePos[1]));
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 14a62d1..d64b46d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -49,6 +49,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
+import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -354,6 +355,13 @@
         }
     }
 
+    static void makeWindowVisibleAndDrawn(WindowState... windows) {
+        makeWindowVisible(windows);
+        for (WindowState win : windows) {
+            win.mWinAnimator.mDrawState = HAS_DRAWN;
+        }
+    }
+
     /** Creates a {@link TaskDisplayArea} right above the default one. */
     static TaskDisplayArea createTaskDisplayArea(DisplayContent displayContent,
             WindowManagerService service, String name, int displayAreaFeature) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
index e0785c1..462df30 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
@@ -231,7 +231,7 @@
 
     @Test
     public void testWindowAttachedWithOptions() {
-        BiFunction<WindowToken, Bundle, RootDisplayArea> selectFunc =
+        BiFunction<Integer, Bundle, RootDisplayArea> selectFunc =
                 ((DisplayAreaPolicyBuilder.Result) mDisplayContent.mDisplayAreaPolicy)
                         .mSelectRootForWindowFunc;
         spyOn(selectFunc);
@@ -241,7 +241,7 @@
                 true /* ownerCanManageAppTokens */, INVALID_UID, true /* roundedCornerOverlay */,
                 false /* fromClientToken */, null /* options */);
 
-        verify(selectFunc).apply(token1, null);
+        verify(selectFunc).apply(token1.windowType, null);
 
         final Bundle options = new Bundle();
         final WindowToken token2 = new WindowToken(mDisplayContent.mWmService, mock(IBinder.class),
@@ -249,6 +249,6 @@
                 true /* ownerCanManageAppTokens */, INVALID_UID, true /* roundedCornerOverlay */,
                 false /* fromClientToken */, options /* options */);
 
-        verify(selectFunc).apply(token2, options);
+        verify(selectFunc).apply(token2.windowType, options);
     }
 }
diff --git a/services/voiceinteraction/OWNERS b/services/voiceinteraction/OWNERS
new file mode 100644
index 0000000..ef1061b
--- /dev/null
+++ b/services/voiceinteraction/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/voice/OWNERS
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 06c23de..b5bb2a8 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -49,7 +49,6 @@
 import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
 import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
 import android.media.permission.Identity;
-import android.media.permission.IdentityContext;
 import android.media.permission.PermissionUtil;
 import android.media.permission.SafeCloseable;
 import android.os.Binder;
@@ -92,7 +91,7 @@
 import com.android.server.SystemService;
 import com.android.server.UiThread;
 import com.android.server.pm.UserManagerInternal;
-import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.permission.LegacyPermissionManagerInternal;
 import com.android.server.soundtrigger.SoundTriggerInternal;
 import com.android.server.utils.TimingsTraceAndSlog;
 import com.android.server.wm.ActivityTaskManagerInternal;
@@ -141,10 +140,10 @@
         mUserManagerInternal = Objects.requireNonNull(
                 LocalServices.getService(UserManagerInternal.class));
 
-        PermissionManagerServiceInternal permissionManagerInternal = LocalServices.getService(
-                PermissionManagerServiceInternal.class);
+        LegacyPermissionManagerInternal permissionManagerInternal = LocalServices.getService(
+                LegacyPermissionManagerInternal.class);
         permissionManagerInternal.setVoiceInteractionPackagesProvider(
-                new PermissionManagerServiceInternal.PackagesProvider() {
+                new LegacyPermissionManagerInternal.PackagesProvider() {
             @Override
             public String[] getPackages(int userId) {
                 mServiceStub.initForUser(userId);
diff --git a/services/wifi/OWNERS b/services/wifi/OWNERS
new file mode 100644
index 0000000..2ae7065
--- /dev/null
+++ b/services/wifi/OWNERS
@@ -0,0 +1 @@
+include /wifi/OWNERS
diff --git a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
index 3104c7e..1a0e526 100644
--- a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
+++ b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java
@@ -34,6 +34,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
+import android.provider.DeviceConfig;
 import android.util.ArraySet;
 import android.util.Log;
 
@@ -42,15 +43,20 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.pm.BackgroundDexOptService;
+import com.android.server.pm.PackageManagerService;
 import com.android.server.wm.ActivityMetricsLaunchObserver;
 import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto;
 import com.android.server.wm.ActivityMetricsLaunchObserver.Temperature;
 import com.android.server.wm.ActivityMetricsLaunchObserverRegistry;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
+import java.time.Duration;
 import java.util.ArrayList;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.BooleanSupplier;
 import java.util.HashMap;
+import java.util.List;
 
 /**
  * System-server-local proxy into the {@code IIorap} native service.
@@ -65,6 +71,7 @@
     /** $> adb shell 'setprop iorapd.forwarding_service.wtf_crash true' */
     private static boolean WTF_CRASH = SystemProperties.getBoolean(
             "iorapd.forwarding_service.wtf_crash", false);
+    private static final Duration TIMEOUT = Duration.ofSeconds(600L);
 
     // "Unique" job ID from the service name. Also equal to 283673059.
     public static final int JOB_ID_IORAPD = encodeEnglishAlphabetStringIntoInt("iorapd");
@@ -80,6 +87,12 @@
     private volatile IorapdJobService mJobService;  // Write-once (null -> non-null forever).
     private volatile static IorapForwardingService sSelfService;  // Write once (null -> non-null).
 
+
+    /**
+     * Atomics set to true if the JobScheduler requests an abort.
+     */
+    private final AtomicBoolean mAbortIdleCompilation = new AtomicBoolean(false);
+
     /**
      * Initializes the system service.
      * <p>
@@ -154,9 +167,27 @@
 
     @VisibleForTesting
     protected boolean isIorapEnabled() {
+        // These two mendel flags should match those in iorapd native process
+        // system/iorapd/src/common/property.h
+        boolean isTracingEnabled =
+            getMendelFlag("iorap_perfetto_enable", "iorapd.perfetto.enable", false);
+        boolean isReadAheadEnabled =
+            getMendelFlag("iorap_readahead_enable", "iorapd.readahead.enable", false);
         // Same as the property in iorapd.rc -- disabling this will mean the 'iorapd' binder process
         // never comes up, so all binder connections will fail indefinitely.
-        return IS_ENABLED;
+        return IS_ENABLED && (isTracingEnabled || isReadAheadEnabled);
+    }
+
+    private boolean getMendelFlag(String mendelFlag, String sysProperty, boolean defaultValue) {
+        // TODO(yawanng) use DeviceConfig to get mendel property.
+        // DeviceConfig doesn't work and the reason is not clear.
+        // Provider service is already up before IORapForwardService.
+        String mendelProperty = "persist.device_config."
+            + DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT
+            + "."
+            + mendelFlag;
+        return SystemProperties.getBoolean(mendelProperty,
+            SystemProperties.getBoolean(sysProperty, defaultValue));
     }
 
     //</editor-fold>
@@ -239,7 +270,9 @@
         //
         // TODO: it would be good to get nodified of 'adb shell stop iorapd' to avoid
         // printing this warning.
-        Log.w(TAG, "Failed to connect to iorapd, is it down? Delay for " + sleepTime);
+        if (DEBUG) {
+            Log.v(TAG, "Failed to connect to iorapd, is it down? Delay for " + sleepTime);
+        }
 
         // Use a handler instead of Thread#sleep to avoid backing up the binder thread
         // when this is called from the death recipient callback.
@@ -275,7 +308,9 @@
         // Connect to the native binder service.
         mIorapRemote = provideIorapRemote();
         if (mIorapRemote == null) {
-            Log.e(TAG, "connectToRemoteAndConfigure - null iorap remote. check for Log.wtf?");
+            if (DEBUG) {
+                Log.e(TAG, "connectToRemoteAndConfigure - null iorap remote. check for Log.wtf?");
+            }
             return false;
         }
         invokeRemote(mIorapRemote,
@@ -542,32 +577,86 @@
             // Tell iorapd to start a background job.
             Log.d(TAG, "Starting background job: " + params.toString());
 
-            // We wait until that job's sequence ID returns to us with 'Completed',
-            RequestId request;
-            synchronized (mLock) {
-                // TODO: would be cleaner if we got the request from the 'invokeRemote' function.
-                // Better yet, consider a Pair<RequestId, Future<TaskResult>> or similar.
-                request = RequestId.nextValueForSequence();
-                mRunningJobs.put(request, params);
-            }
+            mAbortIdleCompilation.set(false);
+            // PackageManagerService starts before IORap service.
+            PackageManagerService pm = (PackageManagerService)ServiceManager.getService("package");
+            List<String> pkgs = pm.getAllPackages();
+            runIdleCompilationAsync(params, pkgs);
+            return true;
+        }
 
-            if (!invokeRemote(mIorapRemote, (IIorap remote) ->
-                    remote.onJobScheduledEvent(request,
-                            JobScheduledEvent.createIdleMaintenance(
-                                    JobScheduledEvent.TYPE_START_JOB,
-                                    params))
-            )) {
-                synchronized (mLock) {
-                    mRunningJobs.remove(request); // Avoid memory leaks.
+        private void runIdleCompilationAsync(final JobParameters params, final List<String> pkgs) {
+            new Thread("IORap_IdleCompilation") {
+                @Override
+                public void run() {
+                    for (int i = 0; i < pkgs.size(); i++) {
+                        String pkg = pkgs.get(i);
+                        if (mAbortIdleCompilation.get()) {
+                            Log.i(TAG, "The idle compilation is aborted");
+                            return;
+                        }
+
+                        // We wait until that job's sequence ID returns to us with 'Completed',
+                        RequestId request;
+                        synchronized (mLock) {
+                            // TODO: would be cleaner if we got the request from the
+                            // 'invokeRemote' function. Better yet, consider
+                            // a Pair<RequestId, Future<TaskResult>> or similar.
+                            request = RequestId.nextValueForSequence();
+                            mRunningJobs.put(request, params);
+                        }
+
+                        Log.i(TAG, String.format("IORap compile package: %s, [%d/%d]",
+                              pkg, i + 1, pkgs.size()));
+                        boolean shouldUpdateVersions = (i == 0);
+                        if (!invokeRemote(mIorapRemote, (IIorap remote) ->
+                                remote.onJobScheduledEvent(request,
+                                        JobScheduledEvent.createIdleMaintenance(
+                                                JobScheduledEvent.TYPE_START_JOB,
+                                                params,
+                                                pkg,
+                                                shouldUpdateVersions)))) {
+                            synchronized (mLock) {
+                                mRunningJobs.remove(request); // Avoid memory leaks.
+                            }
+                        }
+
+                        // Wait until the job is complete and removed from the running jobs.
+                        retryWithTimeout(TIMEOUT, () -> {
+                            synchronized (mLock) {
+                                return !mRunningJobs.containsKey(request);
+                            }
+                        });
+                    }
+
+                    // Finish the job after all packages are compiled.
+                    if (mProxy != null) {
+                        mProxy.jobFinished(params, /*reschedule*/false);
+                    }
+                }
+          }.start();
+        }
+
+        /** Retry until timeout. */
+        private boolean retryWithTimeout(final Duration timeout, BooleanSupplier supplier) {
+            long totalSleepTimeMs = 0L;
+            long sleepIntervalMs = 10L;
+            while (true) {
+                if (supplier.getAsBoolean()) {
+                    return true;
+                }
+                try {
+                    TimeUnit.MILLISECONDS.sleep(sleepIntervalMs);
+                } catch (InterruptedException e) {
+                    Log.e(TAG, e.getMessage());
+                    return false;
                 }
 
-                // Something went wrong on the remote side. Treat the job as being
-                // 'already finished' (i.e. immediately release wake lock).
-                return false;
+                totalSleepTimeMs += sleepIntervalMs;
+                if (totalSleepTimeMs > timeout.toMillis()) {
+                    return false;
+                }
             }
-
-            // True -> keep the wakelock acquired until #jobFinished is called.
-            return true;
         }
 
         // Called by system to prematurely stop the job.
@@ -575,32 +664,7 @@
         public boolean onStopJob(JobParameters params) {
             // As this is unexpected behavior, print a warning.
             Log.w(TAG, "onStopJob(params=" + params.toString() + ")");
-
-            // No longer track this job (avoids a memory leak).
-            boolean wasTracking = false;
-            synchronized (mLock) {
-                for (HashMap.Entry<RequestId, JobParameters> entry : mRunningJobs.entrySet()) {
-                   if (entry.getValue().getJobId() == params.getJobId()) {
-                       mRunningJobs.remove(entry.getKey());
-                       wasTracking = true;
-                   }
-                }
-            }
-
-            // Notify iorapd to stop (abort) the job.
-            if (wasTracking) {
-                invokeRemote(mIorapRemote, (IIorap remote) ->
-                        remote.onJobScheduledEvent(RequestId.nextValueForSequence(),
-                                JobScheduledEvent.createIdleMaintenance(
-                                        JobScheduledEvent.TYPE_STOP_JOB,
-                                        params))
-                );
-            } else {
-                // Even weirder. This could only be considered "correct" if iorapd reported success
-                // concurrently to the JobService requesting an onStopJob.
-                Log.e(TAG, "Untracked onStopJob request");  // see above Log.w for the params.
-            }
-
+            mAbortIdleCompilation.set(true);
 
             // Yes, retry the job at a later time no matter what.
             return true;
@@ -626,18 +690,6 @@
             }
 
             Log.d(TAG, "Finished background job: " + jobParameters.toString());
-
-            // Job is successful and periodic. Do not 'reschedule' according to the back-off
-            // criteria.
-            //
-            // This releases the wakelock that was acquired in #onStartJob.
-
-            IorapdJobServiceProxy proxy = mProxy;
-            if (proxy != null) {
-                proxy.jobFinished(jobParameters, /*reschedule*/false);
-            }
-            // Cannot call 'jobFinished' on 'this' because it was not constructed
-            // from the JobService, so it would get an NPE when calling mEngine.
         }
 
         public void onIorapdDisconnected() {
diff --git a/startop/iorap/src/com/google/android/startop/iorap/JobScheduledEvent.java b/startop/iorap/src/com/google/android/startop/iorap/JobScheduledEvent.java
index 2055b20..b91dd71 100644
--- a/startop/iorap/src/com/google/android/startop/iorap/JobScheduledEvent.java
+++ b/startop/iorap/src/com/google/android/startop/iorap/JobScheduledEvent.java
@@ -55,6 +55,10 @@
     /** @see JobParameters#getJobId() */
     public final int jobId;
 
+    public final String packageName;
+
+    public final boolean shouldUpdateVersions;
+
     /** Device is 'idle' and it's charging (plugged in). */
     public static final int SORT_IDLE_MAINTENANCE = 0;
     private static final int SORT_MAX = 0;
@@ -77,14 +81,22 @@
      * Only the job ID is retained from {@code jobParams}, all other param info is dropped.
      */
     @NonNull
-    public static JobScheduledEvent createIdleMaintenance(@Type int type, JobParameters jobParams) {
-        return new JobScheduledEvent(type, jobParams.getJobId(), SORT_IDLE_MAINTENANCE);
+    public static JobScheduledEvent createIdleMaintenance(
+        @Type int type, JobParameters jobParams, String packageName, boolean shouldUpdateVersions) {
+        return new JobScheduledEvent(
+            type, jobParams.getJobId(), SORT_IDLE_MAINTENANCE, packageName, shouldUpdateVersions);
     }
 
-    private JobScheduledEvent(@Type int type, int jobId, @Sort int sort) {
+    private JobScheduledEvent(@Type int type,
+                              int jobId,
+                              @Sort int sort,
+                              String packageName,
+                              boolean shouldUpdateVersions) {
         this.type = type;
         this.jobId = jobId;
         this.sort = sort;
+        this.packageName = packageName;
+        this.shouldUpdateVersions = shouldUpdateVersions;
 
         checkConstructorArguments();
     }
@@ -108,12 +120,16 @@
     private boolean equals(JobScheduledEvent other) {
         return type == other.type &&
                 jobId == other.jobId &&
-                sort == other.sort;
+                sort == other.sort &&
+                packageName.equals(other.packageName) &&
+                shouldUpdateVersions == other.shouldUpdateVersions;
     }
 
     @Override
     public String toString() {
-        return String.format("{type: %d, jobId: %d, sort: %d}", type, jobId, sort);
+        return String.format(
+            "{type: %d, jobId: %d, sort: %d, packageName: %s, shouldUpdateVersions %b}",
+            type, jobId, sort, packageName, shouldUpdateVersions);
     }
 
     //<editor-fold desc="Binder boilerplate">
@@ -122,6 +138,8 @@
         out.writeInt(type);
         out.writeInt(jobId);
         out.writeInt(sort);
+        out.writeString(packageName);
+        out.writeBoolean(shouldUpdateVersions);
 
         // We do not parcel the entire JobParameters here because there is no C++ equivalent
         // of that class [which the iorapd side of the binder interface requires].
@@ -131,6 +149,8 @@
         this.type = in.readInt();
         this.jobId = in.readInt();
         this.sort = in.readInt();
+        this.packageName = in.readString();
+        this.shouldUpdateVersions = in.readBoolean();
 
         checkConstructorArguments();
     }
diff --git a/telecomm/TEST_MAPPING b/telecomm/TEST_MAPPING
index c9903f9..1963ff3 100644
--- a/telecomm/TEST_MAPPING
+++ b/telecomm/TEST_MAPPING
@@ -23,7 +23,9 @@
           "exclude-annotation": "androidx.test.filters.FlakyTest"
         }
       ]
-    },
+    }
+  ],
+  "presubmit-large": [
     {
       "name": "CtsTelecomTestCases",
       "options": [
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 6288bc1..b1ccb53 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -1988,8 +1988,10 @@
             connection.setAudioModeIsVoip(true);
         }
         connection.setTelecomCallId(callId);
+        PhoneAccountHandle phoneAccountHandle = connection.getPhoneAccountHandle() == null
+                            ? request.getAccountHandle() : connection.getPhoneAccountHandle();
         if (connection.getState() != Connection.STATE_DISCONNECTED) {
-            addConnection(request.getAccountHandle(), callId, connection);
+            addConnection(phoneAccountHandle, callId, connection);
         }
 
         Uri address = connection.getAddress();
@@ -2005,7 +2007,7 @@
                 callId,
                 request,
                 new ParcelableConnection(
-                        request.getAccountHandle(),
+                        phoneAccountHandle,
                         connection.getState(),
                         connection.getConnectionCapabilities(),
                         connection.getConnectionProperties(),
diff --git a/telecomm/java/android/telecom/OWNERS b/telecomm/java/android/telecom/OWNERS
new file mode 100644
index 0000000..6656a01
--- /dev/null
+++ b/telecomm/java/android/telecom/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 20868
+
+rgreenwalt@google.com
+tgunn@google.com
+breadley@google.com
+hallliu@google.com
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 960b0df4..5b03863 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -268,10 +268,69 @@
     /**
      * Optional extra for {@link android.content.Intent#ACTION_CALL} containing a string call
      * subject which will be associated with an outgoing call.  Should only be specified if the
-     * {@link PhoneAccount} supports the capability {@link PhoneAccount#CAPABILITY_CALL_SUBJECT}.
+     * {@link PhoneAccount} supports the capability {@link PhoneAccount#CAPABILITY_CALL_SUBJECT}
+     * or {@link PhoneAccount#CAPABILITY_CALL_COMPOSER}.
      */
     public static final String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
 
+    // Values for EXTRA_PRIORITY
+    /**
+     * Indicates the call composer call priority is normal.
+     *
+     * Reference: RCC.20 Section 2.4.4.2
+     */
+    public static final int PRIORITY_NORMAL = 0;
+
+    /**
+     * Indicates the call composer call priority is urgent.
+     *
+     * Reference: RCC.20 Section 2.4.4.2
+     */
+    public static final int PRIORITY_URGENT = 1;
+
+    /**
+     * Extra for the call composer call priority, either {@link #PRIORITY_NORMAL} or
+     * {@link #PRIORITY_URGENT}.
+     *
+     * Reference: RCC.20 Section 2.4.4.2
+     */
+    public static final String EXTRA_PRIORITY = "android.telecom.extra.PRIORITY";
+
+    /**
+     * Extra for the call composer call location, an {@link android.location.Location} parcelable
+     * class to represent the geolocation as a latitude and longitude pair.
+     *
+     * Reference: RCC.20 Section 2.4.3.2
+     */
+    public static final String EXTRA_LOCATION = "android.telecom.extra.LOCATION";
+
+    /**
+     * A boolean extra set on incoming calls to indicate that the call has a picture specified.
+     * Given that image download could take a (short) time, the EXTRA is set immediately upon
+     * adding the call to the Dialer app, this allows the Dialer app to reserve space for an image
+     * if one is expected. The EXTRA may be unset if the image download ends up failing for some
+     * reason.
+     */
+    public static final String EXTRA_HAS_PICTURE = "android.telecom.extra.HAS_PICTURE";
+
+    /**
+     * A URI representing the picture that was downloaded when a call is received.
+     * This is a content URI within the call log provider which can be used to open a file
+     * descriptor. This could be set a short time after a call is added to the Dialer app if the
+     * download is delayed for some reason. The Dialer app will receive a callback via
+     * {@link Call.Callback#onDetailsChanged} when this value has changed.
+     *
+     * Reference: RCC.20 Section 2.4.3.2
+     */
+    public static final String EXTRA_INCOMING_PICTURE = "android.telecom.extra.INCOMING_PICTURE";
+
+    // TODO(hallliu), This UUID is obtained from TelephonyManager#uploadCallComposerPicture.
+    /**
+     * A ParcelUuid used as a token to represent a picture that was uploaded prior to the call
+     * being placed.
+     */
+    public static final String EXTRA_OUTGOING_PICTURE = "android.telecom.extra.OUTGOING_PICTURE";
+
     /**
      * The extra used by a {@link ConnectionService} to provide the handle of the caller that
      * has initiated a new incoming call.
diff --git a/telephony/java/android/service/euicc/OWNERS b/telephony/java/android/service/euicc/OWNERS
new file mode 100644
index 0000000..6aa399d
--- /dev/null
+++ b/telephony/java/android/service/euicc/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 20868
+
+rgreenwalt@google.com
+tgunn@google.com
+amitmahajan@google.com
diff --git a/telephony/java/android/service/sms/OWNERS b/telephony/java/android/service/sms/OWNERS
new file mode 100644
index 0000000..6aa399d
--- /dev/null
+++ b/telephony/java/android/service/sms/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 20868
+
+rgreenwalt@google.com
+tgunn@google.com
+amitmahajan@google.com
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index b381cce..189a4b8 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -21,7 +21,6 @@
 import android.annotation.NonNull;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.hardware.radio.V1_4.CellInfo.Info;
-import android.hardware.radio.V1_5.CellInfo.CellInfoRatSpecificInfo;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -352,6 +351,13 @@
     }
 
     /** @hide */
+    protected CellInfo(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
+        this.mRegistered = ci.registered;
+        this.mTimeStamp = timeStamp;
+        this.mCellConnectionStatus = ci.connectionStatus;
+    }
+
+    /** @hide */
     public static CellInfo create(android.hardware.radio.V1_0.CellInfo ci) {
         if (ci == null) return null;
         switch(ci.cellInfoType) {
@@ -395,17 +401,49 @@
     public static CellInfo create(android.hardware.radio.V1_5.CellInfo ci, long timeStamp) {
         if (ci == null) return null;
         switch (ci.ratSpecificInfo.getDiscriminator()) {
-            case CellInfoRatSpecificInfo.hidl_discriminator.gsm:
+            case android.hardware.radio.V1_5.CellInfo
+                    .CellInfoRatSpecificInfo.hidl_discriminator.gsm:
                 return new CellInfoGsm(ci, timeStamp);
-            case CellInfoRatSpecificInfo.hidl_discriminator.cdma:
+            case android.hardware.radio.V1_5.CellInfo
+                    .CellInfoRatSpecificInfo.hidl_discriminator.cdma:
                 return new CellInfoCdma(ci, timeStamp);
-            case CellInfoRatSpecificInfo.hidl_discriminator.lte:
+            case android.hardware.radio.V1_5.CellInfo
+                    .CellInfoRatSpecificInfo.hidl_discriminator.lte:
                 return new CellInfoLte(ci, timeStamp);
-            case CellInfoRatSpecificInfo.hidl_discriminator.wcdma:
+            case android.hardware.radio.V1_5.CellInfo
+                    .CellInfoRatSpecificInfo.hidl_discriminator.wcdma:
                 return new CellInfoWcdma(ci, timeStamp);
-            case CellInfoRatSpecificInfo.hidl_discriminator.tdscdma:
+            case android.hardware.radio.V1_5.CellInfo
+                    .CellInfoRatSpecificInfo.hidl_discriminator.tdscdma:
                 return new CellInfoTdscdma(ci, timeStamp);
-            case CellInfoRatSpecificInfo.hidl_discriminator.nr:
+            case android.hardware.radio.V1_5.CellInfo
+                    .CellInfoRatSpecificInfo.hidl_discriminator.nr:
+                return new CellInfoNr(ci, timeStamp);
+            default: return null;
+        }
+    }
+
+    /** @hide */
+    public static CellInfo create(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
+        if (ci == null) return null;
+        switch (ci.ratSpecificInfo.getDiscriminator()) {
+            case android.hardware.radio.V1_6.CellInfo
+                    .CellInfoRatSpecificInfo.hidl_discriminator.gsm:
+                return new CellInfoGsm(ci, timeStamp);
+            case android.hardware.radio.V1_6.CellInfo
+                    .CellInfoRatSpecificInfo.hidl_discriminator.cdma:
+                return new CellInfoCdma(ci, timeStamp);
+            case android.hardware.radio.V1_6.CellInfo
+                    .CellInfoRatSpecificInfo.hidl_discriminator.lte:
+                return new CellInfoLte(ci, timeStamp);
+            case android.hardware.radio.V1_6.CellInfo
+                    .CellInfoRatSpecificInfo.hidl_discriminator.wcdma:
+                return new CellInfoWcdma(ci, timeStamp);
+            case android.hardware.radio.V1_6.CellInfo
+                    .CellInfoRatSpecificInfo.hidl_discriminator.tdscdma:
+                return new CellInfoTdscdma(ci, timeStamp);
+            case android.hardware.radio.V1_6.CellInfo
+                    .CellInfoRatSpecificInfo.hidl_discriminator.nr:
                 return new CellInfoNr(ci, timeStamp);
             default: return null;
         }
diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java
index 3ce99fa..dbb30d2 100644
--- a/telephony/java/android/telephony/CellInfoCdma.java
+++ b/telephony/java/android/telephony/CellInfoCdma.java
@@ -87,6 +87,15 @@
                 new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
     }
 
+    /** @hide */
+    public CellInfoCdma(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
+        super(ci, timeStamp);
+        final android.hardware.radio.V1_2.CellInfoCdma cic = ci.ratSpecificInfo.cdma();
+        mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma);
+        mCellSignalStrengthCdma =
+                new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
+    }
+
     /**
      * @return a {@link CellIdentityCdma} instance.
      */
diff --git a/telephony/java/android/telephony/CellInfoGsm.java b/telephony/java/android/telephony/CellInfoGsm.java
index e296e61..e1d996e 100644
--- a/telephony/java/android/telephony/CellInfoGsm.java
+++ b/telephony/java/android/telephony/CellInfoGsm.java
@@ -82,6 +82,14 @@
         mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
     }
 
+    /** @hide */
+    public CellInfoGsm(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
+        super(ci, timeStamp);
+        final android.hardware.radio.V1_5.CellInfoGsm cig = ci.ratSpecificInfo.gsm();
+        mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm);
+        mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
+    }
+
     /**
      * @return a {@link CellIdentityGsm} instance.
      */
diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java
index 6f81234..39b320a 100644
--- a/telephony/java/android/telephony/CellInfoLte.java
+++ b/telephony/java/android/telephony/CellInfoLte.java
@@ -91,6 +91,15 @@
         mCellConfig = new CellConfigLte();
     }
 
+    /** @hide */
+    public CellInfoLte(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
+        super(ci, timeStamp);
+        final android.hardware.radio.V1_6.CellInfoLte cil = ci.ratSpecificInfo.lte();
+        mCellIdentityLte = new CellIdentityLte(cil.cellIdentityLte);
+        mCellSignalStrengthLte = new CellSignalStrengthLte(cil.signalStrengthLte);
+        mCellConfig = new CellConfigLte();
+    }
+
     /**
      * @return a {@link CellIdentityLte} instance.
      */
diff --git a/telephony/java/android/telephony/CellInfoNr.java b/telephony/java/android/telephony/CellInfoNr.java
index e01e8f0..12e6a38 100644
--- a/telephony/java/android/telephony/CellInfoNr.java
+++ b/telephony/java/android/telephony/CellInfoNr.java
@@ -68,6 +68,14 @@
         mCellSignalStrength = new CellSignalStrengthNr(cil.signalStrengthNr);
     }
 
+    /** @hide */
+    public CellInfoNr(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
+        super(ci, timeStamp);
+        final android.hardware.radio.V1_6.CellInfoNr cil = ci.ratSpecificInfo.nr();
+        mCellIdentity = new CellIdentityNr(cil.cellIdentityNr);
+        mCellSignalStrength = new CellSignalStrengthNr(cil.signalStrengthNr);
+    }
+
     /**
      * @return a {@link CellIdentityNr} instance.
      */
diff --git a/telephony/java/android/telephony/CellInfoTdscdma.java b/telephony/java/android/telephony/CellInfoTdscdma.java
index 038c49a..994b317 100644
--- a/telephony/java/android/telephony/CellInfoTdscdma.java
+++ b/telephony/java/android/telephony/CellInfoTdscdma.java
@@ -85,6 +85,14 @@
         mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
     }
 
+    /** @hide */
+    public CellInfoTdscdma(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
+        super(ci, timeStamp);
+        final android.hardware.radio.V1_5.CellInfoTdscdma cit = ci.ratSpecificInfo.tdscdma();
+        mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma);
+        mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
+    }
+
     /**
      * @return a {@link CellIdentityTdscdma} instance.
      */
diff --git a/telephony/java/android/telephony/CellInfoWcdma.java b/telephony/java/android/telephony/CellInfoWcdma.java
index c74955f..62ac0b8 100644
--- a/telephony/java/android/telephony/CellInfoWcdma.java
+++ b/telephony/java/android/telephony/CellInfoWcdma.java
@@ -80,6 +80,14 @@
         mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
     }
 
+    /** @hide */
+    public CellInfoWcdma(android.hardware.radio.V1_6.CellInfo ci, long timeStamp) {
+        super(ci, timeStamp);
+        final android.hardware.radio.V1_5.CellInfoWcdma ciw = ci.ratSpecificInfo.wcdma();
+        mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma);
+        mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
+    }
+
     /**
      * @return a {@link CellIdentityWcdma} instance.
      */
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 47a8f72..db7d10a 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -86,6 +86,15 @@
     private int mRsrq;
     @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.P)
     private int mRssnr;
+    /**
+     * CSI channel quality indicator (CQI) table index. There are multiple CQI tables.
+     * The definition of CQI in each table is different.
+     *
+     * Reference: 3GPP TS 136.213 section 7.2.3.
+     *
+     * Range [1, 6].
+     */
+    private int mCqiTableIndex;
     @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.P)
     private int mCqi;
     @UnsupportedAppUsage(maxTargetSdk = android.os.Build.VERSION_CODES.P)
@@ -120,6 +129,32 @@
      * @param rsrp in dBm [-140,-43], UNKNOWN
      * @param rsrq in dB [-34, 3], UNKNOWN
      * @param rssnr in dB [-20, +30], UNKNOWN
+     * @param cqiTableIndex [1, 6], UNKNOWN
+     * @param cqi [0, 15], UNKNOWN
+     * @param timingAdvance [0, 1282], UNKNOWN
+     *
+     */
+    /** @hide */
+    public CellSignalStrengthLte(int rssi, int rsrp, int rsrq, int rssnr, int cqiTableIndex,
+            int cqi, int timingAdvance) {
+        mRssi = inRangeOrUnavailable(rssi, -113, -51);
+        mSignalStrength = mRssi;
+        mRsrp = inRangeOrUnavailable(rsrp, -140, -43);
+        mRsrq = inRangeOrUnavailable(rsrq, -34, 3);
+        mRssnr = inRangeOrUnavailable(rssnr, -20, 30);
+        mCqiTableIndex = inRangeOrUnavailable(cqiTableIndex, 1, 6);
+        mCqi = inRangeOrUnavailable(cqi, 0, 15);
+        mTimingAdvance = inRangeOrUnavailable(timingAdvance, 0, 1282);
+        updateLevel(null, null);
+    }
+
+    /**
+     * Construct a cell signal strength
+     *
+     * @param rssi in dBm [-113,-51], UNKNOWN
+     * @param rsrp in dBm [-140,-43], UNKNOWN
+     * @param rsrq in dB [-34, 3], UNKNOWN
+     * @param rssnr in dB [-20, +30], UNKNOWN
      * @param cqi [0, 15], UNKNOWN
      * @param timingAdvance [0, 1282], UNKNOWN
      *
@@ -127,15 +162,7 @@
     /** @hide */
     public CellSignalStrengthLte(int rssi, int rsrp, int rsrq, int rssnr, int cqi,
             int timingAdvance) {
-
-        mRssi = inRangeOrUnavailable(rssi, -113, -51);
-        mSignalStrength = mRssi;
-        mRsrp = inRangeOrUnavailable(rsrp, -140, -43);
-        mRsrq = inRangeOrUnavailable(rsrq, -34, 3);
-        mRssnr = inRangeOrUnavailable(rssnr, -20, 30);
-        mCqi = inRangeOrUnavailable(cqi, 0, 15);
-        mTimingAdvance = inRangeOrUnavailable(timingAdvance, 0, 1282);
-        updateLevel(null, null);
+        this(rssi, rsrp, rsrq, rssnr, CellInfo.UNAVAILABLE, cqi, timingAdvance);
     }
 
     /** @hide */
@@ -148,6 +175,16 @@
     }
 
     /** @hide */
+    public CellSignalStrengthLte(android.hardware.radio.V1_6.LteSignalStrength lte) {
+        // Convert from HAL values as part of construction.
+        this(convertRssiAsuToDBm(lte.base.signalStrength),
+                lte.base.rsrp != CellInfo.UNAVAILABLE ? -lte.base.rsrp : lte.base.rsrp,
+                lte.base.rsrq != CellInfo.UNAVAILABLE ? -lte.base.rsrq : lte.base.rsrq,
+                convertRssnrUnitFromTenDbToDB(lte.base.rssnr), lte.cqiTableIndex, lte.base.cqi,
+                lte.base.timingAdvance);
+    }
+
+    /** @hide */
     public CellSignalStrengthLte(CellSignalStrengthLte s) {
         copyFrom(s);
     }
@@ -159,6 +196,7 @@
         mRsrp = s.mRsrp;
         mRsrq = s.mRsrq;
         mRssnr = s.mRssnr;
+        mCqiTableIndex = s.mCqiTableIndex;
         mCqi = s.mCqi;
         mTimingAdvance = s.mTimingAdvance;
         mLevel = s.mLevel;
@@ -179,6 +217,7 @@
         mRsrp = CellInfo.UNAVAILABLE;
         mRsrq = CellInfo.UNAVAILABLE;
         mRssnr = CellInfo.UNAVAILABLE;
+        mCqiTableIndex = CellInfo.UNAVAILABLE;
         mCqi = CellInfo.UNAVAILABLE;
         mTimingAdvance = CellInfo.UNAVAILABLE;
         mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
@@ -402,6 +441,17 @@
     }
 
     /**
+     * Get table index for channel quality indicator
+     *
+     * @return the CQI table index if available or
+     *         {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable.
+     */
+    /** @hide */
+    public int getCqiTableIndex() {
+        return mCqiTableIndex;
+    }
+
+    /**
      * Get channel quality indicator
      *
      * @return the CQI if available or
@@ -454,7 +504,8 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mRssi, mRsrp, mRsrq, mRssnr, mCqi, mTimingAdvance, mLevel);
+        return Objects.hash(mRssi, mRsrp, mRsrq, mRssnr, mCqiTableIndex, mCqi, mTimingAdvance,
+                mLevel);
     }
 
     private static final CellSignalStrengthLte sInvalid = new CellSignalStrengthLte();
@@ -476,6 +527,7 @@
                 && mRsrp == s.mRsrp
                 && mRsrq == s.mRsrq
                 && mRssnr == s.mRssnr
+                && mCqiTableIndex == s.mCqiTableIndex
                 && mCqi == s.mCqi
                 && mTimingAdvance == s.mTimingAdvance
                 && mLevel == s.mLevel;
@@ -491,6 +543,7 @@
                 + " rsrp=" + mRsrp
                 + " rsrq=" + mRsrq
                 + " rssnr=" + mRssnr
+                + " cqiTableIndex=" + mCqiTableIndex
                 + " cqi=" + mCqi
                 + " ta=" + mTimingAdvance
                 + " level=" + mLevel
@@ -508,6 +561,7 @@
         dest.writeInt(mRsrp);
         dest.writeInt(mRsrq);
         dest.writeInt(mRssnr);
+        dest.writeInt(mCqiTableIndex);
         dest.writeInt(mCqi);
         dest.writeInt(mTimingAdvance);
         dest.writeInt(mLevel);
@@ -523,6 +577,7 @@
         mRsrp = in.readInt();
         mRsrq = in.readInt();
         mRssnr = in.readInt();
+        mCqiTableIndex = in.readInt();
         mCqi = in.readInt();
         mTimingAdvance = in.readInt();
         mLevel = in.readInt();
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index 766019e..1518190 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.IntRange;
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.PersistableBundle;
@@ -27,7 +28,10 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 import java.util.Objects;
+import java.util.stream.Collectors;
 
 /**
  * 5G NR signal strength related information.
@@ -109,6 +113,28 @@
     private int mCsiRsrp;
     private int mCsiRsrq;
     private int mCsiSinr;
+    /**
+     * CSI channel quality indicator (CQI) table index. There are multiple CQI tables.
+     * The definition of CQI in each table is different.
+     *
+     * Reference: 3GPP TS 138.214 section 5.2.2.1.
+     *
+     * Range [1, 3].
+     */
+    private int mCsiCqiTableIndex;
+    /**
+     * CSI channel quality indicators (CQI) for all subbands.
+     *
+     * If the CQI report is for the entire wideband, a single CQI index is provided.
+     * If the CQI report is for all subbands, one CQI index is provided for each subband,
+     * in ascending order of subband index.
+     * If CQI is not available, the CQI report is empty.
+     *
+     * Reference: 3GPP TS 138.214 section 5.2.2.1.
+     *
+     * Range [0, 15] for each CQI.
+     */
+    private List<Integer> mCsiCqiReport;;
     private int mSsRsrp;
     private int mSsRsrq;
     private int mSsSinr;
@@ -138,6 +164,32 @@
      * @param csiRsrp CSI reference signal received power.
      * @param csiRsrq CSI reference signal received quality.
      * @param csiSinr CSI signal-to-noise and interference ratio.
+     * @param csiCqiTableIndex CSI CSI channel quality indicator (CQI) table index.
+     * @param csiCqiReport CSI channel quality indicators (CQI) for all subbands.
+     * @param ssRsrp SS reference signal received power.
+     * @param ssRsrq SS reference signal received quality.
+     * @param ssSinr SS signal-to-noise and interference ratio.
+     * @hide
+     */
+    public CellSignalStrengthNr(int csiRsrp, int csiRsrq, int csiSinr, int csiCqiTableIndex,
+            List<Integer> csiCqiReport, int ssRsrp, int ssRsrq, int ssSinr) {
+        mCsiRsrp = inRangeOrUnavailable(csiRsrp, -140, -44);
+        mCsiRsrq = inRangeOrUnavailable(csiRsrq, -20, -3);
+        mCsiSinr = inRangeOrUnavailable(csiSinr, -23, 23);
+        mCsiCqiTableIndex = inRangeOrUnavailable(csiCqiTableIndex, 1, 3);
+        mCsiCqiReport =  csiCqiReport.stream()
+                .map(cqi -> new Integer(inRangeOrUnavailable(cqi.intValue(), 1, 3)))
+                .collect(Collectors.toList());
+        mSsRsrp = inRangeOrUnavailable(ssRsrp, -140, -44);
+        mSsRsrq = inRangeOrUnavailable(ssRsrq, -43, 20);
+        mSsSinr = inRangeOrUnavailable(ssSinr, -23, 40);
+        updateLevel(null, null);
+    }
+
+    /**
+     * @param csiRsrp CSI reference signal received power.
+     * @param csiRsrq CSI reference signal received quality.
+     * @param csiSinr CSI signal-to-noise and interference ratio.
      * @param ssRsrp SS reference signal received power.
      * @param ssRsrq SS reference signal received quality.
      * @param ssSinr SS signal-to-noise and interference ratio.
@@ -145,13 +197,8 @@
      */
     public CellSignalStrengthNr(
             int csiRsrp, int csiRsrq, int csiSinr, int ssRsrp, int ssRsrq, int ssSinr) {
-        mCsiRsrp = inRangeOrUnavailable(csiRsrp, -140, -44);
-        mCsiRsrq = inRangeOrUnavailable(csiRsrq, -20, -3);
-        mCsiSinr = inRangeOrUnavailable(csiSinr, -23, 23);
-        mSsRsrp = inRangeOrUnavailable(ssRsrp, -140, -44);
-        mSsRsrq = inRangeOrUnavailable(ssRsrq, -43, 20);
-        mSsSinr = inRangeOrUnavailable(ssSinr, -23, 40);
-        updateLevel(null, null);
+        this(csiRsrp, csiRsrq, csiSinr, CellInfo.UNAVAILABLE, Collections.emptyList(),
+                ssRsrp, ssRsrq, ssSinr);
     }
 
     /**
@@ -164,6 +211,15 @@
     }
 
     /**
+     * @hide
+     * @param ss signal strength from modem.
+     */
+    public CellSignalStrengthNr(android.hardware.radio.V1_6.NrSignalStrength ss) {
+        this(flip(ss.base.csiRsrp), flip(ss.base.csiRsrq), ss.base.csiSinr, ss.csiCqiTableIndex,
+                ss.csiCqiReport, flip(ss.base.ssRsrp), flip(ss.base.ssRsrq), ss.base.ssSinr);
+    }
+
+    /**
      * Flip sign cell strength value when taking in the value from hal
      * @param val cell strength value
      * @return flipped value
@@ -232,6 +288,36 @@
         return mCsiSinr;
     }
 
+    /**
+     * Return CSI channel quality indicator (CQI) table index. There are multiple CQI tables.
+     * The definition of CQI in each table is different.
+     *
+     * Reference: 3GPP TS 138.214 section 5.2.2.1.
+     *
+     * Range [1, 3].
+     */
+    /** @hide */
+    public int getCsiCqiTableIndex() {
+        return mCsiCqiTableIndex;
+    }
+    /**
+     * Return a list of CSI channel quality indicators (CQI) for all subbands.
+     *
+     * If the CQI report is for the entire wideband, a single CQI index is provided.
+     * If the CQI report is for all subbands, one CQI index is provided for each subband,
+     * in ascending order of subband index.
+     * If CQI is not available, the CQI report is empty.
+     *
+     * Reference: 3GPP TS 138.214 section 5.2.2.1.
+     *
+     * Range [0, 15] for each CQI.
+     */
+    /** @hide */
+    @NonNull
+    public List<Integer> getCsiCqiReport() {
+        return mCsiCqiReport;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -243,6 +329,8 @@
         dest.writeInt(mCsiRsrp);
         dest.writeInt(mCsiRsrq);
         dest.writeInt(mCsiSinr);
+        dest.writeInt(mCsiCqiTableIndex);
+        dest.writeList(mCsiCqiReport);
         dest.writeInt(mSsRsrp);
         dest.writeInt(mSsRsrq);
         dest.writeInt(mSsSinr);
@@ -253,6 +341,8 @@
         mCsiRsrp = in.readInt();
         mCsiRsrq = in.readInt();
         mCsiSinr = in.readInt();
+        mCsiCqiTableIndex = in.readInt();
+        mCsiCqiReport = in.readArrayList(Integer.class.getClassLoader());
         mSsRsrp = in.readInt();
         mSsRsrq = in.readInt();
         mSsSinr = in.readInt();
@@ -265,6 +355,8 @@
         mCsiRsrp = CellInfo.UNAVAILABLE;
         mCsiRsrq = CellInfo.UNAVAILABLE;
         mCsiSinr = CellInfo.UNAVAILABLE;
+        mCsiCqiTableIndex = CellInfo.UNAVAILABLE;
+        mCsiCqiReport = Collections.emptyList();
         mSsRsrp = CellInfo.UNAVAILABLE;
         mSsRsrq = CellInfo.UNAVAILABLE;
         mSsSinr = CellInfo.UNAVAILABLE;
@@ -408,6 +500,8 @@
         mCsiRsrp = s.mCsiRsrp;
         mCsiRsrq = s.mCsiRsrq;
         mCsiSinr = s.mCsiSinr;
+        mCsiCqiTableIndex = s.mCsiCqiTableIndex;
+        mCsiCqiReport = s.mCsiCqiReport;
         mSsRsrp = s.mSsRsrp;
         mSsRsrq = s.mSsRsrq;
         mSsSinr = s.mSsSinr;
@@ -423,7 +517,8 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mCsiRsrp, mCsiRsrq, mCsiSinr, mSsRsrp, mSsRsrq, mSsSinr, mLevel);
+        return Objects.hash(mCsiRsrp, mCsiRsrq, mCsiSinr, mCsiCqiTableIndex,
+                mCsiCqiReport, mSsRsrp, mSsRsrq, mSsSinr, mLevel);
     }
 
     private static final CellSignalStrengthNr sInvalid = new CellSignalStrengthNr();
@@ -439,6 +534,8 @@
         if (obj instanceof CellSignalStrengthNr) {
             CellSignalStrengthNr o = (CellSignalStrengthNr) obj;
             return mCsiRsrp == o.mCsiRsrp && mCsiRsrq == o.mCsiRsrq && mCsiSinr == o.mCsiSinr
+                    && mCsiCqiTableIndex == o.mCsiCqiTableIndex
+                    && mCsiCqiReport.equals(o.mCsiCqiReport)
                     && mSsRsrp == o.mSsRsrp && mSsRsrq == o.mSsRsrq && mSsSinr == o.mSsSinr
                     && mLevel == o.mLevel;
         }
@@ -451,7 +548,8 @@
                 .append(TAG + ":{")
                 .append(" csiRsrp = " + mCsiRsrp)
                 .append(" csiRsrq = " + mCsiRsrq)
-                .append(" csiSinr = " + mCsiSinr)
+                .append(" csiCqiTableIndex = " + mCsiCqiTableIndex)
+                .append(" csiCqiReport = " + mCsiCqiReport)
                 .append(" ssRsrp = " + mSsRsrp)
                 .append(" ssRsrq = " + mSsRsrq)
                 .append(" ssSinr = " + mSsSinr)
diff --git a/telephony/java/android/telephony/OWNERS b/telephony/java/android/telephony/OWNERS
new file mode 100644
index 0000000..6aa399d
--- /dev/null
+++ b/telephony/java/android/telephony/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 20868
+
+rgreenwalt@google.com
+tgunn@google.com
+amitmahajan@google.com
diff --git a/telephony/java/android/telephony/PhoneCapability.java b/telephony/java/android/telephony/PhoneCapability.java
index b785037..6571858 100644
--- a/telephony/java/android/telephony/PhoneCapability.java
+++ b/telephony/java/android/telephony/PhoneCapability.java
@@ -28,8 +28,6 @@
 /**
  * Define capability of a modem group. That is, the capabilities
  * are shared between those modems defined by list of modem IDs.
- *
- * @hide
  */
 public final class PhoneCapability implements Parcelable {
     // Hardcoded default DSDS capability.
diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java
index 8d49e15..95c69ba 100644
--- a/telephony/java/android/telephony/PhysicalChannelConfig.java
+++ b/telephony/java/android/telephony/PhysicalChannelConfig.java
@@ -29,10 +29,6 @@
 import java.util.Arrays;
 import java.util.Objects;
 
-/**
- * @hide
- */
-@SystemApi
 public final class PhysicalChannelConfig implements Parcelable {
 
     // TODO(b/72993578) consolidate these enums in a central location.
@@ -86,7 +82,7 @@
     private int mFrequencyRange;
 
     /**
-     * The absolute radio frequency channel number, {@link CHANNEL_NUMBER_UNKNOWN} if unknown.
+     * The absolute radio frequency channel number, {@link #CHANNEL_NUMBER_UNKNOWN} if unknown.
      */
     private int mChannelNumber;
 
@@ -97,7 +93,7 @@
     private int[] mContextIds;
 
     /**
-     * The physical cell identifier for this cell - PCI, PSC, {@link PHYSICAL_CELL_ID_UNKNOWN}
+     * The physical cell identifier for this cell - PCI, PSC, {@link #PHYSICAL_CELL_ID_UNKNOWN}
      * if unknown.
      */
     private int mPhysicalCellId;
@@ -153,7 +149,7 @@
 
     /**
      * @return the absolute radio frequency channel number for this physical channel,
-     * {@link CHANNEL_NUMBER_UNKNOWN} if unknown.
+     * {@link #CHANNEL_NUMBER_UNKNOWN} if unknown.
      */
     public int getChannelNumber() {
         return mChannelNumber;
@@ -169,7 +165,7 @@
      * In 5G RAN, this value is physical layer cell identity. The range is [0, 1007].
      * Reference: 3GPP TS 38.211 section 7.4.2.1.
      *
-     * @return the physical cell identifier for this cell, {@link PHYSICAL_CELL_ID_UNKNOWN}
+     * @return the physical cell identifier for this cell, {@link #PHYSICAL_CELL_ID_UNKNOWN}
      * if {@link android.telephony.CellInfo#UNAVAILABLE}.
      */
     @IntRange(from = 0, to = 1007)
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index 7bd0bc0..b317c55 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -187,6 +187,21 @@
                 new CellSignalStrengthNr(signalStrength.nr));
     }
 
+    /**
+     * Constructor for Radio HAL V1.6.
+     *
+     * @param signalStrength signal strength reported from modem.
+     * @hide
+     */
+    public SignalStrength(android.hardware.radio.V1_6.SignalStrength signalStrength) {
+        this(new CellSignalStrengthCdma(signalStrength.cdma, signalStrength.evdo),
+                new CellSignalStrengthGsm(signalStrength.gsm),
+                new CellSignalStrengthWcdma(signalStrength.wcdma),
+                new CellSignalStrengthTdscdma(signalStrength.tdscdma),
+                new CellSignalStrengthLte(signalStrength.lte),
+                new CellSignalStrengthNr(signalStrength.nr));
+    }
+
     private CellSignalStrength getPrimary() {
         // This behavior is intended to replicate the legacy behavior of getLevel() by prioritizing
         // newer faster RATs for default/for display purposes.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 886ec33..239329c 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -124,6 +124,7 @@
 import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
@@ -155,6 +156,7 @@
 public class TelephonyManager {
     private static final String TAG = "TelephonyManager";
 
+    private TelephonyRegistryManager mTelephonyRegistryMgr;
     /**
      * To expand the error codes for {@link TelephonyManager#updateAvailableNetworks} and
      * {@link TelephonyManager#setPreferredOpportunisticDataSubscription}.
@@ -5574,12 +5576,22 @@
      * @param events The telephony state(s) of interest to the listener,
      *               as a bitwise-OR combination of {@link PhoneStateListener}
      *               LISTEN_ flags.
-     * @deprecated use {@link #listen(long, PhoneStateListener) instead due to the event number
-     *             limit increased to 64.
+     * @deprecated Use {@link #registerPhoneStateListener(Executor, PhoneStateListener)}.
      */
     @Deprecated
     public void listen(PhoneStateListener listener, int events) {
-        listen(events, listener);
+        boolean notifyNow = getITelephony() != null;
+        mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class);
+        if (mTelephonyRegistryMgr != null) {
+            if (events != PhoneStateListener.LISTEN_NONE) {
+                mTelephonyRegistryMgr.registerPhoneStateListenerWithEvents(mSubId,
+                        getOpPackageName(), getAttributionTag(), listener, events, notifyNow);
+            } else {
+                unregisterPhoneStateListener(listener);
+            }
+        } else {
+            throw new IllegalStateException("telephony service is null.");
+        }
     }
 
     /**
@@ -5615,18 +5627,21 @@
      *               LISTEN_ flags.
      * @param listener The {@link PhoneStateListener} object to register
      *                 (or unregister)
+     * @deprecated Use {@link #registerPhoneStateListener(Executor, PhoneStateListener)}.
      */
+    @Deprecated
     public void listen(long events, @NonNull PhoneStateListener listener) {
-        if (mContext == null) return;
-        boolean notifyNow = (getITelephony() != null);
-        TelephonyRegistryManager telephonyRegistry =
-                (TelephonyRegistryManager)
-                        mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
-        if (telephonyRegistry != null) {
-            telephonyRegistry.listenForSubscriber(mSubId, getOpPackageName(), getAttributionTag(),
-                    listener, events, notifyNow);
+        mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class);
+        if (mTelephonyRegistryMgr != null) {
+            if (events != PhoneStateListener.LISTEN_NONE) {
+                mTelephonyRegistryMgr.registerPhoneStateListenerWithEvents(mSubId,
+                        getOpPackageName(), getAttributionTag(), listener,
+                        Long.valueOf(events).intValue(), getITelephony() != null);
+            } else {
+                unregisterPhoneStateListener(listener);
+            }
         } else {
-            Rlog.w(TAG, "telephony registry not ready.");
+            throw new IllegalStateException("telephony service is null.");
         }
     }
 
@@ -12290,23 +12305,15 @@
     @NonNull
     public Map<Integer, List<EmergencyNumber>> getEmergencyNumberList(
             @EmergencyServiceCategories int categories) {
-        Map<Integer, List<EmergencyNumber>> emergencyNumberList = new HashMap<>();
+        Map<Integer, List<EmergencyNumber>> emergencyNumberListForCategories = new HashMap<>();
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
-                emergencyNumberList = telephony.getEmergencyNumberList(
-                        mContext.getOpPackageName(), mContext.getAttributionTag());
-                if (emergencyNumberList != null) {
-                    for (Integer subscriptionId : emergencyNumberList.keySet()) {
-                        List<EmergencyNumber> numberList = emergencyNumberList.get(subscriptionId);
-                        for (EmergencyNumber number : numberList) {
-                            if (!number.isInEmergencyServiceCategories(categories)) {
-                                numberList.remove(number);
-                            }
-                        }
-                    }
-                }
-                return emergencyNumberList;
+                Map<Integer, List<EmergencyNumber>> emergencyNumberList =
+                        telephony.getEmergencyNumberList(mContext.getOpPackageName(),
+                                mContext.getAttributionTag());
+                emergencyNumberListForCategories =
+                        filterEmergencyNumbersByCategories(emergencyNumberList, categories);
             } else {
                 throw new IllegalStateException("telephony service is null.");
             }
@@ -12314,7 +12321,34 @@
             Log.e(TAG, "getEmergencyNumberList with Categories RemoteException", ex);
             ex.rethrowAsRuntimeException();
         }
-        return emergencyNumberList;
+        return emergencyNumberListForCategories;
+    }
+
+    /**
+     * Filter emergency numbers with categories.
+     *
+     * @hide
+     */
+    @VisibleForTesting
+    public Map<Integer, List<EmergencyNumber>> filterEmergencyNumbersByCategories(
+            Map<Integer, List<EmergencyNumber>> emergencyNumberList,
+                    @EmergencyServiceCategories int categories) {
+        Map<Integer, List<EmergencyNumber>> emergencyNumberListForCategories = new HashMap<>();
+        if (emergencyNumberList != null) {
+            for (Integer subscriptionId : emergencyNumberList.keySet()) {
+                List<EmergencyNumber> allNumbersForSub = emergencyNumberList.get(
+                        subscriptionId);
+                List<EmergencyNumber> numbersForCategoriesPerSub = new ArrayList<>();
+                for (EmergencyNumber number : allNumbersForSub) {
+                    if (number.isInEmergencyServiceCategories(categories)) {
+                        numbersForCategoriesPerSub.add(number);
+                    }
+                }
+                emergencyNumberListForCategories.put(
+                        subscriptionId, numbersForCategoriesPerSub);
+            }
+        }
+        return emergencyNumberListForCategories;
     }
 
     /**
@@ -14316,4 +14350,69 @@
         }
         return THERMAL_MITIGATION_RESULT_UNKNOWN_ERROR;
     }
+    /**
+     * Registers a listener object to receive notification of changes
+     * in specified telephony states.
+     * <p>
+     * To register a listener, pass a {@link PhoneStateListener} which implements
+     * interfaces of events. For example,
+     * FakeServiceStateChangedListener extends {@link PhoneStateListener} implements
+     * {@link PhoneStateListener.ServiceStateChangedListener}.
+     *
+     * At registration, and when a specified telephony state changes, the telephony manager invokes
+     * the appropriate callback method on the listener object and passes the current (updated)
+     * values.
+     * <p>
+     *
+     * If this TelephonyManager object has been created with {@link #createForSubscriptionId},
+     * applies to the given subId. Otherwise, applies to
+     * {@link SubscriptionManager#getDefaultSubscriptionId()}. To listen events for multiple subIds,
+     * pass a separate listener object to each TelephonyManager object created with
+     * {@link #createForSubscriptionId}.
+     *
+     * Note: if you call this method while in the middle of a binder transaction, you <b>must</b>
+     * call {@link android.os.Binder#clearCallingIdentity()} before calling this method. A
+     * {@link SecurityException} will be thrown otherwise.
+     *
+     * This API should be used sparingly -- large numbers of listeners will cause system
+     * instability. If a process has registered too many listeners without unregistering them, it
+     * may encounter an {@link IllegalStateException} when trying to register more listeners.
+     *
+     * @param executor The executor of where the callback will execute.
+     * @param listener The {@link PhoneStateListener} object to register.
+     */
+    public void registerPhoneStateListener(@NonNull @CallbackExecutor Executor executor,
+            @NonNull PhoneStateListener listener) {
+        if (executor == null || listener == null) {
+            throw new IllegalArgumentException("PhoneStateListener and executor must be non-null");
+        }
+        mTelephonyRegistryMgr = (TelephonyRegistryManager)
+                mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
+        if (mTelephonyRegistryMgr != null) {
+            mTelephonyRegistryMgr.registerPhoneStateListener(executor, mSubId,
+                    getOpPackageName(), getAttributionTag(), listener, getITelephony() != null);
+        } else {
+            throw new IllegalStateException("telephony service is null.");
+        }
+    }
+
+    /**
+     * Unregister an existing {@link PhoneStateListener}.
+     *
+     * @param listener The {@link PhoneStateListener} object to unregister.
+     */
+    public void unregisterPhoneStateListener(@NonNull PhoneStateListener listener) {
+
+        if (mContext == null) {
+            throw new IllegalStateException("telephony service is null.");
+        }
+
+        mTelephonyRegistryMgr = mContext.getSystemService(TelephonyRegistryManager.class);
+        if (mTelephonyRegistryMgr != null) {
+            mTelephonyRegistryMgr.unregisterPhoneStateListener(mSubId, getOpPackageName(),
+                    getAttributionTag(), listener, getITelephony() != null);
+        } else {
+            throw new IllegalStateException("telephony service is null.");
+        }
+    }
 }
diff --git a/telephony/java/android/telephony/cdma/OWNERS b/telephony/java/android/telephony/cdma/OWNERS
new file mode 100644
index 0000000..6aa399d
--- /dev/null
+++ b/telephony/java/android/telephony/cdma/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 20868
+
+rgreenwalt@google.com
+tgunn@google.com
+amitmahajan@google.com
diff --git a/telephony/java/android/telephony/data/OWNERS b/telephony/java/android/telephony/data/OWNERS
new file mode 100644
index 0000000..932b35c
--- /dev/null
+++ b/telephony/java/android/telephony/data/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 20868
+
+rgreenwalt@google.com
+tgunn@google.com
+jackyu@google.com
diff --git a/telephony/java/android/telephony/emergency/OWNERS b/telephony/java/android/telephony/emergency/OWNERS
new file mode 100644
index 0000000..fa07dce
--- /dev/null
+++ b/telephony/java/android/telephony/emergency/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 20868
+
+rgreenwalt@google.com
+tgunn@google.com
+shuoq@google.com
diff --git a/telephony/java/android/telephony/euicc/OWNERS b/telephony/java/android/telephony/euicc/OWNERS
new file mode 100644
index 0000000..9e51a4b
--- /dev/null
+++ b/telephony/java/android/telephony/euicc/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 20868
+
+rgreenwalt@google.com
+tgunn@google.com
+refuhoo@google.com
+amitmahajan@google.com
diff --git a/telephony/java/android/telephony/gsm/OWNERS b/telephony/java/android/telephony/gsm/OWNERS
new file mode 100644
index 0000000..6aa399d
--- /dev/null
+++ b/telephony/java/android/telephony/gsm/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 20868
+
+rgreenwalt@google.com
+tgunn@google.com
+amitmahajan@google.com
diff --git a/telephony/java/android/telephony/ims/ImsReasonInfo.java b/telephony/java/android/telephony/ims/ImsReasonInfo.java
index 184477a..c140249 100644
--- a/telephony/java/android/telephony/ims/ImsReasonInfo.java
+++ b/telephony/java/android/telephony/ims/ImsReasonInfo.java
@@ -1322,6 +1322,13 @@
      */
     public static final int EXTRA_CODE_CALL_RETRY_BY_SETTINGS = 3;
 
+    /**
+     * An extra that may be populated when the {@link #CODE_LOCAL_CALL_CS_RETRY_REQUIRED} result has
+     * been returned.
+     * <p>
+     * Try to connect the call using CS as emergency
+     */
+    public static final int EXTRA_CODE_CALL_RETRY_EMERGENCY = 4;
 
     // For main reason code
     /** @hide */
diff --git a/telephony/java/android/telephony/ims/OWNERS b/telephony/java/android/telephony/ims/OWNERS
new file mode 100644
index 0000000..0854c5d
--- /dev/null
+++ b/telephony/java/android/telephony/ims/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 20868
+
+rgreenwalt@google.com
+tgunn@google.com
+breadley@google.com
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl b/telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl
index b47e3c7..10c50be 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl
@@ -22,7 +22,6 @@
 import android.telephony.ims.aidl.IImsCapabilityCallback;
 import android.telephony.ims.aidl.IOptionsResponseCallback;
 import android.telephony.ims.aidl.IPublishResponseCallback;
-import android.telephony.ims.aidl.IRcsFeatureListener;
 import android.telephony.ims.aidl.ISubscribeResponseCallback;
 import android.telephony.ims.feature.CapabilityChangeRequest;
 
@@ -34,7 +33,6 @@
  */
 interface IImsRcsFeature {
     // Not oneway because we need to verify this completes before doing anything else.
-    void setListener(IRcsFeatureListener listener);
     int queryCapabilityStatus();
     // Inherited from ImsFeature
     int getFeatureState();
@@ -50,14 +48,4 @@
     oneway void subscribeForCapabilities(in List<Uri> uris, ISubscribeResponseCallback cb);
     oneway void sendOptionsCapabilityRequest(in Uri contactUri,
             in List<String> myCapabilities, IOptionsResponseCallback cb);
-    // RcsPresenceExchangeImplBase specific api
-    oneway void requestCapabilities(in List<Uri> uris, int operationToken);
-    oneway void updateCapabilities(in RcsContactUceCapability capabilities, int operationToken);
-    // RcsSipOptionsImplBase specific api
-    oneway void sendCapabilityRequest(in Uri contactUri,
-            in RcsContactUceCapability capabilities, int operationToken);
-    oneway void respondToCapabilityRequest(in String contactUri,
-            in RcsContactUceCapability ownCapabilities, int operationToken);
-    oneway void respondToCapabilityRequestWithError(in Uri contactUri, int code, in String reason,
-            int operationToken);
 }
diff --git a/telephony/java/android/telephony/ims/aidl/IRcsFeatureListener.aidl b/telephony/java/android/telephony/ims/aidl/IRcsFeatureListener.aidl
deleted file mode 100644
index 70cf651..0000000
--- a/telephony/java/android/telephony/ims/aidl/IRcsFeatureListener.aidl
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.ims.aidl;
-
-import android.net.Uri;
-import android.telephony.ims.RcsContactUceCapability;
-
-import java.util.List;
-
-/**
- * Listener interface for updates from the RcsFeature back to the framework.
- * {@hide}
- */
-interface IRcsFeatureListener {
-    //RcsCapabilityExchange specific
-    oneway void onCommandUpdate(int commandCode, int operationToken);
-    // RcsPresenceExchangeImplBase Specific
-    oneway void onNetworkResponse(int code, in String reason, int operationToken);
-    oneway void onCapabilityRequestResponsePresence(in List<RcsContactUceCapability> infos,
-    int operationToken);
-    oneway void onNotifyUpdateCapabilities(int publishTriggerType);
-    oneway void onUnpublish();
-    // RcsSipOptionsImplBase specific
-    oneway void onCapabilityRequestResponseOptions(int code, in String reason,
-            in RcsContactUceCapability info, int operationToken);
-    oneway void onRemoteCapabilityRequest(in Uri contactUri, in RcsContactUceCapability remoteInfo,
-            int operationToken);
-}
diff --git a/telephony/java/android/telephony/ims/aidl/OWNERS b/telephony/java/android/telephony/ims/aidl/OWNERS
new file mode 100644
index 0000000..0854c5d
--- /dev/null
+++ b/telephony/java/android/telephony/ims/aidl/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 20868
+
+rgreenwalt@google.com
+tgunn@google.com
+breadley@google.com
diff --git a/telephony/java/android/telephony/ims/compat/OWNERS b/telephony/java/android/telephony/ims/compat/OWNERS
new file mode 100644
index 0000000..0854c5d
--- /dev/null
+++ b/telephony/java/android/telephony/ims/compat/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 20868
+
+rgreenwalt@google.com
+tgunn@google.com
+breadley@google.com
diff --git a/telephony/java/android/telephony/ims/compat/feature/OWNERS b/telephony/java/android/telephony/ims/compat/feature/OWNERS
new file mode 100644
index 0000000..0854c5d
--- /dev/null
+++ b/telephony/java/android/telephony/ims/compat/feature/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 20868
+
+rgreenwalt@google.com
+tgunn@google.com
+breadley@google.com
diff --git a/telephony/java/android/telephony/ims/compat/stub/OWNERS b/telephony/java/android/telephony/ims/compat/stub/OWNERS
new file mode 100644
index 0000000..0854c5d
--- /dev/null
+++ b/telephony/java/android/telephony/ims/compat/stub/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 20868
+
+rgreenwalt@google.com
+tgunn@google.com
+breadley@google.com
diff --git a/telephony/java/android/telephony/ims/feature/OWNERS b/telephony/java/android/telephony/ims/feature/OWNERS
new file mode 100644
index 0000000..0854c5d
--- /dev/null
+++ b/telephony/java/android/telephony/ims/feature/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 20868
+
+rgreenwalt@google.com
+tgunn@google.com
+breadley@google.com
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index 5de2ddc..cde7067 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -19,17 +19,16 @@
 import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.net.Uri;
 import android.os.RemoteException;
-import android.telephony.ims.RcsContactUceCapability;
 import android.telephony.ims.RcsUceAdapter;
 import android.telephony.ims.aidl.ICapabilityExchangeEventListener;
 import android.telephony.ims.aidl.IImsCapabilityCallback;
 import android.telephony.ims.aidl.IImsRcsFeature;
 import android.telephony.ims.aidl.IOptionsResponseCallback;
 import android.telephony.ims.aidl.IPublishResponseCallback;
-import android.telephony.ims.aidl.IRcsFeatureListener;
 import android.telephony.ims.aidl.ISubscribeResponseCallback;
 import android.telephony.ims.aidl.RcsOptionsResponseAidlWrapper;
 import android.telephony.ims.aidl.RcsPublishResponseAidlWrapper;
@@ -74,16 +73,6 @@
             mExecutor = executor;
         }
 
-        /**
-         * @deprecated This method is deprecated. Please call the method
-         * setCapabilityExchangeEventListener instead.
-         */
-        @Override
-        @Deprecated
-        public void setListener(IRcsFeatureListener listener) {
-            Log.w(LOG_TAG, "The method setListener is deprecated");
-        }
-
         @Override
         public int queryCapabilityStatus() throws RemoteException {
             return executeMethodAsyncForResult(
@@ -124,7 +113,7 @@
         // RcsCapabilityExchangeImplBase specific APIs
         @Override
         public void setCapabilityExchangeEventListener(
-                @NonNull ICapabilityExchangeEventListener listener) throws RemoteException {
+                @Nullable ICapabilityExchangeEventListener listener) throws RemoteException {
             executeMethodAsync(() -> mReference.setCapabilityExchangeEventListener(listener),
                     "setCapabilityExchangeEventListener");
         }
@@ -155,34 +144,6 @@
                     "sendOptionsCapabilityRequest");
         }
 
-        // RcsPresenceExchangeImplBase specific APIS
-        @Override
-        public void requestCapabilities(List<Uri> uris, int operationToken) throws RemoteException {
-            throw new RemoteException("Unsupported operation: requestCapabilities");
-        }
-        @Override
-        public void updateCapabilities(RcsContactUceCapability capabilities, int operationToken)
-                throws RemoteException {
-            throw new RemoteException("Unsupported operation: updateCapabilities");
-        }
-        // RcsSipOptionsImplBase specific APIS
-        @Override
-        public void sendCapabilityRequest(Uri contactUri, RcsContactUceCapability capabilities,
-                int operationToken) throws RemoteException {
-            throw new RemoteException("Unsupported operation: sendCapabilityRequest");
-        }
-        @Override
-        public void respondToCapabilityRequest(String contactUri,
-                RcsContactUceCapability ownCapabilities, int operationToken)
-                throws RemoteException {
-            throw new RemoteException("Unsupported operation: respondToCapabilityRequest");
-        }
-        @Override
-        public void respondToCapabilityRequestWithError(Uri contactUri, int code, String reason,
-                int operationToken) throws RemoteException {
-            throw new RemoteException("Unsupported operation: respondToCapabilityRequestWithError");
-        }
-
         // Call the methods with a clean calling identity on the executor and wait indefinitely for
         // the future to return.
         private void executeMethodAsync(Runnable r, String errorLogName)
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
index e0290a5..e757d9f 100644
--- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -126,7 +126,7 @@
          */
         @Override
         public synchronized String getConfigString(int item) throws RemoteException {
-            if (mProvisionedIntValue.containsKey(item)) {
+            if (mProvisionedStringValue.containsKey(item)) {
                 return mProvisionedStringValue.get(item);
             } else {
                 String retVal = getImsConfigImpl().getConfigString(item);
diff --git a/telephony/java/android/telephony/ims/stub/OWNERS b/telephony/java/android/telephony/ims/stub/OWNERS
new file mode 100644
index 0000000..0854c5d
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 20868
+
+rgreenwalt@google.com
+tgunn@google.com
+breadley@google.com
diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java
deleted file mode 100644
index 0b13efb..0000000
--- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.ims.stub;
-
-import android.annotation.IntDef;
-import android.os.RemoteException;
-import android.telephony.ims.ImsException;
-import android.telephony.ims.aidl.IRcsFeatureListener;
-import android.telephony.ims.feature.ImsFeature;
-import android.telephony.ims.feature.RcsFeature;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Base class for different types of Capability exchange, presence using
- * {@link RcsPresenceExchangeImplBase} and SIP OPTIONS exchange using {@link RcsSipOptionsImplBase}.
- *
- * @hide
- */
-public class RcsCapabilityExchange {
-
-    /**  Service is unknown. */
-    public static final int COMMAND_CODE_SERVICE_UNKNOWN = 0;
-    /** The command completed successfully. */
-    public static final int COMMAND_CODE_SUCCESS = 1;
-    /** The command failed with an unknown error. */
-    public static final int COMMAND_CODE_GENERIC_FAILURE = 2;
-    /**  Invalid parameter(s). */
-    public static final int COMMAND_CODE_INVALID_PARAM = 3;
-    /**  Fetch error. */
-    public static final int COMMAND_CODE_FETCH_ERROR = 4;
-    /**  Request timed out. */
-    public static final int COMMAND_CODE_REQUEST_TIMEOUT = 5;
-    /**  Failure due to insufficient memory available. */
-    public static final int COMMAND_CODE_INSUFFICIENT_MEMORY = 6;
-    /**  Network connection is lost. */
-    public static final int COMMAND_CODE_LOST_NETWORK_CONNECTION = 7;
-    /**  Requested feature/resource is not supported. */
-    public static final int COMMAND_CODE_NOT_SUPPORTED = 8;
-    /**  Contact or resource is not found. */
-    public static final int COMMAND_CODE_NOT_FOUND = 9;
-    /**  Service is not available. */
-    public static final int COMMAND_CODE_SERVICE_UNAVAILABLE = 10;
-    /**  No Change in Capabilities */
-    public static final int COMMAND_CODE_NO_CHANGE_IN_CAP = 11;
-
-    /** @hide*/
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = "COMMAND_CODE_", value = {
-            COMMAND_CODE_SERVICE_UNKNOWN,
-            COMMAND_CODE_SUCCESS,
-            COMMAND_CODE_GENERIC_FAILURE,
-            COMMAND_CODE_INVALID_PARAM,
-            COMMAND_CODE_FETCH_ERROR,
-            COMMAND_CODE_REQUEST_TIMEOUT,
-            COMMAND_CODE_INSUFFICIENT_MEMORY,
-            COMMAND_CODE_LOST_NETWORK_CONNECTION,
-            COMMAND_CODE_NOT_SUPPORTED,
-            COMMAND_CODE_NOT_FOUND,
-            COMMAND_CODE_SERVICE_UNAVAILABLE,
-            COMMAND_CODE_NO_CHANGE_IN_CAP
-    })
-    public @interface CommandCode {}
-
-
-    private RcsFeature mFeature;
-
-    /** @hide */
-    public final void initialize(RcsFeature feature) {
-        mFeature = feature;
-    }
-
-    /** @hide */
-    protected final IRcsFeatureListener getListener() throws ImsException {
-        throw new ImsException("This method is deprecated.",
-                ImsException.CODE_ERROR_UNSUPPORTED_OPERATION);
-    }
-
-    /**
-     * Provides the framework with an update as to whether or not a command completed successfully
-     * locally. This includes capabilities requests and updates from the network. If it does not
-     * complete successfully, then the framework may retry the command again later, depending on the
-     * error. If the command does complete successfully, the framework will then wait for network
-     * updates.
-     *
-     * @param code The result of the pending command. If {@link #COMMAND_CODE_SUCCESS}, further
-     *             updates will be sent for this command using the associated operationToken.
-     * @param operationToken the token associated with the pending command.
-     * @throws ImsException If this {@link RcsCapabilityExchange} instance is not currently
-     * connected to the framework. This can happen if the {@link RcsFeature} is not
-     * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
-     * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
-     * Telephony stack has crashed.
-     */
-    public final void onCommandUpdate(@CommandCode int code, int operationToken)
-            throws ImsException {
-        try {
-            getListener().onCommandUpdate(code, operationToken);
-        } catch (RemoteException e) {
-            throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
-        }
-    }
-}
diff --git a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java
deleted file mode 100644
index bb03448..0000000
--- a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.ims.stub;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.net.Uri;
-import android.os.RemoteException;
-import android.telephony.ims.ImsException;
-import android.telephony.ims.RcsContactUceCapability;
-import android.telephony.ims.feature.ImsFeature;
-import android.telephony.ims.feature.RcsFeature;
-import android.util.Log;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.List;
-
-/**
- * Base implementation for RCS User Capability Exchange using Presence. Any ImsService implementing
- * this service must implement the stub methods {@link #requestCapabilities(List, int)}  and
- * {@link #updateCapabilities(RcsContactUceCapability, int)}.
- *
- * @hide
- */
-public class RcsPresenceExchangeImplBase extends RcsCapabilityExchange {
-
-    private static final String LOG_TAG = "RcsPresenceExchangeIB";
-
-    /**
-     * The request has resulted in any other 4xx/5xx/6xx that is not covered below. No retry will be
-     * attempted.
-     */
-    public static final int RESPONSE_SUBSCRIBE_GENERIC_FAILURE = -1;
-
-    /**
-     * The request has succeeded with a “200” message from the network.
-     */
-    public static final int RESPONSE_SUCCESS = 0;
-
-    /**
-     * The request has resulted in a “403” (User Not Registered) error from the network. Will retry
-     * capability polling with an exponential backoff.
-     */
-    public static final int RESPONSE_NOT_REGISTERED = 1;
-
-    /**
-     * The request has resulted in a “403” (not authorized (Requestor)) error from the network. No
-     * retry will be attempted.
-     */
-    public static final int RESPONSE_NOT_AUTHORIZED_FOR_PRESENCE = 2;
-
-    /**
-     * The request has resulted in a "403” (Forbidden) or other “403” error from the network and
-     * will be handled the same as “404” Not found. No retry will be attempted.
-     */
-    public static final int RESPONSE_FORBIDDEN = 3;
-
-    /**
-     * The request has resulted in a “404” (Not found) result from the network. No retry will be
-     * attempted.
-     */
-    public static final int RESPONSE_NOT_FOUND = 4;
-
-    /**
-     * The request has resulted in a “408” response. Retry after exponential backoff.
-     */
-    public static final int RESPONSE_SIP_REQUEST_TIMEOUT = 5;
-
-    /**
-     *  The network has responded with a “413” (Too Large) response from the network. Capability
-     *  request contains too many items and must be shrunk before the request will be accepted.
-     */
-    public static final int RESPONSE_SUBSCRIBE_TOO_LARGE = 6;
-
-    /**
-     * The request has resulted in a “423” response. Retry after exponential backoff.
-     */
-    public static final int RESPONSE_SIP_INTERVAL_TOO_SHORT = 7;
-
-    /**
-     * The request has resulted in a “503” response. Retry after exponential backoff.
-     */
-    public static final int RESPONSE_SIP_SERVICE_UNAVAILABLE = 8;
-
-    /** @hide*/
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = "RESPONSE_", value = {
-            RESPONSE_SUBSCRIBE_GENERIC_FAILURE,
-            RESPONSE_SUCCESS,
-            RESPONSE_NOT_REGISTERED,
-            RESPONSE_NOT_AUTHORIZED_FOR_PRESENCE,
-            RESPONSE_FORBIDDEN,
-            RESPONSE_NOT_FOUND,
-            RESPONSE_SIP_REQUEST_TIMEOUT,
-            RESPONSE_SUBSCRIBE_TOO_LARGE,
-            RESPONSE_SIP_INTERVAL_TOO_SHORT,
-            RESPONSE_SIP_SERVICE_UNAVAILABLE
-    })
-    public @interface PresenceResponseCode {}
-
-
-    /** A capability update has been requested due to the Entity Tag (ETag) expiring. */
-    public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 0;
-    /** A capability update has been requested due to moving to LTE with VoPS disabled. */
-    public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED = 1;
-    /** A capability update has been requested due to moving to LTE with VoPS enabled. */
-    public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED = 2;
-    /** A capability update has been requested due to moving to eHRPD. */
-    public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 3;
-    /** A capability update has been requested due to moving to HSPA+. */
-    public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS = 4;
-    /** A capability update has been requested due to moving to 3G. */
-    public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 5;
-    /** A capability update has been requested due to moving to 2G. */
-    public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 6;
-    /** A capability update has been requested due to moving to WLAN */
-    public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN = 7;
-    /** A capability update has been requested due to moving to IWLAN */
-    public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN = 8;
-    /** A capability update has been requested but the reason is unknown. */
-    public static final int CAPABILITY_UPDATE_TRIGGER_UNKNOWN = 9;
-    /** A capability update has been requested due to moving to 5G NR with VoPS disabled. */
-    public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED = 10;
-    /** A capability update has been requested due to moving to 5G NR with VoPS enabled. */
-    public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11;
-
-    /** @hide*/
-    @IntDef(value = {
-            CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED,
-            CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED,
-            CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED,
-            CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD,
-            CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS,
-            CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G,
-            CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G,
-            CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN,
-            CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN,
-            CAPABILITY_UPDATE_TRIGGER_UNKNOWN,
-            CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED,
-            CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED
-    }, prefix = "CAPABILITY_UPDATE_TRIGGER_")
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface StackPublishTriggerType {
-    }
-
-    /**
-     * Provide the framework with a subsequent network response update to
-     * {@link #updateCapabilities(RcsContactUceCapability, int)} and
-     * {@link #requestCapabilities(List, int)} operations.
-     *
-     * @param code The SIP response code sent from the network for the operation token specified.
-     * @param reason The optional reason response from the network. If the network provided no
-     *         reason with the code, the string should be empty.
-     * @param operationToken The token associated with the operation this service is providing a
-     *         response for.
-     * @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently
-     * connected to the framework. This can happen if the {@link RcsFeature} is not
-     * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
-     * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
-     * Telephony stack has crashed.
-     */
-    public final void onNetworkResponse(@PresenceResponseCode int code, @NonNull String reason,
-            int operationToken) throws ImsException {
-        try {
-            getListener().onNetworkResponse(code, reason, operationToken);
-        } catch (RemoteException e) {
-            throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
-        }
-    }
-
-    /**
-     * Provides the framework with the requested contacts’ capabilities requested by the framework
-     * using {@link #requestCapabilities(List, int)}.
-     *
-     * @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently
-     * connected to the framework. This can happen if the {@link RcsFeature} is not
-     * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
-     * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
-     * Telephony stack has crashed.
-     */
-    public final void onCapabilityRequestResponse(@NonNull List<RcsContactUceCapability> infos,
-            int operationToken) throws ImsException {
-        try {
-            getListener().onCapabilityRequestResponsePresence(infos, operationToken);
-        } catch (RemoteException e) {
-            throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
-        }
-    }
-
-    /**
-     * Trigger the framework to provide a capability update using
-     * {@link #updateCapabilities(RcsContactUceCapability, int)}.
-     * <p>
-     * This is typically used when trying to generate an initial PUBLISH for a new subscription to
-     * the network. The device will cache all presence publications after boot until this method is
-     * called once.
-     * @param publishTriggerType {@link StackPublishTriggerType} The reason for the capability
-     *         update request.
-     * @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently
-     * connected to the framework. This can happen if the {@link RcsFeature} is not
-     * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
-     * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
-     * Telephony stack has crashed.
-     */
-    public final void onNotifyUpdateCapabilites(@StackPublishTriggerType int publishTriggerType)
-            throws ImsException {
-        try {
-            getListener().onNotifyUpdateCapabilities(publishTriggerType);
-        } catch (RemoteException e) {
-            throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
-        }
-    }
-
-    /**
-     * Notify the framework that the device’s capabilities have been unpublished from the network.
-     *
-     * @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently
-     * connected to the framework. This can happen if the {@link RcsFeature} is not
-     * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
-     * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
-     * Telephony stack has crashed.
-     */
-    public final void onUnpublish() throws ImsException {
-        try {
-            getListener().onUnpublish();
-        } catch (RemoteException e) {
-            throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
-        }
-    }
-
-    /**
-     * The user capabilities of one or multiple contacts have been requested by the framework.
-     * <p>
-     * The implementer must follow up this call with an {@link #onCommandUpdate(int, int)} call to
-     * indicate whether or not this operation succeeded.  If this operation succeeds, network
-     * response updates should be sent to the framework using
-     * {@link #onNetworkResponse(int, String, int)}. When the operation is completed,
-     * {@link #onCapabilityRequestResponse(List, int)} should be called with the presence
-     * information for the contacts specified.
-     * @param uris A {@link List} of the {@link Uri}s that the framework is requesting the UCE
-     *             capabilities for.
-     * @param operationToken The token associated with this operation. Updates to this request using
-     *         {@link #onCommandUpdate(int, int)}, {@link #onNetworkResponse(int, String, int)}, and
-     *         {@link #onCapabilityRequestResponse(List, int)}  must use the same operation token
-     *         in response.
-     */
-    public void requestCapabilities(@NonNull List<Uri> uris, int operationToken) {
-        // Stub - to be implemented by service
-        Log.w(LOG_TAG, "requestCapabilities called with no implementation.");
-        try {
-            getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken);
-        } catch (RemoteException | ImsException e) {
-            // Do not do anything, this is a stub implementation.
-        }
-    }
-
-    /**
-     * The capabilities of this device have been updated and should be published to the network.
-     * <p>
-     * The implementer must follow up this call with an {@link #onCommandUpdate(int, int)} call to
-     * indicate whether or not this operation succeeded. If this operation succeeds, network
-     * response updates should be sent to the framework using
-     * {@link #onNetworkResponse(int, String, int)}.
-     * @param capabilities The capabilities for this device.
-     * @param operationToken The token associated with this operation. Any subsequent
-     *         {@link #onCommandUpdate(int, int)} or {@link #onNetworkResponse(int, String, int)}
-     *         calls regarding this update must use the same token.
-     */
-    public void updateCapabilities(@NonNull RcsContactUceCapability capabilities,
-            int operationToken) {
-        // Stub - to be implemented by service
-        Log.w(LOG_TAG, "updateCapabilities called with no implementation.");
-        try {
-            getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken);
-        } catch (RemoteException | ImsException e) {
-            // Do not do anything, this is a stub implementation.
-        }
-    }
-}
diff --git a/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java b/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java
deleted file mode 100644
index 2035fac..0000000
--- a/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.ims.stub;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.Uri;
-import android.os.RemoteException;
-import android.telephony.ims.ImsException;
-import android.telephony.ims.RcsContactUceCapability;
-import android.telephony.ims.feature.ImsFeature;
-import android.telephony.ims.feature.RcsFeature;
-import android.util.Log;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Base implementation for RCS User Capability Exchange using SIP OPTIONS.
- *
- * @hide
- */
-public class RcsSipOptionsImplBase extends RcsCapabilityExchange {
-
-    private static final String LOG_TAG = "RcsSipOptionsImplBase";
-
-    /**
-     * Indicates a SIP response from the remote user other than 200, 480, 408, 404, or 604.
-     */
-    public static final int RESPONSE_GENERIC_FAILURE = -1;
-
-    /**
-     * Indicates that the remote user responded with a 200 OK response.
-     */
-    public static final int RESPONSE_SUCCESS = 0;
-
-    /**
-     * Indicates that the remote user responded with a 480 TEMPORARY UNAVAILABLE response.
-     */
-    public static final int RESPONSE_TEMPORARILY_UNAVAILABLE = 1;
-
-    /**
-     * Indicates that the remote user responded with a 408 REQUEST TIMEOUT response.
-     */
-    public static final int RESPONSE_REQUEST_TIMEOUT = 2;
-
-    /**
-     * Indicates that the remote user responded with a 404 NOT FOUND response.
-     */
-    public static final int RESPONSE_NOT_FOUND = 3;
-
-    /**
-     * Indicates that the remote user responded with a 604 DOES NOT EXIST ANYWHERE response.
-     */
-    public static final int RESPONSE_DOES_NOT_EXIST_ANYWHERE = 4;
-
-    /**
-     * Indicates that the remote user responded with a 400 BAD REQUEST response.
-     */
-    public static final int RESPONSE_BAD_REQUEST = 5;
-
-    /** @hide*/
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = "RESPONSE_", value = {
-            RESPONSE_GENERIC_FAILURE,
-            RESPONSE_SUCCESS,
-            RESPONSE_TEMPORARILY_UNAVAILABLE,
-            RESPONSE_REQUEST_TIMEOUT,
-            RESPONSE_NOT_FOUND,
-            RESPONSE_DOES_NOT_EXIST_ANYWHERE,
-            RESPONSE_BAD_REQUEST
-    })
-    public @interface SipResponseCode {}
-
-    /**
-     * Send the response of a SIP OPTIONS capability exchange to the framework. If {@code code} is
-     * {@link #RESPONSE_SUCCESS}, info must be non-null.
-     * @param code The SIP response code that was sent by the network in response to the request
-     *        sent by {@link #sendCapabilityRequest(Uri, RcsContactUceCapability, int)}.
-     * @param reason The optional SIP response reason sent by the network. If none was sent, this
-     *        should be an empty string.
-     * @param info the contact's UCE capabilities associated with the capability request.
-     * @param operationToken The token associated with the original capability request, set by
-     *        {@link #sendCapabilityRequest(Uri, RcsContactUceCapability, int)}.
-     * @throws ImsException If this {@link RcsSipOptionsImplBase} instance is not currently
-     * connected to the framework. This can happen if the {@link RcsFeature} is not
-     * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
-     * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
-     * Telephony stack has crashed.
-     */
-    public final void onCapabilityRequestResponse(@SipResponseCode int code, @NonNull String reason,
-            @Nullable RcsContactUceCapability info, int operationToken) throws ImsException {
-        try {
-            getListener().onCapabilityRequestResponseOptions(code, reason, info, operationToken);
-        } catch (RemoteException e) {
-            throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
-        }
-    }
-
-    /**
-     * Inform the framework of a query for this device's UCE capabilities.
-     * <p>
-     * The framework will respond via the
-     * {@link #respondToCapabilityRequest(String, RcsContactUceCapability, int)} or
-     * {@link #respondToCapabilityRequestWithError(Uri, int, String, int)} method.
-     * @param contactUri The URI associated with the remote contact that is requesting capabilities.
-     * @param remoteInfo The remote contact's capability information.
-     * @param operationToken An unique operation token that you have generated that will be returned
-     *         by the framework in
-     *         {@link #respondToCapabilityRequest(String, RcsContactUceCapability, int)}.
-     * @throws ImsException If this {@link RcsSipOptionsImplBase} instance is not currently
-     * connected to the framework. This can happen if the {@link RcsFeature} is not
-     * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
-     * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
-     * Telephony stack has crashed.
-     */
-    public final void onRemoteCapabilityRequest(@NonNull Uri contactUri,
-            @NonNull RcsContactUceCapability remoteInfo, int operationToken) throws ImsException {
-        try {
-            getListener().onRemoteCapabilityRequest(contactUri, remoteInfo, operationToken);
-        } catch (RemoteException e) {
-            throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
-        }
-    }
-
-    /**
-     * Push one's own capabilities to a remote user via the SIP OPTIONS presence exchange mechanism
-     * in order to receive the capabilities of the remote user in response.
-     * <p>
-     * The implementer must call
-     * {@link #onCapabilityRequestResponse(int, String, RcsContactUceCapability, int)} to send the
-     * response of this query back to the framework.
-     * @param contactUri The URI of the remote user that we wish to get the capabilities of.
-     * @param capabilities The capabilities of this device to send to the remote user.
-     * @param operationToken A token generated by the framework that will be passed through
-     * {@link #onCapabilityRequestResponse(int, String, RcsContactUceCapability, int)} when this
-     *         operation has succeeded.
-     */
-    public void sendCapabilityRequest(@NonNull Uri contactUri,
-            @NonNull RcsContactUceCapability capabilities, int operationToken) {
-        // Stub - to be implemented by service
-        Log.w(LOG_TAG, "sendCapabilityRequest called with no implementation.");
-        try {
-            getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken);
-        } catch (RemoteException | ImsException e) {
-            // Do not do anything, this is a stub implementation.
-        }
-    }
-
-    /**
-     * Respond to a remote capability request from the contact specified with the capabilities of
-     * this device.
-     * <p>
-     * The framework will use the same token and uri as what was passed in to
-     * {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)}.
-     * @param contactUri The URI of the remote contact.
-     * @param ownCapabilities The capabilities of this device.
-     * @param operationToken The token generated by the framework that this service obtained when
-     *         {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)} was called.
-     */
-    public void respondToCapabilityRequest(@NonNull String contactUri,
-            @NonNull RcsContactUceCapability ownCapabilities, int operationToken) {
-        // Stub - to be implemented by service
-        Log.w(LOG_TAG, "respondToCapabilityRequest called with no implementation.");
-        try {
-            getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken);
-        } catch (RemoteException | ImsException e) {
-            // Do not do anything, this is a stub implementation.
-        }
-    }
-
-    /**
-     * Respond to a remote capability request from the contact specified with the specified error.
-     * <p>
-     * The framework will use the same token and uri as what was passed in to
-     * {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)}.
-     * @param contactUri A URI containing the remote contact.
-     * @param code The SIP response code to respond with.
-     * @param reason A non-null String containing the reason associated with the SIP code.
-     * @param operationToken The token provided by the framework when
-     *         {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)} was called.
-     */
-    public void respondToCapabilityRequestWithError(@NonNull Uri contactUri,
-            @SipResponseCode int code, @NonNull String reason, int operationToken) {
-        // Stub - to be implemented by service
-        Log.w(LOG_TAG, "respondToCapabiltyRequestWithError called with no implementation.");
-        try {
-            getListener().onCommandUpdate(COMMAND_CODE_NOT_SUPPORTED, operationToken);
-        } catch (RemoteException | ImsException e) {
-            // Do not do anything, this is a stub implementation.
-        }
-    }
-}
diff --git a/telephony/java/android/telephony/mbms/OWNERS b/telephony/java/android/telephony/mbms/OWNERS
new file mode 100644
index 0000000..718e0a2
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 20868
+
+rgreenwalt@google.com
+tgunn@google.com
+hallliu@google.com
diff --git a/telephony/java/android/telephony/mbms/vendor/OWNERS b/telephony/java/android/telephony/mbms/vendor/OWNERS
new file mode 100644
index 0000000..718e0a2
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/vendor/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 20868
+
+rgreenwalt@google.com
+tgunn@google.com
+hallliu@google.com
diff --git a/tests/ActivityManagerPerfTests/OWNERS b/tests/ActivityManagerPerfTests/OWNERS
new file mode 100644
index 0000000..72c0a9e
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/am/OWNERS
diff --git a/tests/AmSlam/OWNERS b/tests/AmSlam/OWNERS
new file mode 100644
index 0000000..72c0a9e
--- /dev/null
+++ b/tests/AmSlam/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/am/OWNERS
diff --git a/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java b/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java
index 7d826f7..e05816e 100644
--- a/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java
+++ b/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java
@@ -264,9 +264,9 @@
             // Set time to future.
             setTimeFutureDays(deltaDays);
 
-            // Set filter to quicken.
-            compilePackageWithFilter(PACKAGE_NAME, "quicken");
-            Assert.assertEquals("quicken", getCompilerFilter(PACKAGE_NAME));
+            // Set filter to verify.
+            compilePackageWithFilter(PACKAGE_NAME, "verify");
+            Assert.assertEquals("verify", getCompilerFilter(PACKAGE_NAME));
 
             // Fill up storage to trigger low storage threshold.
             fillUpToLowStorage();
@@ -290,9 +290,9 @@
             // Set time to future.
             setTimeFutureDays(deltaDays);
 
-            // Set filter to quicken.
-            compilePackageWithFilter(PACKAGE_NAME, "quicken");
-            Assert.assertEquals("quicken", getCompilerFilter(PACKAGE_NAME));
+            // Set filter to speed-profile.
+            compilePackageWithFilter(PACKAGE_NAME, "speed-profile");
+            Assert.assertEquals("speed-profile", getCompilerFilter(PACKAGE_NAME));
 
             // Fill up storage to trigger low storage threshold.
             fillUpToLowStorage();
diff --git a/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java b/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java
new file mode 100644
index 0000000..54d7047
--- /dev/null
+++ b/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.internal.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.os.BatteryStatsManager;
+import android.os.BatteryUsageStats;
+import android.os.UidBatteryConsumer;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class BatteryUsageStatsPerfTest {
+
+    @Rule
+    public final PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    /**
+     * Measures the performance of {@link BatteryStatsManager#getBatteryUsageStats()},
+     * which triggers a battery stats sync on every iteration.
+     */
+    @Test
+    public void testGetBatteryUsageStats() {
+        final Context context = InstrumentationRegistry.getContext();
+        final BatteryStatsManager batteryStatsManager =
+                context.getSystemService(BatteryStatsManager.class);
+
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            BatteryUsageStats batteryUsageStats = batteryStatsManager.getBatteryUsageStats();
+
+            state.pauseTiming();
+
+            List<UidBatteryConsumer> uidBatteryConsumers =
+                    batteryUsageStats.getUidBatteryConsumers();
+            double power = 0;
+            for (int i = 0; i < uidBatteryConsumers.size(); i++) {
+                UidBatteryConsumer uidBatteryConsumer = uidBatteryConsumers.get(i);
+                power += uidBatteryConsumer.getConsumedPower();
+            }
+
+            assertThat(power).isGreaterThan(0.0);
+
+            state.resumeTiming();
+        }
+    }
+}
diff --git a/tests/BlobStoreTestUtils/OWNERS b/tests/BlobStoreTestUtils/OWNERS
new file mode 100644
index 0000000..65bb6b8
--- /dev/null
+++ b/tests/BlobStoreTestUtils/OWNERS
@@ -0,0 +1 @@
+include /apex/blobstore/OWNERS
diff --git a/tests/Camera2Tests/OWNERS b/tests/Camera2Tests/OWNERS
new file mode 100644
index 0000000..f48a95c
--- /dev/null
+++ b/tests/Camera2Tests/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/av:/camera/OWNERS
diff --git a/tests/CanvasCompare/OWNERS b/tests/CanvasCompare/OWNERS
new file mode 100644
index 0000000..c88a9f8
--- /dev/null
+++ b/tests/CanvasCompare/OWNERS
@@ -0,0 +1 @@
+include /libs/hwui/OWNERS
diff --git a/tests/Compatibility/OWNERS b/tests/Compatibility/OWNERS
new file mode 100644
index 0000000..f8c3520
--- /dev/null
+++ b/tests/Compatibility/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/compat/OWNERS
diff --git a/tests/DozeTest/OWNERS b/tests/DozeTest/OWNERS
new file mode 100644
index 0000000..2e96c97
--- /dev/null
+++ b/tests/DozeTest/OWNERS
@@ -0,0 +1 @@
+include /packages/SystemUI/OWNERS
diff --git a/tests/FixVibrateSetting/OWNERS b/tests/FixVibrateSetting/OWNERS
new file mode 100644
index 0000000..cc63ceb
--- /dev/null
+++ b/tests/FixVibrateSetting/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/vibrator/OWNERS
diff --git a/tests/FlickerTests/AndroidManifest.xml b/tests/FlickerTests/AndroidManifest.xml
index 58f56f2..f9f9d58 100644
--- a/tests/FlickerTests/AndroidManifest.xml
+++ b/tests/FlickerTests/AndroidManifest.xml
@@ -21,6 +21,8 @@
     <!-- Read and write traces from external storage -->
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <!-- Allow the test to write directly to /sdcard/ -->
+    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
     <!-- Write secure settings -->
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
     <!-- Capture screen contents -->
@@ -34,7 +36,8 @@
     <!-- Workaround grant runtime permission exception from b/152733071 -->
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
     <uses-permission android:name="android.permission.READ_LOGS"/>
-    <application>
+    <!-- Allow the test to write directly to /sdcard/ -->
+    <application android:requestLegacyExternalStorage="true">
         <uses-library android:name="android.test.runner"/>
     </application>
 
diff --git a/tests/FlickerTests/AndroidTestPhysicalDevices.xml b/tests/FlickerTests/AndroidTestPhysicalDevices.xml
index 1650438..abd620f 100644
--- a/tests/FlickerTests/AndroidTestPhysicalDevices.xml
+++ b/tests/FlickerTests/AndroidTestPhysicalDevices.xml
@@ -34,7 +34,7 @@
         <option name="hidden-api-checks" value="false" />
     </test>
     <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
-        <option name="directory-keys" value="/storage/emulated/0/Android/data/com.android.server.wm.flicker/files" />
+        <option name="directory-keys" value="/sdcard/flicker" />
         <option name="collect-on-run-ended-only" value="true" />
         <option name="clean-up" value="true" />
     </metrics_collector>
diff --git a/tests/FlickerTests/AndroidTestVirtualDevices.xml b/tests/FlickerTests/AndroidTestVirtualDevices.xml
index 222212a..9a5413a 100644
--- a/tests/FlickerTests/AndroidTestVirtualDevices.xml
+++ b/tests/FlickerTests/AndroidTestVirtualDevices.xml
@@ -34,7 +34,7 @@
         <option name="hidden-api-checks" value="false" />
     </test>
     <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
-        <option name="directory-keys" value="/storage/emulated/0/Android/data/com.android.server.wm.flicker/files" />
+        <option name="directory-keys" value="/sdcard/flicker" />
         <option name="collect-on-run-ended-only" value="true" />
         <option name="clean-up" value="true" />
     </metrics_collector>
diff --git a/tests/FlickerTests/OWNERS b/tests/FlickerTests/OWNERS
new file mode 100644
index 0000000..0862c05
--- /dev/null
+++ b/tests/FlickerTests/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index a85e92c..bb03237 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -239,7 +239,7 @@
     bugId: Int = 0,
     enabled: Boolean = bugId == 0
 ) {
-    all(enabled = enabled, bugId = bugId) {
+    all("focusChanges", bugId, enabled) {
         this.focusChanges(windows)
     }
 }
@@ -248,7 +248,7 @@
     bugId: Int = 0,
     enabled: Boolean = bugId == 0
 ) {
-    all(enabled = enabled, bugId = bugId) {
+    all("focusDoesNotChange", bugId, enabled) {
         this.focusDoesNotChange()
     }
 }
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index 7b5dc872..7bd96f5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.server.wm.flicker.ime
 
+import androidx.test.filters.FlakyTest
 import android.view.Surface
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
@@ -42,6 +43,7 @@
 @RequiresDevice
 @RunWith(Parameterized::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 175027130)
 class ReOpenImeWindowTest(
     testName: String,
     flickerSpec: Flicker
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 0c584f4..5aef314 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.server.wm.flicker.launch
 
+import androidx.test.filters.FlakyTest
 import android.view.Surface
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
@@ -53,6 +54,7 @@
 @RequiresDevice
 @RunWith(Parameterized::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 174658929)
 class OpenAppFromOverviewTest(
     testName: String,
     flickerSpec: Flicker
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 0db064a..9d4a718 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -67,7 +67,7 @@
             val instrumentation = InstrumentationRegistry.getInstrumentation()
             val testApp = StandardAppHelper(instrumentation,
                 "com.android.server.wm.flicker.testapp", "SimpleApp")
-            return FlickerTestRunnerFactory(instrumentation)
+            return FlickerTestRunnerFactory(instrumentation, repetitions = 10)
                 .buildRotationTest { configuration ->
                     withTestName {
                         buildTestTag(
diff --git a/tests/HugeBackup/OWNERS b/tests/HugeBackup/OWNERS
new file mode 100644
index 0000000..d99779e
--- /dev/null
+++ b/tests/HugeBackup/OWNERS
@@ -0,0 +1 @@
+include /services/backup/OWNERS
diff --git a/tests/HwAccelerationTest/OWNERS b/tests/HwAccelerationTest/OWNERS
new file mode 100644
index 0000000..c88a9f8
--- /dev/null
+++ b/tests/HwAccelerationTest/OWNERS
@@ -0,0 +1 @@
+include /libs/hwui/OWNERS
diff --git a/tests/Input/OWNERS b/tests/Input/OWNERS
new file mode 100644
index 0000000..d701f23
--- /dev/null
+++ b/tests/Input/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/hardware/input/OWNERS
diff --git a/tests/JobSchedulerPerfTests/OWNERS b/tests/JobSchedulerPerfTests/OWNERS
new file mode 100644
index 0000000..6f207fb1
--- /dev/null
+++ b/tests/JobSchedulerPerfTests/OWNERS
@@ -0,0 +1 @@
+include /apex/jobscheduler/OWNERS
diff --git a/tests/JobSchedulerTestApp/OWNERS b/tests/JobSchedulerTestApp/OWNERS
new file mode 100644
index 0000000..6f207fb1
--- /dev/null
+++ b/tests/JobSchedulerTestApp/OWNERS
@@ -0,0 +1 @@
+include /apex/jobscheduler/OWNERS
diff --git a/tests/LocationTracker/OWNERS b/tests/LocationTracker/OWNERS
new file mode 100644
index 0000000..5ac6028
--- /dev/null
+++ b/tests/LocationTracker/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/location/OWNERS
diff --git a/tests/LowStorageTest/OWNERS b/tests/LowStorageTest/OWNERS
new file mode 100644
index 0000000..6f9dbea
--- /dev/null
+++ b/tests/LowStorageTest/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/os/storage/OWNERS
diff --git a/tests/NetworkSecurityConfigTest/OWNERS b/tests/NetworkSecurityConfigTest/OWNERS
new file mode 100644
index 0000000..aa87958
--- /dev/null
+++ b/tests/NetworkSecurityConfigTest/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/net/OWNERS
diff --git a/tests/PackageWatchdog/OWNERS b/tests/PackageWatchdog/OWNERS
new file mode 100644
index 0000000..d04a706
--- /dev/null
+++ b/tests/PackageWatchdog/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/rollback/OWNERS
diff --git a/tests/PackageWatchdog/src/com/android/server/OWNERS b/tests/PackageWatchdog/src/com/android/server/OWNERS
new file mode 100644
index 0000000..5cf4dcf
--- /dev/null
+++ b/tests/PackageWatchdog/src/com/android/server/OWNERS
@@ -0,0 +1 @@
+per-file PackageWatchdogTest.java = file:/services/core/java/com/android/server/rollback/OWNERS
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index 9738e58..104758d 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -22,6 +22,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
@@ -43,10 +44,15 @@
 import android.os.test.TestLooper;
 import android.provider.DeviceConfig;
 import android.util.AtomicFile;
+import android.util.LongArrayQueue;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
+import android.util.Xml;
 
 import androidx.test.InstrumentationRegistry;
 
 import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.internal.util.XmlUtils;
 import com.android.server.PackageWatchdog.HealthCheckState;
 import com.android.server.PackageWatchdog.MonitoredPackage;
 import com.android.server.PackageWatchdog.PackageHealthObserver;
@@ -64,6 +70,7 @@
 import org.mockito.stubbing.Answer;
 
 import java.io.File;
+import java.io.FileOutputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -739,7 +746,8 @@
                 false /* hasPassedHealthCheck */);
         MonitoredPackage m2 = wd.newMonitoredPackage(APP_B, LONG_DURATION, false);
         MonitoredPackage m3 = wd.newMonitoredPackage(APP_C, LONG_DURATION, false);
-        MonitoredPackage m4 = wd.newMonitoredPackage(APP_D, LONG_DURATION, SHORT_DURATION, true);
+        MonitoredPackage m4 = wd.newMonitoredPackage(APP_D, LONG_DURATION, SHORT_DURATION, true,
+                new LongArrayQueue());
 
         // Verify transition: inactive -> active -> passed
         // Verify initially inactive
@@ -1210,6 +1218,73 @@
         assertThat(observer.mMitigationCounts).isEqualTo(List.of(1, 2, 3, 3, 2, 3));
     }
 
+    @Test
+    public void testNormalizingMitigationCalls()  {
+        PackageWatchdog watchdog = createWatchdog();
+
+        LongArrayQueue mitigationCalls = new LongArrayQueue();
+        mitigationCalls.addLast(1000);
+        mitigationCalls.addLast(2000);
+        mitigationCalls.addLast(3000);
+
+        MonitoredPackage pkg = watchdog.newMonitoredPackage(
+                "test", 123, 456, true, mitigationCalls);
+
+        // Make current system uptime 10000ms.
+        moveTimeForwardAndDispatch(9999);
+
+        LongArrayQueue expectedCalls = pkg.normalizeMitigationCalls();
+
+        assertThat(expectedCalls.size()).isEqualTo(mitigationCalls.size());
+
+        for (int i = 0; i < mitigationCalls.size(); i++) {
+            assertThat(expectedCalls.get(i)).isEqualTo(mitigationCalls.get(i) - 10000);
+        }
+    }
+
+    /**
+     * Ensure that a {@link MonitoredPackage} may be correctly written and read in order to persist
+     * across reboots.
+     */
+    @Test
+    public void testWritingAndReadingMonitoredPackage() throws Exception {
+        PackageWatchdog watchdog = createWatchdog();
+
+        LongArrayQueue mitigationCalls = new LongArrayQueue();
+        mitigationCalls.addLast(1000);
+        mitigationCalls.addLast(2000);
+        mitigationCalls.addLast(3000);
+        MonitoredPackage writePkg = watchdog.newMonitoredPackage(
+                "test.package", 1000, 2000, true, mitigationCalls);
+
+        // Move time forward so that the current uptime is 4000ms. Therefore, the written mitigation
+        // calls will each be reduced by 4000.
+        moveTimeForwardAndDispatch(3999);
+        LongArrayQueue expectedCalls = new LongArrayQueue();
+        expectedCalls.addLast(-3000);
+        expectedCalls.addLast(-2000);
+        expectedCalls.addLast(-1000);
+        MonitoredPackage expectedPkg = watchdog.newMonitoredPackage(
+                "test.package", 1000, 2000, true, expectedCalls);
+
+        // Write the package
+        File tmpFile = File.createTempFile("package-watchdog-test", ".xml");
+        AtomicFile testFile = new AtomicFile(tmpFile);
+        FileOutputStream stream = testFile.startWrite();
+        TypedXmlSerializer outputSerializer = Xml.resolveSerializer(stream);
+        outputSerializer.startDocument(null, true);
+        writePkg.writeLocked(outputSerializer);
+        outputSerializer.endDocument();
+        testFile.finishWrite(stream);
+
+        // Read the package
+        TypedXmlPullParser parser = Xml.resolvePullParser(testFile.openRead());
+        XmlUtils.beginDocument(parser, "package");
+        MonitoredPackage readPkg = watchdog.parseMonitoredPackage(parser);
+
+        assertTrue(readPkg.isEqualTo(expectedPkg));
+    }
+
     private void adoptShellPermissions(String... permissions) {
         InstrumentationRegistry
                 .getInstrumentation()
diff --git a/tests/PlatformCompatGating/OWNERS b/tests/PlatformCompatGating/OWNERS
new file mode 100644
index 0000000..f8c3520
--- /dev/null
+++ b/tests/PlatformCompatGating/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/compat/OWNERS
diff --git a/tests/RollbackTest/OWNERS b/tests/RollbackTest/OWNERS
new file mode 100644
index 0000000..d04a706
--- /dev/null
+++ b/tests/RollbackTest/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/rollback/OWNERS
diff --git a/tests/RollbackTest/TEST_MAPPING b/tests/RollbackTest/TEST_MAPPING
index 0f4c460..7f9f2dc 100644
--- a/tests/RollbackTest/TEST_MAPPING
+++ b/tests/RollbackTest/TEST_MAPPING
@@ -1,5 +1,5 @@
 {
-  "presubmit": [
+  "presubmit-large": [
     {
       "name": "RollbackTest"
     },
diff --git a/tests/SoundTriggerTestApp/OWNERS b/tests/SoundTriggerTestApp/OWNERS
new file mode 100644
index 0000000..816bc6b
--- /dev/null
+++ b/tests/SoundTriggerTestApp/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/media/soundtrigger/OWNERS
diff --git a/tests/SoundTriggerTests/OWNERS b/tests/SoundTriggerTests/OWNERS
new file mode 100644
index 0000000..816bc6b
--- /dev/null
+++ b/tests/SoundTriggerTests/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/media/soundtrigger/OWNERS
diff --git a/tests/StagedInstallTest/OWNERS b/tests/StagedInstallTest/OWNERS
new file mode 100644
index 0000000..d825dfd
--- /dev/null
+++ b/tests/StagedInstallTest/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/OWNERS
diff --git a/tests/StagedInstallTest/TEST_MAPPING b/tests/StagedInstallTest/TEST_MAPPING
index 5a7a5a7..fa2a60b 100644
--- a/tests/StagedInstallTest/TEST_MAPPING
+++ b/tests/StagedInstallTest/TEST_MAPPING
@@ -1,5 +1,5 @@
 {
-  "presubmit": [
+  "presubmit-large": [
     {
       "name": "StagedInstallInternalTest"
     }
diff --git a/tests/StatusBar/OWNERS b/tests/StatusBar/OWNERS
new file mode 100644
index 0000000..2e96c97
--- /dev/null
+++ b/tests/StatusBar/OWNERS
@@ -0,0 +1 @@
+include /packages/SystemUI/OWNERS
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt
index cd4b385..273833b 100644
--- a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt
@@ -23,7 +23,7 @@
 import androidx.test.ext.junit.rules.ActivityScenarioRule
 import com.android.server.wm.flicker.monitor.LayersTraceMonitor
 import com.android.server.wm.flicker.monitor.withSFTracing
-import com.android.server.wm.flicker.traces.layers.LayersTrace
+import com.android.server.wm.traces.parser.layers.LayersTrace
 import junit.framework.Assert
 import org.junit.After
 import org.junit.Before
@@ -52,7 +52,8 @@
     }
 
     fun withTrace(predicate: (it: MainActivity) -> Unit): LayersTrace {
-        return withSFTracing(instrumentation, TRACE_FLAGS) {
+        return withSFTracing(TRACE_FLAGS,
+                outputDir = instrumentation.targetContext.dataDir.toPath()) {
             scenarioRule.getScenario().onActivity {
                 predicate(it)
             }
diff --git a/tests/TaskOrganizerTest/OWNERS b/tests/TaskOrganizerTest/OWNERS
new file mode 100644
index 0000000..0862c05
--- /dev/null
+++ b/tests/TaskOrganizerTest/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt b/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt
index fe9deae..2e3467a 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt
@@ -68,7 +68,8 @@
         val firstBounds = Rect(0, 0, 1080, 800)
         val secondBounds = Rect(0, 1000, 1080, 1800)
 
-        val trace = withSFTracing(instrumentation, TRACE_FLAGS) {
+        val trace = withSFTracing(TRACE_FLAGS,
+                outputDir = instrumentation.targetContext.dataDir.toPath()) {
             lateinit var resizeReadyLatch: CountDownLatch
             scenarioRule.getScenario().onActivity {
                 resizeReadyLatch = it.resizeTaskView(firstBounds, secondBounds)
@@ -77,17 +78,13 @@
         }
 
         // find the frame which match resized buffer size.
-        var frame: Long = -1
-        loop@ for (trace in trace.entries) {
-            for (layer in trace.flattenedLayers) {
-                if (layer.proto.activeBuffer != null &&
-                        layer.proto.activeBuffer.width == firstBounds.width() &&
-                        layer.proto.activeBuffer.height == firstBounds.height()) {
-                    frame = layer.proto.currFrame
-                    break@loop
-                }
-            }
-        }
+        val frame = trace.entries.flatMap { it.flattenedLayers }
+                .firstOrNull { layer ->
+                    !layer.isActiveBufferEmpty &&
+                        layer.activeBuffer?.width == firstBounds.width() &&
+                        layer.activeBuffer?.height == firstBounds.height()
+                }?.currFrame ?: -1
+
         assertNotEquals(-1, frame)
         // layer bounds should be related to parent surfaceview.
         secondBounds.offsetTo(0, 0)
diff --git a/tests/TelephonyCommonTests/OWNERS b/tests/TelephonyCommonTests/OWNERS
new file mode 100644
index 0000000..640baf2
--- /dev/null
+++ b/tests/TelephonyCommonTests/OWNERS
@@ -0,0 +1 @@
+include /telephony/OWNERS
diff --git a/tests/UsageReportingTest/OWNERS b/tests/UsageReportingTest/OWNERS
new file mode 100644
index 0000000..d3227de
--- /dev/null
+++ b/tests/UsageReportingTest/OWNERS
@@ -0,0 +1 @@
+include /services/usage/OWNERS
diff --git a/tests/UsageStatsPerfTests/OWNERS b/tests/UsageStatsPerfTests/OWNERS
new file mode 100644
index 0000000..d3227de
--- /dev/null
+++ b/tests/UsageStatsPerfTests/OWNERS
@@ -0,0 +1 @@
+include /services/usage/OWNERS
diff --git a/tests/UsageStatsTest/OWNERS b/tests/UsageStatsTest/OWNERS
new file mode 100644
index 0000000..d3227de
--- /dev/null
+++ b/tests/UsageStatsTest/OWNERS
@@ -0,0 +1 @@
+include /services/usage/OWNERS
diff --git a/tests/UsbHostExternalManagmentTest/OWNERS b/tests/UsbHostExternalManagmentTest/OWNERS
new file mode 100644
index 0000000..f7b2a37
--- /dev/null
+++ b/tests/UsbHostExternalManagmentTest/OWNERS
@@ -0,0 +1 @@
+include /services/usb/OWNERS
diff --git a/tests/UsbManagerTests/OWNERS b/tests/UsbManagerTests/OWNERS
new file mode 100644
index 0000000..f7b2a37
--- /dev/null
+++ b/tests/UsbManagerTests/OWNERS
@@ -0,0 +1 @@
+include /services/usb/OWNERS
diff --git a/tests/UsbTests/OWNERS b/tests/UsbTests/OWNERS
new file mode 100644
index 0000000..f7b2a37
--- /dev/null
+++ b/tests/UsbTests/OWNERS
@@ -0,0 +1 @@
+include /services/usb/OWNERS
diff --git a/tests/VoiceInteraction/OWNERS b/tests/VoiceInteraction/OWNERS
new file mode 100644
index 0000000..ef1061b
--- /dev/null
+++ b/tests/VoiceInteraction/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/service/voice/OWNERS
diff --git a/tests/WindowAnimationJank/OWNERS b/tests/WindowAnimationJank/OWNERS
new file mode 100644
index 0000000..0862c05
--- /dev/null
+++ b/tests/WindowAnimationJank/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/tests/WindowInsetsTests/OWNERS b/tests/WindowInsetsTests/OWNERS
new file mode 100644
index 0000000..0862c05
--- /dev/null
+++ b/tests/WindowInsetsTests/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/tests/backup/OWNERS b/tests/backup/OWNERS
new file mode 100644
index 0000000..d99779e
--- /dev/null
+++ b/tests/backup/OWNERS
@@ -0,0 +1 @@
+include /services/backup/OWNERS
diff --git a/tests/benchmarks/src/com/android/server/net/OWNERS b/tests/benchmarks/src/com/android/server/net/OWNERS
new file mode 100644
index 0000000..aa87958
--- /dev/null
+++ b/tests/benchmarks/src/com/android/server/net/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/net/OWNERS
diff --git a/tests/net/common/java/android/net/NetworkProviderTest.kt b/tests/net/common/java/android/net/NetworkProviderTest.kt
index dd3f5be..77e9f12 100644
--- a/tests/net/common/java/android/net/NetworkProviderTest.kt
+++ b/tests/net/common/java/android/net/NetworkProviderTest.kt
@@ -33,6 +33,9 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verifyNoMoreInteractions
 import java.util.UUID
 import kotlin.test.assertEquals
 import kotlin.test.assertNotEquals
@@ -87,8 +90,8 @@
         ) = seenEvents.poll(DEFAULT_TIMEOUT_MS) { it is T && predicate(it) }
     }
 
-    private fun createNetworkProvider(): TestNetworkProvider {
-        return TestNetworkProvider(context, mHandlerThread.looper)
+    private fun createNetworkProvider(ctx: Context = context): TestNetworkProvider {
+        return TestNetworkProvider(ctx, mHandlerThread.looper)
     }
 
     @Test
@@ -169,7 +172,12 @@
 
     @Test
     fun testDeclareNetworkRequestUnfulfillable() {
-        val provider = createNetworkProvider()
+        val mockContext = mock(Context::class.java)
+        val provider = createNetworkProvider(mockContext)
+        // ConnectivityManager not required at creation time
+        verifyNoMoreInteractions(mockContext)
+        doReturn(mCm).`when`(mockContext).getSystemService(Context.CONNECTIVITY_SERVICE)
+
         mCm.registerNetworkProvider(provider)
 
         val specifier = StringNetworkSpecifier(UUID.randomUUID().toString())
diff --git a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
index 835a83e..c5b25bd 100644
--- a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
+++ b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
@@ -147,5 +147,11 @@
         assertEquals(resultData.rcvWndScale, wndScale);
         assertEquals(resultData.tos, tos);
         assertEquals(resultData.ttl, ttl);
+
+        final String expected = ""
+                + "android.net.TcpKeepalivePacketDataParcelable{srcAddress: [10, 0, 0, 1],"
+                + " srcPort: 1234, dstAddress: [10, 0, 0, 5], dstPort: 4321, seq: 286331153,"
+                + " ack: 572662306, rcvWnd: 48000, rcvWndScale: 2, tos: 4, ttl: 64}";
+        assertEquals(expected, resultData.toString());
     }
 }
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 5d45737..059e054 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -1958,6 +1958,57 @@
     }
 
     @Test
+    public void testOwnerUidChangeBug() throws Exception {
+        // Owner UIDs are not visible without location permission.
+        setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
+                Manifest.permission.ACCESS_FINE_LOCATION);
+
+        final NetworkCapabilities ncTemplate = new NetworkCapabilities();
+        final int originalOwnerUid = Process.myUid();
+        ncTemplate.setOwnerUid(originalOwnerUid);
+
+        mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(),
+                ncTemplate);
+        mWiFiNetworkAgent.connect(false);
+        waitForIdle();
+
+        // Send ConnectivityService an update to the mWiFiNetworkAgent's capabilities that changes
+        // its owner UID.
+        NetworkCapabilities agentCapabilities = mWiFiNetworkAgent.getNetworkCapabilities();
+        assertEquals(originalOwnerUid, agentCapabilities.getOwnerUid());
+        agentCapabilities.setOwnerUid(42);
+        mWiFiNetworkAgent.setNetworkCapabilities(agentCapabilities, true);
+        waitForIdle();
+
+        // Check that the owner UID is not updated.
+        NetworkCapabilities nc = mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork());
+        assertEquals(originalOwnerUid, nc.getOwnerUid());
+
+        // Make an unrelated change to the capabilities.
+        assertFalse(agentCapabilities.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
+        agentCapabilities.addCapability(NET_CAPABILITY_NOT_CONGESTED);
+        mWiFiNetworkAgent.setNetworkCapabilities(agentCapabilities, true);
+        waitForIdle();
+
+        // Check that both the capability change and the owner UID have been modified.
+        // The owner UID is -1 because it is visible only to the UID that owns the network.
+        nc = mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork());
+        assertEquals(-1, nc.getOwnerUid());
+        assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
+
+        // Set the owner back to originalOwnerUid, update the capabilities, and check that it is
+        // visible again.
+        // TODO: should this even be possible?
+        agentCapabilities.setOwnerUid(originalOwnerUid);
+        agentCapabilities.removeCapability(NET_CAPABILITY_NOT_CONGESTED);
+        mWiFiNetworkAgent.setNetworkCapabilities(agentCapabilities, true);
+        waitForIdle();
+
+        nc = mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork());
+        assertEquals(originalOwnerUid, nc.getOwnerUid());
+    }
+
+    @Test
     public void testMultipleLingering() throws Exception {
         // This test would be flaky with the default 120ms timer: that is short enough that
         // lingered networks are torn down before assertions can be run. We don't want to mock the
@@ -2517,7 +2568,10 @@
 
     @Test
     public void testNoMutableNetworkRequests() throws Exception {
-        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent("a"), 0);
+        // TODO(b/173157160) Please replace FLAG_MUTABLE_UNAUDITED below
+        // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
+        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent("a"),
+                PendingIntent.FLAG_MUTABLE_UNAUDITED);
         NetworkRequest request1 = new NetworkRequest.Builder()
                 .addCapability(NET_CAPABILITY_VALIDATED)
                 .build();
@@ -3177,17 +3231,21 @@
         assertThrows(SecurityException.class, () ->
                 mCm.registerNetworkCallback(r, new NetworkCallback()));
 
+        // TODO(b/173157160) Please replace FLAG_MUTABLE_UNAUDITED below
+        // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
         assertThrows(SecurityException.class, () ->
                 mCm.registerNetworkCallback(r, PendingIntent.getService(
-                        mServiceContext, 0, new Intent(), 0)));
+                        mServiceContext, 0, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED)));
 
         // Requesting a Network with signal strength should get IllegalArgumentException.
         assertThrows(IllegalArgumentException.class, () ->
                 mCm.requestNetwork(r, new NetworkCallback()));
 
+        // TODO(b/173157160) Please replace FLAG_MUTABLE_UNAUDITED below
+        // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
         assertThrows(IllegalArgumentException.class, () ->
                 mCm.requestNetwork(r, PendingIntent.getService(
-                        mServiceContext, 0, new Intent(), 0)));
+                        mServiceContext, 0, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED)));
     }
 
     @Test
@@ -4651,12 +4709,16 @@
         }
         j = 0;
         while (j++ < INTENTS / 2) {
-            PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, new Intent("a" + j), 0);
+            // TODO(b/173157160) Please replace FLAG_MUTABLE_UNAUDITED below
+            // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
+            PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, new Intent("a" + j), PendingIntent.FLAG_MUTABLE_UNAUDITED);
             mCm.requestNetwork(networkRequest, pi);
             registered.add(pi);
         }
         while (j++ < INTENTS) {
-            PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, new Intent("b" + j), 0);
+            // TODO(b/173157160) Please replace FLAG_MUTABLE_UNAUDITED below
+            // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
+            PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, new Intent("b" + j), PendingIntent.FLAG_MUTABLE_UNAUDITED);
             mCm.registerNetworkCallback(networkRequest, pi);
             registered.add(pi);
         }
@@ -4670,11 +4732,15 @@
         );
         assertThrows(TooManyRequestsException.class, () ->
                 mCm.requestNetwork(networkRequest,
-                        PendingIntent.getBroadcast(mContext, 0, new Intent("c"), 0))
+                        // TODO(b/173157160) Please replace FLAG_MUTABLE_UNAUDITED below
+                        // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
+                        PendingIntent.getBroadcast(mContext, 0, new Intent("c"), PendingIntent.FLAG_MUTABLE_UNAUDITED))
         );
         assertThrows(TooManyRequestsException.class, () ->
                 mCm.registerNetworkCallback(networkRequest,
-                        PendingIntent.getBroadcast(mContext, 0, new Intent("d"), 0))
+                        // TODO(b/173157160) Please replace FLAG_MUTABLE_UNAUDITED below
+                        // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
+                        PendingIntent.getBroadcast(mContext, 0, new Intent("d"), PendingIntent.FLAG_MUTABLE_UNAUDITED))
         );
 
         for (Object o : registered) {
@@ -4703,16 +4769,20 @@
         waitForIdle();
 
         for (int i = 0; i < MAX_REQUESTS; i++) {
+            // TODO(b/173157160) Please replace FLAG_MUTABLE_UNAUDITED below
+            // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
             PendingIntent pendingIntent =
-                    PendingIntent.getBroadcast(mContext, 0, new Intent("e" + i), 0);
+                    PendingIntent.getBroadcast(mContext, 0, new Intent("e" + i), PendingIntent.FLAG_MUTABLE_UNAUDITED);
             mCm.requestNetwork(networkRequest, pendingIntent);
             mCm.unregisterNetworkCallback(pendingIntent);
         }
         waitForIdle();
 
         for (int i = 0; i < MAX_REQUESTS; i++) {
+            // TODO(b/173157160) Please replace FLAG_MUTABLE_UNAUDITED below
+            // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
             PendingIntent pendingIntent =
-                    PendingIntent.getBroadcast(mContext, 0, new Intent("f" + i), 0);
+                    PendingIntent.getBroadcast(mContext, 0, new Intent("f" + i), PendingIntent.FLAG_MUTABLE_UNAUDITED);
             mCm.registerNetworkCallback(networkRequest, pendingIntent);
             mCm.unregisterNetworkCallback(pendingIntent);
         }
diff --git a/tests/net/java/com/android/server/NetworkManagementServiceTest.java b/tests/net/java/com/android/server/NetworkManagementServiceTest.java
index 968b307..ea763d2 100644
--- a/tests/net/java/com/android/server/NetworkManagementServiceTest.java
+++ b/tests/net/java/com/android/server/NetworkManagementServiceTest.java
@@ -16,6 +16,12 @@
 
 package com.android.server;
 
+import static android.util.DebugUtils.valueToString;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -29,15 +35,19 @@
 import android.net.INetd;
 import android.net.INetdUnsolicitedEventListener;
 import android.net.LinkAddress;
+import android.net.NetworkPolicyManager;
 import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.util.ArrayMap;
 
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.app.IBatteryStats;
-import com.android.server.NetworkManagementService.SystemServices;
+import com.android.server.NetworkManagementService.Dependencies;
 import com.android.server.net.BaseNetworkObserver;
 
 import org.junit.After;
@@ -49,13 +59,14 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.function.BiFunction;
+
 /**
  * Tests for {@link NetworkManagementService}.
  */
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class NetworkManagementServiceTest {
-
     private NetworkManagementService mNMService;
 
     @Mock private Context mContext;
@@ -66,7 +77,9 @@
     @Captor
     private ArgumentCaptor<INetdUnsolicitedEventListener> mUnsolListenerCaptor;
 
-    private final SystemServices mServices = new SystemServices() {
+    private final MockDependencies mDeps = new MockDependencies();
+
+    private final class MockDependencies extends Dependencies {
         @Override
         public IBinder getService(String name) {
             switch (name) {
@@ -76,14 +89,21 @@
                     throw new UnsupportedOperationException("Unknown service " + name);
             }
         }
+
         @Override
         public void registerLocalService(NetworkManagementInternal nmi) {
         }
+
         @Override
         public INetd getNetd() {
             return mNetdService;
         }
-    };
+
+        @Override
+        public int getCallingUid() {
+            return Process.SYSTEM_UID;
+        }
+    }
 
     @Before
     public void setUp() throws Exception {
@@ -91,7 +111,7 @@
         doNothing().when(mNetdService)
                 .registerUnsolicitedEventListener(mUnsolListenerCaptor.capture());
         // Start the service and wait until it connects to our socket.
-        mNMService = NetworkManagementService.create(mContext, mServices);
+        mNMService = NetworkManagementService.create(mContext, mDeps);
     }
 
     @After
@@ -192,4 +212,105 @@
         // Make sure nothing else was called.
         verifyNoMoreInteractions(observer);
     }
+
+    @Test
+    public void testFirewallEnabled() {
+        mNMService.setFirewallEnabled(true);
+        assertTrue(mNMService.isFirewallEnabled());
+
+        mNMService.setFirewallEnabled(false);
+        assertFalse(mNMService.isFirewallEnabled());
+    }
+
+    private static final int TEST_UID = 111;
+
+    @Test
+    public void testNetworkRestrictedDefault() {
+        assertFalse(mNMService.isNetworkRestricted(TEST_UID));
+    }
+
+    @Test
+    public void testMeteredNetworkRestrictions() throws RemoteException {
+        // Make sure the mocked netd method returns true.
+        doReturn(true).when(mNetdService).bandwidthEnableDataSaver(anyBoolean());
+
+        // Restrict usage of mobile data in background
+        mNMService.setUidMeteredNetworkDenylist(TEST_UID, true);
+        assertTrue("Should be true since mobile data usage is restricted",
+                mNMService.isNetworkRestricted(TEST_UID));
+
+        mNMService.setDataSaverModeEnabled(true);
+        verify(mNetdService).bandwidthEnableDataSaver(true);
+
+        mNMService.setUidMeteredNetworkDenylist(TEST_UID, false);
+        assertTrue("Should be true since data saver is on and the uid is not allowlisted",
+                mNMService.isNetworkRestricted(TEST_UID));
+
+        mNMService.setUidMeteredNetworkAllowlist(TEST_UID, true);
+        assertFalse("Should be false since data saver is on and the uid is allowlisted",
+                mNMService.isNetworkRestricted(TEST_UID));
+
+        // remove uid from allowlist and turn datasaver off again
+        mNMService.setUidMeteredNetworkAllowlist(TEST_UID, false);
+        mNMService.setDataSaverModeEnabled(false);
+        verify(mNetdService).bandwidthEnableDataSaver(false);
+        assertFalse("Network should not be restricted when data saver is off",
+                mNMService.isNetworkRestricted(TEST_UID));
+    }
+
+    @Test
+    public void testFirewallChains() {
+        final ArrayMap<Integer, ArrayMap<Integer, Boolean>> expected = new ArrayMap<>();
+        // Dozable chain
+        final ArrayMap<Integer, Boolean> isRestrictedForDozable = new ArrayMap<>();
+        isRestrictedForDozable.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
+        isRestrictedForDozable.put(INetd.FIREWALL_RULE_ALLOW, false);
+        isRestrictedForDozable.put(INetd.FIREWALL_RULE_DENY, true);
+        expected.put(INetd.FIREWALL_CHAIN_DOZABLE, isRestrictedForDozable);
+        // Powersaver chain
+        final ArrayMap<Integer, Boolean> isRestrictedForPowerSave = new ArrayMap<>();
+        isRestrictedForPowerSave.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
+        isRestrictedForPowerSave.put(INetd.FIREWALL_RULE_ALLOW, false);
+        isRestrictedForPowerSave.put(INetd.FIREWALL_RULE_DENY, true);
+        expected.put(INetd.FIREWALL_CHAIN_POWERSAVE, isRestrictedForPowerSave);
+        // Standby chain
+        final ArrayMap<Integer, Boolean> isRestrictedForStandby = new ArrayMap<>();
+        isRestrictedForStandby.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, false);
+        isRestrictedForStandby.put(INetd.FIREWALL_RULE_ALLOW, false);
+        isRestrictedForStandby.put(INetd.FIREWALL_RULE_DENY, true);
+        expected.put(INetd.FIREWALL_CHAIN_STANDBY, isRestrictedForStandby);
+        // Restricted mode chain
+        final ArrayMap<Integer, Boolean> isRestrictedForRestrictedMode = new ArrayMap<>();
+        isRestrictedForRestrictedMode.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
+        isRestrictedForRestrictedMode.put(INetd.FIREWALL_RULE_ALLOW, false);
+        isRestrictedForRestrictedMode.put(INetd.FIREWALL_RULE_DENY, true);
+        expected.put(INetd.FIREWALL_CHAIN_RESTRICTED, isRestrictedForRestrictedMode);
+
+        final int[] chains = {
+                INetd.FIREWALL_CHAIN_STANDBY,
+                INetd.FIREWALL_CHAIN_POWERSAVE,
+                INetd.FIREWALL_CHAIN_DOZABLE,
+                INetd.FIREWALL_CHAIN_RESTRICTED
+        };
+        final int[] states = {
+                INetd.FIREWALL_RULE_ALLOW,
+                INetd.FIREWALL_RULE_DENY,
+                NetworkPolicyManager.FIREWALL_RULE_DEFAULT
+        };
+        BiFunction<Integer, Integer, String> errorMsg = (chain, state) -> {
+            return String.format("Unexpected value for chain: %s and state: %s",
+                    valueToString(INetd.class, "FIREWALL_CHAIN_", chain),
+                    valueToString(INetd.class, "FIREWALL_RULE_", state));
+        };
+        for (int chain : chains) {
+            final ArrayMap<Integer, Boolean> expectedValues = expected.get(chain);
+            mNMService.setFirewallChainEnabled(chain, true);
+            for (int state : states) {
+                mNMService.setFirewallUidRule(chain, TEST_UID, state);
+                assertEquals(errorMsg.apply(chain, state),
+                        expectedValues.get(state), mNMService.isNetworkRestricted(TEST_UID));
+            }
+            mNMService.setFirewallChainEnabled(chain, false);
+        }
+    }
 }
diff --git a/tests/notification/OWNERS b/tests/notification/OWNERS
new file mode 100644
index 0000000..396fd12
--- /dev/null
+++ b/tests/notification/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/notification/OWNERS
diff --git a/tests/permission/OWNERS b/tests/permission/OWNERS
new file mode 100644
index 0000000..999ea0e
--- /dev/null
+++ b/tests/permission/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/permission/OWNERS
diff --git a/tests/utils/DummyIME/OWNERS b/tests/utils/DummyIME/OWNERS
new file mode 100644
index 0000000..5deb2ce
--- /dev/null
+++ b/tests/utils/DummyIME/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/inputmethod/OWNERS
diff --git a/tests/utils/StubIME/OWNERS b/tests/utils/StubIME/OWNERS
new file mode 100644
index 0000000..5deb2ce
--- /dev/null
+++ b/tests/utils/StubIME/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/inputmethod/OWNERS
diff --git a/tests/utils/hostutils/src/com/android/tests/rollback/OWNERS b/tests/utils/hostutils/src/com/android/tests/rollback/OWNERS
new file mode 100644
index 0000000..d04a706
--- /dev/null
+++ b/tests/utils/hostutils/src/com/android/tests/rollback/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/rollback/OWNERS
diff --git a/tests/utils/testutils/java/com/android/server/accessibility/OWNERS b/tests/utils/testutils/java/com/android/server/accessibility/OWNERS
new file mode 100644
index 0000000..b74281e
--- /dev/null
+++ b/tests/utils/testutils/java/com/android/server/accessibility/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/accessibility/OWNERS
diff --git a/tests/utils/testutils/java/com/android/server/wm/OWNERS b/tests/utils/testutils/java/com/android/server/wm/OWNERS
new file mode 100644
index 0000000..0862c05
--- /dev/null
+++ b/tests/utils/testutils/java/com/android/server/wm/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/tools/aapt/OWNERS b/tools/aapt/OWNERS
new file mode 100644
index 0000000..c232ccd
--- /dev/null
+++ b/tools/aapt/OWNERS
@@ -0,0 +1 @@
+include /tools/aapt2/OWNERS
diff --git a/tools/fonts/OWNERS b/tools/fonts/OWNERS
new file mode 100644
index 0000000..a538331
--- /dev/null
+++ b/tools/fonts/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/graphics/fonts/OWNERS
diff --git a/tools/incident_report/OWNERS b/tools/incident_report/OWNERS
new file mode 100644
index 0000000..f766115
--- /dev/null
+++ b/tools/incident_report/OWNERS
@@ -0,0 +1 @@
+include /cmds/incidentd/OWNERS
diff --git a/tools/incident_section_gen/OWNERS b/tools/incident_section_gen/OWNERS
new file mode 100644
index 0000000..f766115
--- /dev/null
+++ b/tools/incident_section_gen/OWNERS
@@ -0,0 +1 @@
+include /cmds/incidentd/OWNERS
diff --git a/tools/powerstats/OWNERS b/tools/powerstats/OWNERS
new file mode 100644
index 0000000..d68066b
--- /dev/null
+++ b/tools/powerstats/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/power/OWNERS
diff --git a/tools/stats_log_api_gen/OWNERS b/tools/stats_log_api_gen/OWNERS
new file mode 100644
index 0000000..41a0c95
--- /dev/null
+++ b/tools/stats_log_api_gen/OWNERS
@@ -0,0 +1 @@
+yro@google.com
diff --git a/wifi/TEST_MAPPING b/wifi/TEST_MAPPING
index 8c51510..7ddc308 100644
--- a/wifi/TEST_MAPPING
+++ b/wifi/TEST_MAPPING
@@ -1,5 +1,5 @@
 {
-  "presubmit": [
+  "presubmit-large": [
     {
       "name": "CtsWifiTestCases",
       "options": [
@@ -11,9 +11,6 @@
   ],
   "mainline-presubmit": [
     {
-      "name": "FrameworksWifiApiTests[com.google.android.wifi.apex]"
-    },
-    {
       "name": "CtsWifiTestCases[com.google.android.wifi.apex]",
       "options": [
         {
diff --git a/wifi/api/current.txt b/wifi/api/current.txt
index ce2b8ca..e11b33e 100644
--- a/wifi/api/current.txt
+++ b/wifi/api/current.txt
@@ -332,6 +332,7 @@
     method public boolean is5GHzBandSupported();
     method public boolean is6GHzBandSupported();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isAutoWakeupEnabled();
+    method public boolean isBridgedApConcurrencySupported();
     method @Deprecated public boolean isDeviceToApRttSupported();
     method public boolean isEasyConnectSupported();
     method public boolean isEnhancedOpenSupported();
@@ -342,6 +343,7 @@
     method @Deprecated public boolean isScanAlwaysAvailable();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isScanThrottleEnabled();
     method public boolean isStaApConcurrencySupported();
+    method public boolean isStaBridgedApConcurrencySupported();
     method public boolean isTdlsSupported();
     method public boolean isWapiSupported();
     method public boolean isWifiEnabled();
diff --git a/wifi/api/system-current.txt b/wifi/api/system-current.txt
index 48d9fd4..eba7443 100644
--- a/wifi/api/system-current.txt
+++ b/wifi/api/system-current.txt
@@ -483,6 +483,7 @@
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.net.wifi.WifiConfiguration> getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(@NonNull java.util.List<android.net.wifi.ScanResult>);
     method public boolean is60GHzBandSupported();
     method public boolean isApMacRandomizationSupported();
+    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public boolean isCarrierNetworkOffloadEnabled(int, boolean);
     method public boolean isConnectedMacRandomizationSupported();
     method @Deprecated public boolean isDeviceToDeviceRttSupported();
     method public boolean isPortableHotspotSupported();
@@ -501,6 +502,7 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveSoftApBackupData();
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setAutoWakeupEnabled(boolean);
+    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void setCarrierNetworkOffloadEnabled(int, boolean, boolean);
     method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS) public void setCoexUnsafeChannels(@NonNull java.util.Set<android.net.wifi.CoexUnsafeChannel>, int);
     method @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE) public void setDeviceMobilityState(int);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setMacRandomizationSettingPasspointEnabled(@NonNull String, boolean);
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 6dee751..866e913 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -296,4 +296,8 @@
     void startTemporarilyDisablingAllNonCarrierMergedWifi(int subId);
 
     void stopTemporarilyDisablingAllNonCarrierMergedWifi();
+
+    void setCarrierNetworkOffloadEnabled(int subscriptionId, boolean merged, boolean enabled);
+
+    boolean isCarrierNetworkOffloadEnabled(int subscriptionId, boolean merged);
 }
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java
index fddc889..226d1a3 100644
--- a/wifi/java/android/net/wifi/SoftApConfiguration.java
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.java
@@ -935,6 +935,9 @@
          * on the requested bands (if possible).
          * <p>
          *
+         * Use {@link WifiManager#isBridgedApConcurrencySupported()} to determine
+         * whether or not concurrent APs are supported.
+         *
          * @param bands Array of the {@link #BandType}.
          * @return Builder for chaining.
          * @throws IllegalArgumentException when more than 2 bands are set or an invalid band type
@@ -1007,6 +1010,9 @@
          * The {@link SoftApCapability#getSupportedChannelList(int)} can be used to obtain
          * valid channels in each band.
          *
+         * Use {@link WifiManager#isBridgedApConcurrencySupported()} to determine
+         * whether or not concurrent APs are supported.
+         *
          * <p>
          * If not set, the default for the channel is the special value 0 which has the framework
          * auto-select a valid channel from the band configured with {@link #setBands(int[])}.
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 90edc45..e127ea9 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -1335,6 +1335,16 @@
     }
 
     /**
+     * Initialize the value of the app installed device key and cert flag.
+     *
+     * @param isAppInstalledDeviceKeyAndCert true or false
+     * @hide
+     */
+    public void initIsAppInstalledDeviceKeyAndCert(boolean isAppInstalledDeviceKeyAndCert) {
+        mIsAppInstalledDeviceKeyAndCert = isAppInstalledDeviceKeyAndCert;
+    }
+
+    /**
      * Check if CA certificate was installed by an app, or manually (not by an app). If true,
      * CA certificate will be removed from key storage when this network is removed. If not,
      * then certificates and keys remain persistent until the user manually removes them.
@@ -1348,6 +1358,16 @@
     }
 
     /**
+     * Initialize the value of the app installed root CA cert flag.
+     *
+     * @param isAppInstalledCaCert true or false
+     * @hide
+     */
+    public void initIsAppInstalledCaCert(boolean isAppInstalledCaCert) {
+        mIsAppInstalledCaCert = isAppInstalledCaCert;
+    }
+
+    /**
      * Set the OCSP type.
      * @param ocsp is one of {@link ##OCSP_NONE}, {@link #OCSP_REQUEST_CERT_STATUS},
      *                   {@link #OCSP_REQUIRE_CERT_STATUS} or
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index b8fa1e1..2b931a3 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -53,6 +53,7 @@
 import android.os.RemoteException;
 import android.os.WorkSource;
 import android.os.connectivity.WifiActivityEnergyInfo;
+import android.telephony.SubscriptionInfo;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.CloseGuard;
@@ -2488,6 +2489,12 @@
     /** @hide */
     public static final long WIFI_FEATURE_SAE_PK          = 0x10000000000L; // SAE-PK
 
+    /** @hide */
+    public static final long WIFI_FEATURE_STA_BRIDGED_AP       = 0x20000000000L; // STA + Bridged AP
+
+    /** @hide */
+    public static final long WIFI_FEATURE_BRIDGED_AP           = 0x40000000000L; // Bridged AP
+
     private long getSupportedFeatures() {
         try {
             return mService.getSupportedFeatures();
@@ -2688,6 +2695,40 @@
     }
 
     /**
+     * Query whether the device supports Station (STA) + Bridged access point (AP)
+     * concurrency or not.
+     *
+     * The bridged AP support means that the device supports AP + AP concurrency with the 2 APs
+     * bridged together.
+     *
+     * See {@link SoftApConfiguration.Builder#setBands(int[])}
+     * or {@link SoftApConfiguration.Builder#setChannels(SparseIntArray)} to configure bridged AP
+     * when the bridged AP supported.
+     *
+     * @return true if this device supports STA + bridged AP concurrency, false otherwise.
+     */
+    public boolean isStaBridgedApConcurrencySupported() {
+        return isFeatureSupported(WIFI_FEATURE_STA_BRIDGED_AP);
+    }
+
+    /**
+     * Query whether the device supports Bridged Access point (AP) concurrency or not.
+     *
+     * The bridged AP support means that the device supports AP + AP concurrency with the 2 APs
+     * bridged together.
+     *
+     * See {@link SoftApConfiguration.Builder#setBands(int[])}
+     * or {@link SoftApConfiguration.Builder#setChannels(SparseIntArray)} to configure bridged AP
+     * when the bridged AP supported.
+     *
+     * @return true if this device supports bridged AP concurrency, false otherwise.
+     */
+    public boolean isBridgedApConcurrencySupported() {
+        return isFeatureSupported(WIFI_FEATURE_BRIDGED_AP);
+    }
+
+
+    /**
      * Interface for Wi-Fi activity energy info listener. Should be implemented by applications and
      * set when calling {@link WifiManager#getWifiActivityEnergyInfoAsync}.
      *
@@ -6721,4 +6762,63 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Sets the state of carrier offload on merged or unmerged networks for specified subscription.
+     *
+     * <p>
+     * When a subscription's carrier network offload is disabled, all network suggestions related to
+     * this subscription will not be considered for auto join.
+     * <p>
+     * If calling app want disable all carrier network offload from a specified subscription, should
+     * call this API twice to disable both merged and unmerged carrier network suggestions.
+     *
+     * @param subscriptionId See {@link SubscriptionInfo#getSubscriptionId()}.
+     * @param merged True for carrier merged network, false otherwise.
+     *               See {@link WifiNetworkSuggestion.Builder#setCarrierMerged(boolean)}
+     * @param enabled True for enable carrier network offload, false otherwise.
+     * @see #isCarrierNetworkOffloadEnabled(int, boolean)
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD})
+    public void setCarrierNetworkOffloadEnabled(int subscriptionId, boolean merged,
+            boolean enabled) {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            mService.setCarrierNetworkOffloadEnabled(subscriptionId, merged, enabled);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Get the carrier network offload state for merged or unmerged networks for specified
+     * subscription.
+     * @param subscriptionId subscription ID see {@link SubscriptionInfo#getSubscriptionId()}
+     * @param merged True for carrier merged network, false otherwise.
+     *               See {@link WifiNetworkSuggestion.Builder#setCarrierMerged(boolean)}
+     * @return True to indicate that carrier network offload is enabled, false otherwise.
+     * @see #setCarrierNetworkOffloadEnabled(int, boolean, boolean)
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_SETTINGS,
+            android.Manifest.permission.NETWORK_SETUP_WIZARD})
+    public boolean isCarrierNetworkOffloadEnabled(int subscriptionId, boolean merged) {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return mService.isCarrierNetworkOffloadEnabled(subscriptionId, merged);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
 }
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index e606d53..b7450c5 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -917,6 +917,9 @@
             mPasspointConfiguration.setCarrierId(mCarrierId);
             mPasspointConfiguration.setSubscriptionId(mSubscriptionId);
             mPasspointConfiguration.setMeteredOverride(wifiConfiguration.meteredOverride);
+            mPasspointConfiguration.setOemPrivate(mIsNetworkOemPrivate);
+            mPasspointConfiguration.setOemPaid(mIsNetworkOemPaid);
+            mPasspointConfiguration.setCarrierMerged(mIsCarrierMerged);
             wifiConfiguration.macRandomizationSetting = mIsEnhancedMacRandomizationEnabled
                     ? WifiConfiguration.RANDOMIZATION_ENHANCED
                     : WifiConfiguration.RANDOMIZATION_PERSISTENT;
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index e19b095..540bf2a 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -774,9 +774,13 @@
                                     (byte[]) msg.obj);
                             break;
                         case CALLBACK_MATCH_EXPIRED:
+                            if (!SdkLevel.isAtLeastS()) {
+                                break;
+                            }
                             mOriginalCallback
                                     .onServiceLost(new PeerHandle(msg.arg1),
                                             WIFI_AWARE_DISCOVERY_LOST_REASON_PEER_NOT_VISIBLE);
+                            break;
                     }
                 }
             };
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 357c5bc..006fbaa 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -474,6 +474,27 @@
      */
     private boolean mIsEnhancedMacRandomizationEnabled = false;
 
+
+    /**
+     * Indicate whether the network is oem paid or not. Networks are considered oem paid
+     * if the corresponding connection is only available to system apps.
+     * @hide
+     */
+    private boolean mIsOemPaid;
+
+    /**
+     * Indicate whether the network is oem private or not. Networks are considered oem private
+     * if the corresponding connection is only available to system apps.
+     * @hide
+     */
+    private boolean mIsOemPrivate;
+
+    /**
+     * Indicate whether or not the network is a carrier merged network.
+     * @hide
+     */
+    private boolean mIsCarrierMerged;
+
     /**
      * Indicates if the end user has expressed an explicit opinion about the
      * meteredness of this network, such as through the Settings app.
@@ -589,6 +610,54 @@
     }
 
     /**
+     * Set whether the network is oem paid or not.
+     * @hide
+     */
+    public void setOemPaid(boolean isOemPaid) {
+        mIsOemPaid = isOemPaid;
+    }
+
+    /**
+     * Get whether the network is oem paid or not.
+     * @hide
+     */
+    public boolean isOemPaid() {
+        return mIsOemPaid;
+    }
+
+    /**
+     * Set whether the network is oem private or not.
+     * @hide
+     */
+    public void setOemPrivate(boolean isOemPrivate) {
+        mIsOemPrivate = isOemPrivate;
+    }
+
+    /**
+     * Get whether the network is oem private or not.
+     * @hide
+     */
+    public boolean isOemPrivate() {
+        return mIsOemPrivate;
+    }
+
+    /**
+     * Set whether the network is carrier merged or not.
+     * @hide
+     */
+    public void setCarrierMerged(boolean isCarrierMerged) {
+        mIsCarrierMerged = isCarrierMerged;
+    }
+
+    /**
+     * Get whether the network is carrier merged or not.
+     * @hide
+     */
+    public boolean isCarrierMerged() {
+        return mIsCarrierMerged;
+    }
+
+    /**
      * Constructor for creating PasspointConfiguration with default values.
      */
     public PasspointConfiguration() {}
@@ -635,6 +704,9 @@
         mIsMacRandomizationEnabled = source.mIsMacRandomizationEnabled;
         mIsEnhancedMacRandomizationEnabled = source.mIsEnhancedMacRandomizationEnabled;
         mMeteredOverride = source.mMeteredOverride;
+        mIsCarrierMerged = source.mIsCarrierMerged;
+        mIsOemPaid = source.mIsOemPaid;
+        mIsOemPrivate = source.mIsOemPrivate;
     }
 
     @Override
@@ -669,6 +741,9 @@
         dest.writeBoolean(mIsEnhancedMacRandomizationEnabled);
         dest.writeInt(mMeteredOverride);
         dest.writeInt(mSubscriptionId);
+        dest.writeBoolean(mIsCarrierMerged);
+        dest.writeBoolean(mIsOemPaid);
+        dest.writeBoolean(mIsOemPrivate);
     }
 
     @Override
@@ -700,6 +775,9 @@
                 && mUsageLimitTimeLimitInMinutes == that.mUsageLimitTimeLimitInMinutes
                 && mCarrierId == that.mCarrierId
                 && mSubscriptionId == that.mSubscriptionId
+                && mIsOemPrivate == that.mIsOemPrivate
+                && mIsOemPaid == that.mIsOemPaid
+                && mIsCarrierMerged == that.mIsCarrierMerged
                 && mIsAutojoinEnabled == that.mIsAutojoinEnabled
                 && mIsMacRandomizationEnabled == that.mIsMacRandomizationEnabled
                 && mIsEnhancedMacRandomizationEnabled == that.mIsEnhancedMacRandomizationEnabled
@@ -715,7 +793,8 @@
                 mSubscriptionExpirationTimeMillis, mUsageLimitUsageTimePeriodInMinutes,
                 mUsageLimitStartTimeInMillis, mUsageLimitDataLimit, mUsageLimitTimeLimitInMinutes,
                 mServiceFriendlyNames, mCarrierId, mIsAutojoinEnabled, mIsMacRandomizationEnabled,
-                mIsEnhancedMacRandomizationEnabled, mMeteredOverride, mSubscriptionId);
+                mIsEnhancedMacRandomizationEnabled, mMeteredOverride, mSubscriptionId,
+                mIsCarrierMerged, mIsOemPaid, mIsOemPrivate);
     }
 
     @Override
@@ -774,6 +853,9 @@
         builder.append("mIsMacRandomizationEnabled:" + mIsMacRandomizationEnabled);
         builder.append("mIsEnhancedMacRandomizationEnabled:" + mIsEnhancedMacRandomizationEnabled);
         builder.append("mMeteredOverride:" + mMeteredOverride);
+        builder.append("mIsCarrierMerged:" + mIsCarrierMerged);
+        builder.append("mIsOemPaid:" + mIsOemPaid);
+        builder.append("mIsOemPrivate" + mIsOemPrivate);
         return builder.toString();
     }
 
@@ -884,6 +966,10 @@
                 config.mIsEnhancedMacRandomizationEnabled = in.readBoolean();
                 config.mMeteredOverride = in.readInt();
                 config.mSubscriptionId = in.readInt();
+                config.mIsCarrierMerged = in.readBoolean();
+                config.mIsOemPaid = in.readBoolean();
+                config.mIsOemPrivate = in.readBoolean();
+
                 return config;
             }
 
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 39f6f57..52e9139 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -136,6 +136,7 @@
     private static final String[] TEST_MAC_ADDRESSES = {"da:a1:19:0:0:0"};
     private static final int TEST_AP_FREQUENCY = 2412;
     private static final int TEST_AP_BANDWIDTH = SoftApInfo.CHANNEL_WIDTH_20MHZ;
+    private static final int TEST_SUB_ID = 3;
 
     @Mock Context mContext;
     @Mock android.net.wifi.IWifiManager mWifiService;
@@ -2583,10 +2584,29 @@
 
     @Test
     public void testGetNetworkSuggestionUserApprovalStatus() throws Exception {
+        assumeTrue(SdkLevel.isAtLeastS());
+
         when(mWifiService.getNetworkSuggestionUserApprovalStatus(TEST_PACKAGE_NAME))
                 .thenReturn(WifiManager.STATUS_SUGGESTION_APPROVAL_APPROVED_BY_USER);
         assertEquals(WifiManager.STATUS_SUGGESTION_APPROVAL_APPROVED_BY_USER,
                 mWifiManager.getNetworkSuggestionUserApprovalStatus());
         verify(mWifiService).getNetworkSuggestionUserApprovalStatus(TEST_PACKAGE_NAME);
     }
+
+    @Test
+    public void testSetCarrierNetworkOffload() throws Exception {
+        assumeTrue(SdkLevel.isAtLeastS());
+        mWifiManager.setCarrierNetworkOffloadEnabled(TEST_SUB_ID, true, false);
+        verify(mWifiService).setCarrierNetworkOffloadEnabled(TEST_SUB_ID,
+                true, false);
+    }
+
+    @Test
+    public void testGetCarrierNetworkOffload() throws Exception {
+        assumeTrue(SdkLevel.isAtLeastS());
+        when(mWifiService.isCarrierNetworkOffloadEnabled(TEST_SUB_ID, false)).thenReturn(true);
+        assertTrue(mWifiManager.isCarrierNetworkOffloadEnabled(TEST_SUB_ID, false));
+        verify(mWifiService).isCarrierNetworkOffloadEnabled(TEST_SUB_ID, false);
+    }
+
 }
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index 643a78c..5e82918 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -809,7 +809,7 @@
     /**
      * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
      * when both {@link WifiNetworkSuggestion.Builder#setWpa3Passphrase(String)} and
-     * {@link WifiNetworkSuggestion.Builderi
+     * {@link WifiNetworkSuggestion.Builder
      * #setWpa3EnterpriseStandardModeConfig(WifiEnterpriseConfig)}
      * are invoked.
      */
@@ -1310,6 +1310,7 @@
                 .build();
         assertTrue(suggestion.isOemPaid());
         assertFalse(suggestion.isUserAllowedToManuallyConnect);
+        assertTrue(suggestion.getPasspointConfig().isOemPaid());
     }
 
     /**
@@ -1345,6 +1346,7 @@
                 .build();
         assertTrue(suggestion.isOemPrivate());
         assertFalse(suggestion.isUserAllowedToManuallyConnect);
+        assertTrue(suggestion.getPasspointConfig().isOemPrivate());
     }
 
     /**
@@ -1439,6 +1441,25 @@
     }
 
     /**
+     * Validate {@link WifiNetworkSuggestion.Builder#setCarrierMerged(boolean)} (boolean)} set the
+     * correct value to the passpoint network.
+     */
+    @Test
+    public void testSetCarrierMergedNetworkOnPasspointNetwork() {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        PasspointConfiguration passpointConfiguration = PasspointTestUtils.createConfig();
+        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+                .setPasspointConfig(passpointConfiguration)
+                .setSubscriptionId(1)
+                .setCarrierMerged(true)
+                .setIsMetered(true)
+                .build();
+        assertTrue(suggestion.isCarrierMerged());
+        assertTrue(suggestion.getPasspointConfig().isCarrierMerged());
+    }
+
+    /**
      * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
      * when set both {@link WifiNetworkSuggestion.Builder#setCarrierMerged(boolean)} (boolean)}
      * to true on a network is not metered.