Merge "Enable left badge, hidden badge"
diff --git a/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt b/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt
index 29721c5..9e519f7 100644
--- a/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt
+++ b/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt
@@ -184,11 +184,11 @@
 
                 override fun startParsingPackage(
                     packageName: String,
-                    baseCodePath: String,
-                    codePath: String,
+                    baseApkPath: String,
+                    path: String,
                     manifestArray: TypedArray,
                     isCoreApp: Boolean
-                ) = ParsingPackageImpl(packageName, baseCodePath, codePath, manifestArray)
+                ) = ParsingPackageImpl(packageName, baseApkPath, path, manifestArray)
             })
 
         override fun parseImpl(file: File) =
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
index 2697428..a701f86 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
@@ -21,14 +21,12 @@
 import android.app.Activity;
 import android.content.Context;
 import android.graphics.Point;
-import android.graphics.Rect;
 import android.os.RemoteException;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 import android.perftests.utils.PerfTestActivity;
 import android.platform.test.annotations.Presubmit;
 import android.util.MergedConfiguration;
-import android.view.DisplayCutout;
 import android.view.IWindow;
 import android.view.IWindowSession;
 import android.view.InsetsSourceControl;
@@ -38,6 +36,7 @@
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.widget.LinearLayout;
+import android.window.ClientWindowFrames;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.rule.ActivityTestRule;
@@ -125,13 +124,7 @@
     }
 
     private static class RelayoutRunner {
-        final Rect mOutFrame = new Rect();
-        final Rect mOutContentInsets = new Rect();
-        final Rect mOutVisibleInsets = new Rect();
-        final Rect mOutStableInsets = new Rect();
-        final Rect mOutBackDropFrame = new Rect();
-        final DisplayCutout.ParcelableWrapper mOutDisplayCutout =
-                new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT);
+        final ClientWindowFrames mOutFrames = new ClientWindowFrames();
         final MergedConfiguration mOutMergedConfiguration = new MergedConfiguration();
         final InsetsState mOutInsetsState = new InsetsState();
         final InsetsSourceControl[] mOutControls = new InsetsSourceControl[0];
@@ -164,11 +157,9 @@
             final IWindowSession session = WindowManagerGlobal.getWindowSession();
             while (state.keepRunning()) {
                 session.relayout(mWindow, mSeq, mParams, mWidth, mHeight,
-                        mViewVisibility.getAsInt(), mFlags, mFrameNumber, mOutFrame,
-                        mOutContentInsets, mOutVisibleInsets, mOutStableInsets,
-                        mOutBackDropFrame, mOutDisplayCutout, mOutMergedConfiguration,
-                        mOutSurfaceControl, mOutInsetsState, mOutControls, mOutSurfaceSize,
-                        mOutBlastSurfaceControl);
+                        mViewVisibility.getAsInt(), mFlags, mFrameNumber, mOutFrames,
+                        mOutMergedConfiguration, mOutSurfaceControl, mOutInsetsState, mOutControls,
+                        mOutSurfaceSize, mOutBlastSurfaceControl);
             }
         }
     }
diff --git a/api/current.txt b/api/current.txt
index e678d16..5f32dec 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -31303,6 +31303,7 @@
 
   @Deprecated public static class WifiConfiguration.GroupCipher {
     field @Deprecated public static final int CCMP = 3; // 0x3
+    field @Deprecated public static final int GCMP_128 = 7; // 0x7
     field @Deprecated public static final int GCMP_256 = 5; // 0x5
     field @Deprecated public static final int SMS4 = 6; // 0x6
     field @Deprecated public static final int TKIP = 2; // 0x2
@@ -31332,6 +31333,7 @@
 
   @Deprecated public static class WifiConfiguration.PairwiseCipher {
     field @Deprecated public static final int CCMP = 2; // 0x2
+    field @Deprecated public static final int GCMP_128 = 5; // 0x5
     field @Deprecated public static final int GCMP_256 = 3; // 0x3
     field @Deprecated public static final int NONE = 0; // 0x0
     field @Deprecated public static final int SMS4 = 4; // 0x4
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index 097609e..c12d897 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -57,6 +57,10 @@
     field public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 65536; // 0x10000
   }
 
+  public static final class MediaSession.Token implements android.os.Parcelable {
+    method public int getUid();
+  }
+
   public final class MediaSessionManager {
     method public void dispatchMediaKeyEventAsSystemService(@NonNull android.view.KeyEvent);
     method public boolean dispatchMediaKeyEventAsSystemService(@NonNull android.media.session.MediaSession.Token, @NonNull android.view.KeyEvent);
diff --git a/api/system-current.txt b/api/system-current.txt
old mode 100755
new mode 100644
index 3ec3467..b908cae
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -205,6 +205,7 @@
     field public static final String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS";
     field public static final String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS";
     field public static final String SECURE_ELEMENT_PRIVILEGED_OPERATION = "android.permission.SECURE_ELEMENT_PRIVILEGED_OPERATION";
+    field public static final String SEND_CATEGORY_CAR_NOTIFICATIONS = "android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS";
     field public static final String SEND_DEVICE_CUSTOMIZATION_READY = "android.permission.SEND_DEVICE_CUSTOMIZATION_READY";
     field public static final String SEND_SHOW_SUSPENDED_APP_DETAILS = "android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS";
     field public static final String SEND_SMS_NO_CONFIRMATION = "android.permission.SEND_SMS_NO_CONFIRMATION";
@@ -7343,6 +7344,7 @@
     method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.WifiConfiguration getWifiApConfiguration();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public int getWifiApState();
     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 public boolean isConnectedMacRandomizationSupported();
     method @Deprecated public boolean isDeviceToDeviceRttSupported();
@@ -7582,6 +7584,7 @@
     field public static final int WIFI_BAND_5_GHZ = 2; // 0x2
     field public static final int WIFI_BAND_5_GHZ_DFS_ONLY = 4; // 0x4
     field public static final int WIFI_BAND_5_GHZ_WITH_DFS = 6; // 0x6
+    field public static final int WIFI_BAND_60_GHZ = 16; // 0x10
     field public static final int WIFI_BAND_6_GHZ = 8; // 0x8
     field public static final int WIFI_BAND_BOTH = 3; // 0x3
     field public static final int WIFI_BAND_BOTH_WITH_DFS = 7; // 0x7
@@ -7821,6 +7824,8 @@
     field public static final int BSS_CAPABILITY_CF_POLL_REQUEST = 8; // 0x8
     field public static final int BSS_CAPABILITY_CHANNEL_AGILITY = 128; // 0x80
     field public static final int BSS_CAPABILITY_DELAYED_BLOCK_ACK = 16384; // 0x4000
+    field public static final int BSS_CAPABILITY_DMG_ESS = 3; // 0x3
+    field public static final int BSS_CAPABILITY_DMG_IBSS = 1; // 0x1
     field public static final int BSS_CAPABILITY_DSSS_OFDM = 8192; // 0x2000
     field public static final int BSS_CAPABILITY_ESS = 1; // 0x1
     field public static final int BSS_CAPABILITY_IBSS = 2; // 0x2
diff --git a/api/test-current.txt b/api/test-current.txt
index 3de1d93..de2919b 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -133,7 +133,6 @@
   public class ActivityTaskManager {
     method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void clearLaunchParamsForPackages(java.util.List<java.lang.String>);
     method public static boolean currentUiModeSupportsErrorDialogs(@NonNull android.content.Context);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public String listAllStacks();
     method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void moveTaskToStack(int, int, boolean);
     method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public boolean moveTopActivityToPinnedStack(int, android.graphics.Rect);
     method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void removeStacksInWindowingModes(int[]) throws java.lang.SecurityException;
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index e6e22ba..94c2305 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -488,6 +488,8 @@
         UIInteractionFrameInfoReported ui_interaction_frame_info_reported =
             305 [(module) = "framework"];
         UIActionLatencyReported ui_action_latency_reported = 306 [(module) = "framework"];
+        WifiDisconnectReported wifi_disconnect_reported = 307 [(module) = "wifi"];
+        WifiConnectionStateChanged wifi_connection_state_changed = 308 [(module) = "wifi"];
 
         // StatsdStats tracks platform atoms with ids upto 500.
         // Update StatsdStats::kMaxPushedAtomId when atom ids here approach that value.
@@ -854,10 +856,10 @@
 }
 
 /**
- * Logs whether a wifi connection is successful and reasons for failure if it isn't.
+ * Logs whether a Wifi connection attempt was successful and reasons for failure if it wasn't.
  *
  * Logged from:
- *   frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeImpl.java
+ *   frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiMetrics.java
  */
 message WifiConnectionResultReported {
     enum FailureCode {
@@ -869,13 +871,159 @@
         FAILURE_DHCP = 5;
         FAILURE_NETWORK_DISCONNECTION = 6;
         FAILURE_ROAM_TIMEOUT = 7;
+        FAILURE_WRONG_PASSWORD = 8;
     }
-    // true represents a successful connection
+
+    enum Trigger {
+        UNKNOWN = 0;
+        // Connection attempt was initiated manually.
+        MANUAL = 1;
+        // Automatic reconnection to the same network as connected previously.
+        RECONNECT_SAME_NETWORK = 2;
+        // Automatic reconnection to a saved network, but not the previous one.
+        AUTOCONNECT_CONFIGURED_NETWORK = 3;
+        // Automatic first connection attempt after device boot.
+        AUTOCONNECT_BOOT = 4;
+    }
+
+    // True represents a successful connection.
     optional bool connection_result = 1;
-    // reason for the connection failure
+    // Reason for the connection failure.
     optional FailureCode failure_code = 2;
-    // scan rssi before the connection attempt
+    // Scan RSSI before the connection attempt.
     optional int32 rssi = 3;
+    // Time taken by this connection attempt.
+    optional int32 connection_attempt_duration_millis = 4;
+    // Band bucket the connected network is on.
+    optional android.net.wifi.WifiBandBucket band = 5;
+    // Authentication type.
+    optional android.net.wifi.WifiAuthType auth_type = 6;
+    // What triggered this connection attempt.
+    optional Trigger trigger = 7;
+    // Whether this network was used (successfully connected to) previously.
+    optional bool network_used = 8;
+    // Time taken from the last successful connection (or device boot if that's the first one).
+    optional int32 time_since_last_connection_seconds = 9;
+}
+
+/**
+ * Logs when a Wifi connection drops.
+ *
+ * Logged from:
+ *   frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiMetrics.java
+ */
+message WifiDisconnectReported {
+    enum FailureCode {
+        UNKNOWN = 0;
+
+        // Wifi supplicant failure reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45).
+        // See ISupplicantStaIfaceCallback.java:ReasonCode
+        UNSPECIFIED = 1;
+        PREV_AUTH_NOT_VALID = 2;
+        DEAUTH_LEAVING = 3;
+        DISASSOC_DUE_TO_INACTIVITY = 4;
+        DISASSOC_AP_BUSY = 5;
+        CLASS2_FRAME_FROM_NONAUTH_STA = 6;
+        CLASS3_FRAME_FROM_NONASSOC_STA = 7;
+        DISASSOC_STA_HAS_LEFT = 8;
+        STA_REQ_ASSOC_WITHOUT_AUTH = 9;
+        PWR_CAPABILITY_NOT_VALID = 10;
+        SUPPORTED_CHANNEL_NOT_VALID = 11;
+        BSS_TRANSITION_DISASSOC = 12;
+        INVALID_IE = 13;
+        MICHAEL_MIC_FAILURE = 14;
+        FOURWAY_HANDSHAKE_TIMEOUT = 15;
+        GROUP_KEY_UPDATE_TIMEOUT = 16;
+        IE_IN_4WAY_DIFFERS = 17;
+        GROUP_CIPHER_NOT_VALID = 18;
+        PAIRWISE_CIPHER_NOT_VALID = 19;
+        AKMP_NOT_VALID = 20;
+        UNSUPPORTED_RSN_IE_VERSION = 21;
+        INVALID_RSN_IE_CAPAB = 22;
+        IEEE_802_1X_AUTH_FAILED = 23;
+        CIPHER_SUITE_REJECTED = 24;
+        TDLS_TEARDOWN_UNREACHABLE = 25;
+        TDLS_TEARDOWN_UNSPECIFIED = 26;
+        SSP_REQUESTED_DISASSOC = 27;
+        NO_SSP_ROAMING_AGREEMENT = 28;
+        BAD_CIPHER_OR_AKM = 29;
+        NOT_AUTHORIZED_THIS_LOCATION = 30;
+        SERVICE_CHANGE_PRECLUDES_TS = 31;
+        UNSPECIFIED_QOS_REASON = 32;
+        NOT_ENOUGH_BANDWIDTH = 33;
+        DISASSOC_LOW_ACK = 34;
+        EXCEEDED_TXOP = 35;
+        STA_LEAVING = 36;
+        END_TS_BA_DLS = 37;
+        UNKNOWN_TS_BA = 38;
+        TIMEOUT = 39;
+        PEERKEY_MISMATCH = 45;
+        AUTHORIZED_ACCESS_LIMIT_REACHED = 46;
+        EXTERNAL_SERVICE_REQUIREMENTS = 47;
+        INVALID_FT_ACTION_FRAME_COUNT = 48;
+        INVALID_PMKID = 49;
+        INVALID_MDE = 50;
+        INVALID_FTE = 51;
+        MESH_PEERING_CANCELLED = 52;
+        MESH_MAX_PEERS = 53;
+        MESH_CONFIG_POLICY_VIOLATION = 54;
+        MESH_CLOSE_RCVD = 55;
+        MESH_MAX_RETRIES = 56;
+        MESH_CONFIRM_TIMEOUT = 57;
+        MESH_INVALID_GTK = 58;
+        MESH_INCONSISTENT_PARAMS = 59;
+        MESH_INVALID_SECURITY_CAP = 60;
+        MESH_PATH_ERROR_NO_PROXY_INFO = 61;
+        MESH_PATH_ERROR_NO_FORWARDING_INFO = 62;
+        MESH_PATH_ERROR_DEST_UNREACHABLE = 63;
+        MAC_ADDRESS_ALREADY_EXISTS_IN_MBSS = 64;
+        MESH_CHANNEL_SWITCH_REGULATORY_REQ = 65;
+        MESH_CHANNEL_SWITCH_UNSPECIFIED = 66;
+
+        // ClientModeImpl error codes
+        // Defined in /frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiMetrics.java
+        IFACE_DESTROYED = 10000;
+        WIFI_DISABLED = 10001;
+        SUPPLICANT_DISCONNECTED = 10002;
+        CONNECTING_WATCHDOG_TIMER = 10003;
+        ROAM_WATCHDOG_TIMER = 10004;
+    }
+
+    // How long the session lasted from successful connection to disconnect.
+    optional int32 connected_duration_seconds = 1;
+
+    // Reason for the disconnect.
+    optional FailureCode failure_code = 2;
+
+    // Band bucket the connected network was on.
+    optional android.net.wifi.WifiBandBucket band = 3;
+
+    // Authentication type.
+    optional android.net.wifi.WifiAuthType auth_type = 4;
+
+    // Last seen RSSI before the disconnect.
+    optional int32 last_rssi = 5;
+
+    // Last seen link speed before the disconnect.
+    optional int32 last_link_speed = 6;
+}
+
+/**
+ * Logs when Wifi connection is established or dropped.
+ *
+ * Logged from:
+ *   frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiMetrics.java
+ */
+message WifiConnectionStateChanged {
+    optional bool is_connected = 1;
+
+    // Band bucket the connected network was on.
+    // Filled for both connected and disconnected cases.
+    optional android.net.wifi.WifiBandBucket band = 2;
+
+    // Authentication type.
+    // Filled for both connected and disconnected cases.
+    optional android.net.wifi.WifiAuthType auth_type = 3;
 }
 
 /**
@@ -11239,4 +11387,4 @@
 
     // List of leasees of this Blob
     optional BlobLeaseeListProto leasees = 5 [(log_mode) = MODE_BYTES];
-}
+}
\ No newline at end of file
diff --git a/core/java/android/app/ActivityManager.aidl b/core/java/android/app/ActivityManager.aidl
index 29260e9..45a0e87 100644
--- a/core/java/android/app/ActivityManager.aidl
+++ b/core/java/android/app/ActivityManager.aidl
@@ -24,8 +24,6 @@
 parcelable ActivityManager.RunningServiceInfo;
 parcelable ActivityManager.RunningTaskInfo;
 /** @hide */
-parcelable ActivityManager.StackInfo;
-/** @hide */
 parcelable ActivityManager.TaskThumbnail;
 /** @hide */
 parcelable ActivityManager.TaskSnapshot;
\ No newline at end of file
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index a88c6a8..5aecb61 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -76,7 +76,6 @@
 import android.util.Singleton;
 import android.util.Size;
 import android.view.Surface;
-import android.window.WindowContainerToken;
 
 import com.android.internal.app.LocalePicker;
 import com.android.internal.app.procstats.ProcessStats;
@@ -2815,160 +2814,6 @@
     }
 
     /**
-     * Information you can retrieve about an ActivityStack in the system.
-     * @hide
-     */
-    public static class StackInfo implements Parcelable {
-        @UnsupportedAppUsage
-        public int stackId;
-        @UnsupportedAppUsage
-        public Rect bounds = new Rect();
-        @UnsupportedAppUsage
-        public int[] taskIds;
-        @UnsupportedAppUsage
-        public String[] taskNames;
-        @UnsupportedAppUsage
-        public Rect[] taskBounds;
-        @UnsupportedAppUsage
-        public int[] taskUserIds;
-        @UnsupportedAppUsage
-        public ComponentName topActivity;
-        @UnsupportedAppUsage
-        public int displayId;
-        @UnsupportedAppUsage
-        public int userId;
-        @UnsupportedAppUsage
-        public boolean visible;
-        // Index of the stack in the display's stack list, can be used for comparison of stack order
-        // TODO: Can be removed since no one is using it.
-        @UnsupportedAppUsage
-        @Deprecated
-        public int position;
-        public WindowContainerToken stackToken;
-        /**
-         * The full configuration the stack is currently running in.
-         * @hide
-         */
-        final public Configuration configuration = new Configuration();
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(stackId);
-            dest.writeInt(bounds.left);
-            dest.writeInt(bounds.top);
-            dest.writeInt(bounds.right);
-            dest.writeInt(bounds.bottom);
-            dest.writeIntArray(taskIds);
-            dest.writeStringArray(taskNames);
-            final int boundsCount = taskBounds == null ? 0 : taskBounds.length;
-            dest.writeInt(boundsCount);
-            for (int i = 0; i < boundsCount; i++) {
-                dest.writeInt(taskBounds[i].left);
-                dest.writeInt(taskBounds[i].top);
-                dest.writeInt(taskBounds[i].right);
-                dest.writeInt(taskBounds[i].bottom);
-            }
-            dest.writeIntArray(taskUserIds);
-            dest.writeInt(displayId);
-            dest.writeInt(userId);
-            dest.writeInt(visible ? 1 : 0);
-            dest.writeInt(position);
-            stackToken.writeToParcel(dest, 0);
-            if (topActivity != null) {
-                dest.writeInt(1);
-                topActivity.writeToParcel(dest, 0);
-            } else {
-                dest.writeInt(0);
-            }
-            configuration.writeToParcel(dest, flags);
-        }
-
-        public void readFromParcel(Parcel source) {
-            stackId = source.readInt();
-            bounds = new Rect(
-                    source.readInt(), source.readInt(), source.readInt(), source.readInt());
-            taskIds = source.createIntArray();
-            taskNames = source.createStringArray();
-            final int boundsCount = source.readInt();
-            if (boundsCount > 0) {
-                taskBounds = new Rect[boundsCount];
-                for (int i = 0; i < boundsCount; i++) {
-                    taskBounds[i] = new Rect();
-                    taskBounds[i].set(
-                            source.readInt(), source.readInt(), source.readInt(), source.readInt());
-                }
-            } else {
-                taskBounds = null;
-            }
-            taskUserIds = source.createIntArray();
-            displayId = source.readInt();
-            userId = source.readInt();
-            visible = source.readInt() > 0;
-            position = source.readInt();
-            stackToken = WindowContainerToken.CREATOR.createFromParcel(source);
-            if (source.readInt() > 0) {
-                topActivity = ComponentName.readFromParcel(source);
-            }
-            configuration.readFromParcel(source);
-        }
-
-        public static final @android.annotation.NonNull Creator<StackInfo> CREATOR = new Creator<StackInfo>() {
-            @Override
-            public StackInfo createFromParcel(Parcel source) {
-                return new StackInfo(source);
-            }
-            @Override
-            public StackInfo[] newArray(int size) {
-                return new StackInfo[size];
-            }
-        };
-
-        public StackInfo() {
-        }
-
-        private StackInfo(Parcel source) {
-            readFromParcel(source);
-        }
-
-        @UnsupportedAppUsage
-        public String toString(String prefix) {
-            StringBuilder sb = new StringBuilder(256);
-            sb.append(prefix); sb.append("Stack id="); sb.append(stackId);
-                    sb.append(" bounds="); sb.append(bounds.toShortString());
-                    sb.append(" displayId="); sb.append(displayId);
-                    sb.append(" userId="); sb.append(userId);
-                    sb.append("\n");
-                    sb.append(" configuration="); sb.append(configuration);
-                    sb.append("\n");
-            prefix = prefix + "  ";
-            for (int i = 0; i < taskIds.length; ++i) {
-                sb.append(prefix); sb.append("taskId="); sb.append(taskIds[i]);
-                        sb.append(": "); sb.append(taskNames[i]);
-                        if (taskBounds != null) {
-                            sb.append(" bounds="); sb.append(taskBounds[i].toShortString());
-                        }
-                        sb.append(" userId=").append(taskUserIds[i]);
-                        sb.append(" visible=").append(visible);
-                        if (topActivity != null) {
-                            sb.append(" topActivity=").append(topActivity);
-                        }
-                        sb.append("\n");
-            }
-            return sb.toString();
-        }
-
-        @Override
-        public String toString() {
-            return toString("");
-        }
-    }
-
-    /**
      * @hide
      */
     @RequiresPermission(anyOf={Manifest.permission.CLEAR_APP_USER_DATA,
diff --git a/core/java/android/app/ActivityTaskManager.aidl b/core/java/android/app/ActivityTaskManager.aidl
new file mode 100644
index 0000000..a12bcd5
--- /dev/null
+++ b/core/java/android/app/ActivityTaskManager.aidl
@@ -0,0 +1,20 @@
+/**
+ * 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;
+
+/** @hide */
+parcelable ActivityTaskManager.RootTaskInfo;
\ No newline at end of file
diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java
index 4283d7a..3e4d5ee 100644
--- a/core/java/android/app/ActivityTaskManager.java
+++ b/core/java/android/app/ActivityTaskManager.java
@@ -29,6 +29,8 @@
 import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.DisplayMetrics;
@@ -391,27 +393,6 @@
     }
 
     /**
-     * List all activity stacks information.
-     */
-    @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
-    public String listAllStacks() {
-        final List<ActivityManager.StackInfo> stacks;
-        try {
-            stacks = getService().getAllStackInfos();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-
-        final StringBuilder sb = new StringBuilder();
-        if (stacks != null) {
-            for (ActivityManager.StackInfo info : stacks) {
-                sb.append(info).append("\n");
-            }
-        }
-        return sb.toString();
-    }
-
-    /**
      * Clears launch params for the given package.
      * @param packageNames the names of the packages of which the launch params are to be cleared
      */
@@ -468,4 +449,96 @@
         final Configuration config = context.getResources().getConfiguration();
         return currentUiModeSupportsErrorDialogs(config);
     }
+
+    /**
+     * Information you can retrieve about a root task in the system.
+     * @hide
+     */
+    public static class RootTaskInfo extends TaskInfo implements Parcelable {
+        // TODO(b/148895075): Move some of the fields to TaskInfo.
+        public Rect bounds = new Rect();
+        public int[] childTaskIds;
+        public String[] childTaskNames;
+        public Rect[] childTaskBounds;
+        public int[] childTaskUserIds;
+        public boolean visible;
+        // Index of the stack in the display's stack list, can be used for comparison of stack order
+        public int position;
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeTypedObject(bounds, flags);
+            dest.writeIntArray(childTaskIds);
+            dest.writeStringArray(childTaskNames);
+            dest.writeTypedArray(childTaskBounds, flags);
+            dest.writeIntArray(childTaskUserIds);
+            dest.writeInt(visible ? 1 : 0);
+            dest.writeInt(position);
+            super.writeToParcel(dest, flags);
+        }
+
+        @Override
+        void readFromParcel(Parcel source) {
+            bounds = source.readTypedObject(Rect.CREATOR);
+            childTaskIds = source.createIntArray();
+            childTaskNames = source.createStringArray();
+            childTaskBounds = source.createTypedArray(Rect.CREATOR);
+            childTaskUserIds = source.createIntArray();
+            visible = source.readInt() > 0;
+            position = source.readInt();
+            super.readFromParcel(source);
+        }
+
+        public static final @NonNull Creator<RootTaskInfo> CREATOR = new Creator<>() {
+            @Override
+            public RootTaskInfo createFromParcel(Parcel source) {
+                return new RootTaskInfo(source);
+            }
+
+            @Override
+            public RootTaskInfo[] newArray(int size) {
+                return new RootTaskInfo[size];
+            }
+        };
+
+        public RootTaskInfo() {
+        }
+
+        private RootTaskInfo(Parcel source) {
+            readFromParcel(source);
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(256);
+            sb.append("RootTask id="); sb.append(taskId);
+            sb.append(" bounds="); sb.append(bounds.toShortString());
+            sb.append(" displayId="); sb.append(displayId);
+            sb.append(" userId="); sb.append(userId);
+            sb.append("\n");
+
+            sb.append(" configuration="); sb.append(configuration);
+            sb.append("\n");
+
+            for (int i = 0; i < childTaskIds.length; ++i) {
+                sb.append("  taskId="); sb.append(childTaskIds[i]);
+                sb.append(": "); sb.append(childTaskNames[i]);
+                if (childTaskBounds != null) {
+                    sb.append(" bounds="); sb.append(childTaskBounds[i].toShortString());
+                }
+                sb.append(" userId=").append(childTaskUserIds[i]);
+                sb.append(" visible=").append(visible);
+                if (topActivity != null) {
+                    sb.append(" topActivity=").append(topActivity);
+                }
+                sb.append("\n");
+            }
+            return sb.toString();
+        }
+    }
 }
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index f640119..45b25a3 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -17,6 +17,7 @@
 package android.app;
 
 import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
 import android.app.ApplicationErrorReport;
 import android.app.ApplicationExitInfo;
 import android.app.ContentProviderHolder;
@@ -448,12 +449,11 @@
     @UnsupportedAppUsage
     void hang(in IBinder who, boolean allowRestart);
 
-    @UnsupportedAppUsage
-    List<ActivityManager.StackInfo> getAllStackInfos();
+    List<ActivityTaskManager.RootTaskInfo> getAllRootTaskInfos();
     @UnsupportedAppUsage
     void moveTaskToStack(int taskId, int stackId, boolean toTop);
     void setFocusedStack(int stackId);
-    ActivityManager.StackInfo getFocusedStackInfo();
+    ActivityTaskManager.RootTaskInfo getFocusedRootTaskInfo();
     @UnsupportedAppUsage
     void restart();
     void performIdleMaintenance();
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 72a3637d..f3c7fe94 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -17,6 +17,7 @@
 package android.app;
 
 import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
 import android.app.ApplicationErrorReport;
 import android.app.ContentProviderHolder;
 import android.app.GrantedUriPermission;
@@ -186,7 +187,7 @@
             in AssistStructure structure, in AssistContent content, in Uri referrer);
 
     void setFocusedStack(int stackId);
-    ActivityManager.StackInfo getFocusedStackInfo();
+    ActivityTaskManager.RootTaskInfo getFocusedRootTaskInfo();
     Rect getTaskBounds(int taskId);
 
     void cancelRecentsAnimation(boolean restoreHomeStackPosition);
@@ -260,11 +261,10 @@
     /** Removes stack of the activity types from the system. */
     void removeStacksWithActivityTypes(in int[] activityTypes);
 
-    List<ActivityManager.StackInfo> getAllStackInfos();
-    ActivityManager.StackInfo getStackInfo(int windowingMode, int activityType);
-    List<ActivityManager.StackInfo> getAllStackInfosOnDisplay(int displayId);
-    ActivityManager.StackInfo getStackInfoOnDisplay(int windowingMode, int activityType,
-            int displayId);
+    List<ActivityTaskManager.RootTaskInfo> getAllRootTaskInfos();
+    ActivityTaskManager.RootTaskInfo getRootTaskInfo(int windowingMode, int activityType);
+    List<ActivityTaskManager.RootTaskInfo> getAllRootTaskInfosOnDisplay(int displayId);
+    ActivityTaskManager.RootTaskInfo getRootTaskInfoOnDisplay(int windowingMode, int activityType, int displayId);
 
     /**
      * Informs ActivityTaskManagerService that the keyguard is showing.
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index f3f00e5..4718cf1 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -36,7 +36,8 @@
     private static final String TAG = "TaskInfo";
 
     /**
-     * The id of the user the task was running as.
+     * The id of the user the task was running as if this is a leaf task. The id of the current
+     * running user of the system otherwise.
      * @hide
      */
     @UnsupportedAppUsage
diff --git a/core/java/android/content/PermissionChecker.java b/core/java/android/content/PermissionChecker.java
index b434072..eec7c9c 100644
--- a/core/java/android/content/PermissionChecker.java
+++ b/core/java/android/content/PermissionChecker.java
@@ -343,20 +343,22 @@
      * @param permission The permission to check.
      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
      *     or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
-     * @param attributionTag attribution tag of caller (if not self)
+     * @param callingPackageName package name tag of caller (if not self)
+     * @param callingAttributionTag attribution tag of caller (if not self)
      * @param message A message describing the reason the permission was checked
      *
      * @see #checkCallingOrSelfPermissionForPreflight(Context, String)
      */
     @PermissionResult
     public static int checkCallingOrSelfPermissionForDataDelivery(@NonNull Context context,
-            @NonNull String permission, @Nullable String attributionTag, @Nullable String message) {
-        String packageName = (Binder.getCallingPid() == Process.myPid())
-                ? context.getPackageName() : null;
-        attributionTag = (Binder.getCallingPid() == Process.myPid())
-                ? context.getAttributionTag() : attributionTag;
+            @NonNull String permission, @Nullable String callingPackageName,
+            @Nullable String callingAttributionTag, @Nullable String message) {
+        callingPackageName = (Binder.getCallingPid() == Process.myPid())
+                ? context.getPackageName() : callingPackageName;
+        callingAttributionTag = (Binder.getCallingPid() == Process.myPid())
+                ? context.getAttributionTag() : callingAttributionTag;
         return checkPermissionForDataDelivery(context, permission, Binder.getCallingPid(),
-                Binder.getCallingUid(), packageName, attributionTag, message);
+                Binder.getCallingUid(), callingPackageName, callingAttributionTag, message);
     }
 
     /**
@@ -375,15 +377,15 @@
      * app's fg/gb state) and this check will not leave a trace that permission protected
      * data was delivered. When you are about to deliver the location data to a registered
      * listener you should use {@link #checkCallingOrSelfPermissionForDataDelivery(Context,
-     * String, String, String)} which will evaluate the permission access based on the current
-     * fg/bg state of the app and leave a record that the data was accessed.
+     * String, String, String, String)} which will evaluate the permission access based on the
+     * current fg/bg state of the app and leave a record that the data was accessed.
      *
      * @param context Context for accessing resources.
      * @param permission The permission to check.
      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
      *     or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
      *
-     * @see #checkCallingOrSelfPermissionForDataDelivery(Context, String, String, String)
+     * @see #checkCallingOrSelfPermissionForDataDelivery(Context, String, String, String, String)
      */
     @PermissionResult
     public static int checkCallingOrSelfPermissionForPreflight(@NonNull Context context,
diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
index e450748..e573539 100644
--- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -579,8 +579,8 @@
         ii.handleProfiling = i.isHandleProfiling();
         ii.functionalTest = i.isFunctionalTest();
 
-        ii.sourceDir = pkg.getBaseCodePath();
-        ii.publicSourceDir = pkg.getBaseCodePath();
+        ii.sourceDir = pkg.getBaseApkPath();
+        ii.publicSourceDir = pkg.getBaseApkPath();
         ii.splitNames = pkg.getSplitNames();
         ii.splitSourceDirs = pkg.getSplitCodePaths();
         ii.splitPublicSourceDirs = pkg.getSplitCodePaths();
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index f9679c7..ed12a17 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -145,7 +145,7 @@
     private String realPackage;
 
     @NonNull
-    protected String baseCodePath;
+    protected String mBaseApkPath;
 
     private boolean requiredForAllUsers;
     @Nullable
@@ -280,7 +280,7 @@
 
     @NonNull
     @DataClass.ParcelWith(ForInternedString.class)
-    protected String codePath;
+    protected String mPath;
 
     private boolean use32BitAbi;
     private boolean visibleToInstantApps;
@@ -429,11 +429,11 @@
     private ArraySet<String> mimeGroups;
 
     @VisibleForTesting
-    public ParsingPackageImpl(@NonNull String packageName, @NonNull String baseCodePath,
-            @NonNull String codePath, @Nullable TypedArray manifestArray) {
+    public ParsingPackageImpl(@NonNull String packageName, @NonNull String baseApkPath,
+            @NonNull String path, @Nullable TypedArray manifestArray) {
         this.packageName = TextUtils.safeIntern(packageName);
-        this.baseCodePath = baseCodePath;
-        this.codePath = codePath;
+        this.mBaseApkPath = baseApkPath;
+        this.mPath = path;
 
         if (manifestArray != null) {
             versionCode = manifestArray.getInteger(R.styleable.AndroidManifest_versionCode, 0);
@@ -961,10 +961,10 @@
         appInfo.volumeUuid = volumeUuid;
         appInfo.zygotePreloadName = zygotePreloadName;
         appInfo.setGwpAsanMode(gwpAsanMode);
-        appInfo.setBaseCodePath(baseCodePath);
-        appInfo.setBaseResourcePath(baseCodePath);
-        appInfo.setCodePath(codePath);
-        appInfo.setResourcePath(codePath);
+        appInfo.setBaseCodePath(mBaseApkPath);
+        appInfo.setBaseResourcePath(mBaseApkPath);
+        appInfo.setCodePath(mPath);
+        appInfo.setResourcePath(mPath);
         appInfo.setSplitCodePaths(splitCodePaths);
         appInfo.setSplitResourcePaths(splitCodePaths);
         appInfo.setVersionCode(PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode));
@@ -993,7 +993,7 @@
         dest.writeString(this.compileSdkVersionCodeName);
         sForInternedString.parcel(this.packageName, dest, flags);
         dest.writeString(this.realPackage);
-        dest.writeString(this.baseCodePath);
+        dest.writeString(this.mBaseApkPath);
         dest.writeBoolean(this.requiredForAllUsers);
         dest.writeString(this.restrictedAccountType);
         dest.writeString(this.requiredAccountType);
@@ -1048,7 +1048,7 @@
         dest.writeBundle(this.metaData);
         sForInternedString.parcel(this.volumeUuid, dest, flags);
         dest.writeParcelable(this.signingDetails, flags);
-        dest.writeString(this.codePath);
+        dest.writeString(this.mPath);
         dest.writeBoolean(this.use32BitAbi);
         dest.writeBoolean(this.visibleToInstantApps);
         dest.writeBoolean(this.forceQueryable);
@@ -1157,7 +1157,7 @@
         this.compileSdkVersionCodeName = in.readString();
         this.packageName = sForInternedString.unparcel(in);
         this.realPackage = in.readString();
-        this.baseCodePath = in.readString();
+        this.mBaseApkPath = in.readString();
         this.requiredForAllUsers = in.readBoolean();
         this.restrictedAccountType = in.readString();
         this.requiredAccountType = in.readString();
@@ -1212,7 +1212,7 @@
         this.metaData = in.readBundle(boot);
         this.volumeUuid = sForInternedString.unparcel(in);
         this.signingDetails = in.readParcelable(boot);
-        this.codePath = in.readString();
+        this.mPath = in.readString();
         this.use32BitAbi = in.readBoolean();
         this.visibleToInstantApps = in.readBoolean();
         this.forceQueryable = in.readBoolean();
@@ -1361,8 +1361,8 @@
 
     @NonNull
     @Override
-    public String getBaseCodePath() {
-        return baseCodePath;
+    public String getBaseApkPath() {
+        return mBaseApkPath;
     }
 
     @Override
@@ -1647,8 +1647,8 @@
 
     @NonNull
     @Override
-    public String getCodePath() {
-        return codePath;
+    public String getPath() {
+        return mPath;
     }
 
     @Override
diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java
index 7e0fe7d..dbd15f5 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageRead.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java
@@ -548,7 +548,7 @@
     String getPackageName();
 
     /** Path of base APK */
-    String getBaseCodePath();
+    String getBaseApkPath();
 
     /**
      * Path where this package was found on disk. For monolithic packages
@@ -556,7 +556,7 @@
      * path to the cluster directory.
      */
     @NonNull
-    String getCodePath();
+    String getPath();
 
     /**
      * @see ApplicationInfo#compatibleWidthLimitDp
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 741e80c..bce75cd 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -162,10 +162,10 @@
             @Override
             public ParsingPackage startParsingPackage(
                     @NonNull String packageName,
-                    @NonNull String baseCodePath,
-                    @NonNull String codePath,
+                    @NonNull String baseApkPath,
+                    @NonNull String path,
                     @NonNull TypedArray manifestArray, boolean isCoreApp) {
-                return new ParsingPackageImpl(packageName, baseCodePath, codePath, manifestArray);
+                return new ParsingPackageImpl(packageName, baseApkPath, path, manifestArray);
             }
         });
         try {
@@ -1213,9 +1213,9 @@
                 features = ArrayUtils.add(features, featureInfo);
             } else {
                 Slog.w(TAG,
-                        "Unknown element under <feature-group>: " + innerTagName +
-                                " at " + pkg.getBaseCodePath() + " " +
-                                parser.getPositionDescription());
+                        "Unknown element under <feature-group>: " + innerTagName
+                                + " at " + pkg.getBaseApkPath() + " "
+                                + parser.getPositionDescription());
             }
         }
 
@@ -2419,7 +2419,7 @@
                     R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyValue);
             if (!PackageParser.checkRequiredSystemProperties(propName, propValue)) {
                 String message = "Skipping target and overlay pair " + target + " and "
-                        + pkg.getBaseCodePath()
+                        + pkg.getBaseApkPath()
                         + ": overlay ignored due to required system property: "
                         + propName + " with value: " + propValue;
                 Slog.i(TAG, message);
@@ -2674,7 +2674,7 @@
                                     "<meta-data> only supports string, integer, float, color, "
                                             + "boolean, and resource reference types: "
                                             + parser.getName() + " at "
-                                            + pkg.getBaseCodePath() + " "
+                                            + pkg.getBaseApkPath() + " "
                                             + parser.getPositionDescription());
                         } else {
                             return input.error("<meta-data> only supports string, integer, float, "
@@ -2711,7 +2711,7 @@
         try {
             ParseResult<SigningDetails> result = getSigningDetails(
                     input,
-                    pkg.getBaseCodePath(),
+                    pkg.getBaseApkPath(),
                     skipVerify,
                     pkg.isStaticSharedLibrary(),
                     signingDetails,
@@ -2857,7 +2857,7 @@
         boolean hasFeature(String feature);
 
         ParsingPackage startParsingPackage(@NonNull String packageName,
-                @NonNull String baseCodePath, @NonNull String codePath,
+                @NonNull String baseApkPath, @NonNull String path,
                 @NonNull TypedArray manifestArray, boolean isCoreApp);
     }
 }
diff --git a/core/java/android/content/pm/parsing/ParsingUtils.java b/core/java/android/content/pm/parsing/ParsingUtils.java
index 17cd101..5da5fbf 100644
--- a/core/java/android/content/pm/parsing/ParsingUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingUtils.java
@@ -61,7 +61,7 @@
             return input.error("Bad element under " + parentTag + ": " + parser.getName());
         }
         Slog.w(TAG, "Unknown element under " + parentTag + ": "
-                + parser.getName() + " at " + pkg.getBaseCodePath() + " "
+                + parser.getName() + " at " + pkg.getBaseApkPath() + " "
                 + parser.getPositionDescription());
         XmlUtils.skipCurrentTag(parser);
         return input.success(null); // Type doesn't matter
diff --git a/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java b/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java
index fac5cd3..f70d62b 100644
--- a/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java
@@ -113,7 +113,7 @@
         ParsedIntentInfo intent = intentResult.getResult();
         int actionCount = intent.countActions();
         if (actionCount == 0 && failOnNoActions) {
-            Slog.w(TAG, "No actions in " + parser.getName() + " at " + pkg.getBaseCodePath() + " "
+            Slog.w(TAG, "No actions in " + parser.getName() + " at " + pkg.getBaseApkPath() + " "
                     + parser.getPositionDescription());
             // Backward-compat, do not actually fail
             return input.success(null);
diff --git a/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java b/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java
index d813720..37cbeca 100644
--- a/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java
@@ -246,7 +246,7 @@
                 }
 
                 Slog.w(TAG, "Unknown element under <path-permission>: " + name + " at "
-                        + pkg.getBaseCodePath() + " " + parser.getPositionDescription());
+                        + pkg.getBaseApkPath() + " " + parser.getPositionDescription());
             }
 
             return input.success(provider);
@@ -292,7 +292,8 @@
                             "No readPermission or writePermission for <path-permission>");
                 }
                 Slog.w(TAG, "No readPermission or writePermission for <path-permission>: "
-                        + name + " at " + pkg.getBaseCodePath() + " " + parser.getPositionDescription());
+                        + name + " at " + pkg.getBaseApkPath() + " "
+                        + parser.getPositionDescription());
                 return input.success(provider);
             }
 
@@ -341,7 +342,7 @@
                 }
 
                 Slog.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: "
-                        + name + " at " + pkg.getBaseCodePath()
+                        + name + " at " + pkg.getBaseApkPath()
                         + " "
                         + parser.getPositionDescription());
             }
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 8e865e7..1db544c 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -1027,6 +1027,18 @@
 
         /**
          * R.
+         *
+         * <p>Applications targeting this or a later release will get these new changes in behavior.
+         * For more information about this release, see the
+         * <a href="/about/versions/11">Android 11 overview</a>.</p>
+         * <ul>
+         * <li><a href="/about/versions/11/behavior-changes-all">Behavior changes: all apps</a></li>
+         * <li><a href="/about/versions/11/behavior-changes-11">Behavior changes: Apps targeting
+         * Android 11</a></li>
+         * <li><a href="/about/versions/11/non-sdk-11">Updates to non-SDK interface restrictions
+         * in Android 11</a></li>
+         * </ul>
+         *
          */
         public static final int R = 30;
 
diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java
index e05991b..a79a1cf 100644
--- a/core/java/android/os/storage/StorageManagerInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -118,7 +118,7 @@
      * affects them.
      */
     public abstract void onAppOpsChanged(int code, int uid,
-            @Nullable String packageName, int mode);
+            @Nullable String packageName, int mode, int previousMode);
 
     /**
      * Asks the StorageManager to reset all state for the provided user; this will result
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 739e169..18337b6 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6801,6 +6801,13 @@
         public static final String KEYGUARD_SLICE_URI = "keyguard_slice_uri";
 
         /**
+         * Whether to draw text in bold.
+         *
+         * @hide
+         */
+        public static final String FORCE_BOLD_TEXT = "force_bold_text";
+
+        /**
          * Whether to speak passwords while in accessibility mode.
          *
          * @deprecated The speaking of passwords is controlled by individual accessibility services.
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index e083417..19860eb 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -71,6 +71,7 @@
 import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
+import android.window.ClientWindowFrames;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.HandlerCaller;
@@ -186,17 +187,11 @@
         int mCurWindowFlags = mWindowFlags;
         int mCurWindowPrivateFlags = mWindowPrivateFlags;
         Rect mPreviewSurfacePosition;
-        final Rect mVisibleInsets = new Rect();
-        final Rect mWinFrame = new Rect();
-        final Rect mContentInsets = new Rect();
-        final Rect mStableInsets = new Rect();
+        final ClientWindowFrames mWinFrames = new ClientWindowFrames();
         final Rect mDispatchedContentInsets = new Rect();
         final Rect mDispatchedStableInsets = new Rect();
         final Rect mFinalSystemInsets = new Rect();
         final Rect mFinalStableInsets = new Rect();
-        final Rect mBackdropFrame = new Rect();
-        final DisplayCutout.ParcelableWrapper mDisplayCutout =
-                new DisplayCutout.ParcelableWrapper();
         DisplayCutout mDispatchedDisplayCutout = DisplayCutout.NO_CUTOUT;
         final InsetsState mInsetsState = new InsetsState();
         final InsetsSourceControl[] mTempControls = new InsetsSourceControl[0];
@@ -332,11 +327,9 @@
 
         final BaseIWindow mWindow = new BaseIWindow() {
             @Override
-            public void resized(Rect frame, Rect contentInsets,
-                    Rect visibleInsets, Rect stableInsets, boolean reportDraw,
-                    MergedConfiguration mergedConfiguration, Rect backDropRect, boolean forceLayout,
-                    boolean alwaysConsumeSystemBars, int displayId,
-                    DisplayCutout.ParcelableWrapper displayCutout) {
+            public void resized(ClientWindowFrames frames, boolean reportDraw,
+                    MergedConfiguration mergedConfiguration, boolean forceLayout,
+                    boolean alwaysConsumeSystemBars, int displayId) {
                 Message msg = mCaller.obtainMessageI(MSG_WINDOW_RESIZED,
                         reportDraw ? 1 : 0);
                 mCaller.sendMessage(msg);
@@ -749,10 +742,7 @@
                     out.print(" mCurWindowFlags="); out.println(mCurWindowFlags);
             out.print(prefix); out.print("mWindowPrivateFlags="); out.print(mWindowPrivateFlags);
                     out.print(" mCurWindowPrivateFlags="); out.println(mCurWindowPrivateFlags);
-            out.print(prefix); out.print("mVisibleInsets=");
-                    out.print(mVisibleInsets.toShortString());
-                    out.print(" mWinFrame="); out.print(mWinFrame.toShortString());
-                    out.print(" mContentInsets="); out.println(mContentInsets.toShortString());
+            out.print(prefix); out.println("mWinFrames="); out.println(mWinFrames);
             out.print(prefix); out.print("mConfiguration=");
                     out.println(mMergedConfiguration.getMergedConfiguration());
             out.print(prefix); out.print("mLayout="); out.println(mLayout);
@@ -890,8 +880,8 @@
                         InputChannel inputChannel = new InputChannel();
 
                         if (mSession.addToDisplay(mWindow, mWindow.mSeq, mLayout, View.VISIBLE,
-                                mDisplay.getDisplayId(), mWinFrame, mContentInsets, mStableInsets,
-                                mDisplayCutout, inputChannel,
+                                mDisplay.getDisplayId(), mWinFrames.frame, mWinFrames.contentInsets,
+                                mWinFrames.stableInsets, mWinFrames.displayCutout, inputChannel,
                                 mInsetsState, mTempControls) < 0) {
                             Log.w(TAG, "Failed to add window while updating wallpaper surface.");
                             return;
@@ -914,34 +904,32 @@
 
                     final int relayoutResult = mSession.relayout(
                         mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
-                            View.VISIBLE, 0, -1, mWinFrame, mContentInsets,
-                            mVisibleInsets, mStableInsets, mBackdropFrame,
-                            mDisplayCutout, mMergedConfiguration, mSurfaceControl,
+                            View.VISIBLE, 0, -1, mWinFrames, mMergedConfiguration, mSurfaceControl,
                             mInsetsState, mTempControls, mSurfaceSize, mTmpSurfaceControl);
                     if (mSurfaceControl.isValid()) {
                         mSurfaceHolder.mSurface.copyFrom(mSurfaceControl);
                     }
 
                     if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface
-                            + ", frame=" + mWinFrame);
+                            + ", frame=" + mWinFrames);
 
-                    int w = mWinFrame.width();
-                    int h = mWinFrame.height();
+                    int w = mWinFrames.frame.width();
+                    int h = mWinFrames.frame.height();
 
                     if (!fixedSize) {
                         final Rect padding = mIWallpaperEngine.mDisplayPadding;
                         w += padding.left + padding.right;
                         h += padding.top + padding.bottom;
-                        mContentInsets.left += padding.left;
-                        mContentInsets.top += padding.top;
-                        mContentInsets.right += padding.right;
-                        mContentInsets.bottom += padding.bottom;
-                        mStableInsets.left += padding.left;
-                        mStableInsets.top += padding.top;
-                        mStableInsets.right += padding.right;
-                        mStableInsets.bottom += padding.bottom;
-                        mDisplayCutout.set(mDisplayCutout.get().inset(-padding.left, -padding.top,
-                                -padding.right, -padding.bottom));
+                        mWinFrames.contentInsets.left += padding.left;
+                        mWinFrames.contentInsets.top += padding.top;
+                        mWinFrames.contentInsets.right += padding.right;
+                        mWinFrames.contentInsets.bottom += padding.bottom;
+                        mWinFrames.stableInsets.left += padding.left;
+                        mWinFrames.stableInsets.top += padding.top;
+                        mWinFrames.stableInsets.right += padding.right;
+                        mWinFrames.stableInsets.bottom += padding.bottom;
+                        mWinFrames.displayCutout.set(mWinFrames.displayCutout.get().inset(
+                                -padding.left, -padding.top, -padding.right, -padding.bottom));
                     } else {
                         w = myWidth;
                         h = myHeight;
@@ -960,9 +948,10 @@
                         Log.v(TAG, "Wallpaper size has changed: (" + mCurWidth + ", " + mCurHeight);
                     }
 
-                    insetsChanged |= !mDispatchedContentInsets.equals(mContentInsets);
-                    insetsChanged |= !mDispatchedStableInsets.equals(mStableInsets);
-                    insetsChanged |= !mDispatchedDisplayCutout.equals(mDisplayCutout.get());
+                    final DisplayCutout displayCutout = mWinFrames.displayCutout.get();
+                    insetsChanged |= !mDispatchedContentInsets.equals(mWinFrames.contentInsets);
+                    insetsChanged |= !mDispatchedStableInsets.equals(mWinFrames.stableInsets);
+                    insetsChanged |= !mDispatchedDisplayCutout.equals(displayCutout);
 
                     mSurfaceHolder.setSurfaceFrameSize(w, h);
                     mSurfaceHolder.mSurfaceLock.unlock();
@@ -1021,9 +1010,9 @@
                         }
 
                         if (insetsChanged) {
-                            mDispatchedContentInsets.set(mContentInsets);
-                            mDispatchedStableInsets.set(mStableInsets);
-                            mDispatchedDisplayCutout = mDisplayCutout.get();
+                            mDispatchedContentInsets.set(mWinFrames.contentInsets);
+                            mDispatchedStableInsets.set(mWinFrames.stableInsets);
+                            mDispatchedDisplayCutout = displayCutout;
                             mFinalStableInsets.set(mDispatchedStableInsets);
                             WindowInsets insets = new WindowInsets(mFinalSystemInsets,
                                     mFinalStableInsets,
diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java
index 4b42209..5fd192a 100644
--- a/core/java/android/speech/RecognitionService.java
+++ b/core/java/android/speech/RecognitionService.java
@@ -183,10 +183,9 @@
             @NonNull String packageName, @Nullable String featureId) {
         if (DBG) Log.d(TAG, "checkPermissions");
         if (forDataDelivery) {
-            if (PermissionChecker.checkCallingPermissionForDataDelivery(this,
+            if (PermissionChecker.checkCallingOrSelfPermissionForDataDelivery(this,
                     android.Manifest.permission.RECORD_AUDIO, packageName, featureId,
-                    null /*message*/)
-                             == PermissionChecker.PERMISSION_GRANTED) {
+                    null /*message*/) == PermissionChecker.PERMISSION_GRANTED) {
                 return true;
             }
         } else {
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index e338fd97..0973608 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -65,6 +65,7 @@
         DEFAULT_FLAGS.put(SETTINGS_DO_NOT_RESTORE_PRESERVED, "true");
 
         DEFAULT_FLAGS.put("settings_tether_all_in_one", "false");
+        DEFAULT_FLAGS.put("settings_silky_home", "false");
     }
 
     /**
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index e09bf9d..94e641c 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -29,6 +29,7 @@
 import android.view.IScrollCaptureController;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
+import android.window.ClientWindowFrames;
 
 import com.android.internal.os.IResultReceiver;
 
@@ -52,11 +53,9 @@
      */
     void executeCommand(String command, String parameters, in ParcelFileDescriptor descriptor);
 
-    void resized(in Rect frame, in Rect contentInsets,
-            in Rect visibleInsets, in Rect stableInsets, boolean reportDraw,
-            in MergedConfiguration newMergedConfiguration, in Rect backDropFrame,
-            boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
-            in DisplayCutout.ParcelableWrapper displayCutout);
+    void resized(in ClientWindowFrames frames, boolean reportDraw,
+            in MergedConfiguration newMergedConfiguration,
+            boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId);
 
     /**
      * Called when the window location in parent display has changed. The offset will only be a
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 819e89b..70850d8 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -34,6 +34,7 @@
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
+import android.window.ClientWindowFrames;
 
 import java.util.List;
 
@@ -107,10 +108,7 @@
      */
     int relayout(IWindow window, int seq, in WindowManager.LayoutParams attrs,
             int requestedWidth, int requestedHeight, int viewVisibility,
-            int flags, long frameNumber, out Rect outFrame,
-            out Rect outContentInsets, out Rect outVisibleInsets, out Rect outStableInsets,
-            out Rect outBackdropFrame,
-            out DisplayCutout.ParcelableWrapper displayCutout,
+            int flags, long frameNumber, out ClientWindowFrames outFrames,
             out MergedConfiguration outMergedConfiguration, out SurfaceControl outSurfaceControl,
             out InsetsState insetsState, out InsetsSourceControl[] activeControls,
             out Point outSurfaceSize, out SurfaceControl outBlastSurfaceControl);
@@ -152,12 +150,6 @@
             in Rect visibleInsets, in Region touchableRegion);
 
     /**
-     * Return the current display size in which the window is being laid out,
-     * accounting for screen decorations around it.
-     */
-    void getDisplayFrame(IWindow window, out Rect outDisplayFrame);
-
-    /**
      * Called when the client has finished drawing the surface, if needed.
      *
      * @param postDrawTransaction transaction filled by the client that can be
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 8917821..92a0f63 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -14940,20 +14940,12 @@
      * inside.  In effect, this tells you the available area where content can
      * be placed and remain visible to users.
      *
-     * <p>This function requires an IPC back to the window manager to retrieve
-     * the requested information, so should not be used in performance critical
-     * code like drawing.
-     *
      * @param outRect Filled in with the visible display frame.  If the view
      * is not attached to a window, this is simply the raw display size.
      */
     public void getWindowVisibleDisplayFrame(Rect outRect) {
         if (mAttachInfo != null) {
-            try {
-                mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect);
-            } catch (RemoteException e) {
-                return;
-            }
+            mAttachInfo.mViewRootImpl.getDisplayFrame(outRect);
             // XXX This is really broken, and probably all needs to be done
             // in the window manager, and we need to know more about whether
             // we want the area behind or in front of the IME.
@@ -14979,11 +14971,7 @@
     @UnsupportedAppUsage
     public void getWindowDisplayFrame(Rect outRect) {
         if (mAttachInfo != null) {
-            try {
-                mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect);
-            } catch (RemoteException e) {
-                return;
-            }
+            mAttachInfo.mViewRootImpl.getDisplayFrame(outRect);
             return;
         }
         // The view is not attached to a display so we don't have a context.
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 8a5be75..4303d70 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -33,7 +33,6 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.os.RemoteException;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.TypedValue;
@@ -755,11 +754,7 @@
 
         try {
             Rect outRect = new Rect();
-            try {
-                root.mAttachInfo.mSession.getDisplayFrame(root.mAttachInfo.mWindow, outRect);
-            } catch (RemoteException e) {
-                // Ignore
-            }
+            root.mAttachInfo.mViewRootImpl.getDisplayFrame(outRect);
 
             clientStream.writeInt(outRect.width());
             clientStream.writeInt(outRect.height());
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index ccce565..af839d4 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -137,7 +137,6 @@
 import android.view.Window.OnContentApplyWindowInsetsListener;
 import android.view.WindowInsets.Type;
 import android.view.WindowInsets.Type.InsetsType;
-import android.view.WindowManager.LayoutParams;
 import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -160,6 +159,7 @@
 import android.view.contentcapture.MainContentCaptureSession;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.Scroller;
+import android.window.ClientWindowFrames;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
@@ -560,8 +560,11 @@
     boolean mAdded;
     boolean mAddedTouchMode;
 
-    final Rect mTmpFrame = new Rect();
-    final Rect mTmpRect = new Rect();
+    /**
+     * It usually keeps the latest layout result from {@link IWindow#resized} or
+     * {@link IWindowSession#relayout}.
+     */
+    private final ClientWindowFrames mTmpFrames = new ClientWindowFrames();
 
     // These are accessed by multiple threads.
     final Rect mWinFrame; // frame given by window manager.
@@ -1033,11 +1036,11 @@
                     collectViewAttributes();
                     adjustLayoutParamsForCompatibility(mWindowAttributes);
                     res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,
-                            getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,
+                            getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrames.frame,
                             mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                             mAttachInfo.mDisplayCutout, inputChannel,
                             mTempInsets, mTempControls);
-                    setFrame(mTmpFrame);
+                    setFrame(mTmpFrames.frame);
                 } catch (RemoteException e) {
                     mAdded = false;
                     mView = null;
@@ -1475,6 +1478,55 @@
         scheduleTraversals();
     }
 
+    /** Handles messages {@link #MSG_RESIZED} and {@link #MSG_RESIZED_REPORT}. */
+    private void handleResized(int msg, SomeArgs args) {
+        if (!mAdded) {
+            return;
+        }
+
+        final ClientWindowFrames frames = (ClientWindowFrames) args.arg1;
+        final MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg2;
+        final boolean forceNextWindowRelayout = args.argi1 != 0;
+        final int displayId = args.argi3;
+        final Rect backdropFrame = frames.backdropFrame;
+        final DisplayCutout displayCutout = frames.displayCutout.get();
+
+        final boolean frameChanged = !mWinFrame.equals(frames.frame);
+        final boolean cutoutChanged = !mPendingDisplayCutout.get().equals(displayCutout);
+        final boolean backdropFrameChanged = !mPendingBackDropFrame.equals(backdropFrame);
+        final boolean configChanged = !mLastReportedMergedConfiguration.equals(mergedConfiguration);
+        final boolean displayChanged = mDisplay.getDisplayId() != displayId;
+        if (msg == MSG_RESIZED && !frameChanged && !cutoutChanged && !backdropFrameChanged
+                && !configChanged && !displayChanged && !forceNextWindowRelayout) {
+            return;
+        }
+
+        if (configChanged) {
+            // If configuration changed - notify about that and, maybe, about move to display.
+            performConfigurationChange(mergedConfiguration, false /* force */,
+                    displayChanged ? displayId : INVALID_DISPLAY /* same display */);
+        } else if (displayChanged) {
+            // Moved to display without config change - report last applied one.
+            onMovedToDisplay(displayId, mLastConfigurationFromResources);
+        }
+
+        setFrame(frames.frame);
+        mTmpFrames.displayFrame.set(frames.displayFrame);
+        mPendingDisplayCutout.set(displayCutout);
+        mPendingBackDropFrame.set(backdropFrame);
+        mForceNextWindowRelayout = forceNextWindowRelayout;
+        mPendingAlwaysConsumeSystemBars = args.argi2 != 0;
+
+        if (msg == MSG_RESIZED_REPORT) {
+            reportNextDraw();
+        }
+
+        if (mView != null && (frameChanged || cutoutChanged || configChanged)) {
+            forceLayout(mView);
+        }
+        requestLayout();
+    }
+
     private final DisplayListener mDisplayListener = new DisplayListener() {
         @Override
         public void onDisplayChanged(int displayId) {
@@ -4923,60 +4975,13 @@
                 case MSG_DISPATCH_GET_NEW_SURFACE:
                     handleGetNewSurface();
                     break;
-                case MSG_RESIZED: {
-                    // Recycled in the fall through...
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    if (mWinFrame.equals(args.arg1)
-                            && mPendingDisplayCutout.get().equals(args.arg9)
-                            && mPendingBackDropFrame.equals(args.arg8)
-                            && mLastReportedMergedConfiguration.equals(args.arg4)
-                            && args.argi1 == 0
-                            && mDisplay.getDisplayId() == args.argi3) {
-                        break;
-                    }
-                } // fall through...
-                case MSG_RESIZED_REPORT:
-                    if (mAdded) {
-                        SomeArgs args = (SomeArgs) msg.obj;
-
-                        final int displayId = args.argi3;
-                        MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg4;
-                        final boolean displayChanged = mDisplay.getDisplayId() != displayId;
-                        boolean configChanged = false;
-
-                        if (!mLastReportedMergedConfiguration.equals(mergedConfiguration)) {
-                            // If configuration changed - notify about that and, maybe,
-                            // about move to display.
-                            performConfigurationChange(mergedConfiguration, false /* force */,
-                                    displayChanged
-                                            ? displayId : INVALID_DISPLAY /* same display */);
-                            configChanged = true;
-                        } else if (displayChanged) {
-                            // Moved to display without config change - report last applied one.
-                            onMovedToDisplay(displayId, mLastConfigurationFromResources);
-                        }
-
-                        final boolean framesChanged = !mWinFrame.equals(args.arg1)
-                                || !mPendingDisplayCutout.get().equals(args.arg9);
-
-                        setFrame((Rect) args.arg1);
-                        mPendingDisplayCutout.set((DisplayCutout) args.arg9);
-                        mPendingBackDropFrame.set((Rect) args.arg8);
-                        mForceNextWindowRelayout = args.argi1 != 0;
-                        mPendingAlwaysConsumeSystemBars = args.argi2 != 0;
-
-                        args.recycle();
-
-                        if (msg.what == MSG_RESIZED_REPORT) {
-                            reportNextDraw();
-                        }
-
-                        if (mView != null && (framesChanged || configChanged)) {
-                            forceLayout(mView);
-                        }
-                        requestLayout();
-                    }
+                case MSG_RESIZED:
+                case MSG_RESIZED_REPORT: {
+                    final SomeArgs args = (SomeArgs) msg.obj;
+                    handleResized(msg.what, args);
+                    args.recycle();
                     break;
+                }
                 case MSG_INSETS_CHANGED:
                     mInsetsController.onStateChanged((InsetsState) msg.obj);
                     break;
@@ -5011,11 +5016,11 @@
                         final int h = mWinFrame.height();
                         final int l = msg.arg1;
                         final int t = msg.arg2;
-                        mTmpFrame.left = l;
-                        mTmpFrame.right = l + w;
-                        mTmpFrame.top = t;
-                        mTmpFrame.bottom = t + h;
-                        setFrame(mTmpFrame);
+                        mTmpFrames.frame.left = l;
+                        mTmpFrames.frame.right = l + w;
+                        mTmpFrames.frame.top = t;
+                        mTmpFrames.frame.bottom = t + h;
+                        setFrame(mTmpFrames.frame);
 
                         mPendingBackDropFrame.set(mWinFrame);
                         maybeHandleWindowMove(mWinFrame);
@@ -7422,9 +7427,10 @@
                 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
                 (int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
                 insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
-                mTmpFrame, mTmpRect, mTmpRect, mTmpRect, mPendingBackDropFrame,
-                mPendingDisplayCutout, mPendingMergedConfiguration, mSurfaceControl, mTempInsets,
+                mTmpFrames, mPendingMergedConfiguration, mSurfaceControl, mTempInsets,
                 mTempControls, mSurfaceSize, mBlastSurfaceControl);
+        mPendingDisplayCutout.set(mTmpFrames.displayCutout);
+        mPendingBackDropFrame.set(mTmpFrames.backdropFrame);
         if (mSurfaceControl.isValid()) {
             if (!useBLAST()) {
                 mSurface.copyFrom(mSurfaceControl);
@@ -7450,9 +7456,9 @@
         }
 
         if (mTranslator != null) {
-            mTranslator.translateRectInScreenToAppWinFrame(mTmpFrame);
+            mTranslator.translateRectInScreenToAppWinFrame(mTmpFrames.frame);
         }
-        setFrame(mTmpFrame);
+        setFrame(mTmpFrames.frame);
         mInsetsController.onStateChanged(mTempInsets);
         mInsetsController.onControlsChanged(mTempControls);
         return relayoutResult;
@@ -7464,6 +7470,14 @@
     }
 
     /**
+     * Gets the current display size in which the window is being laid out, accounting for screen
+     * decorations around it.
+     */
+    void getDisplayFrame(Rect outFrame) {
+        outFrame.set(mTmpFrames.displayFrame);
+    }
+
+    /**
      * {@inheritDoc}
      */
     @Override
@@ -7746,11 +7760,14 @@
     }
 
     @UnsupportedAppUsage
-    private void dispatchResized(Rect frame, Rect contentInsets,
-            Rect visibleInsets, Rect stableInsets, boolean reportDraw,
-            MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
-            boolean alwaysConsumeSystemBars, int displayId,
-            DisplayCutout.ParcelableWrapper displayCutout) {
+    private void dispatchResized(ClientWindowFrames frames, boolean reportDraw,
+            MergedConfiguration mergedConfiguration, boolean forceLayout,
+            boolean alwaysConsumeSystemBars, int displayId) {
+        final Rect frame = frames.frame;
+        final Rect contentInsets = frames.contentInsets;
+        final Rect visibleInsets = frames.visibleInsets;
+        final Rect stableInsets = frames.stableInsets;
+        final Rect backDropFrame = frames.backdropFrame;
         if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString()
                 + " contentInsets=" + contentInsets.toShortString()
                 + " visibleInsets=" + visibleInsets.toShortString()
@@ -7777,14 +7794,9 @@
         }
         SomeArgs args = SomeArgs.obtain();
         final boolean sameProcessCall = (Binder.getCallingPid() == android.os.Process.myPid());
-        args.arg1 = sameProcessCall ? new Rect(frame) : frame;
-        args.arg2 = sameProcessCall ? new Rect(contentInsets) : contentInsets;
-        args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
-        args.arg4 = sameProcessCall && mergedConfiguration != null
+        args.arg1 = sameProcessCall ? new ClientWindowFrames(frames) : frames;
+        args.arg2 = sameProcessCall && mergedConfiguration != null
                 ? new MergedConfiguration(mergedConfiguration) : mergedConfiguration;
-        args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets;
-        args.arg8 = sameProcessCall ? new Rect(backDropFrame) : backDropFrame;
-        args.arg9 = displayCutout.get(); // DisplayCutout is immutable.
         args.argi1 = forceLayout ? 1 : 0;
         args.argi2 = alwaysConsumeSystemBars ? 1 : 0;
         args.argi3 = displayId;
@@ -9078,17 +9090,13 @@
         }
 
         @Override
-        public void resized(Rect frame, Rect contentInsets,
-                Rect visibleInsets, Rect stableInsets, boolean reportDraw,
-                MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
-                boolean alwaysConsumeSystemBars, int displayId,
-                DisplayCutout.ParcelableWrapper displayCutout) {
+        public void resized(ClientWindowFrames frames, boolean reportDraw,
+                MergedConfiguration mergedConfiguration, boolean forceLayout,
+                boolean alwaysConsumeSystemBars, int displayId) {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
-                viewAncestor.dispatchResized(frame, contentInsets,
-                        visibleInsets, stableInsets, reportDraw, mergedConfiguration,
-                        backDropFrame, forceLayout, alwaysConsumeSystemBars, displayId,
-                        displayCutout);
+                viewAncestor.dispatchResized(frames, reportDraw, mergedConfiguration, forceLayout,
+                        alwaysConsumeSystemBars, displayId);
             }
         }
 
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 060311e..368918d 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -26,6 +26,7 @@
 import android.os.RemoteException;
 import android.util.Log;
 import android.util.MergedConfiguration;
+import android.window.ClientWindowFrames;
 
 import java.util.HashMap;
 import java.util.Objects;
@@ -224,9 +225,7 @@
     @Override
     public int relayout(IWindow window, int seq, WindowManager.LayoutParams inAttrs,
             int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,
-            Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,
-            Rect outStableInsets, Rect outBackdropFrame,
-            DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration,
+            ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
             SurfaceControl outSurfaceControl, InsetsState outInsetsState,
             InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
             SurfaceControl outBLASTSurfaceControl) {
@@ -255,7 +254,8 @@
             t.hide(sc).apply();
             outSurfaceControl.release();
         }
-        outFrame.set(0, 0, attrs.width, attrs.height);
+        outFrames.frame.set(0, 0, attrs.width, attrs.height);
+        outFrames.displayFrame.set(outFrames.frame);
 
         mergedConfiguration.setConfiguration(mConfiguration, mConfiguration);
 
@@ -292,11 +292,6 @@
     }
 
     @Override
-    public void getDisplayFrame(android.view.IWindow window,
-            android.graphics.Rect outDisplayFrame) {
-    }
-
-    @Override
     public void finishDrawing(android.view.IWindow window,
             android.view.SurfaceControl.Transaction postDrawTransaction) {
         synchronized (this) {
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/ContainerView.java b/core/java/android/window/ClientWindowFrames.aidl
similarity index 61%
copy from packages/SystemUI/src/com/android/keyguard/dagger/ContainerView.java
copy to core/java/android/window/ClientWindowFrames.aidl
index e65f19d..22bbea9 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/ContainerView.java
+++ b/core/java/android/window/ClientWindowFrames.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,17 +14,6 @@
  * limitations under the License.
  */
 
-package com.android.keyguard.dagger;
+package android.window;
 
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
-import javax.inject.Qualifier;
-
-@Qualifier
-@Documented
-@Retention(RUNTIME)
-public @interface ContainerView {
-}
+parcelable ClientWindowFrames;
diff --git a/core/java/android/window/ClientWindowFrames.java b/core/java/android/window/ClientWindowFrames.java
new file mode 100644
index 0000000..0523e64
--- /dev/null
+++ b/core/java/android/window/ClientWindowFrames.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.window;
+
+import android.annotation.NonNull;
+import android.graphics.Rect;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.DisplayCutout;
+
+/**
+ * The window frame container class used by client side for layout.
+ * @hide
+ */
+public class ClientWindowFrames implements Parcelable {
+    /** The actual window bounds. */
+    public final @NonNull Rect frame;
+
+    /**
+     * The container frame that is usually the same as display size. It may exclude the area of
+     * insets if the window layout parameter has specified fit-insets-sides.
+     */
+    public final @NonNull Rect displayFrame;
+
+    /** The background area while the window is resizing. */
+    public final @NonNull Rect backdropFrame;
+
+    /** The area cut from the display. */
+    public final @NonNull DisplayCutout.ParcelableWrapper displayCutout;
+
+    // TODO(b/149813814): Remove legacy insets.
+    public final Rect contentInsets;
+    public final Rect visibleInsets;
+    public final Rect stableInsets;
+
+    public ClientWindowFrames() {
+        frame = new Rect();
+        displayFrame = new Rect();
+        backdropFrame = new Rect();
+        displayCutout = new DisplayCutout.ParcelableWrapper();
+        contentInsets = new Rect();
+        visibleInsets = new Rect();
+        stableInsets = new Rect();
+    }
+
+    public ClientWindowFrames(ClientWindowFrames other) {
+        frame = new Rect(other.frame);
+        displayFrame = new Rect(other.displayFrame);
+        backdropFrame = new Rect(other.backdropFrame);
+        displayCutout = new DisplayCutout.ParcelableWrapper(other.displayCutout.get());
+        contentInsets = new Rect(other.contentInsets);
+        visibleInsets = new Rect(other.visibleInsets);
+        stableInsets = new Rect(other.stableInsets);
+    }
+
+    private ClientWindowFrames(Parcel in) {
+        frame = Rect.CREATOR.createFromParcel(in);
+        displayFrame = Rect.CREATOR.createFromParcel(in);
+        backdropFrame = Rect.CREATOR.createFromParcel(in);
+        displayCutout = DisplayCutout.ParcelableWrapper.CREATOR.createFromParcel(in);
+        contentInsets = Rect.CREATOR.createFromParcel(in);
+        visibleInsets = Rect.CREATOR.createFromParcel(in);
+        stableInsets = Rect.CREATOR.createFromParcel(in);
+    }
+
+    /** Needed for AIDL out parameters. */
+    public void readFromParcel(Parcel in) {
+        frame.set(Rect.CREATOR.createFromParcel(in));
+        displayFrame.set(Rect.CREATOR.createFromParcel(in));
+        backdropFrame.set(Rect.CREATOR.createFromParcel(in));
+        displayCutout.set(DisplayCutout.ParcelableWrapper.CREATOR.createFromParcel(in));
+        contentInsets.set(Rect.CREATOR.createFromParcel(in));
+        visibleInsets.set(Rect.CREATOR.createFromParcel(in));
+        stableInsets.set(Rect.CREATOR.createFromParcel(in));
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        frame.writeToParcel(dest, flags);
+        displayFrame.writeToParcel(dest, flags);
+        backdropFrame.writeToParcel(dest, flags);
+        displayCutout.writeToParcel(dest, flags);
+        contentInsets.writeToParcel(dest, flags);
+        visibleInsets.writeToParcel(dest, flags);
+        stableInsets.writeToParcel(dest, flags);
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder(32);
+        return "ClientWindowFrames{frame=" + frame.toShortString(sb)
+                + " display=" + displayFrame.toShortString(sb)
+                + " backdrop=" + backdropFrame.toShortString(sb)
+                + " cutout=" + displayCutout + "}";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Creator<ClientWindowFrames> CREATOR = new Creator<ClientWindowFrames>() {
+        public ClientWindowFrames createFromParcel(Parcel in) {
+            return new ClientWindowFrames(in);
+        }
+
+        public ClientWindowFrames[] newArray(int size) {
+            return new ClientWindowFrames[size];
+        }
+    };
+}
diff --git a/core/java/android/window/VirtualDisplayTaskEmbedder.java b/core/java/android/window/VirtualDisplayTaskEmbedder.java
index 9013da3..db27d62 100644
--- a/core/java/android/window/VirtualDisplayTaskEmbedder.java
+++ b/core/java/android/window/VirtualDisplayTaskEmbedder.java
@@ -25,6 +25,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
+import android.app.ActivityTaskManager.RootTaskInfo;
 import android.app.ActivityView;
 import android.app.TaskStackListener;
 import android.content.ComponentName;
@@ -357,40 +358,40 @@
     private class TaskStackListenerImpl extends TaskStackListener {
 
         @Override
-        public void onTaskDescriptionChanged(ActivityManager.RunningTaskInfo taskInfo)
+        public void onTaskDescriptionChanged(ActivityManager.RunningTaskInfo runningTaskInfo)
                 throws RemoteException {
             if (!isInitialized()) {
                 return;
             }
-            if (taskInfo.displayId != getDisplayId()) {
+            if (runningTaskInfo.displayId != getDisplayId()) {
                 return;
             }
-            ActivityManager.StackInfo stackInfo = getTopMostStackInfo();
-            if (stackInfo == null) {
+            RootTaskInfo taskInfo = getTopMostRootTaskInfo();
+            if (taskInfo == null) {
                 return;
             }
             // Found the topmost stack on target display. Now check if the topmost task's
             // description changed.
-            if (taskInfo.taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) {
+            if (runningTaskInfo.taskId == taskInfo.childTaskIds[taskInfo.childTaskIds.length - 1]) {
                 mHost.post(()-> mHost.onTaskBackgroundColorChanged(VirtualDisplayTaskEmbedder.this,
-                        taskInfo.taskDescription.getBackgroundColor()));
+                        runningTaskInfo.taskDescription.getBackgroundColor()));
             }
         }
 
         @Override
-        public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo)
+        public void onTaskMovedToFront(ActivityManager.RunningTaskInfo runningTaskInfo)
                 throws RemoteException {
             if (!isInitialized() || mListener == null
-                    || taskInfo.displayId != getDisplayId()) {
+                    || runningTaskInfo.displayId != getDisplayId()) {
                 return;
             }
 
-            ActivityManager.StackInfo stackInfo = getTopMostStackInfo();
-            // if StackInfo was null or unrelated to the "move to front" then there's no use
+            RootTaskInfo taskInfo = getTopMostRootTaskInfo();
+            // if TaskInfo was null or unrelated to the "move to front" then there's no use
             // notifying the callback
-            if (stackInfo != null
-                    && taskInfo.taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) {
-                mListener.onTaskMovedToFront(taskInfo.taskId);
+            if (taskInfo != null && runningTaskInfo.taskId == taskInfo.childTaskIds[
+                    taskInfo.childTaskIds.length - 1]) {
+                mListener.onTaskMovedToFront(runningTaskInfo.taskId);
             }
         }
 
@@ -400,11 +401,11 @@
                 return;
             }
 
-            ActivityManager.StackInfo stackInfo = getTopMostStackInfo();
-            // if StackInfo was null or unrelated to the task creation then there's no use
+            RootTaskInfo taskInfo = getTopMostRootTaskInfo();
+            // if TaskInfo was null or unrelated to the task creation then there's no use
             // notifying the callback
-            if (stackInfo != null
-                    && taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) {
+            if (taskInfo != null
+                    && taskId == taskInfo.childTaskIds[taskInfo.childTaskIds.length - 1]) {
                 mListener.onTaskCreated(taskId, componentName);
             }
         }
@@ -420,16 +421,16 @@
             mListener.onTaskRemovalStarted(taskInfo.taskId);
         }
 
-        private ActivityManager.StackInfo getTopMostStackInfo() throws RemoteException {
+        private RootTaskInfo getTopMostRootTaskInfo() throws RemoteException {
             // Find the topmost task on our virtual display - it will define the background
             // color of the surface view during resizing.
             final int displayId = getDisplayId();
-            final List<ActivityManager.StackInfo> stackInfoList =
-                    mActivityTaskManager.getAllStackInfosOnDisplay(displayId);
-            if (stackInfoList.isEmpty()) {
+            final List<RootTaskInfo> taskInfoList =
+                    mActivityTaskManager.getAllRootTaskInfosOnDisplay(displayId);
+            if (taskInfoList.isEmpty()) {
                 return null;
             }
-            return stackInfoList.get(0);
+            return taskInfoList.get(0);
         }
     }
 }
diff --git a/core/java/com/android/internal/content/om/OverlayConfig.java b/core/java/com/android/internal/content/om/OverlayConfig.java
index 3b5cf48..b38f623e 100644
--- a/core/java/com/android/internal/content/om/OverlayConfig.java
+++ b/core/java/com/android/internal/content/om/OverlayConfig.java
@@ -296,7 +296,7 @@
             if (p.getOverlayTarget() != null && isSystem) {
                 overlays.add(new ParsedOverlayInfo(p.getPackageName(), p.getOverlayTarget(),
                         p.getTargetSdkVersion(), p.isOverlayIsStatic(), p.getOverlayPriority(),
-                        new File(p.getBaseCodePath())));
+                        new File(p.getBaseApkPath())));
             }
         });
         return overlays;
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index e5c8450..dd1978e 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -45,8 +45,8 @@
     private long mBeginTime = UNKNOWN_TIMESTAMP;
     private long mEndTime = UNKNOWN_TIMESTAMP;
     private boolean mShouldTriggerTrace;
-    private long mTotalFramesCount = 0;
-    private long mMissedFramesCount = 0;
+    private int mTotalFramesCount = 0;
+    private int mMissedFramesCount = 0;
     private long mMaxFrameTimeNanos = 0;
 
     private Session mSession;
@@ -124,6 +124,15 @@
         if (mEndTime != UNKNOWN_TIMESTAMP && vsyncTimestamp > mEndTime) {
             // The tracing has been ended, remove the observer, see if need to trigger perfetto.
             mRendererWrapper.removeObserver(mObserver);
+
+            // Log the frame stats as counters to make them easily accessible in traces.
+            Trace.traceCounter(Trace.TRACE_TAG_APP, mSession.getName() + "#missedFrames",
+                    mMissedFramesCount);
+            Trace.traceCounter(Trace.TRACE_TAG_APP, mSession.getName() + "#totalFrames",
+                    mTotalFramesCount);
+            Trace.traceCounter(Trace.TRACE_TAG_APP, mSession.getName() + "#maxFrameTimeMillis",
+                    (int) (mMaxFrameTimeNanos / 1_000_000));
+
             // Trigger perfetto if necessary.
             if (mShouldTriggerTrace) {
                 if (DEBUG) {
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 8498151..41bf74c 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -256,7 +256,7 @@
     @GuardedBy("this")
     private long mNumBatchedSingleUidCpuTimeReads;
     @GuardedBy("this")
-    private long mCpuTimeReadsTrackingStartTime = SystemClock.uptimeMillis();
+    private long mCpuTimeReadsTrackingStartTimeMs = SystemClock.uptimeMillis();
     @GuardedBy("this")
     private int mNumUidsRemoved;
     @GuardedBy("this")
@@ -290,7 +290,7 @@
     public final class UidToRemove {
         int startUid;
         int endUid;
-        long timeAddedInQueue;
+        long mTimeAddedInQueueMs;
 
         /** Remove just one UID */
         public UidToRemove(int uid, long timestamp) {
@@ -301,7 +301,7 @@
         public UidToRemove(int startUid, int endUid, long timestamp) {
             this.startUid = startUid;
             this.endUid = endUid;
-            timeAddedInQueue = timestamp;
+            mTimeAddedInQueueMs = timestamp;
         }
 
         void remove() {
@@ -382,9 +382,9 @@
                 }
                 boolean changed = setChargingLocked(true);
                 if (changed) {
-                    final long uptime = mClocks.uptimeMillis();
-                    final long elapsedRealtime = mClocks.elapsedRealtime();
-                    addHistoryRecordLocked(elapsedRealtime, uptime);
+                    final long uptimeMs = mClocks.uptimeMillis();
+                    final long elapsedRealtimeMs = mClocks.elapsedRealtime();
+                    addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
                 }
             }
         }
@@ -502,9 +502,9 @@
     }
 
     public void clearPendingRemovedUids() {
-        long cutOffTime = mClocks.elapsedRealtime() - mConstants.UID_REMOVE_DELAY_MS;
+        long cutOffTimeMs = mClocks.elapsedRealtime() - mConstants.UID_REMOVE_DELAY_MS;
         while (!mPendingRemovedUids.isEmpty()
-                && mPendingRemovedUids.peek().timeAddedInQueue < cutOffTime) {
+                && mPendingRemovedUids.peek().mTimeAddedInQueueMs < cutOffTimeMs) {
             mPendingRemovedUids.poll().remove();
         }
     }
@@ -572,7 +572,7 @@
     }
 
     @VisibleForTesting
-    public long[] addCpuTimes(long[] timesA, long[] timesB) {
+    public static long[] addCpuTimes(long[] timesA, long[] timesB) {
         if (timesA != null && timesB != null) {
             for (int i = timesA.length - 1; i >= 0; --i) {
                 timesA[i] += timesB[i];
@@ -700,7 +700,7 @@
 
     final HistoryEventTracker mActiveEvents = new HistoryEventTracker();
 
-    long mHistoryBaseTime;
+    long mHistoryBaseTimeMs;
     protected boolean mHaveBatteryLevel = false;
     protected boolean mRecordingHistory = false;
     int mNumHistoryItems;
@@ -719,9 +719,9 @@
     int mHistoryBufferLastPos = -1;
     int mActiveHistoryStates = 0xffffffff;
     int mActiveHistoryStates2 = 0xffffffff;
-    long mLastHistoryElapsedRealtime = 0;
-    long mTrackRunningHistoryElapsedRealtime = 0;
-    long mTrackRunningHistoryUptime = 0;
+    long mLastHistoryElapsedRealtimeMs = 0;
+    long mTrackRunningHistoryElapsedRealtimeMs = 0;
+    long mTrackRunningHistoryUptimeMs = 0;
 
     final BatteryStatsHistory mBatteryStatsHistory;
 
@@ -742,28 +742,28 @@
     /**
      * Total time (in milliseconds) spent executing in user code.
      */
-    long mLastStepCpuUserTime;
-    long mCurStepCpuUserTime;
+    long mLastStepCpuUserTimeMs;
+    long mCurStepCpuUserTimeMs;
     /**
      * Total time (in milliseconds) spent executing in kernel code.
      */
-    long mLastStepCpuSystemTime;
-    long mCurStepCpuSystemTime;
+    long mLastStepCpuSystemTimeMs;
+    long mCurStepCpuSystemTimeMs;
     /**
      * Times from /proc/stat (but measured in milliseconds).
      */
-    long mLastStepStatUserTime;
-    long mLastStepStatSystemTime;
-    long mLastStepStatIOWaitTime;
-    long mLastStepStatIrqTime;
-    long mLastStepStatSoftIrqTime;
-    long mLastStepStatIdleTime;
-    long mCurStepStatUserTime;
-    long mCurStepStatSystemTime;
-    long mCurStepStatIOWaitTime;
-    long mCurStepStatIrqTime;
-    long mCurStepStatSoftIrqTime;
-    long mCurStepStatIdleTime;
+    long mLastStepStatUserTimeMs;
+    long mLastStepStatSystemTimeMs;
+    long mLastStepStatIOWaitTimeMs;
+    long mLastStepStatIrqTimeMs;
+    long mLastStepStatSoftIrqTimeMs;
+    long mLastStepStatIdleTimeMs;
+    long mCurStepStatUserTimeMs;
+    long mCurStepStatSystemTimeMs;
+    long mCurStepStatIOWaitTimeMs;
+    long mCurStepStatIrqTimeMs;
+    long mCurStepStatSoftIrqTimeMs;
+    long mCurStepStatIdleTimeMs;
 
     private HistoryItem mHistoryIterator;
     private boolean mReadOverflow;
@@ -771,14 +771,14 @@
 
     int mStartCount;
 
-    long mStartClockTime;
+    long mStartClockTimeMs;
     String mStartPlatformVersion;
     String mEndPlatformVersion;
 
-    long mUptime;
-    long mUptimeStart;
-    long mRealtime;
-    long mRealtimeStart;
+    long mUptimeUs;
+    long mUptimeStartUs;
+    long mRealtimeUs;
+    long mRealtimeStartUs;
 
     int mWakeLockNesting;
     boolean mWakeLockImportant;
@@ -810,9 +810,9 @@
     StopwatchTimer mDeviceLightIdlingTimer;
 
     int mDeviceIdleMode;
-    long mLastIdleTimeStart;
-    long mLongestLightIdleTime;
-    long mLongestFullIdleTime;
+    long mLastIdleTimeStartMs;
+    long mLongestLightIdleTimeMs;
+    long mLongestFullIdleTimeMs;
     StopwatchTimer mDeviceIdleModeLightTimer;
     StopwatchTimer mDeviceIdleModeFullTimer;
 
@@ -921,7 +921,7 @@
     protected StopwatchTimer mBluetoothScanTimer;
 
     int mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
-    long mMobileRadioActiveStartTime;
+    long mMobileRadioActiveStartTimeMs;
     StopwatchTimer mMobileRadioActiveTimer;
     StopwatchTimer mMobileRadioActivePerAppTimer;
     LongSamplingCounter mMobileRadioActiveAdjustedTime;
@@ -989,13 +989,13 @@
 
     static final int MAX_DAILY_ITEMS = 10;
 
-    long mDailyStartTime = 0;
-    long mNextMinDailyDeadline = 0;
-    long mNextMaxDailyDeadline = 0;
+    long mDailyStartTimeMs = 0;
+    long mNextMinDailyDeadlineMs = 0;
+    long mNextMaxDailyDeadlineMs = 0;
 
     final ArrayList<DailyItem> mDailyItems = new ArrayList<>();
 
-    long mLastWriteTime = 0; // Milliseconds
+    long mLastWriteTimeMs = 0; // Milliseconds
 
     private int mPhoneServiceState = -1;
     private int mPhoneServiceStateRaw = -1;
@@ -1131,8 +1131,8 @@
      * TimeBase observer.
      */
     public interface TimeBaseObs {
-        void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime);
-        void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime);
+        void onTimeStarted(long elapsedRealtimeUs, long baseUptimeUs, long baseRealtimeUs);
+        void onTimeStopped(long elapsedRealtimeUs, long baseUptimeUs, long baseRealtimeUs);
 
         /**
          * Reset the observer's state, returns true if the timer/counter is inactive
@@ -1140,7 +1140,18 @@
          * @param detachIfReset detach if true, no-op if false.
          * @return Returns true if the timer/counter is inactive and can be destroyed.
          */
-        boolean reset(boolean detachIfReset);
+        default boolean reset(boolean detachIfReset) {
+            return reset(detachIfReset, SystemClock.elapsedRealtime() * 1000);
+        }
+
+        /**
+         * @see #reset(boolean)
+         * @param detachIfReset detach if true, no-op if false.
+         * @param elapsedRealtimeUs the timestamp when this reset is actually reequested
+         * @return Returns true if the timer/counter is inactive and can be destroyed.
+         */
+        boolean reset(boolean detachIfReset, long elapsedRealtimeUs);
+
         /**
          * Detach the observer from TimeBase.
          */
@@ -1150,17 +1161,19 @@
     // methods are protected not private to be VisibleForTesting
     public static class TimeBase {
         protected final Collection<TimeBaseObs> mObservers;
-        protected long mUptime;
-        protected long mRealtime;
+
+        // All below time metrics are in microseconds.
+        protected long mUptimeUs;
+        protected long mRealtimeUs;
 
         protected boolean mRunning;
 
-        protected long mPastUptime;
-        protected long mUptimeStart;
-        protected long mPastRealtime;
-        protected long mRealtimeStart;
-        protected long mUnpluggedUptime;
-        protected long mUnpluggedRealtime;
+        protected long mPastUptimeUs;
+        protected long mUptimeStartUs;
+        protected long mPastRealtimeUs;
+        protected long mRealtimeStartUs;
+        protected long mUnpluggedUptimeUs;
+        protected long mUnpluggedRealtimeUs;
 
         public void dump(PrintWriter pw, String prefix) {
             StringBuilder sb = new StringBuilder(128);
@@ -1168,26 +1181,26 @@
             sb.setLength(0);
             sb.append(prefix);
                     sb.append("mUptime=");
-                    formatTimeMs(sb, mUptime / 1000);
+                    formatTimeMs(sb, mUptimeUs / 1000);
             pw.println(sb.toString());
             sb.setLength(0);
             sb.append(prefix);
                     sb.append("mRealtime=");
-                    formatTimeMs(sb, mRealtime / 1000);
+                    formatTimeMs(sb, mRealtimeUs / 1000);
             pw.println(sb.toString());
             sb.setLength(0);
             sb.append(prefix);
                     sb.append("mPastUptime=");
-                    formatTimeMs(sb, mPastUptime / 1000); sb.append("mUptimeStart=");
-                    formatTimeMs(sb, mUptimeStart / 1000);
-                    sb.append("mUnpluggedUptime="); formatTimeMs(sb, mUnpluggedUptime / 1000);
+                    formatTimeMs(sb, mPastUptimeUs / 1000); sb.append("mUptimeStart=");
+                    formatTimeMs(sb, mUptimeStartUs / 1000);
+                    sb.append("mUnpluggedUptime="); formatTimeMs(sb, mUnpluggedUptimeUs / 1000);
             pw.println(sb.toString());
             sb.setLength(0);
             sb.append(prefix);
                     sb.append("mPastRealtime=");
-                    formatTimeMs(sb, mPastRealtime / 1000); sb.append("mRealtimeStart=");
-                    formatTimeMs(sb, mRealtimeStart / 1000);
-                    sb.append("mUnpluggedRealtime="); formatTimeMs(sb, mUnpluggedRealtime / 1000);
+                    formatTimeMs(sb, mPastRealtimeUs / 1000); sb.append("mRealtimeStart=");
+                    formatTimeMs(sb, mRealtimeStartUs / 1000);
+                    sb.append("mUnpluggedRealtime="); formatTimeMs(sb, mUnpluggedRealtimeUs / 1000);
             pw.println(sb.toString());
         }
         /**
@@ -1219,94 +1232,96 @@
             return mObservers.contains(observer);
         }
 
-        public void init(long uptime, long realtime) {
-            mRealtime = 0;
-            mUptime = 0;
-            mPastUptime = 0;
-            mPastRealtime = 0;
-            mUptimeStart = uptime;
-            mRealtimeStart = realtime;
-            mUnpluggedUptime = getUptime(mUptimeStart);
-            mUnpluggedRealtime = getRealtime(mRealtimeStart);
+        public void init(long uptimeUs, long elapsedRealtimeUs) {
+            mRealtimeUs = 0;
+            mUptimeUs = 0;
+            mPastUptimeUs = 0;
+            mPastRealtimeUs = 0;
+            mUptimeStartUs = uptimeUs;
+            mRealtimeStartUs = elapsedRealtimeUs;
+            mUnpluggedUptimeUs = getUptime(mUptimeStartUs);
+            mUnpluggedRealtimeUs = getRealtime(mRealtimeStartUs);
         }
 
-        public void reset(long uptime, long realtime) {
+        public void reset(long uptimeUs, long elapsedRealtimeUs) {
             if (!mRunning) {
-                mPastUptime = 0;
-                mPastRealtime = 0;
+                mPastUptimeUs = 0;
+                mPastRealtimeUs = 0;
             } else {
-                mUptimeStart = uptime;
-                mRealtimeStart = realtime;
-                // TODO: Since mUptimeStart was just reset and we are running, getUptime will
-                // just return mPastUptime. Also, are we sure we don't want to reset that?
-                mUnpluggedUptime = getUptime(uptime);
+                mUptimeStartUs = uptimeUs;
+                mRealtimeStartUs = elapsedRealtimeUs;
+                // TODO: Since mUptimeStartUs was just reset and we are running, getUptime will
+                // just return mPastUptimeUs. Also, are we sure we don't want to reset that?
+                mUnpluggedUptimeUs = getUptime(uptimeUs);
                 // TODO: likewise.
-                mUnpluggedRealtime = getRealtime(realtime);
+                mUnpluggedRealtimeUs = getRealtime(elapsedRealtimeUs);
             }
         }
 
-        public long computeUptime(long curTime, int which) {
-            return mUptime + getUptime(curTime);
+        public long computeUptime(long curTimeUs, int which) {
+            return mUptimeUs + getUptime(curTimeUs);
         }
 
-        public long computeRealtime(long curTime, int which) {
-            return mRealtime + getRealtime(curTime);
+        public long computeRealtime(long curTimeUs, int which) {
+            return mRealtimeUs + getRealtime(curTimeUs);
         }
 
-        public long getUptime(long curTime) {
-            long time = mPastUptime;
+        public long getUptime(long curTimeUs) {
+            long time = mPastUptimeUs;
             if (mRunning) {
-                time += curTime - mUptimeStart;
+                time += curTimeUs - mUptimeStartUs;
             }
             return time;
         }
 
-        public long getRealtime(long curTime) {
-            long time = mPastRealtime;
+        public long getRealtime(long curTimeUs) {
+            long time = mPastRealtimeUs;
             if (mRunning) {
-                time += curTime - mRealtimeStart;
+                time += curTimeUs - mRealtimeStartUs;
             }
             return time;
         }
 
         public long getUptimeStart() {
-            return mUptimeStart;
+            return mUptimeStartUs;
         }
 
         public long getRealtimeStart() {
-            return mRealtimeStart;
+            return mRealtimeStartUs;
         }
 
         public boolean isRunning() {
             return mRunning;
         }
 
-        public boolean setRunning(boolean running, long uptime, long realtime) {
+        public boolean setRunning(boolean running, long uptimeUs, long elapsedRealtimeUs) {
             if (mRunning != running) {
                 mRunning = running;
                 if (running) {
-                    mUptimeStart = uptime;
-                    mRealtimeStart = realtime;
-                    long batteryUptime = mUnpluggedUptime = getUptime(uptime);
-                    long batteryRealtime = mUnpluggedRealtime = getRealtime(realtime);
+                    mUptimeStartUs = uptimeUs;
+                    mRealtimeStartUs = elapsedRealtimeUs;
+                    long batteryUptimeUs = mUnpluggedUptimeUs = getUptime(uptimeUs);
+                    long batteryRealtimeUs = mUnpluggedRealtimeUs = getRealtime(elapsedRealtimeUs);
                     // Normally we do not use Iterator in framework code to avoid alloc/dealloc
                     // Iterator object, here is an exception because mObservers' type is Collection
                     // instead of list.
                     final Iterator<TimeBaseObs> iter = mObservers.iterator();
                     while (iter.hasNext()) {
-                        iter.next().onTimeStarted(realtime, batteryUptime, batteryRealtime);
+                        iter.next().onTimeStarted(
+                                elapsedRealtimeUs, batteryUptimeUs, batteryRealtimeUs);
                     }
                 } else {
-                    mPastUptime += uptime - mUptimeStart;
-                    mPastRealtime += realtime - mRealtimeStart;
-                    long batteryUptime = getUptime(uptime);
-                    long batteryRealtime = getRealtime(realtime);
+                    mPastUptimeUs += uptimeUs - mUptimeStartUs;
+                    mPastRealtimeUs += elapsedRealtimeUs - mRealtimeStartUs;
+                    long batteryUptimeUs = getUptime(uptimeUs);
+                    long batteryRealtimeUs = getRealtime(elapsedRealtimeUs);
                     // Normally we do not use Iterator in framework code to avoid alloc/dealloc
                     // Iterator object, here is an exception because mObservers' type is Collection
                     // instead of list.
                     final Iterator<TimeBaseObs> iter = mObservers.iterator();
                     while (iter.hasNext()) {
-                        iter.next().onTimeStopped(realtime, batteryUptime, batteryRealtime);
+                        iter.next().onTimeStopped(
+                                elapsedRealtimeUs, batteryUptimeUs, batteryRealtimeUs);
                     }
                 }
                 return true;
@@ -1315,38 +1330,38 @@
         }
 
         public void readSummaryFromParcel(Parcel in) {
-            mUptime = in.readLong();
-            mRealtime = in.readLong();
+            mUptimeUs = in.readLong();
+            mRealtimeUs = in.readLong();
         }
 
-        public void writeSummaryToParcel(Parcel out, long uptime, long realtime) {
-            out.writeLong(computeUptime(uptime, STATS_SINCE_CHARGED));
-            out.writeLong(computeRealtime(realtime, STATS_SINCE_CHARGED));
+        public void writeSummaryToParcel(Parcel out, long uptimeUs, long elapsedRealtimeUs) {
+            out.writeLong(computeUptime(uptimeUs, STATS_SINCE_CHARGED));
+            out.writeLong(computeRealtime(elapsedRealtimeUs, STATS_SINCE_CHARGED));
         }
 
         public void readFromParcel(Parcel in) {
             mRunning = false;
-            mUptime = in.readLong();
-            mPastUptime = in.readLong();
-            mUptimeStart = in.readLong();
-            mRealtime = in.readLong();
-            mPastRealtime = in.readLong();
-            mRealtimeStart = in.readLong();
-            mUnpluggedUptime = in.readLong();
-            mUnpluggedRealtime = in.readLong();
+            mUptimeUs = in.readLong();
+            mPastUptimeUs = in.readLong();
+            mUptimeStartUs = in.readLong();
+            mRealtimeUs = in.readLong();
+            mPastRealtimeUs = in.readLong();
+            mRealtimeStartUs = in.readLong();
+            mUnpluggedUptimeUs = in.readLong();
+            mUnpluggedRealtimeUs = in.readLong();
         }
 
-        public void writeToParcel(Parcel out, long uptime, long realtime) {
-            final long runningUptime = getUptime(uptime);
-            final long runningRealtime = getRealtime(realtime);
-            out.writeLong(mUptime);
+        public void writeToParcel(Parcel out, long uptimeUs, long elapsedRealtimeUs) {
+            final long runningUptime = getUptime(uptimeUs);
+            final long runningRealtime = getRealtime(elapsedRealtimeUs);
+            out.writeLong(mUptimeUs);
             out.writeLong(runningUptime);
-            out.writeLong(mUptimeStart);
-            out.writeLong(mRealtime);
+            out.writeLong(mUptimeStartUs);
+            out.writeLong(mRealtimeUs);
             out.writeLong(runningRealtime);
-            out.writeLong(mRealtimeStart);
-            out.writeLong(mUnpluggedUptime);
-            out.writeLong(mUnpluggedRealtime);
+            out.writeLong(mRealtimeStartUs);
+            out.writeLong(mUnpluggedUptimeUs);
+            out.writeLong(mUnpluggedRealtimeUs);
         }
     }
 
@@ -1374,11 +1389,11 @@
         }
 
         @Override
-        public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
+        public void onTimeStarted(long elapsedRealtimeUs, long baseUptimeUs, long baseRealtimeUs) {
         }
 
         @Override
-        public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
+        public void onTimeStopped(long elapsedRealtimeUs, long baseUptimeUs, long baseRealtimeUs) {
         }
 
         /**
@@ -1436,7 +1451,7 @@
          * Clear state of this counter.
          */
         @Override
-        public boolean reset(boolean detachIfReset) {
+        public boolean reset(boolean detachIfReset, long elapsedRealtimeUs /* unused */) {
             mCount.set(0);
             if (detachIfReset) {
                 detach();
@@ -1481,11 +1496,11 @@
         }
 
         @Override
-        public void onTimeStarted(long elapsedRealTime, long baseUptime, long baseRealtime) {
+        public void onTimeStarted(long elapsedRealTimeUs, long baseUptimeUs, long baseRealtimeUs) {
         }
 
         @Override
-        public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
+        public void onTimeStopped(long elapsedRealtimeUs, long baseUptimeUs, long baseRealtimeUs) {
         }
 
         @Override
@@ -1524,7 +1539,7 @@
          * Clear state of this counter.
          */
         @Override
-        public boolean reset(boolean detachIfReset) {
+        public boolean reset(boolean detachIfReset, long elapsedRealtimeUs /* unused */) {
             if (mCounts != null) {
                 Arrays.fill(mCounts, 0);
             }
@@ -1608,11 +1623,11 @@
         }
 
         @Override
-        public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
+        public void onTimeStarted(long elapsedRealtimeUs, long baseUptimeUs, long baseRealtimeUs) {
         }
 
         @Override
-        public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
+        public void onTimeStopped(long elapsedRealtimeUs, long baseUptimeUs, long baseRealtimeUs) {
         }
 
         public long getCountLocked(int which) {
@@ -1638,7 +1653,7 @@
          * Clear state of this counter.
          */
         @Override
-        public boolean reset(boolean detachIfReset) {
+        public boolean reset(boolean detachIfReset, long elapsedRealtimeUs /* unused */) {
             mCount = 0;
             if (detachIfReset) {
                 detach();
@@ -1678,13 +1693,13 @@
          * boot, to the last time something interesting happened in the
          * current run.
          */
-        protected long mTotalTime;
+        protected long mTotalTimeUs;
 
         /**
          * The total time this timer has been running until the latest mark has been set.
-         * Subtract this from mTotalTime to get the time spent running since the mark was set.
+         * Subtract this from mTotalTimeUs to get the time spent running since the mark was set.
          */
-        protected long mTimeBeforeMark;
+        protected long mTimeBeforeMarkUs;
 
         /**
          * Constructs from a parcel.
@@ -1698,10 +1713,10 @@
             mTimeBase = timeBase;
 
             mCount = in.readInt();
-            mTotalTime = in.readLong();
-            mTimeBeforeMark = in.readLong();
+            mTotalTimeUs = in.readLong();
+            mTimeBeforeMarkUs = in.readLong();
             timeBase.add(this);
-            if (DEBUG) Log.i(TAG, "**** READ TIMER #" + mType + ": mTotalTime=" + mTotalTime);
+            if (DEBUG) Log.i(TAG, "**** READ TIMER #" + mType + ": mTotalTime=" + mTotalTimeUs);
         }
 
         public Timer(Clocks clocks, int type, TimeBase timeBase) {
@@ -1714,14 +1729,17 @@
         public void writeToParcel(Parcel out, long elapsedRealtimeUs) {
             if (DEBUG) {
                 Log.i(TAG, "**** WRITING TIMER #" + mType + ": mTotalTime="
-                        + computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs)));
+                        + computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs),
+                                elapsedRealtimeUs));
             }
             out.writeInt(computeCurrentCountLocked());
-            out.writeLong(computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs)));
-            out.writeLong(mTimeBeforeMark);
+            out.writeLong(computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs),
+                        elapsedRealtimeUs));
+            out.writeLong(mTimeBeforeMarkUs);
         }
 
-        protected abstract long computeRunTimeLocked(long curBatteryRealtime);
+        protected abstract long computeRunTimeLocked(long curBatteryRealtime,
+                long elapsedRealtimeUs);
 
         protected abstract int computeCurrentCountLocked();
 
@@ -1731,7 +1749,12 @@
          */
         @Override
         public boolean reset(boolean detachIfReset) {
-            mTotalTime = mTimeBeforeMark = 0;
+            return reset(detachIfReset, mClocks.elapsedRealtime() * 1000);
+        }
+
+        @Override
+        public boolean reset(boolean detachIfReset, long elapsedRealtimeUs /* unused */) {
+            mTotalTimeUs = mTimeBeforeMarkUs = 0;
             mCount = 0;
             if (detachIfReset) {
                 detach();
@@ -1745,19 +1768,20 @@
         }
 
         @Override
-        public void onTimeStarted(long elapsedRealtime, long timeBaseUptime, long baseRealtime) {
+        public void onTimeStarted(long elapsedRealtimeUs, long timeBaseUptimeUs,
+                long baseRealtimeUs) {
         }
 
         @Override
-        public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
+        public void onTimeStopped(long elapsedRealtimeUs, long baseUptimeUs, long baseRealtimeUs) {
             if (DEBUG && mType < 0) {
-                Log.v(TAG, "plug #" + mType + ": realtime=" + baseRealtime
-                        + " old mTotalTime=" + mTotalTime);
+                Log.v(TAG, "plug #" + mType + ": realtime=" + baseRealtimeUs
+                        + " old mTotalTime=" + mTotalTimeUs);
             }
-            mTotalTime = computeRunTimeLocked(baseRealtime);
+            mTotalTimeUs = computeRunTimeLocked(baseRealtimeUs, elapsedRealtimeUs);
             mCount = computeCurrentCountLocked();
             if (DEBUG && mType < 0) {
-                Log.v(TAG, "plug #" + mType + ": new mTotalTime=" + mTotalTime);
+                Log.v(TAG, "plug #" + mType + ": new mTotalTime=" + mTotalTimeUs);
             }
         }
 
@@ -1780,7 +1804,8 @@
         @Override
         @UnsupportedAppUsage
         public long getTotalTimeLocked(long elapsedRealtimeUs, int which) {
-            return computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs));
+            return computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs),
+                    elapsedRealtimeUs);
         }
 
         @Override
@@ -1791,29 +1816,31 @@
 
         @Override
         public long getTimeSinceMarkLocked(long elapsedRealtimeUs) {
-            long val = computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs));
-            return val - mTimeBeforeMark;
+            long val = computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs),
+                    elapsedRealtimeUs);
+            return val - mTimeBeforeMarkUs;
         }
 
         @Override
         public void logState(Printer pw, String prefix) {
             pw.println(prefix + "mCount=" + mCount);
-            pw.println(prefix + "mTotalTime=" + mTotalTime);
+            pw.println(prefix + "mTotalTime=" + mTotalTimeUs);
         }
 
 
         public void writeSummaryFromParcelLocked(Parcel out, long elapsedRealtimeUs) {
-            long runTime = computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs));
-            out.writeLong(runTime);
+            long runTimeUs = computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs),
+                    elapsedRealtimeUs);
+            out.writeLong(runTimeUs);
             out.writeInt(computeCurrentCountLocked());
         }
 
         public void readSummaryFromParcelLocked(Parcel in) {
             // Multiply by 1000 for backwards compatibility
-            mTotalTime = in.readLong();
+            mTotalTimeUs = in.readLong();
             mCount = in.readInt();
             // When reading the summary, we set the mark to be the latest information.
-            mTimeBeforeMark = mTotalTime;
+            mTimeBeforeMarkUs = mTotalTimeUs;
         }
     }
 
@@ -1843,14 +1870,14 @@
         /**
          * The most recent reported total_time from /proc/wakelocks.
          */
-        long mCurrentReportedTotalTime;
+        long mCurrentReportedTotalTimeUs;
 
 
         /**
          * The reported total_time from /proc/wakelocks when unplug() was last
          * called.
          */
-        long mUnpluggedReportedTotalTime;
+        long mUnpluggedReportedTotalTimeUs;
 
         /**
          * Whether we are currently in a discharge cycle.
@@ -1872,8 +1899,8 @@
             super(clocks, 0, timeBase, in);
             mCurrentReportedCount = in.readInt();
             mUnpluggedReportedCount = in.readInt();
-            mCurrentReportedTotalTime = in.readLong();
-            mUnpluggedReportedTotalTime = in.readLong();
+            mCurrentReportedTotalTimeUs = in.readLong();
+            mUnpluggedReportedTotalTimeUs = in.readLong();
             mTrackingReportedValues = in.readInt() == 1;
             mTimeBaseRunning = timeBase.isRunning();
         }
@@ -1890,9 +1917,16 @@
          * be less than the values used for a previous invocation.
          */
         public void endSample() {
-            mTotalTime = computeRunTimeLocked(0 /* unused by us */);
+            endSample(mClocks.elapsedRealtime() * 1000);
+        }
+
+        /**
+         * @see #endSample()
+         */
+        public void endSample(long elapsedRealtimeUs) {
+            mTotalTimeUs = computeRunTimeLocked(0 /* unused by us */, elapsedRealtimeUs);
             mCount = computeCurrentCountLocked();
-            mUnpluggedReportedTotalTime = mCurrentReportedTotalTime = 0;
+            mUnpluggedReportedTotalTimeUs = mCurrentReportedTotalTimeUs = 0;
             mUnpluggedReportedCount = mCurrentReportedCount = 0;
             mTrackingReportedValues = false;
         }
@@ -1911,26 +1945,33 @@
          *
          * If the values being recorded have been reset, the monotonically increasing requirement
          * will be broken. In this case, {@link #endSample()} is automatically called and
-         * the total value of totalTime and count are recorded, starting a new monotonically
+         * the total value of totalTimeUs and count are recorded, starting a new monotonically
          * increasing sample.
          *
-         * @param totalTime total time of sample in microseconds.
+         * @param totalTimeUs total time of sample in microseconds.
          * @param count total number of times the event being sampled occurred.
          */
-        public void update(long totalTime, int count) {
+        public void updated(long totalTimeUs, int count) {
+            update(totalTimeUs, count, mClocks.elapsedRealtime() * 1000);
+        }
+
+        /**
+         * @see #update(long, int)
+         */
+        public void update(long totalTimeUs, int count, long elapsedRealtimeUs) {
             if (mTimeBaseRunning && !mTrackingReportedValues) {
                 // Updating the reported value for the first time.
-                mUnpluggedReportedTotalTime = totalTime;
+                mUnpluggedReportedTotalTimeUs = totalTimeUs;
                 mUnpluggedReportedCount = count;
             }
 
             mTrackingReportedValues = true;
 
-            if (totalTime < mCurrentReportedTotalTime || count < mCurrentReportedCount) {
-                endSample();
+            if (totalTimeUs < mCurrentReportedTotalTimeUs || count < mCurrentReportedCount) {
+                endSample(elapsedRealtimeUs);
             }
 
-            mCurrentReportedTotalTime = totalTime;
+            mCurrentReportedTotalTimeUs = totalTimeUs;
             mCurrentReportedCount = count;
         }
 
@@ -1940,23 +1981,31 @@
          * @param deltaTime additional time recorded since the last sampled event, in microseconds.
          * @param deltaCount additional number of times the event being sampled occurred.
          */
-        public void add(long deltaTime, int deltaCount) {
-            update(mCurrentReportedTotalTime + deltaTime, mCurrentReportedCount + deltaCount);
+        public void add(long deltaTimeUs, int deltaCount) {
+            add(deltaTimeUs, deltaCount, mClocks.elapsedRealtime() * 1000);
+        }
+
+        /**
+         * @see #add(long, int)
+         */
+        public void add(long deltaTimeUs, int deltaCount, long elapsedRealtimeUs) {
+            update(mCurrentReportedTotalTimeUs + deltaTimeUs, mCurrentReportedCount + deltaCount,
+                    elapsedRealtimeUs);
         }
 
         @Override
-        public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
-            super.onTimeStarted(elapsedRealtime, baseUptime, baseRealtime);
+        public void onTimeStarted(long elapsedRealtimeUs, long baseUptimeUs, long baseRealtimeUs) {
+            super.onTimeStarted(elapsedRealtimeUs, baseUptimeUs, baseRealtimeUs);
             if (mTrackingReportedValues) {
-                mUnpluggedReportedTotalTime = mCurrentReportedTotalTime;
+                mUnpluggedReportedTotalTimeUs = mCurrentReportedTotalTimeUs;
                 mUnpluggedReportedCount = mCurrentReportedCount;
             }
             mTimeBaseRunning = true;
         }
 
         @Override
-        public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
-            super.onTimeStopped(elapsedRealtime, baseUptime, baseRealtime);
+        public void onTimeStopped(long elapsedRealtimeUs, long baseUptimeUs, long baseRealtimeUs) {
+            super.onTimeStopped(elapsedRealtimeUs, baseUptimeUs, baseRealtimeUs);
             mTimeBaseRunning = false;
         }
 
@@ -1965,14 +2014,14 @@
             super.logState(pw, prefix);
             pw.println(prefix + "mCurrentReportedCount=" + mCurrentReportedCount
                     + " mUnpluggedReportedCount=" + mUnpluggedReportedCount
-                    + " mCurrentReportedTotalTime=" + mCurrentReportedTotalTime
-                    + " mUnpluggedReportedTotalTime=" + mUnpluggedReportedTotalTime);
+                    + " mCurrentReportedTotalTime=" + mCurrentReportedTotalTimeUs
+                    + " mUnpluggedReportedTotalTime=" + mUnpluggedReportedTotalTimeUs);
         }
 
         @Override
-        protected long computeRunTimeLocked(long curBatteryRealtime) {
-            return mTotalTime + (mTimeBaseRunning && mTrackingReportedValues
-                    ? mCurrentReportedTotalTime - mUnpluggedReportedTotalTime : 0);
+        protected long computeRunTimeLocked(long curBatteryRealtime, long elapsedRealtimeUs) {
+            return mTotalTimeUs + (mTimeBaseRunning && mTrackingReportedValues
+                    ? mCurrentReportedTotalTimeUs - mUnpluggedReportedTotalTimeUs : 0);
         }
 
         @Override
@@ -1986,16 +2035,16 @@
             super.writeToParcel(out, elapsedRealtimeUs);
             out.writeInt(mCurrentReportedCount);
             out.writeInt(mUnpluggedReportedCount);
-            out.writeLong(mCurrentReportedTotalTime);
-            out.writeLong(mUnpluggedReportedTotalTime);
+            out.writeLong(mCurrentReportedTotalTimeUs);
+            out.writeLong(mUnpluggedReportedTotalTimeUs);
             out.writeInt(mTrackingReportedValues ? 1 : 0);
         }
 
         @Override
-        public boolean reset(boolean detachIfReset) {
-            super.reset(detachIfReset);
+        public boolean reset(boolean detachIfReset, long elapsedRealtimeUs) {
+            super.reset(detachIfReset, elapsedRealtimeUs);
             mTrackingReportedValues = false;
-            mUnpluggedReportedTotalTime = 0;
+            mUnpluggedReportedTotalTimeUs = 0;
             mUnpluggedReportedCount = 0;
             return true;
         }
@@ -2011,12 +2060,12 @@
         /**
          * The last time at which we updated the timer.  This is in elapsed realtime microseconds.
          */
-        long mLastAddedTime;
+        long mLastAddedTimeUs;
 
         /**
          * The last duration that we added to the timer.  This is in microseconds.
          */
-        long mLastAddedDuration;
+        long mLastAddedDurationUs;
 
         /**
          * Whether we are currently in a discharge cycle.
@@ -2026,8 +2075,8 @@
         BatchTimer(Clocks clocks, Uid uid, int type, TimeBase timeBase, Parcel in) {
             super(clocks, type, timeBase, in);
             mUid = uid;
-            mLastAddedTime = in.readLong();
-            mLastAddedDuration = in.readLong();
+            mLastAddedTimeUs = in.readLong();
+            mLastAddedDurationUs = in.readLong();
             mInDischarge = timeBase.isRunning();
         }
 
@@ -2040,74 +2089,82 @@
         @Override
         public void writeToParcel(Parcel out, long elapsedRealtimeUs) {
             super.writeToParcel(out, elapsedRealtimeUs);
-            out.writeLong(mLastAddedTime);
-            out.writeLong(mLastAddedDuration);
+            out.writeLong(mLastAddedTimeUs);
+            out.writeLong(mLastAddedDurationUs);
         }
 
         @Override
-        public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
-            recomputeLastDuration(mClocks.elapsedRealtime() * 1000, false);
+        public void onTimeStopped(long elapsedRealtimeUs, long baseUptimeUs, long baseRealtimeUs) {
+            recomputeLastDuration(elapsedRealtimeUs, false);
             mInDischarge = false;
-            super.onTimeStopped(elapsedRealtime, baseUptime, baseRealtime);
+            super.onTimeStopped(elapsedRealtimeUs, baseUptimeUs, baseRealtimeUs);
         }
 
         @Override
-        public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
-            recomputeLastDuration(elapsedRealtime, false);
+        public void onTimeStarted(long elapsedRealtimeUs, long baseUptimeUs, long baseRealtimeUs) {
+            recomputeLastDuration(elapsedRealtimeUs, false);
             mInDischarge = true;
             // If we are still within the last added duration, then re-added whatever remains.
-            if (mLastAddedTime == elapsedRealtime) {
-                mTotalTime += mLastAddedDuration;
+            if (mLastAddedTimeUs == elapsedRealtimeUs) {
+                mTotalTimeUs += mLastAddedDurationUs;
             }
-            super.onTimeStarted(elapsedRealtime, baseUptime, baseRealtime);
+            super.onTimeStarted(elapsedRealtimeUs, baseUptimeUs, baseRealtimeUs);
         }
 
         @Override
         public void logState(Printer pw, String prefix) {
             super.logState(pw, prefix);
-            pw.println(prefix + "mLastAddedTime=" + mLastAddedTime
-                    + " mLastAddedDuration=" + mLastAddedDuration);
+            pw.println(prefix + "mLastAddedTime=" + mLastAddedTimeUs
+                    + " mLastAddedDuration=" + mLastAddedDurationUs);
         }
 
-        private long computeOverage(long curTime) {
-            if (mLastAddedTime > 0) {
-                return mLastAddedDuration - curTime;
+        private long computeOverage(long curTimeUs) {
+            if (mLastAddedTimeUs > 0) {
+                return mLastAddedDurationUs - curTimeUs;
             }
             return 0;
         }
 
-        private void recomputeLastDuration(long curTime, boolean abort) {
-            final long overage = computeOverage(curTime);
+        private void recomputeLastDuration(long curTimeUs, boolean abort) {
+            final long overage = computeOverage(curTimeUs);
             if (overage > 0) {
                 // Aborting before the duration ran out -- roll back the remaining
                 // duration.  Only do this if currently discharging; otherwise we didn't
                 // actually add the time.
                 if (mInDischarge) {
-                    mTotalTime -= overage;
+                    mTotalTimeUs -= overage;
                 }
                 if (abort) {
-                    mLastAddedTime = 0;
+                    mLastAddedTimeUs = 0;
                 } else {
-                    mLastAddedTime = curTime;
-                    mLastAddedDuration -= overage;
+                    mLastAddedTimeUs = curTimeUs;
+                    mLastAddedDurationUs -= overage;
                 }
             }
         }
 
-        public void addDuration(BatteryStatsImpl stats, long durationMillis) {
-            final long now = mClocks.elapsedRealtime() * 1000;
-            recomputeLastDuration(now, true);
-            mLastAddedTime = now;
-            mLastAddedDuration = durationMillis * 1000;
+        public void addDuration(BatteryStatsImpl stats, long durationMs) {
+            addDuration(stats, durationMs, mClocks.elapsedRealtime());
+        }
+
+        public void addDuration(BatteryStatsImpl stats, long durationMs, long elapsedRealtimeMs) {
+            final long nowUs = elapsedRealtimeMs * 1000;
+            recomputeLastDuration(nowUs, true);
+            mLastAddedTimeUs = nowUs;
+            mLastAddedDurationUs = durationMs * 1000;
             if (mInDischarge) {
-                mTotalTime += mLastAddedDuration;
+                mTotalTimeUs += mLastAddedDurationUs;
                 mCount++;
             }
         }
 
         public void abortLastDuration(BatteryStatsImpl stats) {
-            final long now = mClocks.elapsedRealtime() * 1000;
-            recomputeLastDuration(now, true);
+            abortLastDuration(stats, mClocks.elapsedRealtime());
+        }
+
+        public void abortLastDuration(BatteryStatsImpl stats, long elapsedRealtimeMs) {
+            final long nowUs = elapsedRealtimeMs * 1000;
+            recomputeLastDuration(nowUs, true);
         }
 
         @Override
@@ -2116,20 +2173,19 @@
         }
 
         @Override
-        protected long computeRunTimeLocked(long curBatteryRealtime) {
-            final long overage = computeOverage(mClocks.elapsedRealtime() * 1000);
+        protected long computeRunTimeLocked(long curBatteryRealtimeUs, long elapsedRealtimeUs) {
+            final long overage = computeOverage(elapsedRealtimeUs);
             if (overage > 0) {
-                return mTotalTime = overage;
+                return mTotalTimeUs = overage;
             }
-            return mTotalTime;
+            return mTotalTimeUs;
         }
 
         @Override
-        public boolean reset(boolean detachIfReset) {
-            final long now = mClocks.elapsedRealtime() * 1000;
-            recomputeLastDuration(now, true);
-            boolean stillActive = mLastAddedTime == now;
-            super.reset(!stillActive && detachIfReset);
+        public boolean reset(boolean detachIfReset, long elapsedRealtimeUs) {
+            recomputeLastDuration(elapsedRealtimeUs, true);
+            boolean stillActive = mLastAddedTimeUs == elapsedRealtimeUs;
+            super.reset(!stillActive && detachIfReset, elapsedRealtimeUs);
             return !stillActive;
         }
     }
@@ -2225,10 +2281,10 @@
          *
          * If the timer is also running, store the start time.
          */
-        public void onTimeStarted(long elapsedRealtimeUs, long baseUptime, long baseRealtime) {
-            super.onTimeStarted(elapsedRealtimeUs, baseUptime, baseRealtime);
+        public void onTimeStarted(long elapsedRealtimeUs, long baseUptimeUs, long baseRealtimeUs) {
+            super.onTimeStarted(elapsedRealtimeUs, baseUptimeUs, baseRealtimeUs);
             if (mNesting > 0) {
-                mStartTimeMs = baseRealtime / 1000;
+                mStartTimeMs = baseRealtimeUs / 1000;
             }
         }
 
@@ -2238,8 +2294,8 @@
          * If the timer is running, add the duration into mCurrentDurationMs.
          */
         @Override
-        public void onTimeStopped(long elapsedRealtimeUs, long baseUptime, long baseRealtimeUs) {
-            super.onTimeStopped(elapsedRealtimeUs, baseUptime, baseRealtimeUs);
+        public void onTimeStopped(long elapsedRealtimeUs, long baseUptimeUs, long baseRealtimeUs) {
+            super.onTimeStopped(elapsedRealtimeUs, baseUptimeUs, baseRealtimeUs);
             if (mNesting > 0) {
                 // baseRealtimeUs has already been converted to the timebase's realtime.
                 mCurrentDurationMs += (baseRealtimeUs / 1000) - mStartTimeMs;
@@ -2284,13 +2340,13 @@
         }
 
         @Override
-        public boolean reset(boolean detachIfReset) {
-            boolean result = super.reset(detachIfReset);
+        public boolean reset(boolean detachIfReset, long elapsedRealtimeUs) {
+            boolean result = super.reset(detachIfReset, elapsedRealtimeUs);
             mMaxDurationMs = 0;
             mTotalDurationMs = 0;
             mCurrentDurationMs = 0;
             if (mNesting > 0) {
-                mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime() * 1000) / 1000;
+                mStartTimeMs = mTimeBase.getRealtime(elapsedRealtimeUs) / 1000;
             } else {
                 mStartTimeMs = -1;
             }
@@ -2364,16 +2420,16 @@
          * subtract this from the current battery time to find the amount of
          * time we have been running since we last computed an update.
          */
-        long mUpdateTime;
+        long mUpdateTimeUs;
 
         /**
          * The total time at which the timer was acquired, to determine if it
          * was actually held for an interesting duration. If time base was not running when timer
          * was acquired, will be -1.
          */
-        long mAcquireTime = -1;
+        long mAcquireTimeUs = -1;
 
-        long mTimeout;
+        long mTimeoutUs;
 
         /**
          * For partial wake locks, keep track of whether we are in the list
@@ -2387,7 +2443,7 @@
             super(clocks, type, timeBase, in);
             mUid = uid;
             mTimerPool = timerPool;
-            mUpdateTime = in.readLong();
+            mUpdateTimeUs = in.readLong();
         }
 
         public StopwatchTimer(Clocks clocks, Uid uid, int type, ArrayList<StopwatchTimer> timerPool,
@@ -2397,56 +2453,56 @@
             mTimerPool = timerPool;
         }
 
-        public void setTimeout(long timeout) {
-            mTimeout = timeout;
+        public void setTimeout(long timeoutUs) {
+            mTimeoutUs = timeoutUs;
         }
 
         public void writeToParcel(Parcel out, long elapsedRealtimeUs) {
             super.writeToParcel(out, elapsedRealtimeUs);
-            out.writeLong(mUpdateTime);
+            out.writeLong(mUpdateTimeUs);
         }
 
-        public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
+        public void onTimeStopped(long elapsedRealtimeUs, long baseUptimeUs, long baseRealtimeUs) {
             if (mNesting > 0) {
                 if (DEBUG && mType < 0) {
-                    Log.v(TAG, "old mUpdateTime=" + mUpdateTime);
+                    Log.v(TAG, "old mUpdateTime=" + mUpdateTimeUs);
                 }
-                super.onTimeStopped(elapsedRealtime, baseUptime, baseRealtime);
-                mUpdateTime = baseRealtime;
+                super.onTimeStopped(elapsedRealtimeUs, baseUptimeUs, baseRealtimeUs);
+                mUpdateTimeUs = baseRealtimeUs;
                 if (DEBUG && mType < 0) {
-                    Log.v(TAG, "new mUpdateTime=" + mUpdateTime);
+                    Log.v(TAG, "new mUpdateTime=" + mUpdateTimeUs);
                 }
             }
         }
 
         public void logState(Printer pw, String prefix) {
             super.logState(pw, prefix);
-            pw.println(prefix + "mNesting=" + mNesting + " mUpdateTime=" + mUpdateTime
-                    + " mAcquireTime=" + mAcquireTime);
+            pw.println(prefix + "mNesting=" + mNesting + " mUpdateTime=" + mUpdateTimeUs
+                    + " mAcquireTime=" + mAcquireTimeUs);
         }
 
         public void startRunningLocked(long elapsedRealtimeMs) {
             if (mNesting++ == 0) {
-                final long batteryRealtime = mTimeBase.getRealtime(elapsedRealtimeMs * 1000);
-                mUpdateTime = batteryRealtime;
+                final long batteryRealtimeUs = mTimeBase.getRealtime(elapsedRealtimeMs * 1000);
+                mUpdateTimeUs = batteryRealtimeUs;
                 if (mTimerPool != null) {
                     // Accumulate time to all currently active timers before adding
                     // this new one to the pool.
-                    refreshTimersLocked(batteryRealtime, mTimerPool, null);
+                    refreshTimersLocked(batteryRealtimeUs, mTimerPool, null);
                     // Add this timer to the active pool
                     mTimerPool.add(this);
                 }
                 if (mTimeBase.isRunning()) {
                     // Increment the count
                     mCount++;
-                    mAcquireTime = mTotalTime;
+                    mAcquireTimeUs = mTotalTimeUs;
                 } else {
-                    mAcquireTime = -1;
+                    mAcquireTimeUs = -1;
                 }
                 if (DEBUG && mType < 0) {
-                    Log.v(TAG, "start #" + mType + ": mUpdateTime=" + mUpdateTime
-                            + " mTotalTime=" + mTotalTime + " mCount=" + mCount
-                            + " mAcquireTime=" + mAcquireTime);
+                    Log.v(TAG, "start #" + mType + ": mUpdateTime=" + mUpdateTimeUs
+                            + " mTotalTime=" + mTotalTimeUs + " mCount=" + mCount
+                            + " mAcquireTime=" + mAcquireTimeUs);
                 }
             }
         }
@@ -2461,26 +2517,27 @@
                 return;
             }
             if (--mNesting == 0) {
-                final long batteryRealtime = mTimeBase.getRealtime(elapsedRealtimeMs * 1000);
+                final long batteryRealtimeUs = mTimeBase.getRealtime(elapsedRealtimeMs * 1000);
                 if (mTimerPool != null) {
                     // Accumulate time to all active counters, scaled by the total
                     // active in the pool, before taking this one out of the pool.
-                    refreshTimersLocked(batteryRealtime, mTimerPool, null);
+                    refreshTimersLocked(batteryRealtimeUs, mTimerPool, null);
                     // Remove this timer from the active pool
                     mTimerPool.remove(this);
                 } else {
                     mNesting = 1;
-                    mTotalTime = computeRunTimeLocked(batteryRealtime);
+                    mTotalTimeUs = computeRunTimeLocked(batteryRealtimeUs,
+                            elapsedRealtimeMs * 1000);
                     mNesting = 0;
                 }
 
                 if (DEBUG && mType < 0) {
-                    Log.v(TAG, "stop #" + mType + ": mUpdateTime=" + mUpdateTime
-                            + " mTotalTime=" + mTotalTime + " mCount=" + mCount
-                            + " mAcquireTime=" + mAcquireTime);
+                    Log.v(TAG, "stop #" + mType + ": mUpdateTime=" + mUpdateTimeUs
+                            + " mTotalTime=" + mTotalTimeUs + " mCount=" + mCount
+                            + " mAcquireTime=" + mAcquireTimeUs);
                 }
 
-                if (mAcquireTime >= 0 && mTotalTime == mAcquireTime) {
+                if (mAcquireTimeUs >= 0 && mTotalTimeUs == mAcquireTimeUs) {
                     // If there was no change in the time, then discard this
                     // count.  A somewhat cheezy strategy, but hey.
                     mCount--;
@@ -2497,32 +2554,32 @@
 
         // Update the total time for all other running Timers with the same type as this Timer
         // due to a change in timer count
-        private static long refreshTimersLocked(long batteryRealtime,
+        private static long refreshTimersLocked(long batteryRealtimeUs,
                 final ArrayList<StopwatchTimer> pool, StopwatchTimer self) {
-            long selfTime = 0;
+            long selfTimeUs = 0;
             final int N = pool.size();
             for (int i=N-1; i>= 0; i--) {
                 final StopwatchTimer t = pool.get(i);
-                long heldTime = batteryRealtime - t.mUpdateTime;
-                if (heldTime > 0) {
-                    final long myTime = heldTime / N;
+                long heldTimeUs = batteryRealtimeUs - t.mUpdateTimeUs;
+                if (heldTimeUs > 0) {
+                    final long myTimeUs = heldTimeUs / N;
                     if (t == self) {
-                        selfTime = myTime;
+                        selfTimeUs = myTimeUs;
                     }
-                    t.mTotalTime += myTime;
+                    t.mTotalTimeUs += myTimeUs;
                 }
-                t.mUpdateTime = batteryRealtime;
+                t.mUpdateTimeUs = batteryRealtimeUs;
             }
-            return selfTime;
+            return selfTimeUs;
         }
 
         @Override
-        protected long computeRunTimeLocked(long curBatteryRealtime) {
-            if (mTimeout > 0 && curBatteryRealtime > mUpdateTime + mTimeout) {
-                curBatteryRealtime = mUpdateTime + mTimeout;
+        protected long computeRunTimeLocked(long curBatteryRealtimeUs, long elapsedRealtimeUs) {
+            if (mTimeoutUs > 0 && curBatteryRealtimeUs > mUpdateTimeUs + mTimeoutUs) {
+                curBatteryRealtimeUs = mUpdateTimeUs + mTimeoutUs;
             }
-            return mTotalTime + (mNesting > 0
-                    ? (curBatteryRealtime - mUpdateTime)
+            return mTotalTimeUs + (mNesting > 0
+                    ? (curBatteryRealtimeUs - mUpdateTimeUs)
                             / (mTimerPool != null ? mTimerPool.size() : 1)
                     : 0);
         }
@@ -2533,13 +2590,14 @@
         }
 
         @Override
-        public boolean reset(boolean detachIfReset) {
+        public boolean reset(boolean detachIfReset, long elapsedRealtimeUs) {
             boolean canDetach = mNesting <= 0;
-            super.reset(canDetach && detachIfReset);
+            super.reset(canDetach && detachIfReset, elapsedRealtimeUs);
             if (mNesting > 0) {
-                mUpdateTime = mTimeBase.getRealtime(mClocks.elapsedRealtime() * 1000);
+                mUpdateTimeUs = mTimeBase.getRealtime(elapsedRealtimeUs);
             }
-            mAcquireTime = -1; // to ensure mCount isn't decreased to -1 if timer is stopped later.
+            // To ensure mCount isn't decreased to -1 if timer is stopped later.
+            mAcquireTimeUs = -1;
             return canDetach;
         }
 
@@ -2565,17 +2623,17 @@
          * @param elapsedRealtimeMs the current elapsed realtime in milliseconds.
          */
         public void setMark(long elapsedRealtimeMs) {
-            final long batteryRealtime = mTimeBase.getRealtime(elapsedRealtimeMs * 1000);
+            final long batteryRealtimeUs = mTimeBase.getRealtime(elapsedRealtimeMs * 1000);
             if (mNesting > 0) {
                 // We are running.
                 if (mTimerPool != null) {
-                    refreshTimersLocked(batteryRealtime, mTimerPool, this);
+                    refreshTimersLocked(batteryRealtimeUs, mTimerPool, this);
                 } else {
-                    mTotalTime += batteryRealtime - mUpdateTime;
-                    mUpdateTime = batteryRealtime;
+                    mTotalTimeUs += batteryRealtimeUs - mUpdateTimeUs;
+                    mUpdateTimeUs = batteryRealtimeUs;
                 }
             }
-            mTimeBeforeMark = mTotalTime;
+            mTimeBeforeMarkUs = mTotalTimeUs;
         }
     }
 
@@ -2641,11 +2699,11 @@
         }
 
         @Override
-        public boolean reset(boolean detachIfReset) {
+        public boolean reset(boolean detachIfReset, long elapsedRealtimeUs) {
             boolean active = false;
             // Do not detach the subTimer explicitly since that'll be done by DualTimer.detach().
-            active |= !mSubTimer.reset(false);
-            active |= !super.reset(detachIfReset);
+            active |= !mSubTimer.reset(false, elapsedRealtimeUs);
+            active |= !super.reset(detachIfReset, elapsedRealtimeUs);
             return !active;
         }
 
@@ -2682,10 +2740,10 @@
         final ArrayMap<String, T> mMap = new ArrayMap<>();
         T mCurOverflow;
         ArrayMap<String, MutableInt> mActiveOverflow;
-        long mLastOverflowTime;
-        long mLastOverflowFinishTime;
-        long mLastClearTime;
-        long mLastCleanupTime;
+        long mLastOverflowTimeMs;
+        long mLastOverflowFinishTimeMs;
+        long mLastClearTimeMs;
+        long mLastCleanupTimeMs;
 
         public OverflowArrayMap(int uid) {
             mUid = uid;
@@ -2696,7 +2754,7 @@
         }
 
         public void clear() {
-            mLastClearTime = SystemClock.elapsedRealtime();
+            mLastClearTimeMs = SystemClock.elapsedRealtime();
             mMap.clear();
             mCurOverflow = null;
             mActiveOverflow = null;
@@ -2712,8 +2770,8 @@
             }
         }
 
-        public void cleanup() {
-            mLastCleanupTime = SystemClock.elapsedRealtime();
+        public void cleanup(long elapsedRealtimeMs) {
+            mLastCleanupTimeMs = elapsedRealtimeMs;
             if (mActiveOverflow != null) {
                 if (mActiveOverflow.size() == 0) {
                     mActiveOverflow = null;
@@ -2737,7 +2795,7 @@
             }
         }
 
-        public T startObject(String name) {
+        public T startObject(String name, long elapsedRealtimeMs) {
             if (name == null) {
                 name = "";
             }
@@ -2780,7 +2838,7 @@
                     mActiveOverflow = new ArrayMap<>();
                 }
                 mActiveOverflow.put(name, new MutableInt(1));
-                mLastOverflowTime = SystemClock.elapsedRealtime();
+                mLastOverflowTimeMs = elapsedRealtimeMs;
                 return obj;
             }
 
@@ -2790,7 +2848,7 @@
             return obj;
         }
 
-        public T stopObject(String name) {
+        public T stopObject(String name, long elapsedRealtimeMs) {
             if (name == null) {
                 name = "";
             }
@@ -2810,7 +2868,7 @@
                         over.value--;
                         if (over.value <= 0) {
                             mActiveOverflow.remove(name);
-                            mLastOverflowFinishTime = SystemClock.elapsedRealtime();
+                            mLastOverflowFinishTimeMs = elapsedRealtimeMs;
                         }
                         return obj;
                     }
@@ -2830,22 +2888,22 @@
             sb.append(mActiveOverflow);
             sb.append(" curoverflow=");
             sb.append(mCurOverflow);
-            long now = SystemClock.elapsedRealtime();
-            if (mLastOverflowTime != 0) {
+            long now = elapsedRealtimeMs;
+            if (mLastOverflowTimeMs != 0) {
                 sb.append(" lastOverflowTime=");
-                TimeUtils.formatDuration(mLastOverflowTime-now, sb);
+                TimeUtils.formatDuration(mLastOverflowTimeMs - now, sb);
             }
-            if (mLastOverflowFinishTime != 0) {
+            if (mLastOverflowFinishTimeMs != 0) {
                 sb.append(" lastOverflowFinishTime=");
-                TimeUtils.formatDuration(mLastOverflowFinishTime-now, sb);
+                TimeUtils.formatDuration(mLastOverflowFinishTimeMs - now, sb);
             }
-            if (mLastClearTime != 0) {
+            if (mLastClearTimeMs != 0) {
                 sb.append(" lastClearTime=");
-                TimeUtils.formatDuration(mLastClearTime-now, sb);
+                TimeUtils.formatDuration(mLastClearTimeMs - now, sb);
             }
-            if (mLastCleanupTime != 0) {
+            if (mLastCleanupTimeMs != 0) {
                 sb.append(" lastCleanupTime=");
-                TimeUtils.formatDuration(mLastCleanupTime-now, sb);
+                TimeUtils.formatDuration(mLastCleanupTimeMs - now, sb);
             }
             Slog.wtf(TAG, sb.toString());
             return null;
@@ -2943,16 +3001,16 @@
             mMonitoredRailChargeConsumedMaMs.writeToParcel(dest);
         }
 
-        public void reset(boolean detachIfReset) {
-            mIdleTimeMillis.reset(detachIfReset);
-            mScanTimeMillis.reset(detachIfReset);
-            mSleepTimeMillis.reset(detachIfReset);
-            mRxTimeMillis.reset(detachIfReset);
+        public void reset(boolean detachIfReset, long elapsedRealtimeUs) {
+            mIdleTimeMillis.reset(detachIfReset, elapsedRealtimeUs);
+            mScanTimeMillis.reset(detachIfReset, elapsedRealtimeUs);
+            mSleepTimeMillis.reset(detachIfReset, elapsedRealtimeUs);
+            mRxTimeMillis.reset(detachIfReset, elapsedRealtimeUs);
             for (LongSamplingCounter counter : mTxTimeMillis) {
-                counter.reset(detachIfReset);
+                counter.reset(detachIfReset, elapsedRealtimeUs);
             }
-            mPowerDrainMaMs.reset(detachIfReset);
-            mMonitoredRailChargeConsumedMaMs.reset(detachIfReset);
+            mPowerDrainMaMs.reset(detachIfReset, elapsedRealtimeUs);
+            mMonitoredRailChargeConsumedMaMs.reset(detachIfReset, elapsedRealtimeUs);
         }
 
         public void detach() {
@@ -3416,82 +3474,82 @@
             final int NU = mUidStats.size();
             for (int i=0; i<NU; i++) {
                 final BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
-                uid.mLastStepUserTime = uid.mCurStepUserTime;
-                uid.mLastStepSystemTime = uid.mCurStepSystemTime;
+                uid.mLastStepUserTimeMs = uid.mCurStepUserTimeMs;
+                uid.mLastStepSystemTimeMs = uid.mCurStepSystemTimeMs;
             }
-            mLastStepCpuUserTime = mCurStepCpuUserTime;
-            mLastStepCpuSystemTime = mCurStepCpuSystemTime;
-            mLastStepStatUserTime = mCurStepStatUserTime;
-            mLastStepStatSystemTime = mCurStepStatSystemTime;
-            mLastStepStatIOWaitTime = mCurStepStatIOWaitTime;
-            mLastStepStatIrqTime = mCurStepStatIrqTime;
-            mLastStepStatSoftIrqTime = mCurStepStatSoftIrqTime;
-            mLastStepStatIdleTime = mCurStepStatIdleTime;
+            mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs;
+            mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs;
+            mLastStepStatUserTimeMs = mCurStepStatUserTimeMs;
+            mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs;
+            mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs;
+            mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs;
+            mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs;
+            mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs;
             tmp.clear();
             return;
         }
         if (DEBUG) {
-            Slog.d(TAG, "Step stats last: user=" + mLastStepCpuUserTime + " sys="
-                    + mLastStepStatSystemTime + " io=" + mLastStepStatIOWaitTime
-                    + " irq=" + mLastStepStatIrqTime + " sirq="
-                    + mLastStepStatSoftIrqTime + " idle=" + mLastStepStatIdleTime);
-            Slog.d(TAG, "Step stats cur: user=" + mCurStepCpuUserTime + " sys="
-                    + mCurStepStatSystemTime + " io=" + mCurStepStatIOWaitTime
-                    + " irq=" + mCurStepStatIrqTime + " sirq="
-                    + mCurStepStatSoftIrqTime + " idle=" + mCurStepStatIdleTime);
+            Slog.d(TAG, "Step stats last: user=" + mLastStepCpuUserTimeMs + " sys="
+                    + mLastStepStatSystemTimeMs + " io=" + mLastStepStatIOWaitTimeMs
+                    + " irq=" + mLastStepStatIrqTimeMs + " sirq="
+                    + mLastStepStatSoftIrqTimeMs + " idle=" + mLastStepStatIdleTimeMs);
+            Slog.d(TAG, "Step stats cur: user=" + mCurStepCpuUserTimeMs + " sys="
+                    + mCurStepStatSystemTimeMs + " io=" + mCurStepStatIOWaitTimeMs
+                    + " irq=" + mCurStepStatIrqTimeMs + " sirq="
+                    + mCurStepStatSoftIrqTimeMs + " idle=" + mCurStepStatIdleTimeMs);
         }
-        out.userTime = (int)(mCurStepCpuUserTime - mLastStepCpuUserTime);
-        out.systemTime = (int)(mCurStepCpuSystemTime - mLastStepCpuSystemTime);
-        out.statUserTime = (int)(mCurStepStatUserTime - mLastStepStatUserTime);
-        out.statSystemTime = (int)(mCurStepStatSystemTime - mLastStepStatSystemTime);
-        out.statIOWaitTime = (int)(mCurStepStatIOWaitTime - mLastStepStatIOWaitTime);
-        out.statIrqTime = (int)(mCurStepStatIrqTime - mLastStepStatIrqTime);
-        out.statSoftIrqTime = (int)(mCurStepStatSoftIrqTime - mLastStepStatSoftIrqTime);
-        out.statIdlTime = (int)(mCurStepStatIdleTime - mLastStepStatIdleTime);
+        out.userTime = (int) (mCurStepCpuUserTimeMs - mLastStepCpuUserTimeMs);
+        out.systemTime = (int) (mCurStepCpuSystemTimeMs - mLastStepCpuSystemTimeMs);
+        out.statUserTime = (int) (mCurStepStatUserTimeMs - mLastStepStatUserTimeMs);
+        out.statSystemTime = (int) (mCurStepStatSystemTimeMs - mLastStepStatSystemTimeMs);
+        out.statIOWaitTime = (int) (mCurStepStatIOWaitTimeMs - mLastStepStatIOWaitTimeMs);
+        out.statIrqTime = (int) (mCurStepStatIrqTimeMs - mLastStepStatIrqTimeMs);
+        out.statSoftIrqTime = (int) (mCurStepStatSoftIrqTimeMs - mLastStepStatSoftIrqTimeMs);
+        out.statIdlTime = (int) (mCurStepStatIdleTimeMs - mLastStepStatIdleTimeMs);
         out.appCpuUid1 = out.appCpuUid2 = out.appCpuUid3 = -1;
         out.appCpuUTime1 = out.appCpuUTime2 = out.appCpuUTime3 = 0;
         out.appCpuSTime1 = out.appCpuSTime2 = out.appCpuSTime3 = 0;
         final int NU = mUidStats.size();
         for (int i=0; i<NU; i++) {
             final BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
-            final int totalUTime = (int)(uid.mCurStepUserTime - uid.mLastStepUserTime);
-            final int totalSTime = (int)(uid.mCurStepSystemTime - uid.mLastStepSystemTime);
-            final int totalTime = totalUTime + totalSTime;
-            uid.mLastStepUserTime = uid.mCurStepUserTime;
-            uid.mLastStepSystemTime = uid.mCurStepSystemTime;
-            if (totalTime <= (out.appCpuUTime3+out.appCpuSTime3)) {
+            final int totalUTimeMs = (int) (uid.mCurStepUserTimeMs - uid.mLastStepUserTimeMs);
+            final int totalSTimeMs = (int) (uid.mCurStepSystemTimeMs - uid.mLastStepSystemTimeMs);
+            final int totalTimeMs = totalUTimeMs + totalSTimeMs;
+            uid.mLastStepUserTimeMs = uid.mCurStepUserTimeMs;
+            uid.mLastStepSystemTimeMs = uid.mCurStepSystemTimeMs;
+            if (totalTimeMs <= (out.appCpuUTime3 + out.appCpuSTime3)) {
                 continue;
             }
-            if (totalTime <= (out.appCpuUTime2+out.appCpuSTime2)) {
+            if (totalTimeMs <= (out.appCpuUTime2 + out.appCpuSTime2)) {
                 out.appCpuUid3 = uid.mUid;
-                out.appCpuUTime3 = totalUTime;
-                out.appCpuSTime3 = totalSTime;
+                out.appCpuUTime3 = totalUTimeMs;
+                out.appCpuSTime3 = totalSTimeMs;
             } else {
                 out.appCpuUid3 = out.appCpuUid2;
                 out.appCpuUTime3 = out.appCpuUTime2;
                 out.appCpuSTime3 = out.appCpuSTime2;
-                if (totalTime <= (out.appCpuUTime1+out.appCpuSTime1)) {
+                if (totalTimeMs <= (out.appCpuUTime1 + out.appCpuSTime1)) {
                     out.appCpuUid2 = uid.mUid;
-                    out.appCpuUTime2 = totalUTime;
-                    out.appCpuSTime2 = totalSTime;
+                    out.appCpuUTime2 = totalUTimeMs;
+                    out.appCpuSTime2 = totalSTimeMs;
                 } else {
                     out.appCpuUid2 = out.appCpuUid1;
                     out.appCpuUTime2 = out.appCpuUTime1;
                     out.appCpuSTime2 = out.appCpuSTime1;
                     out.appCpuUid1 = uid.mUid;
-                    out.appCpuUTime1 = totalUTime;
-                    out.appCpuSTime1 = totalSTime;
+                    out.appCpuUTime1 = totalUTimeMs;
+                    out.appCpuSTime1 = totalSTimeMs;
                 }
             }
         }
-        mLastStepCpuUserTime = mCurStepCpuUserTime;
-        mLastStepCpuSystemTime = mCurStepCpuSystemTime;
-        mLastStepStatUserTime = mCurStepStatUserTime;
-        mLastStepStatSystemTime = mCurStepStatSystemTime;
-        mLastStepStatIOWaitTime = mCurStepStatIOWaitTime;
-        mLastStepStatIrqTime = mCurStepStatIrqTime;
-        mLastStepStatSoftIrqTime = mCurStepStatSoftIrqTime;
-        mLastStepStatIdleTime = mCurStepStatIdleTime;
+        mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs;
+        mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs;
+        mLastStepStatUserTimeMs = mCurStepStatUserTimeMs;
+        mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs;
+        mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs;
+        mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs;
+        mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs;
+        mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs;
     }
 
     public void readHistoryDelta(Parcel src, HistoryItem cur) {
@@ -3631,29 +3689,35 @@
     }
 
     public void createFakeHistoryEvents(long numEvents) {
+        final long elapsedRealtimeMs = mClocks.elapsedRealtime();
+        final long uptimeMs = mClocks.uptimeMillis();
         for(long i = 0; i < numEvents; i++) {
-            noteLongPartialWakelockStart("name1", "historyName1", 1000);
-            noteLongPartialWakelockFinish("name1", "historyName1", 1000);
+            noteLongPartialWakelockStart("name1", "historyName1", 1000,
+                    elapsedRealtimeMs, uptimeMs);
+            noteLongPartialWakelockFinish("name1", "historyName1", 1000,
+                    elapsedRealtimeMs, uptimeMs);
         }
     }
 
-    void addHistoryBufferLocked(long elapsedRealtimeMs, HistoryItem cur) {
+    void addHistoryBufferLocked(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur) {
         if (!mHaveBatteryLevel || !mRecordingHistory) {
             return;
         }
 
-        final long timeDiff = (mHistoryBaseTime+elapsedRealtimeMs) - mHistoryLastWritten.time;
+        final long timeDiffMs = (mHistoryBaseTimeMs + elapsedRealtimeMs) - mHistoryLastWritten.time;
         final int diffStates = mHistoryLastWritten.states^(cur.states&mActiveHistoryStates);
         final int diffStates2 = mHistoryLastWritten.states2^(cur.states2&mActiveHistoryStates2);
         final int lastDiffStates = mHistoryLastWritten.states^mHistoryLastLastWritten.states;
         final int lastDiffStates2 = mHistoryLastWritten.states2^mHistoryLastLastWritten.states2;
-        if (DEBUG) Slog.i(TAG, "ADD: tdelta=" + timeDiff + " diff="
-                + Integer.toHexString(diffStates) + " lastDiff="
-                + Integer.toHexString(lastDiffStates) + " diff2="
-                + Integer.toHexString(diffStates2) + " lastDiff2="
-                + Integer.toHexString(lastDiffStates2));
+        if (DEBUG) {
+            Slog.i(TAG, "ADD: tdelta=" + timeDiffMs + " diff="
+                    + Integer.toHexString(diffStates) + " lastDiff="
+                    + Integer.toHexString(lastDiffStates) + " diff2="
+                    + Integer.toHexString(diffStates2) + " lastDiff2="
+                    + Integer.toHexString(lastDiffStates2));
+        }
         if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE
-                && timeDiff < 1000 && (diffStates&lastDiffStates) == 0
+                && timeDiffMs < 1000 && (diffStates & lastDiffStates) == 0
                 && (diffStates2&lastDiffStates2) == 0
                 && (mHistoryLastWritten.wakelockTag == null || cur.wakelockTag == null)
                 && (mHistoryLastWritten.wakeReasonTag == null || cur.wakeReasonTag == null)
@@ -3674,7 +3738,7 @@
             mHistoryBuffer.setDataSize(mHistoryBufferLastPos);
             mHistoryBuffer.setDataPosition(mHistoryBufferLastPos);
             mHistoryBufferLastPos = -1;
-            elapsedRealtimeMs = mHistoryLastWritten.time - mHistoryBaseTime;
+            elapsedRealtimeMs = mHistoryLastWritten.time - mHistoryBaseTimeMs;
             // If the last written history had a wakelock tag, we need to retain it.
             // Note that the condition above made sure that we aren't in a case where
             // both it and the current history item have a wakelock tag.
@@ -3714,11 +3778,9 @@
             mHistoryBuffer.setDataPosition(0);
             mHistoryBuffer.setDataCapacity(mConstants.MAX_HISTORY_BUFFER / 2);
             mHistoryBufferLastPos = -1;
-            final long elapsedRealtime = mClocks.elapsedRealtime();
-            final long uptime = mClocks.uptimeMillis();
             HistoryItem newItem = new HistoryItem();
             newItem.setTo(cur);
-            startRecordingHistory(elapsedRealtime, uptime, false);
+            startRecordingHistory(elapsedRealtimeMs, uptimeMs, false);
             addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_UPDATE, newItem);
             return;
         }
@@ -3737,11 +3799,11 @@
         }
         mHistoryBufferLastPos = mHistoryBuffer.dataPosition();
         mHistoryLastLastWritten.setTo(mHistoryLastWritten);
-        mHistoryLastWritten.setTo(mHistoryBaseTime + elapsedRealtimeMs, cmd, cur);
+        mHistoryLastWritten.setTo(mHistoryBaseTimeMs + elapsedRealtimeMs, cmd, cur);
         mHistoryLastWritten.states &= mActiveHistoryStates;
         mHistoryLastWritten.states2 &= mActiveHistoryStates2;
         writeHistoryDelta(mHistoryBuffer, mHistoryLastWritten, mHistoryLastLastWritten);
-        mLastHistoryElapsedRealtime = elapsedRealtimeMs;
+        mLastHistoryElapsedRealtimeMs = elapsedRealtimeMs;
         cur.wakelockTag = null;
         cur.wakeReasonTag = null;
         cur.eventCode = HistoryItem.EVENT_NONE;
@@ -3755,27 +3817,27 @@
     int mChangedStates2 = 0;
 
     void addHistoryRecordLocked(long elapsedRealtimeMs, long uptimeMs) {
-        if (mTrackRunningHistoryElapsedRealtime != 0) {
-            final long diffElapsed = elapsedRealtimeMs - mTrackRunningHistoryElapsedRealtime;
-            final long diffUptime = uptimeMs - mTrackRunningHistoryUptime;
-            if (diffUptime < (diffElapsed-20)) {
-                final long wakeElapsedTime = elapsedRealtimeMs - (diffElapsed - diffUptime);
+        if (mTrackRunningHistoryElapsedRealtimeMs != 0) {
+            final long diffElapsedMs = elapsedRealtimeMs - mTrackRunningHistoryElapsedRealtimeMs;
+            final long diffUptimeMs = uptimeMs - mTrackRunningHistoryUptimeMs;
+            if (diffUptimeMs < (diffElapsedMs - 20)) {
+                final long wakeElapsedTimeMs = elapsedRealtimeMs - (diffElapsedMs - diffUptimeMs);
                 mHistoryAddTmp.setTo(mHistoryLastWritten);
                 mHistoryAddTmp.wakelockTag = null;
                 mHistoryAddTmp.wakeReasonTag = null;
                 mHistoryAddTmp.eventCode = HistoryItem.EVENT_NONE;
                 mHistoryAddTmp.states &= ~HistoryItem.STATE_CPU_RUNNING_FLAG;
-                addHistoryRecordInnerLocked(wakeElapsedTime, mHistoryAddTmp);
+                addHistoryRecordInnerLocked(wakeElapsedTimeMs, uptimeMs, mHistoryAddTmp);
             }
         }
         mHistoryCur.states |= HistoryItem.STATE_CPU_RUNNING_FLAG;
-        mTrackRunningHistoryElapsedRealtime = elapsedRealtimeMs;
-        mTrackRunningHistoryUptime = uptimeMs;
-        addHistoryRecordInnerLocked(elapsedRealtimeMs, mHistoryCur);
+        mTrackRunningHistoryElapsedRealtimeMs = elapsedRealtimeMs;
+        mTrackRunningHistoryUptimeMs = uptimeMs;
+        addHistoryRecordInnerLocked(elapsedRealtimeMs, uptimeMs, mHistoryCur);
     }
 
-    void addHistoryRecordInnerLocked(long elapsedRealtimeMs, HistoryItem cur) {
-        addHistoryBufferLocked(elapsedRealtimeMs, cur);
+    void addHistoryRecordInnerLocked(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur) {
+        addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, cur);
 
         if (!USE_OLD_HISTORY) {
             return;
@@ -3790,13 +3852,13 @@
         // are now resetting back to their original value, then just collapse
         // into one record.
         if (mHistoryEnd != null && mHistoryEnd.cmd == HistoryItem.CMD_UPDATE
-                && (mHistoryBaseTime+elapsedRealtimeMs) < (mHistoryEnd.time+1000)
+                && (mHistoryBaseTimeMs + elapsedRealtimeMs) < (mHistoryEnd.time + 1000)
                 && ((mHistoryEnd.states^cur.states)&mChangedStates&mActiveHistoryStates) == 0
                 && ((mHistoryEnd.states2^cur.states2)&mChangedStates2&mActiveHistoryStates2) == 0) {
             // If the current is the same as the one before, then we no
             // longer need the entry.
             if (mHistoryLastEnd != null && mHistoryLastEnd.cmd == HistoryItem.CMD_UPDATE
-                    && (mHistoryBaseTime+elapsedRealtimeMs) < (mHistoryEnd.time+500)
+                    && (mHistoryBaseTimeMs + elapsedRealtimeMs) < (mHistoryEnd.time + 500)
                     && mHistoryLastEnd.sameNonEvent(cur)) {
                 mHistoryLastEnd.next = null;
                 mHistoryEnd.next = mHistoryCache;
@@ -3832,7 +3894,7 @@
         } else {
             rec = new HistoryItem();
         }
-        rec.setTo(mHistoryBaseTime + elapsedRealtimeMs, cmd, cur);
+        rec.setTo(mHistoryBaseTimeMs + elapsedRealtimeMs, cmd, cur);
 
         addHistoryRecordLocked(rec);
     }
@@ -3860,10 +3922,10 @@
             mNumHistoryItems = 0;
         }
 
-        mHistoryBaseTime = 0;
-        mLastHistoryElapsedRealtime = 0;
-        mTrackRunningHistoryElapsedRealtime = 0;
-        mTrackRunningHistoryUptime = 0;
+        mHistoryBaseTimeMs = 0;
+        mLastHistoryElapsedRealtimeMs = 0;
+        mTrackRunningHistoryElapsedRealtimeMs = 0;
+        mTrackRunningHistoryUptimeMs = 0;
 
         mHistoryBuffer.setDataSize(0);
         mHistoryBuffer.setDataPosition(0);
@@ -3879,8 +3941,8 @@
     }
 
     @GuardedBy("this")
-    public void updateTimeBasesLocked(boolean unplugged, int screenState, long uptime,
-            long realtime) {
+    public void updateTimeBasesLocked(boolean unplugged, int screenState, long uptimeUs,
+            long realtimeUs) {
         final boolean screenOff = !isScreenOn(screenState);
         final boolean updateOnBatteryTimeBase = unplugged != mOnBatteryTimeBase.isRunning();
         final boolean updateOnBatteryScreenOffTimeBase =
@@ -3888,14 +3950,15 @@
 
         if (updateOnBatteryScreenOffTimeBase || updateOnBatteryTimeBase) {
             if (updateOnBatteryScreenOffTimeBase) {
-                updateKernelWakelocksLocked();
+                updateKernelWakelocksLocked(realtimeUs);
                 updateBatteryPropertiesLocked();
             }
             // This if{} is only necessary due to SCREEN_OFF_RPM_STATS_ENABLED, which exists because
             // updateRpmStatsLocked is too slow to run each screen change. When the speed is
             // improved, remove the surrounding if{}.
             if (SCREEN_OFF_RPM_STATS_ENABLED || updateOnBatteryTimeBase) {
-                updateRpmStatsLocked(); // if either OnBattery or OnBatteryScreenOff timebase changes.
+                // if either OnBattery or OnBatteryScreenOfftimebase changes.
+                updateRpmStatsLocked(realtimeUs);
             }
             if (DEBUG_ENERGY_CPU) {
                 Slog.d(TAG, "Updating cpu time because screen is now "
@@ -3903,16 +3966,17 @@
                         + " and battery is " + (unplugged ? "on" : "off"));
             }
 
-            mOnBatteryTimeBase.setRunning(unplugged, uptime, realtime);
+            mOnBatteryTimeBase.setRunning(unplugged, uptimeUs, realtimeUs);
             if (updateOnBatteryTimeBase) {
                 for (int i = mUidStats.size() - 1; i >= 0; --i) {
-                    mUidStats.valueAt(i).updateOnBatteryBgTimeBase(uptime, realtime);
+                    mUidStats.valueAt(i).updateOnBatteryBgTimeBase(uptimeUs, realtimeUs);
                 }
             }
             if (updateOnBatteryScreenOffTimeBase) {
-                mOnBatteryScreenOffTimeBase.setRunning(unplugged && screenOff, uptime, realtime);
+                mOnBatteryScreenOffTimeBase.setRunning(unplugged && screenOff,
+                        uptimeUs, realtimeUs);
                 for (int i = mUidStats.size() - 1; i >= 0; --i) {
-                    mUidStats.valueAt(i).updateOnBatteryScreenOffBgTimeBase(uptime, realtime);
+                    mUidStats.valueAt(i).updateOnBatteryScreenOffBgTimeBase(uptimeUs, realtimeUs);
                 }
             }
         }
@@ -3931,8 +3995,14 @@
     }
 
     public void addIsolatedUidLocked(int isolatedUid, int appUid) {
+        addIsolatedUidLocked(isolatedUid, appUid,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void addIsolatedUidLocked(int isolatedUid, int appUid,
+            long elapsedRealtimeMs, long uptimeMs) {
         mIsolatedUids.put(isolatedUid, appUid);
-        final Uid u = getUidStatsLocked(appUid);
+        final Uid u = getUidStatsLocked(appUid, elapsedRealtimeMs, uptimeMs);
         u.addIsolatedUid(isolatedUid);
     }
 
@@ -3955,14 +4025,22 @@
      */
     @GuardedBy("this")
     public void removeIsolatedUidLocked(int isolatedUid) {
+        removeIsolatedUidLocked(isolatedUid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    /**
+     * @see #removeIsolatedUidLocked(int)
+     */
+    @GuardedBy("this")
+    public void removeIsolatedUidLocked(int isolatedUid, long elapsedRealtimeMs, long uptimeMs) {
         final int idx = mIsolatedUids.indexOfKey(isolatedUid);
         if (idx >= 0) {
             final int ownerUid = mIsolatedUids.valueAt(idx);
-            final Uid u = getUidStatsLocked(ownerUid);
+            final Uid u = getUidStatsLocked(ownerUid, elapsedRealtimeMs, uptimeMs);
             u.removeIsolatedUid(isolatedUid);
             mIsolatedUids.removeAt(idx);
         }
-        mPendingRemovedUids.add(new UidToRemove(isolatedUid, mClocks.elapsedRealtime()));
+        mPendingRemovedUids.add(new UidToRemove(isolatedUid, elapsedRealtimeMs));
     }
 
     public int mapUid(int uid) {
@@ -3971,26 +4049,39 @@
     }
 
     public void noteEventLocked(int code, String name, int uid) {
+        noteEventLocked(code, name, uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteEventLocked(int code, String name, int uid,
+            long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
         if (!mActiveEvents.updateState(code, name, uid, 0)) {
             return;
         }
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
-        addHistoryEventLocked(elapsedRealtime, uptime, code, name, uid);
+        addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, code, name, uid);
     }
 
     public void noteCurrentTimeChangedLocked() {
         final long currentTime = System.currentTimeMillis();
         final long elapsedRealtime = mClocks.elapsedRealtime();
         final long uptime = mClocks.uptimeMillis();
-        recordCurrentTimeChangeLocked(currentTime, elapsedRealtime, uptime);
+        noteCurrentTimeChangedLocked(currentTime, elapsedRealtime, uptime);
+    }
+
+    public void noteCurrentTimeChangedLocked(long currentTimeMs,
+            long elapsedRealtimeMs, long uptimeMs) {
+        recordCurrentTimeChangeLocked(currentTimeMs, elapsedRealtimeMs, uptimeMs);
     }
 
     public void noteProcessStartLocked(String name, int uid) {
+        noteProcessStartLocked(name, uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteProcessStartLocked(String name, int uid,
+            long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
         if (isOnBattery()) {
-            Uid u = getUidStatsLocked(uid);
+            Uid u = getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs);
             u.getProcessStatsLocked(name).incStartsLocked();
         }
         if (!mActiveEvents.updateState(HistoryItem.EVENT_PROC_START, name, uid, 0)) {
@@ -3999,28 +4090,40 @@
         if (!mRecordAllHistory) {
             return;
         }
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
-        addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PROC_START, name, uid);
+        addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_PROC_START, name, uid);
     }
 
     public void noteProcessCrashLocked(String name, int uid) {
+        noteProcessCrashLocked(name, uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteProcessCrashLocked(String name, int uid,
+            long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
         if (isOnBattery()) {
-            Uid u = getUidStatsLocked(uid);
+            Uid u = getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs);
             u.getProcessStatsLocked(name).incNumCrashesLocked();
         }
     }
 
     public void noteProcessAnrLocked(String name, int uid) {
+        noteProcessAnrLocked(name, uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteProcessAnrLocked(String name, int uid, long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
         if (isOnBattery()) {
-            Uid u = getUidStatsLocked(uid);
+            Uid u = getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs);
             u.getProcessStatsLocked(name).incNumAnrsLocked();
         }
     }
 
     public void noteUidProcessStateLocked(int uid, int state) {
+        noteUidProcessStateLocked(uid, state, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteUidProcessStateLocked(int uid, int state,
+            long elapsedRealtimeMs, long uptimeMs) {
         int parentUid = mapUid(uid);
         if (uid != parentUid) {
             // Isolated UIDs process state is already rolled up into parent, so no need to track
@@ -4032,10 +4135,16 @@
         // and isolated uids rather than only the parent uid.
         FrameworkStatsLog.write(FrameworkStatsLog.UID_PROCESS_STATE_CHANGED, uid,
                 ActivityManager.processStateAmToProto(state));
-        getUidStatsLocked(uid).updateUidProcessStateLocked(state);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .updateUidProcessStateLocked(state, elapsedRealtimeMs, uptimeMs);
     }
 
     public void noteProcessFinishLocked(String name, int uid) {
+        noteProcessFinishLocked(name, uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteProcessFinishLocked(String name, int uid,
+            long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
         if (!mActiveEvents.updateState(HistoryItem.EVENT_PROC_FINISH, name, uid, 0)) {
             return;
@@ -4043,82 +4152,120 @@
         if (!mRecordAllHistory) {
             return;
         }
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
-        addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PROC_FINISH, name, uid);
+        addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_PROC_FINISH,
+                name, uid);
     }
 
     public void noteSyncStartLocked(String name, int uid) {
+        noteSyncStartLocked(name, uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteSyncStartLocked(String name, int uid, long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
-        getUidStatsLocked(uid).noteStartSyncLocked(name, elapsedRealtime);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteStartSyncLocked(name, elapsedRealtimeMs);
         if (!mActiveEvents.updateState(HistoryItem.EVENT_SYNC_START, name, uid, 0)) {
             return;
         }
-        addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_SYNC_START, name, uid);
+        addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_SYNC_START, name, uid);
     }
 
     public void noteSyncFinishLocked(String name, int uid) {
+        noteSyncFinishLocked(name, uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteSyncFinishLocked(String name, int uid, long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
-        getUidStatsLocked(uid).noteStopSyncLocked(name, elapsedRealtime);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteStopSyncLocked(name, elapsedRealtimeMs);
         if (!mActiveEvents.updateState(HistoryItem.EVENT_SYNC_FINISH, name, uid, 0)) {
             return;
         }
-        addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_SYNC_FINISH, name, uid);
+        addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_SYNC_FINISH,
+                name, uid);
     }
 
     public void noteJobStartLocked(String name, int uid) {
+        noteJobStartLocked(name, uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteJobStartLocked(String name, int uid, long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
-        getUidStatsLocked(uid).noteStartJobLocked(name, elapsedRealtime);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteStartJobLocked(name, elapsedRealtimeMs);
         if (!mActiveEvents.updateState(HistoryItem.EVENT_JOB_START, name, uid, 0)) {
             return;
         }
-        addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_JOB_START, name, uid);
+        addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_JOB_START, name, uid);
     }
 
     public void noteJobFinishLocked(String name, int uid, int stopReason) {
+        noteJobFinishLocked(name, uid, stopReason,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteJobFinishLocked(String name, int uid, int stopReason,
+            long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
-        getUidStatsLocked(uid).noteStopJobLocked(name, elapsedRealtime, stopReason);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteStopJobLocked(name, elapsedRealtimeMs, stopReason);
         if (!mActiveEvents.updateState(HistoryItem.EVENT_JOB_FINISH, name, uid, 0)) {
             return;
         }
-        addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_JOB_FINISH, name, uid);
+        addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_JOB_FINISH, name, uid);
     }
 
     public void noteJobsDeferredLocked(int uid, int numDeferred, long sinceLast) {
+        noteJobsDeferredLocked(uid, numDeferred, sinceLast,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteJobsDeferredLocked(int uid, int numDeferred, long sinceLast,
+            long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
-        getUidStatsLocked(uid).noteJobsDeferredLocked(numDeferred, sinceLast);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteJobsDeferredLocked(numDeferred, sinceLast);
     }
 
     public void noteAlarmStartLocked(String name, WorkSource workSource, int uid) {
-        noteAlarmStartOrFinishLocked(HistoryItem.EVENT_ALARM_START, name, workSource, uid);
+        noteAlarmStartLocked(name, workSource, uid,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteAlarmStartLocked(String name, WorkSource workSource, int uid,
+            long elapsedRealtimeMs, long uptimeMs) {
+        noteAlarmStartOrFinishLocked(HistoryItem.EVENT_ALARM_START, name, workSource, uid,
+                elapsedRealtimeMs, uptimeMs);
     }
 
     public void noteAlarmFinishLocked(String name, WorkSource workSource, int uid) {
-        noteAlarmStartOrFinishLocked(HistoryItem.EVENT_ALARM_FINISH, name, workSource, uid);
+        noteAlarmFinishLocked(name, workSource, uid,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteAlarmFinishLocked(String name, WorkSource workSource, int uid,
+            long elapsedRealtimeMs, long uptimeMs) {
+        noteAlarmStartOrFinishLocked(HistoryItem.EVENT_ALARM_FINISH, name, workSource, uid,
+                elapsedRealtimeMs, uptimeMs);
     }
 
     private void noteAlarmStartOrFinishLocked(int historyItem, String name, WorkSource workSource,
             int uid) {
+        noteAlarmStartOrFinishLocked(historyItem, name, workSource, uid,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    private void noteAlarmStartOrFinishLocked(int historyItem, String name, WorkSource workSource,
+            int uid, long elapsedRealtimeMs, long uptimeMs) {
         if (!mRecordAllHistory) {
             return;
         }
 
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
-
         if (workSource != null) {
             for (int i = 0; i < workSource.size(); ++i) {
                 uid = mapUid(workSource.getUid(i));
                 if (mActiveEvents.updateState(historyItem, name, uid, 0)) {
-                    addHistoryEventLocked(elapsedRealtime, uptime, historyItem, name, uid);
+                    addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, historyItem, name, uid);
                 }
             }
 
@@ -4127,7 +4274,7 @@
                 for (int i = 0; i < workChains.size(); ++i) {
                     uid = mapUid(workChains.get(i).getAttributionUid());
                     if (mActiveEvents.updateState(historyItem, name, uid, 0)) {
-                        addHistoryEventLocked(elapsedRealtime, uptime, historyItem, name, uid);
+                        addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, historyItem, name, uid);
                     }
                 }
             }
@@ -4135,13 +4282,19 @@
             uid = mapUid(uid);
 
             if (mActiveEvents.updateState(historyItem, name, uid, 0)) {
-                addHistoryEventLocked(elapsedRealtime, uptime, historyItem, name, uid);
+                addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, historyItem, name, uid);
             }
         }
     }
 
     public void noteWakupAlarmLocked(String packageName, int uid, WorkSource workSource,
             String tag) {
+        noteWakupAlarmLocked(packageName, uid, workSource, tag,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteWakupAlarmLocked(String packageName, int uid, WorkSource workSource,
+            String tag, long elapsedRealtimeMs, long uptimeMs) {
         if (workSource != null) {
             for (int i = 0; i < workSource.size(); ++i) {
                 uid = workSource.getUid(i);
@@ -4149,7 +4302,8 @@
 
                 if (isOnBattery()) {
                     BatteryStatsImpl.Uid.Pkg pkg = getPackageStatsLocked(uid,
-                            workSourceName != null ? workSourceName : packageName);
+                            workSourceName != null ? workSourceName : packageName,
+                            elapsedRealtimeMs, uptimeMs);
                     pkg.noteWakeupAlarmLocked(tag);
                 }
             }
@@ -4161,14 +4315,16 @@
                     uid = wc.getAttributionUid();
 
                     if (isOnBattery()) {
-                        BatteryStatsImpl.Uid.Pkg pkg = getPackageStatsLocked(uid, packageName);
+                        BatteryStatsImpl.Uid.Pkg pkg = getPackageStatsLocked(uid, packageName,
+                                elapsedRealtimeMs, uptimeMs);
                         pkg.noteWakeupAlarmLocked(tag);
                     }
                 }
             }
         } else {
             if (isOnBattery()) {
-                BatteryStatsImpl.Uid.Pkg pkg = getPackageStatsLocked(uid, packageName);
+                BatteryStatsImpl.Uid.Pkg pkg = getPackageStatsLocked(uid, packageName,
+                        elapsedRealtimeMs, uptimeMs);
                 pkg.noteWakeupAlarmLocked(tag);
             }
         }
@@ -4228,7 +4384,8 @@
     public void setPretendScreenOff(boolean pretendScreenOff) {
         if (mPretendScreenOff != pretendScreenOff) {
             mPretendScreenOff = pretendScreenOff;
-            noteScreenStateLocked(pretendScreenOff ? Display.STATE_OFF : Display.STATE_ON);
+            noteScreenStateLocked(pretendScreenOff ? Display.STATE_OFF : Display.STATE_ON,
+                    mClocks.elapsedRealtime(), mClocks.uptimeMillis(), System.currentTimeMillis());
         }
     }
 
@@ -4236,19 +4393,25 @@
     private int mInitialAcquireWakeUid = -1;
 
     public void noteStartWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName,
-        int type, boolean unimportantForLogging, long elapsedRealtime, long uptime) {
+            int type, boolean unimportantForLogging) {
+        noteStartWakeLocked(uid, pid, wc, name, historyName, type, unimportantForLogging,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteStartWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName,
+            int type, boolean unimportantForLogging, long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
         if (type == WAKE_TYPE_PARTIAL) {
             // Only care about partial wake locks, since full wake locks
             // will be canceled when the user puts the screen to sleep.
-            aggregateLastWakeupUptimeLocked(uptime);
+            aggregateLastWakeupUptimeLocked(elapsedRealtimeMs, uptimeMs);
             if (historyName == null) {
                 historyName = name;
             }
             if (mRecordAllHistory) {
                 if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName,
                         uid, 0)) {
-                    addHistoryEventLocked(elapsedRealtime, uptime,
+                    addHistoryEventLocked(elapsedRealtimeMs, uptimeMs,
                             HistoryItem.EVENT_WAKE_LOCK_START, historyName, uid);
                 }
             }
@@ -4260,7 +4423,7 @@
                 mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName;
                 mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
                 mWakeLockImportant = !unimportantForLogging;
-                addHistoryRecordLocked(elapsedRealtime, uptime);
+                addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
             } else if (!mWakeLockImportant && !unimportantForLogging
                     && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE) {
                 if (mHistoryLastWritten.wakelockTag != null) {
@@ -4269,7 +4432,7 @@
                     mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
                     mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName;
                     mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
-                    addHistoryRecordLocked(elapsedRealtime, uptime);
+                    addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
                 }
                 mWakeLockImportant = true;
             }
@@ -4285,7 +4448,8 @@
                 requestWakelockCpuUpdate();
             }
 
-            getUidStatsLocked(uid).noteStartWakeLocked(pid, name, type, elapsedRealtime);
+            getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                    .noteStartWakeLocked(pid, name, type, elapsedRealtimeMs);
 
             if (wc != null) {
                 FrameworkStatsLog.write(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, wc.getUids(),
@@ -4300,7 +4464,13 @@
     }
 
     public void noteStopWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName,
-            int type, long elapsedRealtime, long uptime) {
+            int type) {
+        noteStopWakeLocked(uid, pid, wc, name, historyName, type,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteStopWakeLocked(int uid, int pid, WorkChain wc, String name, String historyName,
+            int type, long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
         if (type == WAKE_TYPE_PARTIAL) {
             mWakeLockNesting--;
@@ -4310,7 +4480,7 @@
                 }
                 if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName,
                         uid, 0)) {
-                    addHistoryEventLocked(elapsedRealtime, uptime,
+                    addHistoryEventLocked(elapsedRealtimeMs, uptimeMs,
                             HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName, uid);
                 }
             }
@@ -4320,7 +4490,7 @@
                         + Integer.toHexString(mHistoryCur.states));
                 mInitialAcquireWakeName = null;
                 mInitialAcquireWakeUid = -1;
-                addHistoryRecordLocked(elapsedRealtime, uptime);
+                addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
             }
         }
         if (uid >= 0) {
@@ -4331,7 +4501,8 @@
                 requestWakelockCpuUpdate();
             }
 
-            getUidStatsLocked(uid).noteStopWakeLocked(pid, name, type, elapsedRealtime);
+            getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                    .noteStopWakeLocked(pid, name, type, elapsedRealtimeMs);
             if (wc != null) {
                 FrameworkStatsLog.write(FrameworkStatsLog.WAKELOCK_STATE_CHANGED, wc.getUids(),
                         wc.getTags(), getPowerManagerWakeLockLevel(type), name,
@@ -4377,12 +4548,17 @@
 
     public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name,
             String historyName, int type, boolean unimportantForLogging) {
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
+        noteStartWakeFromSourceLocked(ws, pid, name, historyName, type, unimportantForLogging,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name,
+            String historyName, int type, boolean unimportantForLogging,
+            long elapsedRealtimeMs, long uptimeMs) {
         final int N = ws.size();
         for (int i=0; i<N; i++) {
             noteStartWakeLocked(ws.getUid(i), pid, null, name, historyName, type,
-                    unimportantForLogging, elapsedRealtime, uptime);
+                    unimportantForLogging, elapsedRealtimeMs, uptimeMs);
         }
 
         List<WorkChain> wcs = ws.getWorkChains();
@@ -4390,7 +4566,7 @@
             for (int i = 0; i < wcs.size(); ++i) {
                 final WorkChain wc = wcs.get(i);
                 noteStartWakeLocked(wc.getAttributionUid(), pid, wc, name, historyName, type,
-                        unimportantForLogging, elapsedRealtime, uptime);
+                        unimportantForLogging, elapsedRealtimeMs, uptimeMs);
             }
         }
     }
@@ -4398,9 +4574,15 @@
     public void noteChangeWakelockFromSourceLocked(WorkSource ws, int pid, String name,
             String historyName, int type, WorkSource newWs, int newPid, String newName,
             String newHistoryName, int newType, boolean newUnimportantForLogging) {
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
+        noteChangeWakelockFromSourceLocked(ws, pid, name, historyName, type, newWs, newPid,
+                newName, newHistoryName, newType, newUnimportantForLogging,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
 
+    public void noteChangeWakelockFromSourceLocked(WorkSource ws, int pid, String name,
+            String historyName, int type, WorkSource newWs, int newPid, String newName,
+            String newHistoryName, int newType, boolean newUnimportantForLogging,
+            long elapsedRealtimeMs, long uptimeMs) {
         List<WorkChain>[] wcs = WorkSource.diffChains(ws, newWs);
 
         // For correct semantics, we start the need worksources first, so that we won't
@@ -4411,7 +4593,7 @@
         final int NN = newWs.size();
         for (int i=0; i<NN; i++) {
             noteStartWakeLocked(newWs.getUid(i), newPid, null, newName, newHistoryName, newType,
-                    newUnimportantForLogging, elapsedRealtime, uptime);
+                    newUnimportantForLogging, elapsedRealtimeMs, uptimeMs);
         }
         if (wcs != null) {
             List<WorkChain> newChains = wcs[0];
@@ -4419,8 +4601,8 @@
                 for (int i = 0; i < newChains.size(); ++i) {
                     final WorkChain newChain = newChains.get(i);
                     noteStartWakeLocked(newChain.getAttributionUid(), newPid, newChain, newName,
-                        newHistoryName, newType, newUnimportantForLogging, elapsedRealtime,
-                        uptime);
+                            newHistoryName, newType, newUnimportantForLogging, elapsedRealtimeMs,
+                            uptimeMs);
                 }
             }
         }
@@ -4428,8 +4610,8 @@
         // Then the stops :
         final int NO = ws.size();
         for (int i=0; i<NO; i++) {
-            noteStopWakeLocked(ws.getUid(i), pid, null, name, historyName, type, elapsedRealtime,
-                    uptime);
+            noteStopWakeLocked(ws.getUid(i), pid, null, name, historyName, type, elapsedRealtimeMs,
+                    uptimeMs);
         }
         if (wcs != null) {
             List<WorkChain> goneChains = wcs[1];
@@ -4437,7 +4619,7 @@
                 for (int i = 0; i < goneChains.size(); ++i) {
                     final WorkChain goneChain = goneChains.get(i);
                     noteStopWakeLocked(goneChain.getAttributionUid(), pid, goneChain, name,
-                            historyName, type, elapsedRealtime, uptime);
+                            historyName, type, elapsedRealtimeMs, uptimeMs);
                 }
             }
         }
@@ -4445,12 +4627,16 @@
 
     public void noteStopWakeFromSourceLocked(WorkSource ws, int pid, String name,
             String historyName, int type) {
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
+        noteStopWakeFromSourceLocked(ws, pid, name, historyName, type,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteStopWakeFromSourceLocked(WorkSource ws, int pid, String name,
+            String historyName, int type, long elapsedRealtimeMs, long uptimeMs) {
         final int N = ws.size();
         for (int i=0; i<N; i++) {
-            noteStopWakeLocked(ws.getUid(i), pid, null, name, historyName, type, elapsedRealtime,
-                    uptime);
+            noteStopWakeLocked(ws.getUid(i), pid, null, name, historyName, type, elapsedRealtimeMs,
+                    uptimeMs);
         }
 
         List<WorkChain> wcs = ws.getWorkChains();
@@ -4458,22 +4644,35 @@
             for (int i = 0; i < wcs.size(); ++i) {
                 final WorkChain wc = wcs.get(i);
                 noteStopWakeLocked(wc.getAttributionUid(), pid, wc, name, historyName, type,
-                        elapsedRealtime, uptime);
+                        elapsedRealtimeMs, uptimeMs);
             }
         }
     }
 
     public void noteLongPartialWakelockStart(String name, String historyName, int uid) {
+        noteLongPartialWakelockStart(name, historyName, uid,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteLongPartialWakelockStart(String name, String historyName, int uid,
+            long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
-        noteLongPartialWakeLockStartInternal(name, historyName, uid);
+        noteLongPartialWakeLockStartInternal(name, historyName, uid, elapsedRealtimeMs, uptimeMs);
     }
 
     public void noteLongPartialWakelockStartFromSource(String name, String historyName,
             WorkSource workSource) {
+        noteLongPartialWakelockStartFromSource(name, historyName, workSource,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteLongPartialWakelockStartFromSource(String name, String historyName,
+            WorkSource workSource, long elapsedRealtimeMs, long uptimeMs) {
         final int N = workSource.size();
         for (int i = 0; i < N; ++i) {
             final int uid = mapUid(workSource.getUid(i));
-            noteLongPartialWakeLockStartInternal(name, historyName, uid);
+            noteLongPartialWakeLockStartInternal(name, historyName, uid,
+                    elapsedRealtimeMs, uptimeMs);
         }
 
         final List<WorkChain> workChains = workSource.getWorkChains();
@@ -4481,14 +4680,14 @@
             for (int i = 0; i < workChains.size(); ++i) {
                 final WorkChain workChain = workChains.get(i);
                 final int uid = workChain.getAttributionUid();
-                noteLongPartialWakeLockStartInternal(name, historyName, uid);
+                noteLongPartialWakeLockStartInternal(name, historyName, uid,
+                        elapsedRealtimeMs, uptimeMs);
             }
         }
     }
 
-    private void noteLongPartialWakeLockStartInternal(String name, String historyName, int uid) {
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
+    private void noteLongPartialWakeLockStartInternal(String name, String historyName, int uid,
+            long elapsedRealtimeMs, long uptimeMs) {
         if (historyName == null) {
             historyName = name;
         }
@@ -4496,21 +4695,34 @@
                 0)) {
             return;
         }
-        addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_LONG_WAKE_LOCK_START,
+        addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_LONG_WAKE_LOCK_START,
                 historyName, uid);
     }
 
     public void noteLongPartialWakelockFinish(String name, String historyName, int uid) {
+        noteLongPartialWakelockFinish(name, historyName, uid,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteLongPartialWakelockFinish(String name, String historyName, int uid,
+            long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
-        noteLongPartialWakeLockFinishInternal(name, historyName, uid);
+        noteLongPartialWakeLockFinishInternal(name, historyName, uid, elapsedRealtimeMs, uptimeMs);
     }
 
     public void noteLongPartialWakelockFinishFromSource(String name, String historyName,
             WorkSource workSource) {
+        noteLongPartialWakelockFinishFromSource(name, historyName, workSource,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteLongPartialWakelockFinishFromSource(String name, String historyName,
+            WorkSource workSource, long elapsedRealtimeMs, long uptimeMs) {
         final int N = workSource.size();
         for (int i = 0; i < N; ++i) {
             final int uid = mapUid(workSource.getUid(i));
-            noteLongPartialWakeLockFinishInternal(name, historyName, uid);
+            noteLongPartialWakeLockFinishInternal(name, historyName, uid,
+                    elapsedRealtimeMs, uptimeMs);
         }
 
         final List<WorkChain> workChains = workSource.getWorkChains();
@@ -4518,14 +4730,14 @@
             for (int i = 0; i < workChains.size(); ++i) {
                 final WorkChain workChain = workChains.get(i);
                 final int uid = workChain.getAttributionUid();
-                noteLongPartialWakeLockFinishInternal(name, historyName, uid);
+                noteLongPartialWakeLockFinishInternal(name, historyName, uid,
+                        elapsedRealtimeMs, uptimeMs);
             }
         }
     }
 
-    private void noteLongPartialWakeLockFinishInternal(String name, String historyName, int uid) {
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
+    private void noteLongPartialWakeLockFinishInternal(String name, String historyName, int uid,
+            long elapsedRealtimeMs, long uptimeMs) {
         if (historyName == null) {
             historyName = name;
         }
@@ -4533,33 +4745,35 @@
                 0)) {
             return;
         }
-        addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH,
+        addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH,
                 historyName, uid);
     }
 
-    void aggregateLastWakeupUptimeLocked(long uptimeMs) {
+    void aggregateLastWakeupUptimeLocked(long elapsedRealtimeMs, long uptimeMs) {
         if (mLastWakeupReason != null) {
-            long deltaUptime = uptimeMs - mLastWakeupUptimeMs;
+            long deltaUptimeMs = uptimeMs - mLastWakeupUptimeMs;
             SamplingTimer timer = getWakeupReasonTimerLocked(mLastWakeupReason);
-            timer.add(deltaUptime * 1000, 1); // time in in microseconds
+            timer.add(deltaUptimeMs * 1000, 1, elapsedRealtimeMs); // time in in microseconds
             FrameworkStatsLog.write(FrameworkStatsLog.KERNEL_WAKEUP_REPORTED, mLastWakeupReason,
-                    /* duration_usec */ deltaUptime * 1000);
+                    /* duration_usec */ deltaUptimeMs * 1000);
             mLastWakeupReason = null;
         }
     }
 
     public void noteWakeupReasonLocked(String reason) {
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
+        noteWakeupReasonLocked(reason, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteWakeupReasonLocked(String reason, long elapsedRealtimeMs, long uptimeMs) {
         if (DEBUG_HISTORY) Slog.v(TAG, "Wakeup reason \"" + reason +"\": "
                 + Integer.toHexString(mHistoryCur.states));
-        aggregateLastWakeupUptimeLocked(uptime);
+        aggregateLastWakeupUptimeLocked(elapsedRealtimeMs, uptimeMs);
         mHistoryCur.wakeReasonTag = mHistoryCur.localWakeReasonTag;
         mHistoryCur.wakeReasonTag.string = reason;
         mHistoryCur.wakeReasonTag.uid = 0;
         mLastWakeupReason = reason;
-        mLastWakeupUptimeMs = uptime;
-        addHistoryRecordLocked(elapsedRealtime, uptime);
+        mLastWakeupUptimeMs = uptimeMs;
+        addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
     }
 
     public boolean startAddingCpuLocked() {
@@ -4567,21 +4781,23 @@
         return mOnBatteryInternal;
     }
 
-    public void finishAddingCpuLocked(int totalUTime, int totalSTime, int statUserTime,
-                                      int statSystemTime, int statIOWaitTime, int statIrqTime,
-                                      int statSoftIrqTime, int statIdleTime) {
-        if (DEBUG) Slog.d(TAG, "Adding cpu: tuser=" + totalUTime + " tsys=" + totalSTime
-                + " user=" + statUserTime + " sys=" + statSystemTime
-                + " io=" + statIOWaitTime + " irq=" + statIrqTime
-                + " sirq=" + statSoftIrqTime + " idle=" + statIdleTime);
-        mCurStepCpuUserTime += totalUTime;
-        mCurStepCpuSystemTime += totalSTime;
-        mCurStepStatUserTime += statUserTime;
-        mCurStepStatSystemTime += statSystemTime;
-        mCurStepStatIOWaitTime += statIOWaitTime;
-        mCurStepStatIrqTime += statIrqTime;
-        mCurStepStatSoftIrqTime += statSoftIrqTime;
-        mCurStepStatIdleTime += statIdleTime;
+    public void finishAddingCpuLocked(int totalUTimeMs, int totalSTimeMs, int statUserTimeMs,
+                                      int statSystemTimeMs, int statIOWaitTimeMs, int statIrqTimeMs,
+                                      int statSoftIrqTimeMs, int statIdleTimeMs) {
+        if (DEBUG) {
+            Slog.d(TAG, "Adding cpu: tuser=" + totalUTimeMs + " tsys=" + totalSTimeMs
+                    + " user=" + statUserTimeMs + " sys=" + statSystemTimeMs
+                    + " io=" + statIOWaitTimeMs + " irq=" + statIrqTimeMs
+                    + " sirq=" + statSoftIrqTimeMs + " idle=" + statIdleTimeMs);
+        }
+        mCurStepCpuUserTimeMs += totalUTimeMs;
+        mCurStepCpuSystemTimeMs += totalSTimeMs;
+        mCurStepStatUserTimeMs += statUserTimeMs;
+        mCurStepStatSystemTimeMs += statSystemTimeMs;
+        mCurStepStatIOWaitTimeMs += statIOWaitTimeMs;
+        mCurStepStatIrqTimeMs += statIrqTimeMs;
+        mCurStepStatSoftIrqTimeMs += statSoftIrqTimeMs;
+        mCurStepStatIdleTimeMs += statIdleTimeMs;
     }
 
     public void noteProcessDiedLocked(int uid, int pid) {
@@ -4592,65 +4808,76 @@
         }
     }
 
-    public long getProcessWakeTime(int uid, int pid, long realtime) {
+    public long getProcessWakeTime(int uid, int pid, long realtimeMs) {
         uid = mapUid(uid);
         Uid u = mUidStats.get(uid);
         if (u != null) {
             Uid.Pid p = u.mPids.get(pid);
             if (p != null) {
-                return p.mWakeSumMs + (p.mWakeNesting > 0 ? (realtime - p.mWakeStartMs) : 0);
+                return p.mWakeSumMs + (p.mWakeNesting > 0 ? (realtimeMs - p.mWakeStartMs) : 0);
             }
         }
         return 0;
     }
 
-    public void reportExcessiveCpuLocked(int uid, String proc, long overTime, long usedTime) {
+    public void reportExcessiveCpuLocked(int uid, String proc, long overTimeMs, long usedTimeMs) {
         uid = mapUid(uid);
         Uid u = mUidStats.get(uid);
         if (u != null) {
-            u.reportExcessiveCpuLocked(proc, overTime, usedTime);
+            u.reportExcessiveCpuLocked(proc, overTimeMs, usedTimeMs);
         }
     }
 
     int mSensorNesting;
 
     public void noteStartSensorLocked(int uid, int sensor) {
+        noteStartSensorLocked(uid, sensor, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteStartSensorLocked(int uid, int sensor, long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
         if (mSensorNesting == 0) {
             mHistoryCur.states |= HistoryItem.STATE_SENSOR_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Start sensor to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
         }
         mSensorNesting++;
-        getUidStatsLocked(uid).noteStartSensor(sensor, elapsedRealtime);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteStartSensor(sensor, elapsedRealtimeMs);
     }
 
     public void noteStopSensorLocked(int uid, int sensor) {
+        noteStopSensorLocked(uid, sensor, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteStopSensorLocked(int uid, int sensor, long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
         mSensorNesting--;
         if (mSensorNesting == 0) {
             mHistoryCur.states &= ~HistoryItem.STATE_SENSOR_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Stop sensor to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
         }
-        getUidStatsLocked(uid).noteStopSensor(sensor, elapsedRealtime);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteStopSensor(sensor, elapsedRealtimeMs);
     }
 
     int mGpsNesting;
 
     public void noteGpsChangedLocked(WorkSource oldWs, WorkSource newWs) {
+        noteGpsChangedLocked(oldWs, newWs, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteGpsChangedLocked(WorkSource oldWs, WorkSource newWs,
+            long elapsedRealtimeMs, long uptimeMs) {
         for (int i = 0; i < newWs.size(); ++i) {
-            noteStartGpsLocked(newWs.getUid(i), null);
+            noteStartGpsLocked(newWs.getUid(i), null, elapsedRealtimeMs, uptimeMs);
         }
 
         for (int i = 0; i < oldWs.size(); ++i) {
-            noteStopGpsLocked((oldWs.getUid(i)), null);
+            noteStopGpsLocked((oldWs.getUid(i)), null, elapsedRealtimeMs, uptimeMs);
         }
 
         List<WorkChain>[] wcs = WorkSource.diffChains(oldWs, newWs);
@@ -4658,28 +4885,27 @@
             if (wcs[0] != null) {
                 final List<WorkChain> newChains = wcs[0];
                 for (int i = 0; i < newChains.size(); ++i) {
-                    noteStartGpsLocked(-1, newChains.get(i));
+                    noteStartGpsLocked(-1, newChains.get(i), elapsedRealtimeMs, uptimeMs);
                 }
             }
 
             if (wcs[1] != null) {
                 final List<WorkChain> goneChains = wcs[1];
                 for (int i = 0; i < goneChains.size(); ++i) {
-                    noteStopGpsLocked(-1, goneChains.get(i));
+                    noteStopGpsLocked(-1, goneChains.get(i), elapsedRealtimeMs, uptimeMs);
                 }
             }
         }
     }
 
-    private void noteStartGpsLocked(int uid, WorkChain workChain) {
+    private void noteStartGpsLocked(int uid, WorkChain workChain,
+            long elapsedRealtimeMs, long uptimeMs) {
         uid = getAttributionUid(uid, workChain);
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
         if (mGpsNesting == 0) {
             mHistoryCur.states |= HistoryItem.STATE_GPS_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Start GPS to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
         }
         mGpsNesting++;
 
@@ -4692,20 +4918,19 @@
                     FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__ON);
         }
 
-        getUidStatsLocked(uid).noteStartGps(elapsedRealtime);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs).noteStartGps(elapsedRealtimeMs);
     }
 
-    private void noteStopGpsLocked(int uid, WorkChain workChain) {
+    private void noteStopGpsLocked(int uid, WorkChain workChain,
+            long elapsedRealtimeMs, long uptimeMs) {
         uid = getAttributionUid(uid, workChain);
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
         mGpsNesting--;
         if (mGpsNesting == 0) {
             mHistoryCur.states &= ~HistoryItem.STATE_GPS_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Stop GPS to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
-            stopAllGpsSignalQualityTimersLocked(-1);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
+            stopAllGpsSignalQualityTimersLocked(-1, elapsedRealtimeMs);
             mGpsSignalQualityBin = -1;
         }
 
@@ -4717,29 +4942,31 @@
                     workChain.getTags(), FrameworkStatsLog.GPS_SCAN_STATE_CHANGED__STATE__OFF);
         }
 
-        getUidStatsLocked(uid).noteStopGps(elapsedRealtime);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs).noteStopGps(elapsedRealtimeMs);
     }
 
     public void noteGpsSignalQualityLocked(int signalLevel) {
+        noteGpsSignalQualityLocked(signalLevel, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteGpsSignalQualityLocked(int signalLevel, long elapsedRealtimeMs, long uptimeMs) {
         if (mGpsNesting == 0) {
             return;
         }
         if (signalLevel < 0 || signalLevel >= GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS) {
-            stopAllGpsSignalQualityTimersLocked(-1);
+            stopAllGpsSignalQualityTimersLocked(-1, elapsedRealtimeMs);
             return;
         }
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
         if (mGpsSignalQualityBin != signalLevel) {
             if (mGpsSignalQualityBin >= 0) {
-                mGpsSignalQualityTimer[mGpsSignalQualityBin].stopRunningLocked(elapsedRealtime);
+                mGpsSignalQualityTimer[mGpsSignalQualityBin].stopRunningLocked(elapsedRealtimeMs);
             }
             if(!mGpsSignalQualityTimer[signalLevel].isRunningLocked()) {
-                mGpsSignalQualityTimer[signalLevel].startRunningLocked(elapsedRealtime);
+                mGpsSignalQualityTimer[signalLevel].startRunningLocked(elapsedRealtimeMs);
             }
             mHistoryCur.states2 = (mHistoryCur.states2&~HistoryItem.STATE2_GPS_SIGNAL_QUALITY_MASK)
                     | (signalLevel << HistoryItem.STATE2_GPS_SIGNAL_QUALITY_SHIFT);
-            addHistoryRecordLocked(elapsedRealtime, uptime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
             mGpsSignalQualityBin = signalLevel;
         }
         return;
@@ -4747,6 +4974,13 @@
 
     @GuardedBy("this")
     public void noteScreenStateLocked(int state) {
+        noteScreenStateLocked(state, mClocks.elapsedRealtime(), mClocks.uptimeMillis(),
+                System.currentTimeMillis());
+    }
+
+    @GuardedBy("this")
+    public void noteScreenStateLocked(int state,
+            long elapsedRealtimeMs, long uptimeMs, long currentTimeMs) {
         state = mPretendScreenOff ? Display.STATE_OFF : state;
 
         // Battery stats relies on there being 4 states. To accommodate this, new states beyond the
@@ -4763,7 +4997,7 @@
         }
 
         if (mScreenState != state) {
-            recordDailyStatsIfNeededLocked(true);
+            recordDailyStatsIfNeededLocked(true, currentTimeMs);
             final int oldState = mScreenState;
             mScreenState = state;
             if (DEBUG) Slog.v(TAG, "Screen state: oldState=" + Display.stateToString(oldState)
@@ -4779,56 +5013,55 @@
                 }
             }
 
-            final long elapsedRealtime = mClocks.elapsedRealtime();
-            final long uptime = mClocks.uptimeMillis();
-
             boolean updateHistory = false;
             if (isScreenDoze(state) && !isScreenDoze(oldState)) {
                 mHistoryCur.states |= HistoryItem.STATE_SCREEN_DOZE_FLAG;
-                mScreenDozeTimer.startRunningLocked(elapsedRealtime);
+                mScreenDozeTimer.startRunningLocked(elapsedRealtimeMs);
                 updateHistory = true;
             } else if (isScreenDoze(oldState) && !isScreenDoze(state)) {
                 mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_DOZE_FLAG;
-                mScreenDozeTimer.stopRunningLocked(elapsedRealtime);
+                mScreenDozeTimer.stopRunningLocked(elapsedRealtimeMs);
                 updateHistory = true;
             }
             if (isScreenOn(state)) {
                 mHistoryCur.states |= HistoryItem.STATE_SCREEN_ON_FLAG;
                 if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: "
                         + Integer.toHexString(mHistoryCur.states));
-                mScreenOnTimer.startRunningLocked(elapsedRealtime);
+                mScreenOnTimer.startRunningLocked(elapsedRealtimeMs);
                 if (mScreenBrightnessBin >= 0) {
-                    mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(elapsedRealtime);
+                    mScreenBrightnessTimer[mScreenBrightnessBin]
+                            .startRunningLocked(elapsedRealtimeMs);
                 }
                 updateHistory = true;
             } else if (isScreenOn(oldState)) {
                 mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_ON_FLAG;
                 if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: "
                         + Integer.toHexString(mHistoryCur.states));
-                mScreenOnTimer.stopRunningLocked(elapsedRealtime);
+                mScreenOnTimer.stopRunningLocked(elapsedRealtimeMs);
                 if (mScreenBrightnessBin >= 0) {
-                    mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(elapsedRealtime);
+                    mScreenBrightnessTimer[mScreenBrightnessBin]
+                            .stopRunningLocked(elapsedRealtimeMs);
                 }
                 updateHistory = true;
             }
             if (updateHistory) {
                 if (DEBUG_HISTORY) Slog.v(TAG, "Screen state to: "
                         + Display.stateToString(state));
-                addHistoryRecordLocked(elapsedRealtime, uptime);
+                addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
             }
             mExternalSync.scheduleCpuSyncDueToScreenStateChange(
                     mOnBatteryTimeBase.isRunning(), mOnBatteryScreenOffTimeBase.isRunning());
             if (isScreenOn(state)) {
                 updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), state,
-                        mClocks.uptimeMillis() * 1000, elapsedRealtime * 1000);
+                        uptimeMs * 1000, elapsedRealtimeMs * 1000);
                 // Fake a wake lock, so we consider the device waked as long as the screen is on.
                 noteStartWakeLocked(-1, -1, null, "screen", null, WAKE_TYPE_PARTIAL, false,
-                        elapsedRealtime, uptime);
+                        elapsedRealtimeMs, uptimeMs);
             } else if (isScreenOn(oldState)) {
                 noteStopWakeLocked(-1, -1, null, "screen", "screen", WAKE_TYPE_PARTIAL,
-                        elapsedRealtime, uptime);
+                        elapsedRealtimeMs, uptimeMs);
                 updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), state,
-                        mClocks.uptimeMillis() * 1000, elapsedRealtime * 1000);
+                        uptimeMs * 1000, elapsedRealtimeMs * 1000);
             }
             // Update discharge amounts.
             if (mOnBatteryInternal) {
@@ -4839,23 +5072,27 @@
 
     @UnsupportedAppUsage
     public void noteScreenBrightnessLocked(int brightness) {
+        noteScreenBrightnessLocked(brightness, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteScreenBrightnessLocked(int brightness, long elapsedRealtimeMs, long uptimeMs) {
         // Bin the brightness.
         int bin = brightness / (256/NUM_SCREEN_BRIGHTNESS_BINS);
         if (bin < 0) bin = 0;
         else if (bin >= NUM_SCREEN_BRIGHTNESS_BINS) bin = NUM_SCREEN_BRIGHTNESS_BINS-1;
         if (mScreenBrightnessBin != bin) {
-            final long elapsedRealtime = mClocks.elapsedRealtime();
-            final long uptime = mClocks.uptimeMillis();
             mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_BRIGHTNESS_MASK)
                     | (bin << HistoryItem.STATE_BRIGHTNESS_SHIFT);
             if (DEBUG_HISTORY) Slog.v(TAG, "Screen brightness " + bin + " to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
             if (mScreenState == Display.STATE_ON) {
                 if (mScreenBrightnessBin >= 0) {
-                    mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(elapsedRealtime);
+                    mScreenBrightnessTimer[mScreenBrightnessBin]
+                            .stopRunningLocked(elapsedRealtimeMs);
                 }
-                mScreenBrightnessTimer[bin].startRunningLocked(elapsedRealtime);
+                mScreenBrightnessTimer[bin]
+                        .startRunningLocked(elapsedRealtimeMs);
             }
             mScreenBrightnessBin = bin;
         }
@@ -4863,36 +5100,50 @@
 
     @UnsupportedAppUsage
     public void noteUserActivityLocked(int uid, int event) {
+        noteUserActivityLocked(uid, event, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteUserActivityLocked(int uid, int event, long elapsedRealtimeMs, long uptimeMs) {
         if (mOnBatteryInternal) {
             uid = mapUid(uid);
-            getUidStatsLocked(uid).noteUserActivityLocked(event);
+            getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs).noteUserActivityLocked(event);
         }
     }
 
     public void noteWakeUpLocked(String reason, int reasonUid) {
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
-        addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_SCREEN_WAKE_UP,
+        noteWakeUpLocked(reason, reasonUid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteWakeUpLocked(String reason, int reasonUid,
+            long elapsedRealtimeMs, long uptimeMs) {
+        addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_SCREEN_WAKE_UP,
                 reason, reasonUid);
     }
 
     public void noteInteractiveLocked(boolean interactive) {
+        noteInteractiveLocked(interactive, mClocks.elapsedRealtime());
+    }
+
+    public void noteInteractiveLocked(boolean interactive, long elapsedRealtimeMs) {
         if (mInteractive != interactive) {
-            final long elapsedRealtime = mClocks.elapsedRealtime();
             mInteractive = interactive;
             if (DEBUG) Slog.v(TAG, "Interactive: " + interactive);
             if (interactive) {
-                mInteractiveTimer.startRunningLocked(elapsedRealtime);
+                mInteractiveTimer.startRunningLocked(elapsedRealtimeMs);
             } else {
-                mInteractiveTimer.stopRunningLocked(elapsedRealtime);
+                mInteractiveTimer.stopRunningLocked(elapsedRealtimeMs);
             }
         }
     }
 
     public void noteConnectivityChangedLocked(int type, String extra) {
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
-        addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_CONNECTIVITY_CHANGED,
+        noteConnectivityChangedLocked(type, extra,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteConnectivityChangedLocked(int type, String extra,
+            long elapsedRealtimeMs, long uptimeMs) {
+        addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_CONNECTIVITY_CHANGED,
                 extra, type);
         mNumConnectivityChange++;
     }
@@ -4902,15 +5153,19 @@
         uid = mapUid(uid);
         addHistoryEventLocked(elapsedRealtimeMillis, uptimeMillis, HistoryItem.EVENT_WAKEUP_AP, "",
                 uid);
-        getUidStatsLocked(uid).noteMobileRadioApWakeupLocked();
+        getUidStatsLocked(uid, elapsedRealtimeMillis, uptimeMillis).noteMobileRadioApWakeupLocked();
     }
 
     /**
      * Updates the radio power state and returns true if an external stats collection should occur.
      */
     public boolean noteMobileRadioPowerStateLocked(int powerState, long timestampNs, int uid) {
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
+        return noteMobileRadioPowerStateLocked(powerState, timestampNs, uid,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public boolean noteMobileRadioPowerStateLocked(int powerState, long timestampNs, int uid,
+            long elapsedRealtimeMs, long uptimeMs) {
         if (mMobileRadioPowerState != powerState) {
             long realElapsedRealtimeMs;
             final boolean active =
@@ -4918,31 +5173,31 @@
                             || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
             if (active) {
                 if (uid > 0) {
-                    noteMobileRadioApWakeupLocked(elapsedRealtime, uptime, uid);
+                    noteMobileRadioApWakeupLocked(elapsedRealtimeMs, uptimeMs, uid);
                 }
 
-                mMobileRadioActiveStartTime = realElapsedRealtimeMs = timestampNs / (1000 * 1000);
+                mMobileRadioActiveStartTimeMs = realElapsedRealtimeMs = timestampNs / (1000 * 1000);
                 mHistoryCur.states |= HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
             } else {
                 realElapsedRealtimeMs = timestampNs / (1000*1000);
-                long lastUpdateTimeMs = mMobileRadioActiveStartTime;
+                long lastUpdateTimeMs = mMobileRadioActiveStartTimeMs;
                 if (realElapsedRealtimeMs < lastUpdateTimeMs) {
                     Slog.wtf(TAG, "Data connection inactive timestamp " + realElapsedRealtimeMs
                             + " is before start time " + lastUpdateTimeMs);
-                    realElapsedRealtimeMs = elapsedRealtime;
-                } else if (realElapsedRealtimeMs < elapsedRealtime) {
-                    mMobileRadioActiveAdjustedTime.addCountLocked(elapsedRealtime
+                    realElapsedRealtimeMs = elapsedRealtimeMs;
+                } else if (realElapsedRealtimeMs < elapsedRealtimeMs) {
+                    mMobileRadioActiveAdjustedTime.addCountLocked(elapsedRealtimeMs
                             - realElapsedRealtimeMs);
                 }
                 mHistoryCur.states &= ~HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
             }
             if (DEBUG_HISTORY) Slog.v(TAG, "Mobile network active " + active + " to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
             mMobileRadioPowerState = powerState;
             if (active) {
-                mMobileRadioActiveTimer.startRunningLocked(elapsedRealtime);
-                mMobileRadioActivePerAppTimer.startRunningLocked(elapsedRealtime);
+                mMobileRadioActiveTimer.startRunningLocked(elapsedRealtimeMs);
+                mMobileRadioActivePerAppTimer.startRunningLocked(elapsedRealtimeMs);
             } else {
                 mMobileRadioActiveTimer.stopRunningLocked(realElapsedRealtimeMs);
                 mMobileRadioActivePerAppTimer.stopRunningLocked(realElapsedRealtimeMs);
@@ -4954,25 +5209,27 @@
     }
 
     public void notePowerSaveModeLocked(boolean enabled) {
+        notePowerSaveModeLocked(enabled, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void notePowerSaveModeLocked(boolean enabled, long elapsedRealtimeMs, long uptimeMs) {
         if (mPowerSaveModeEnabled != enabled) {
             int stepState = enabled ? STEP_LEVEL_MODE_POWER_SAVE : 0;
             mModStepMode |= (mCurStepMode&STEP_LEVEL_MODE_POWER_SAVE) ^ stepState;
             mCurStepMode = (mCurStepMode&~STEP_LEVEL_MODE_POWER_SAVE) | stepState;
-            final long elapsedRealtime = mClocks.elapsedRealtime();
-            final long uptime = mClocks.uptimeMillis();
             mPowerSaveModeEnabled = enabled;
             if (enabled) {
                 mHistoryCur.states2 |= HistoryItem.STATE2_POWER_SAVE_FLAG;
                 if (DEBUG_HISTORY) Slog.v(TAG, "Power save mode enabled to: "
                         + Integer.toHexString(mHistoryCur.states2));
-                mPowerSaveModeEnabledTimer.startRunningLocked(elapsedRealtime);
+                mPowerSaveModeEnabledTimer.startRunningLocked(elapsedRealtimeMs);
             } else {
                 mHistoryCur.states2 &= ~HistoryItem.STATE2_POWER_SAVE_FLAG;
                 if (DEBUG_HISTORY) Slog.v(TAG, "Power save mode disabled to: "
                         + Integer.toHexString(mHistoryCur.states2));
-                mPowerSaveModeEnabledTimer.stopRunningLocked(elapsedRealtime);
+                mPowerSaveModeEnabledTimer.stopRunningLocked(elapsedRealtimeMs);
             }
-            addHistoryRecordLocked(elapsedRealtime, uptime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
             FrameworkStatsLog.write(FrameworkStatsLog.BATTERY_SAVER_MODE_STATE_CHANGED,
                     enabled
                         ? FrameworkStatsLog.BATTERY_SAVER_MODE_STATE_CHANGED__STATE__ON
@@ -4981,8 +5238,12 @@
     }
 
     public void noteDeviceIdleModeLocked(final int mode, String activeReason, int activeUid) {
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
+        noteDeviceIdleModeLocked(mode, activeReason, activeUid,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteDeviceIdleModeLocked(final int mode, String activeReason, int activeUid,
+            long elapsedRealtimeMs, long uptimeMs) {
         boolean nowIdling = mode == DEVICE_IDLE_MODE_DEEP;
         if (mDeviceIdling && !nowIdling && activeReason == null) {
             // We don't go out of general idling mode until explicitly taken out of
@@ -4996,7 +5257,7 @@
             nowLightIdling = true;
         }
         if (activeReason != null && (mDeviceIdling || mDeviceLightIdling)) {
-            addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_ACTIVE,
+            addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_ACTIVE,
                     activeReason, activeUid);
         }
         if (mDeviceIdling != nowIdling || mDeviceLightIdling != nowLightIdling) {
@@ -5012,17 +5273,17 @@
             mModStepMode |= (mCurStepMode&STEP_LEVEL_MODE_DEVICE_IDLE) ^ stepState;
             mCurStepMode = (mCurStepMode&~STEP_LEVEL_MODE_DEVICE_IDLE) | stepState;
             if (nowIdling) {
-                mDeviceIdlingTimer.startRunningLocked(elapsedRealtime);
+                mDeviceIdlingTimer.startRunningLocked(elapsedRealtimeMs);
             } else {
-                mDeviceIdlingTimer.stopRunningLocked(elapsedRealtime);
+                mDeviceIdlingTimer.stopRunningLocked(elapsedRealtimeMs);
             }
         }
         if (mDeviceLightIdling != nowLightIdling) {
             mDeviceLightIdling = nowLightIdling;
             if (nowLightIdling) {
-                mDeviceLightIdlingTimer.startRunningLocked(elapsedRealtime);
+                mDeviceLightIdlingTimer.startRunningLocked(elapsedRealtimeMs);
             } else {
-                mDeviceLightIdlingTimer.stopRunningLocked(elapsedRealtime);
+                mDeviceLightIdlingTimer.stopRunningLocked(elapsedRealtimeMs);
             }
         }
         if (mDeviceIdleMode != mode) {
@@ -5030,24 +5291,24 @@
                     | (mode << HistoryItem.STATE2_DEVICE_IDLE_SHIFT);
             if (DEBUG_HISTORY) Slog.v(TAG, "Device idle mode changed to: "
                     + Integer.toHexString(mHistoryCur.states2));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
-            long lastDuration = elapsedRealtime - mLastIdleTimeStart;
-            mLastIdleTimeStart = elapsedRealtime;
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
+            long lastDuration = elapsedRealtimeMs - mLastIdleTimeStartMs;
+            mLastIdleTimeStartMs = elapsedRealtimeMs;
             if (mDeviceIdleMode == DEVICE_IDLE_MODE_LIGHT) {
-                if (lastDuration > mLongestLightIdleTime) {
-                    mLongestLightIdleTime = lastDuration;
+                if (lastDuration > mLongestLightIdleTimeMs) {
+                    mLongestLightIdleTimeMs = lastDuration;
                 }
-                mDeviceIdleModeLightTimer.stopRunningLocked(elapsedRealtime);
+                mDeviceIdleModeLightTimer.stopRunningLocked(elapsedRealtimeMs);
             } else if (mDeviceIdleMode == DEVICE_IDLE_MODE_DEEP) {
-                if (lastDuration > mLongestFullIdleTime) {
-                    mLongestFullIdleTime = lastDuration;
+                if (lastDuration > mLongestFullIdleTimeMs) {
+                    mLongestFullIdleTimeMs = lastDuration;
                 }
-                mDeviceIdleModeFullTimer.stopRunningLocked(elapsedRealtime);
+                mDeviceIdleModeFullTimer.stopRunningLocked(elapsedRealtimeMs);
             }
             if (mode == DEVICE_IDLE_MODE_LIGHT) {
-                mDeviceIdleModeLightTimer.startRunningLocked(elapsedRealtime);
+                mDeviceIdleModeLightTimer.startRunningLocked(elapsedRealtimeMs);
             } else if (mode == DEVICE_IDLE_MODE_DEEP) {
-                mDeviceIdleModeFullTimer.startRunningLocked(elapsedRealtime);
+                mDeviceIdleModeFullTimer.startRunningLocked(elapsedRealtimeMs);
             }
             mDeviceIdleMode = mode;
             FrameworkStatsLog.write(FrameworkStatsLog.DEVICE_IDLE_MODE_STATE_CHANGED, mode);
@@ -5055,10 +5316,14 @@
     }
 
     public void notePackageInstalledLocked(String pkgName, long versionCode) {
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
+        notePackageInstalledLocked(pkgName, versionCode,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void notePackageInstalledLocked(String pkgName, long versionCode,
+            long elapsedRealtimeMs, long uptimeMs) {
         // XXX need to figure out what to do with long version codes.
-        addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PACKAGE_INSTALLED,
+        addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.EVENT_PACKAGE_INSTALLED,
                 pkgName, (int)versionCode);
         PackageChange pc = new PackageChange();
         pc.mPackageName = pkgName;
@@ -5068,10 +5333,13 @@
     }
 
     public void notePackageUninstalledLocked(String pkgName) {
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
-        addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PACKAGE_UNINSTALLED,
-                pkgName, 0);
+        notePackageUninstalledLocked(pkgName, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void notePackageUninstalledLocked(String pkgName,
+            long elapsedRealtimeMs, long uptimeMs) {
+        addHistoryEventLocked(elapsedRealtimeMs, uptimeMs,
+                HistoryItem.EVENT_PACKAGE_UNINSTALLED, pkgName, 0);
         PackageChange pc = new PackageChange();
         pc.mPackageName = pkgName;
         pc.mUpdate = true;
@@ -5086,42 +5354,49 @@
     }
 
     void stopAllGpsSignalQualityTimersLocked(int except) {
-        final long elapsedRealtime = mClocks.elapsedRealtime();
+        stopAllGpsSignalQualityTimersLocked(except, mClocks.elapsedRealtime());
+    }
+
+    void stopAllGpsSignalQualityTimersLocked(int except, long elapsedRealtimeMs) {
         for (int i = 0; i < GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
             if (i == except) {
                 continue;
             }
             while (mGpsSignalQualityTimer[i].isRunningLocked()) {
-                mGpsSignalQualityTimer[i].stopRunningLocked(elapsedRealtime);
+                mGpsSignalQualityTimer[i].stopRunningLocked(elapsedRealtimeMs);
             }
         }
     }
 
     @UnsupportedAppUsage
     public void notePhoneOnLocked() {
+        notePhoneOnLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void notePhoneOnLocked(long elapsedRealtimeMs, long uptimeMs) {
         if (!mPhoneOn) {
-            final long elapsedRealtime = mClocks.elapsedRealtime();
-            final long uptime = mClocks.uptimeMillis();
             mHistoryCur.states2 |= HistoryItem.STATE2_PHONE_IN_CALL_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Phone on to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
             mPhoneOn = true;
-            mPhoneOnTimer.startRunningLocked(elapsedRealtime);
+            mPhoneOnTimer.startRunningLocked(elapsedRealtimeMs);
         }
     }
 
     @UnsupportedAppUsage
     public void notePhoneOffLocked() {
+        notePhoneOffLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void notePhoneOffLocked(long elapsedRealtimeMs, long uptimeMs) {
         if (mPhoneOn) {
-            final long elapsedRealtime = mClocks.elapsedRealtime();
-            final long uptime = mClocks.uptimeMillis();
             mHistoryCur.states2 &= ~HistoryItem.STATE2_PHONE_IN_CALL_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Phone off to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
             mPhoneOn = false;
-            mPhoneOnTimer.stopRunningLocked(elapsedRealtime);
+            mPhoneOnTimer.stopRunningLocked(elapsedRealtimeMs);
         }
     }
 
@@ -5133,7 +5408,8 @@
             public void onReceive(Context context, Intent intent) {
                 final boolean state = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
                 synchronized (BatteryStatsImpl.this) {
-                    noteUsbConnectionStateLocked(state);
+                    noteUsbConnectionStateLocked(state, mClocks.elapsedRealtime(),
+                            mClocks.uptimeMillis());
                 }
             }
         }, usbStateFilter);
@@ -5142,12 +5418,14 @@
                 final Intent usbState = context.registerReceiver(null, usbStateFilter);
                 final boolean initState = usbState != null && usbState.getBooleanExtra(
                         UsbManager.USB_CONNECTED, false);
-                noteUsbConnectionStateLocked(initState);
+                noteUsbConnectionStateLocked(initState, mClocks.elapsedRealtime(),
+                        mClocks.uptimeMillis());
             }
         }
     }
 
-    private void noteUsbConnectionStateLocked(boolean connected) {
+    private void noteUsbConnectionStateLocked(boolean connected, long elapsedRealtimeMs,
+            long uptimeMs) {
         int newState = connected ? USB_DATA_CONNECTED : USB_DATA_DISCONNECTED;
         if (mUsbDataState != newState) {
             mUsbDataState = newState;
@@ -5156,18 +5434,17 @@
             } else {
                 mHistoryCur.states2 &= ~HistoryItem.STATE2_USB_DATA_LINK_FLAG;
             }
-            addHistoryRecordLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
         }
     }
 
-    void stopAllPhoneSignalStrengthTimersLocked(int except) {
-        final long elapsedRealtime = mClocks.elapsedRealtime();
+    void stopAllPhoneSignalStrengthTimersLocked(int except, long elapsedRealtimeMs) {
         for (int i = 0; i < CellSignalStrength.getNumSignalStrengthLevels(); i++) {
             if (i == except) {
                 continue;
             }
             while (mPhoneSignalStrengthsTimer[i].isRunningLocked()) {
-                mPhoneSignalStrengthsTimer[i].stopRunningLocked(elapsedRealtime);
+                mPhoneSignalStrengthsTimer[i].stopRunningLocked(elapsedRealtimeMs);
             }
         }
     }
@@ -5185,7 +5462,8 @@
         return state;
     }
 
-    private void updateAllPhoneStateLocked(int state, int simState, int strengthBin) {
+    private void updateAllPhoneStateLocked(int state, int simState, int strengthBin,
+            long elapsedRealtimeMs, long uptimeMs) {
         boolean scanning = false;
         boolean newHistory = false;
 
@@ -5193,9 +5471,6 @@
         mPhoneSimStateRaw = simState;
         mPhoneSignalStrengthBinRaw = strengthBin;
 
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
-
         if (simState == TelephonyManager.SIM_STATE_ABSENT) {
             // In this case we will always be STATE_OUT_OF_SERVICE, so need
             // to infer that we are scanning from other data.
@@ -5223,7 +5498,7 @@
                 newHistory = true;
                 if (DEBUG_HISTORY) Slog.v(TAG, "Phone started scanning to: "
                         + Integer.toHexString(mHistoryCur.states));
-                mPhoneSignalScanningTimer.startRunningLocked(elapsedRealtime);
+                mPhoneSignalScanningTimer.startRunningLocked(elapsedRealtimeMs);
                 FrameworkStatsLog.write(FrameworkStatsLog.PHONE_SERVICE_STATE_CHANGED, state,
                         simState, strengthBin);
             }
@@ -5236,7 +5511,7 @@
                 if (DEBUG_HISTORY) Slog.v(TAG, "Phone stopped scanning to: "
                         + Integer.toHexString(mHistoryCur.states));
                 newHistory = true;
-                mPhoneSignalScanningTimer.stopRunningLocked(elapsedRealtime);
+                mPhoneSignalScanningTimer.stopRunningLocked(elapsedRealtimeMs);
                 FrameworkStatsLog.write(FrameworkStatsLog.PHONE_SERVICE_STATE_CHANGED, state,
                         simState, strengthBin);
             }
@@ -5254,13 +5529,14 @@
         if (mPhoneSignalStrengthBin != strengthBin) {
             if (mPhoneSignalStrengthBin >= 0) {
                 mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].stopRunningLocked(
-                        elapsedRealtime);
+                        elapsedRealtimeMs);
             }
             if (strengthBin >= 0) {
                 if (!mPhoneSignalStrengthsTimer[strengthBin].isRunningLocked()) {
-                    mPhoneSignalStrengthsTimer[strengthBin].startRunningLocked(elapsedRealtime);
+                    mPhoneSignalStrengthsTimer[strengthBin].startRunningLocked(elapsedRealtimeMs);
                 }
-                mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_MASK)
+                mHistoryCur.states =
+                        (mHistoryCur.states & ~HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_MASK)
                         | (strengthBin << HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_SHIFT);
                 if (DEBUG_HISTORY) Slog.v(TAG, "Signal strength " + strengthBin + " to: "
                         + Integer.toHexString(mHistoryCur.states));
@@ -5268,13 +5544,13 @@
                 FrameworkStatsLog.write(
                         FrameworkStatsLog.PHONE_SIGNAL_STRENGTH_CHANGED, strengthBin);
             } else {
-                stopAllPhoneSignalStrengthTimersLocked(-1);
+                stopAllPhoneSignalStrengthTimersLocked(-1, elapsedRealtimeMs);
             }
             mPhoneSignalStrengthBin = strengthBin;
         }
 
         if (newHistory) {
-            addHistoryRecordLocked(elapsedRealtime, uptime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
         }
     }
 
@@ -5283,18 +5559,37 @@
      * @param state phone state from ServiceState.getState()
      */
     public void notePhoneStateLocked(int state, int simState) {
-        updateAllPhoneStateLocked(state, simState, mPhoneSignalStrengthBinRaw);
+        notePhoneStateLocked(state, simState, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void notePhoneStateLocked(int state, int simState,
+            long elapsedRealtimeMs, long uptimeMs) {
+        updateAllPhoneStateLocked(state, simState, mPhoneSignalStrengthBinRaw,
+                elapsedRealtimeMs, uptimeMs);
     }
 
     @UnsupportedAppUsage
     public void notePhoneSignalStrengthLocked(SignalStrength signalStrength) {
+        notePhoneSignalStrengthLocked(signalStrength,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void notePhoneSignalStrengthLocked(SignalStrength signalStrength,
+            long elapsedRealtimeMs, long uptimeMs) {
         // Bin the strength.
         int bin = signalStrength.getLevel();
-        updateAllPhoneStateLocked(mPhoneServiceStateRaw, mPhoneSimStateRaw, bin);
+        updateAllPhoneStateLocked(mPhoneServiceStateRaw, mPhoneSimStateRaw, bin,
+                elapsedRealtimeMs, uptimeMs);
     }
 
     @UnsupportedAppUsage
     public void notePhoneDataConnectionStateLocked(int dataType, boolean hasData, int serviceType) {
+        notePhoneDataConnectionStateLocked(dataType, hasData, serviceType,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void notePhoneDataConnectionStateLocked(int dataType, boolean hasData, int serviceType,
+            long elapsedRealtimeMs, long uptimeMs) {
         // BatteryStats uses 0 to represent no network type.
         // Telephony does not have a concept of no network type, and uses 0 to represent unknown.
         // Unknown is included in DATA_CONNECTION_OTHER.
@@ -5318,312 +5613,374 @@
         }
         if (DEBUG) Log.i(TAG, "Phone Data Connection -> " + dataType + " = " + hasData);
         if (mPhoneDataConnectionType != bin) {
-            final long elapsedRealtime = mClocks.elapsedRealtime();
-            final long uptime = mClocks.uptimeMillis();
             mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_DATA_CONNECTION_MASK)
                     | (bin << HistoryItem.STATE_DATA_CONNECTION_SHIFT);
             if (DEBUG_HISTORY) Slog.v(TAG, "Data connection " + bin + " to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
             if (mPhoneDataConnectionType >= 0) {
                 mPhoneDataConnectionsTimer[mPhoneDataConnectionType].stopRunningLocked(
-                        elapsedRealtime);
+                        elapsedRealtimeMs);
             }
             mPhoneDataConnectionType = bin;
-            mPhoneDataConnectionsTimer[bin].startRunningLocked(elapsedRealtime);
+            mPhoneDataConnectionsTimer[bin].startRunningLocked(elapsedRealtimeMs);
         }
     }
 
     public void noteWifiOnLocked() {
+        noteWifiOnLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteWifiOnLocked(long elapsedRealtimeMs, long uptimeMs) {
         if (!mWifiOn) {
-            final long elapsedRealtime = mClocks.elapsedRealtime();
-            final long uptime = mClocks.uptimeMillis();
             mHistoryCur.states2 |= HistoryItem.STATE2_WIFI_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI on to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
             mWifiOn = true;
-            mWifiOnTimer.startRunningLocked(elapsedRealtime);
+            mWifiOnTimer.startRunningLocked(elapsedRealtimeMs);
             scheduleSyncExternalStatsLocked("wifi-off", ExternalStatsSync.UPDATE_WIFI);
         }
     }
 
     public void noteWifiOffLocked() {
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
+        noteWifiOffLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteWifiOffLocked(long elapsedRealtimeMs, long uptimeMs) {
         if (mWifiOn) {
             mHistoryCur.states2 &= ~HistoryItem.STATE2_WIFI_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI off to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
             mWifiOn = false;
-            mWifiOnTimer.stopRunningLocked(elapsedRealtime);
+            mWifiOnTimer.stopRunningLocked(elapsedRealtimeMs);
             scheduleSyncExternalStatsLocked("wifi-on", ExternalStatsSync.UPDATE_WIFI);
         }
     }
 
     @UnsupportedAppUsage
     public void noteAudioOnLocked(int uid) {
+        noteAudioOnLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteAudioOnLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
         if (mAudioOnNesting == 0) {
             mHistoryCur.states |= HistoryItem.STATE_AUDIO_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Audio on to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
-            mAudioOnTimer.startRunningLocked(elapsedRealtime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
+            mAudioOnTimer.startRunningLocked(elapsedRealtimeMs);
         }
         mAudioOnNesting++;
-        getUidStatsLocked(uid).noteAudioTurnedOnLocked(elapsedRealtime);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteAudioTurnedOnLocked(elapsedRealtimeMs);
     }
 
     @UnsupportedAppUsage
     public void noteAudioOffLocked(int uid) {
+        noteAudioOffLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteAudioOffLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
         if (mAudioOnNesting == 0) {
             return;
         }
         uid = mapUid(uid);
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
         if (--mAudioOnNesting == 0) {
             mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
-            mAudioOnTimer.stopRunningLocked(elapsedRealtime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
+            mAudioOnTimer.stopRunningLocked(elapsedRealtimeMs);
         }
-        getUidStatsLocked(uid).noteAudioTurnedOffLocked(elapsedRealtime);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteAudioTurnedOffLocked(elapsedRealtimeMs);
     }
 
     @UnsupportedAppUsage
     public void noteVideoOnLocked(int uid) {
+        noteVideoOnLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteVideoOnLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
         if (mVideoOnNesting == 0) {
             mHistoryCur.states2 |= HistoryItem.STATE2_VIDEO_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Video on to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
-            mVideoOnTimer.startRunningLocked(elapsedRealtime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
+            mVideoOnTimer.startRunningLocked(elapsedRealtimeMs);
         }
         mVideoOnNesting++;
-        getUidStatsLocked(uid).noteVideoTurnedOnLocked(elapsedRealtime);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteVideoTurnedOnLocked(elapsedRealtimeMs);
     }
 
     @UnsupportedAppUsage
     public void noteVideoOffLocked(int uid) {
+        noteVideoOffLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteVideoOffLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
         if (mVideoOnNesting == 0) {
             return;
         }
         uid = mapUid(uid);
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
         if (--mVideoOnNesting == 0) {
             mHistoryCur.states2 &= ~HistoryItem.STATE2_VIDEO_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
-            mVideoOnTimer.stopRunningLocked(elapsedRealtime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
+            mVideoOnTimer.stopRunningLocked(elapsedRealtimeMs);
         }
-        getUidStatsLocked(uid).noteVideoTurnedOffLocked(elapsedRealtime);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteVideoTurnedOffLocked(elapsedRealtimeMs);
     }
 
     public void noteResetAudioLocked() {
+        noteResetAudioLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteResetAudioLocked(long elapsedRealtimeMs, long uptimeMs) {
         if (mAudioOnNesting > 0) {
-            final long elapsedRealtime = mClocks.elapsedRealtime();
-            final long uptime = mClocks.uptimeMillis();
             mAudioOnNesting = 0;
             mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
-            mAudioOnTimer.stopAllRunningLocked(elapsedRealtime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
+            mAudioOnTimer.stopAllRunningLocked(elapsedRealtimeMs);
             for (int i=0; i<mUidStats.size(); i++) {
                 BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
-                uid.noteResetAudioLocked(elapsedRealtime);
+                uid.noteResetAudioLocked(elapsedRealtimeMs);
             }
         }
     }
 
     public void noteResetVideoLocked() {
+        noteResetVideoLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteResetVideoLocked(long elapsedRealtimeMs, long uptimeMs) {
         if (mVideoOnNesting > 0) {
-            final long elapsedRealtime = mClocks.elapsedRealtime();
-            final long uptime = mClocks.uptimeMillis();
             mVideoOnNesting = 0;
             mHistoryCur.states2 &= ~HistoryItem.STATE2_VIDEO_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
-            mVideoOnTimer.stopAllRunningLocked(elapsedRealtime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
+            mVideoOnTimer.stopAllRunningLocked(elapsedRealtimeMs);
             for (int i=0; i<mUidStats.size(); i++) {
                 BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
-                uid.noteResetVideoLocked(elapsedRealtime);
+                uid.noteResetVideoLocked(elapsedRealtimeMs);
             }
         }
     }
 
     public void noteActivityResumedLocked(int uid) {
+        noteActivityResumedLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteActivityResumedLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
-        getUidStatsLocked(uid).noteActivityResumedLocked(mClocks.elapsedRealtime());
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteActivityResumedLocked(elapsedRealtimeMs);
     }
 
     public void noteActivityPausedLocked(int uid) {
+        noteActivityPausedLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteActivityPausedLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
-        getUidStatsLocked(uid).noteActivityPausedLocked(mClocks.elapsedRealtime());
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteActivityPausedLocked(elapsedRealtimeMs);
     }
 
     public void noteVibratorOnLocked(int uid, long durationMillis) {
+        noteVibratorOnLocked(uid, durationMillis,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteVibratorOnLocked(int uid, long durationMillis,
+            long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
-        getUidStatsLocked(uid).noteVibratorOnLocked(durationMillis);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteVibratorOnLocked(durationMillis, elapsedRealtimeMs);
     }
 
     public void noteVibratorOffLocked(int uid) {
+        noteVibratorOffLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteVibratorOffLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
-        getUidStatsLocked(uid).noteVibratorOffLocked();
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteVibratorOffLocked(elapsedRealtimeMs);
     }
 
     public void noteFlashlightOnLocked(int uid) {
+        noteFlashlightOnLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteFlashlightOnLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
         if (mFlashlightOnNesting++ == 0) {
             mHistoryCur.states2 |= HistoryItem.STATE2_FLASHLIGHT_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight on to: "
                     + Integer.toHexString(mHistoryCur.states2));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
-            mFlashlightOnTimer.startRunningLocked(elapsedRealtime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
+            mFlashlightOnTimer.startRunningLocked(elapsedRealtimeMs);
         }
-        getUidStatsLocked(uid).noteFlashlightTurnedOnLocked(elapsedRealtime);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteFlashlightTurnedOnLocked(elapsedRealtimeMs);
     }
 
     public void noteFlashlightOffLocked(int uid) {
+        noteFlashlightOffLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteFlashlightOffLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
         if (mFlashlightOnNesting == 0) {
             return;
         }
         uid = mapUid(uid);
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
         if (--mFlashlightOnNesting == 0) {
             mHistoryCur.states2 &= ~HistoryItem.STATE2_FLASHLIGHT_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight off to: "
                     + Integer.toHexString(mHistoryCur.states2));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
-            mFlashlightOnTimer.stopRunningLocked(elapsedRealtime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
+            mFlashlightOnTimer.stopRunningLocked(elapsedRealtimeMs);
         }
-        getUidStatsLocked(uid).noteFlashlightTurnedOffLocked(elapsedRealtime);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteFlashlightTurnedOffLocked(elapsedRealtimeMs);
     }
 
     public void noteCameraOnLocked(int uid) {
+        noteCameraOnLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteCameraOnLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
         if (mCameraOnNesting++ == 0) {
             mHistoryCur.states2 |= HistoryItem.STATE2_CAMERA_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Camera on to: "
                     + Integer.toHexString(mHistoryCur.states2));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
-            mCameraOnTimer.startRunningLocked(elapsedRealtime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
+            mCameraOnTimer.startRunningLocked(elapsedRealtimeMs);
         }
-        getUidStatsLocked(uid).noteCameraTurnedOnLocked(elapsedRealtime);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteCameraTurnedOnLocked(elapsedRealtimeMs);
     }
 
     public void noteCameraOffLocked(int uid) {
+        noteCameraOffLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteCameraOffLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
         if (mCameraOnNesting == 0) {
             return;
         }
         uid = mapUid(uid);
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
         if (--mCameraOnNesting == 0) {
             mHistoryCur.states2 &= ~HistoryItem.STATE2_CAMERA_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Camera off to: "
                     + Integer.toHexString(mHistoryCur.states2));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
-            mCameraOnTimer.stopRunningLocked(elapsedRealtime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
+            mCameraOnTimer.stopRunningLocked(elapsedRealtimeMs);
         }
-        getUidStatsLocked(uid).noteCameraTurnedOffLocked(elapsedRealtime);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteCameraTurnedOffLocked(elapsedRealtimeMs);
     }
 
     public void noteResetCameraLocked() {
+        noteResetCameraLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteResetCameraLocked(long elapsedRealtimeMs, long uptimeMs) {
         if (mCameraOnNesting > 0) {
-            final long elapsedRealtime = mClocks.elapsedRealtime();
-            final long uptime = mClocks.uptimeMillis();
             mCameraOnNesting = 0;
             mHistoryCur.states2 &= ~HistoryItem.STATE2_CAMERA_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Camera off to: "
                     + Integer.toHexString(mHistoryCur.states2));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
-            mCameraOnTimer.stopAllRunningLocked(elapsedRealtime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
+            mCameraOnTimer.stopAllRunningLocked(elapsedRealtimeMs);
             for (int i=0; i<mUidStats.size(); i++) {
                 BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
-                uid.noteResetCameraLocked(elapsedRealtime);
+                uid.noteResetCameraLocked(elapsedRealtimeMs);
             }
         }
     }
 
     public void noteResetFlashlightLocked() {
+        noteResetFlashlightLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteResetFlashlightLocked(long elapsedRealtimeMs, long uptimeMs) {
         if (mFlashlightOnNesting > 0) {
-            final long elapsedRealtime = mClocks.elapsedRealtime();
-            final long uptime = mClocks.uptimeMillis();
             mFlashlightOnNesting = 0;
             mHistoryCur.states2 &= ~HistoryItem.STATE2_FLASHLIGHT_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "Flashlight off to: "
                     + Integer.toHexString(mHistoryCur.states2));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
-            mFlashlightOnTimer.stopAllRunningLocked(elapsedRealtime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
+            mFlashlightOnTimer.stopAllRunningLocked(elapsedRealtimeMs);
             for (int i=0; i<mUidStats.size(); i++) {
                 BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
-                uid.noteResetFlashlightLocked(elapsedRealtime);
+                uid.noteResetFlashlightLocked(elapsedRealtimeMs);
             }
         }
     }
 
     private void noteBluetoothScanStartedLocked(WorkChain workChain, int uid,
-            boolean isUnoptimized) {
+            boolean isUnoptimized, long elapsedRealtimeMs, long uptimeMs) {
         uid = getAttributionUid(uid, workChain);
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
         if (mBluetoothScanNesting == 0) {
             mHistoryCur.states2 |= HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "BLE scan started for: "
                     + Integer.toHexString(mHistoryCur.states2));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
-            mBluetoothScanTimer.startRunningLocked(elapsedRealtime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
+            mBluetoothScanTimer.startRunningLocked(elapsedRealtimeMs);
         }
         mBluetoothScanNesting++;
-        getUidStatsLocked(uid).noteBluetoothScanStartedLocked(elapsedRealtime, isUnoptimized);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteBluetoothScanStartedLocked(elapsedRealtimeMs, isUnoptimized);
     }
 
     public void noteBluetoothScanStartedFromSourceLocked(WorkSource ws, boolean isUnoptimized) {
+        noteBluetoothScanStartedFromSourceLocked(ws, isUnoptimized,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteBluetoothScanStartedFromSourceLocked(WorkSource ws, boolean isUnoptimized,
+            long elapsedRealtimeMs, long uptimeMs) {
         final int N = ws.size();
         for (int i = 0; i < N; i++) {
-            noteBluetoothScanStartedLocked(null, ws.getUid(i), isUnoptimized);
+            noteBluetoothScanStartedLocked(null, ws.getUid(i), isUnoptimized,
+                    elapsedRealtimeMs, uptimeMs);
         }
 
         final List<WorkChain> workChains = ws.getWorkChains();
         if (workChains != null) {
             for (int i = 0; i < workChains.size(); ++i) {
-                noteBluetoothScanStartedLocked(workChains.get(i), -1, isUnoptimized);
+                noteBluetoothScanStartedLocked(workChains.get(i), -1, isUnoptimized,
+                        elapsedRealtimeMs, uptimeMs);
             }
         }
     }
 
     private void noteBluetoothScanStoppedLocked(WorkChain workChain, int uid,
-            boolean isUnoptimized) {
+            boolean isUnoptimized, long elapsedRealtimeMs, long uptimeMs) {
         uid = getAttributionUid(uid, workChain);
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
         mBluetoothScanNesting--;
         if (mBluetoothScanNesting == 0) {
             mHistoryCur.states2 &= ~HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "BLE scan stopped for: "
                     + Integer.toHexString(mHistoryCur.states2));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
-            mBluetoothScanTimer.stopRunningLocked(elapsedRealtime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
+            mBluetoothScanTimer.stopRunningLocked(elapsedRealtimeMs);
         }
-        getUidStatsLocked(uid).noteBluetoothScanStoppedLocked(elapsedRealtime, isUnoptimized);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteBluetoothScanStoppedLocked(elapsedRealtimeMs, isUnoptimized);
     }
 
     private int getAttributionUid(int uid, WorkChain workChain) {
@@ -5635,41 +5992,58 @@
     }
 
     public void noteBluetoothScanStoppedFromSourceLocked(WorkSource ws, boolean isUnoptimized) {
+        noteBluetoothScanStoppedFromSourceLocked(ws, isUnoptimized,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteBluetoothScanStoppedFromSourceLocked(WorkSource ws, boolean isUnoptimized,
+            long elapsedRealtimeMs, long uptimeMs) {
         final int N = ws.size();
         for (int i = 0; i < N; i++) {
-            noteBluetoothScanStoppedLocked(null, ws.getUid(i), isUnoptimized);
+            noteBluetoothScanStoppedLocked(null, ws.getUid(i), isUnoptimized,
+                    elapsedRealtimeMs, uptimeMs);
         }
 
         final List<WorkChain> workChains = ws.getWorkChains();
         if (workChains != null) {
             for (int i = 0; i < workChains.size(); ++i) {
-                noteBluetoothScanStoppedLocked(workChains.get(i), -1, isUnoptimized);
+                noteBluetoothScanStoppedLocked(workChains.get(i), -1, isUnoptimized,
+                        elapsedRealtimeMs, uptimeMs);
             }
         }
     }
 
     public void noteResetBluetoothScanLocked() {
+        noteResetBluetoothScanLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteResetBluetoothScanLocked(long elapsedRealtimeMs, long uptimeMs) {
         if (mBluetoothScanNesting > 0) {
-            final long elapsedRealtime = mClocks.elapsedRealtime();
-            final long uptime = mClocks.uptimeMillis();
             mBluetoothScanNesting = 0;
             mHistoryCur.states2 &= ~HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "BLE can stopped for: "
                     + Integer.toHexString(mHistoryCur.states2));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
-            mBluetoothScanTimer.stopAllRunningLocked(elapsedRealtime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
+            mBluetoothScanTimer.stopAllRunningLocked(elapsedRealtimeMs);
             for (int i=0; i<mUidStats.size(); i++) {
                 BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
-                uid.noteResetBluetoothScanLocked(elapsedRealtime);
+                uid.noteResetBluetoothScanLocked(elapsedRealtimeMs);
             }
         }
     }
 
     public void noteBluetoothScanResultsFromSourceLocked(WorkSource ws, int numNewResults) {
+        noteBluetoothScanResultsFromSourceLocked(ws, numNewResults,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteBluetoothScanResultsFromSourceLocked(WorkSource ws, int numNewResults,
+            long elapsedRealtimeMs, long uptimeMs) {
         final int N = ws.size();
         for (int i = 0; i < N; i++) {
             int uid = mapUid(ws.getUid(i));
-            getUidStatsLocked(uid).noteBluetoothScanResultsLocked(numNewResults);
+            getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                    .noteBluetoothScanResultsLocked(numNewResults);
         }
 
         final List<WorkChain> workChains = ws.getWorkChains();
@@ -5677,7 +6051,8 @@
             for (int i = 0; i < workChains.size(); ++i) {
                 final WorkChain wc = workChains.get(i);
                 int uid = mapUid(wc.getAttributionUid());
-                getUidStatsLocked(uid).noteBluetoothScanResultsLocked(numNewResults);
+                getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                        .noteBluetoothScanResultsLocked(numNewResults);
             }
         }
     }
@@ -5687,55 +6062,62 @@
         uid = mapUid(uid);
         addHistoryEventLocked(elapsedRealtimeMillis, uptimeMillis, HistoryItem.EVENT_WAKEUP_AP, "",
                 uid);
-        getUidStatsLocked(uid).noteWifiRadioApWakeupLocked();
+        getUidStatsLocked(uid, elapsedRealtimeMillis, uptimeMillis).noteWifiRadioApWakeupLocked();
     }
 
     public void noteWifiRadioPowerState(int powerState, long timestampNs, int uid) {
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
+        noteWifiRadioPowerState(powerState, timestampNs, uid,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteWifiRadioPowerState(int powerState, long timestampNs, int uid,
+            long elapsedRealtimeMs, long uptimeMs) {
         if (mWifiRadioPowerState != powerState) {
             final boolean active =
                     powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
                             || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
             if (active) {
                 if (uid > 0) {
-                    noteWifiRadioApWakeupLocked(elapsedRealtime, uptime, uid);
+                    noteWifiRadioApWakeupLocked(elapsedRealtimeMs, uptimeMs, uid);
                 }
                 mHistoryCur.states |= HistoryItem.STATE_WIFI_RADIO_ACTIVE_FLAG;
-                mWifiActiveTimer.startRunningLocked(elapsedRealtime);
+                mWifiActiveTimer.startRunningLocked(elapsedRealtimeMs);
             } else {
                 mHistoryCur.states &= ~HistoryItem.STATE_WIFI_RADIO_ACTIVE_FLAG;
-                mWifiActiveTimer.stopRunningLocked(
-                    timestampNs / (1000 * 1000));
+                mWifiActiveTimer.stopRunningLocked(timestampNs / (1000 * 1000));
             }
             if (DEBUG_HISTORY) Slog.v(TAG, "Wifi network active " + active + " to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
             mWifiRadioPowerState = powerState;
         }
     }
 
     public void noteWifiRunningLocked(WorkSource ws) {
+        noteWifiRunningLocked(ws, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteWifiRunningLocked(WorkSource ws, long elapsedRealtimeMs, long uptimeMs) {
         if (!mGlobalWifiRunning) {
-            final long elapsedRealtime = mClocks.elapsedRealtime();
-            final long uptime = mClocks.uptimeMillis();
             mHistoryCur.states2 |= HistoryItem.STATE2_WIFI_RUNNING_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI running to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
             mGlobalWifiRunning = true;
-            mGlobalWifiRunningTimer.startRunningLocked(elapsedRealtime);
+            mGlobalWifiRunningTimer.startRunningLocked(elapsedRealtimeMs);
             int N = ws.size();
             for (int i=0; i<N; i++) {
                 int uid = mapUid(ws.getUid(i));
-                getUidStatsLocked(uid).noteWifiRunningLocked(elapsedRealtime);
+                getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                        .noteWifiRunningLocked(elapsedRealtimeMs);
             }
 
             List<WorkChain> workChains = ws.getWorkChains();
             if (workChains != null) {
                 for (int i = 0; i < workChains.size(); ++i) {
                     int uid = mapUid(workChains.get(i).getAttributionUid());
-                    getUidStatsLocked(uid).noteWifiRunningLocked(elapsedRealtime);
+                    getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                            .noteWifiRunningLocked(elapsedRealtimeMs);
                 }
             }
 
@@ -5746,33 +6128,42 @@
     }
 
     public void noteWifiRunningChangedLocked(WorkSource oldWs, WorkSource newWs) {
+        noteWifiRunningChangedLocked(oldWs, newWs,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteWifiRunningChangedLocked(WorkSource oldWs, WorkSource newWs,
+            long elapsedRealtimeMs, long uptimeMs) {
         if (mGlobalWifiRunning) {
-            final long elapsedRealtime = mClocks.elapsedRealtime();
             int N = oldWs.size();
             for (int i=0; i<N; i++) {
                 int uid = mapUid(oldWs.getUid(i));
-                getUidStatsLocked(uid).noteWifiStoppedLocked(elapsedRealtime);
+                getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                        .noteWifiStoppedLocked(elapsedRealtimeMs);
             }
 
             List<WorkChain> workChains = oldWs.getWorkChains();
             if (workChains != null) {
                 for (int i = 0; i < workChains.size(); ++i) {
                     int uid = mapUid(workChains.get(i).getAttributionUid());
-                    getUidStatsLocked(uid).noteWifiStoppedLocked(elapsedRealtime);
+                    getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                            .noteWifiStoppedLocked(elapsedRealtimeMs);
                 }
             }
 
             N = newWs.size();
             for (int i=0; i<N; i++) {
                 int uid = mapUid(newWs.getUid(i));
-                getUidStatsLocked(uid).noteWifiRunningLocked(elapsedRealtime);
+                getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                        .noteWifiRunningLocked(elapsedRealtimeMs);
             }
 
             workChains = newWs.getWorkChains();
             if (workChains != null) {
                 for (int i = 0; i < workChains.size(); ++i) {
                     int uid = mapUid(workChains.get(i).getAttributionUid());
-                    getUidStatsLocked(uid).noteWifiRunningLocked(elapsedRealtime);
+                    getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                            .noteWifiRunningLocked(elapsedRealtimeMs);
                 }
             }
         } else {
@@ -5781,26 +6172,30 @@
     }
 
     public void noteWifiStoppedLocked(WorkSource ws) {
+        noteWifiStoppedLocked(ws, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteWifiStoppedLocked(WorkSource ws, long elapsedRealtimeMs, long uptimeMs) {
         if (mGlobalWifiRunning) {
-            final long elapsedRealtime = mClocks.elapsedRealtime();
-            final long uptime = mClocks.uptimeMillis();
             mHistoryCur.states2 &= ~HistoryItem.STATE2_WIFI_RUNNING_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI stopped to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
             mGlobalWifiRunning = false;
-            mGlobalWifiRunningTimer.stopRunningLocked(elapsedRealtime);
+            mGlobalWifiRunningTimer.stopRunningLocked(elapsedRealtimeMs);
             int N = ws.size();
             for (int i=0; i<N; i++) {
                 int uid = mapUid(ws.getUid(i));
-                getUidStatsLocked(uid).noteWifiStoppedLocked(elapsedRealtime);
+                getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                        .noteWifiStoppedLocked(elapsedRealtimeMs);
             }
 
             List<WorkChain> workChains = ws.getWorkChains();
             if (workChains != null) {
                 for (int i = 0; i < workChains.size(); ++i) {
                     int uid = mapUid(workChains.get(i).getAttributionUid());
-                    getUidStatsLocked(uid).noteWifiStoppedLocked(elapsedRealtime);
+                    getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                            .noteWifiStoppedLocked(elapsedRealtimeMs);
                 }
             }
 
@@ -5811,71 +6206,79 @@
     }
 
     public void noteWifiStateLocked(int wifiState, String accessPoint) {
+        noteWifiStateLocked(wifiState, accessPoint, mClocks.elapsedRealtime());
+    }
+
+    public void noteWifiStateLocked(int wifiState, String accessPoint, long elapsedRealtimeMs) {
         if (DEBUG) Log.i(TAG, "WiFi state -> " + wifiState);
         if (mWifiState != wifiState) {
-            final long elapsedRealtime = mClocks.elapsedRealtime();
             if (mWifiState >= 0) {
-                mWifiStateTimer[mWifiState].stopRunningLocked(elapsedRealtime);
+                mWifiStateTimer[mWifiState].stopRunningLocked(elapsedRealtimeMs);
             }
             mWifiState = wifiState;
-            mWifiStateTimer[wifiState].startRunningLocked(elapsedRealtime);
+            mWifiStateTimer[wifiState].startRunningLocked(elapsedRealtimeMs);
             scheduleSyncExternalStatsLocked("wifi-state", ExternalStatsSync.UPDATE_WIFI);
         }
     }
 
     public void noteWifiSupplicantStateChangedLocked(int supplState, boolean failedAuth) {
+        noteWifiSupplicantStateChangedLocked(supplState, failedAuth,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteWifiSupplicantStateChangedLocked(int supplState, boolean failedAuth,
+            long elapsedRealtimeMs, long uptimeMs) {
         if (DEBUG) Log.i(TAG, "WiFi suppl state -> " + supplState);
         if (mWifiSupplState != supplState) {
-            final long elapsedRealtime = mClocks.elapsedRealtime();
-            final long uptime = mClocks.uptimeMillis();
             if (mWifiSupplState >= 0) {
-                mWifiSupplStateTimer[mWifiSupplState].stopRunningLocked(elapsedRealtime);
+                mWifiSupplStateTimer[mWifiSupplState].stopRunningLocked(elapsedRealtimeMs);
             }
             mWifiSupplState = supplState;
-            mWifiSupplStateTimer[supplState].startRunningLocked(elapsedRealtime);
+            mWifiSupplStateTimer[supplState].startRunningLocked(elapsedRealtimeMs);
             mHistoryCur.states2 =
                     (mHistoryCur.states2&~HistoryItem.STATE2_WIFI_SUPPL_STATE_MASK)
                     | (supplState << HistoryItem.STATE2_WIFI_SUPPL_STATE_SHIFT);
             if (DEBUG_HISTORY) Slog.v(TAG, "Wifi suppl state " + supplState + " to: "
                     + Integer.toHexString(mHistoryCur.states2));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
         }
     }
 
-    void stopAllWifiSignalStrengthTimersLocked(int except) {
-        final long elapsedRealtime = mClocks.elapsedRealtime();
+    void stopAllWifiSignalStrengthTimersLocked(int except, long elapsedRealtimeMs) {
         for (int i = 0; i < NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
             if (i == except) {
                 continue;
             }
             while (mWifiSignalStrengthsTimer[i].isRunningLocked()) {
-                mWifiSignalStrengthsTimer[i].stopRunningLocked(elapsedRealtime);
+                mWifiSignalStrengthsTimer[i].stopRunningLocked(elapsedRealtimeMs);
             }
         }
     }
 
     public void noteWifiRssiChangedLocked(int newRssi) {
+        noteWifiRssiChangedLocked(newRssi, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteWifiRssiChangedLocked(int newRssi, long elapsedRealtimeMs, long uptimeMs) {
         int strengthBin = WifiManager.calculateSignalLevel(newRssi, NUM_WIFI_SIGNAL_STRENGTH_BINS);
         if (DEBUG) Log.i(TAG, "WiFi rssi -> " + newRssi + " bin=" + strengthBin);
         if (mWifiSignalStrengthBin != strengthBin) {
-            final long elapsedRealtime = mClocks.elapsedRealtime();
-            final long uptime = mClocks.uptimeMillis();
             if (mWifiSignalStrengthBin >= 0) {
                 mWifiSignalStrengthsTimer[mWifiSignalStrengthBin].stopRunningLocked(
-                        elapsedRealtime);
+                        elapsedRealtimeMs);
             }
             if (strengthBin >= 0) {
                 if (!mWifiSignalStrengthsTimer[strengthBin].isRunningLocked()) {
-                    mWifiSignalStrengthsTimer[strengthBin].startRunningLocked(elapsedRealtime);
+                    mWifiSignalStrengthsTimer[strengthBin].startRunningLocked(elapsedRealtimeMs);
                 }
                 mHistoryCur.states2 =
                         (mHistoryCur.states2&~HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_MASK)
                         | (strengthBin << HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_SHIFT);
                 if (DEBUG_HISTORY) Slog.v(TAG, "Wifi signal strength " + strengthBin + " to: "
                         + Integer.toHexString(mHistoryCur.states2));
-                addHistoryRecordLocked(elapsedRealtime, uptime);
+                addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
             } else {
-                stopAllWifiSignalStrengthTimersLocked(-1);
+                stopAllWifiSignalStrengthTimersLocked(-1, elapsedRealtimeMs);
             }
             mWifiSignalStrengthBin = strengthBin;
         }
@@ -5885,121 +6288,155 @@
 
     @UnsupportedAppUsage
     public void noteFullWifiLockAcquiredLocked(int uid) {
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
+        noteFullWifiLockAcquiredLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteFullWifiLockAcquiredLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
         if (mWifiFullLockNesting == 0) {
             mHistoryCur.states |= HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock on to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
         }
         mWifiFullLockNesting++;
-        getUidStatsLocked(uid).noteFullWifiLockAcquiredLocked(elapsedRealtime);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteFullWifiLockAcquiredLocked(elapsedRealtimeMs);
     }
 
     @UnsupportedAppUsage
     public void noteFullWifiLockReleasedLocked(int uid) {
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
+        noteFullWifiLockReleasedLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteFullWifiLockReleasedLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
         mWifiFullLockNesting--;
         if (mWifiFullLockNesting == 0) {
             mHistoryCur.states &= ~HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock off to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
         }
-        getUidStatsLocked(uid).noteFullWifiLockReleasedLocked(elapsedRealtime);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteFullWifiLockReleasedLocked(elapsedRealtimeMs);
     }
 
     int mWifiScanNesting = 0;
 
     public void noteWifiScanStartedLocked(int uid) {
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
+        noteWifiScanStartedLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteWifiScanStartedLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
         if (mWifiScanNesting == 0) {
             mHistoryCur.states |= HistoryItem.STATE_WIFI_SCAN_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan started for: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
         }
         mWifiScanNesting++;
-        getUidStatsLocked(uid).noteWifiScanStartedLocked(elapsedRealtime);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteWifiScanStartedLocked(elapsedRealtimeMs);
     }
 
     public void noteWifiScanStoppedLocked(int uid) {
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
+        noteWifiScanStoppedLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteWifiScanStoppedLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
         mWifiScanNesting--;
         if (mWifiScanNesting == 0) {
             mHistoryCur.states &= ~HistoryItem.STATE_WIFI_SCAN_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan stopped for: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
         }
-        getUidStatsLocked(uid).noteWifiScanStoppedLocked(elapsedRealtime);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteWifiScanStoppedLocked(elapsedRealtimeMs);
     }
 
     public void noteWifiBatchedScanStartedLocked(int uid, int csph) {
+        noteWifiBatchedScanStartedLocked(uid, csph,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteWifiBatchedScanStartedLocked(int uid, int csph,
+            long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        getUidStatsLocked(uid).noteWifiBatchedScanStartedLocked(csph, elapsedRealtime);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteWifiBatchedScanStartedLocked(csph, elapsedRealtimeMs);
     }
 
     public void noteWifiBatchedScanStoppedLocked(int uid) {
+        noteWifiBatchedScanStoppedLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteWifiBatchedScanStoppedLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        getUidStatsLocked(uid).noteWifiBatchedScanStoppedLocked(elapsedRealtime);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteWifiBatchedScanStoppedLocked(elapsedRealtimeMs);
     }
 
     int mWifiMulticastNesting = 0;
 
     @UnsupportedAppUsage
     public void noteWifiMulticastEnabledLocked(int uid) {
+        noteWifiMulticastEnabledLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteWifiMulticastEnabledLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
         if (mWifiMulticastNesting == 0) {
             mHistoryCur.states |= HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
 
             // Start Wifi Multicast overall timer
             if (!mWifiMulticastWakelockTimer.isRunningLocked()) {
                 if (DEBUG_HISTORY) Slog.v(TAG, "WiFi Multicast Overall Timer Started");
-                mWifiMulticastWakelockTimer.startRunningLocked(elapsedRealtime);
+                mWifiMulticastWakelockTimer.startRunningLocked(elapsedRealtimeMs);
             }
         }
         mWifiMulticastNesting++;
-        getUidStatsLocked(uid).noteWifiMulticastEnabledLocked(elapsedRealtime);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteWifiMulticastEnabledLocked(elapsedRealtimeMs);
     }
 
     @UnsupportedAppUsage
     public void noteWifiMulticastDisabledLocked(int uid) {
+        noteWifiMulticastDisabledLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteWifiMulticastDisabledLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
         mWifiMulticastNesting--;
         if (mWifiMulticastNesting == 0) {
             mHistoryCur.states &= ~HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast off to: "
                     + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(elapsedRealtime, uptime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
 
             // Stop Wifi Multicast overall timer
             if (mWifiMulticastWakelockTimer.isRunningLocked()) {
                 if (DEBUG_HISTORY) Slog.v(TAG, "Multicast Overall Timer Stopped");
-                mWifiMulticastWakelockTimer.stopRunningLocked(elapsedRealtime);
+                mWifiMulticastWakelockTimer.stopRunningLocked(elapsedRealtimeMs);
             }
         }
-        getUidStatsLocked(uid).noteWifiMulticastDisabledLocked(elapsedRealtime);
+        getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs)
+                .noteWifiMulticastDisabledLocked(elapsedRealtimeMs);
     }
 
     public void noteFullWifiLockAcquiredFromSourceLocked(WorkSource ws) {
+        noteFullWifiLockAcquiredFromSourceLocked(ws,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteFullWifiLockAcquiredFromSourceLocked(WorkSource ws,
+            long elapsedRealtimeMs, long uptimeMs) {
         int N = ws.size();
         for (int i=0; i<N; i++) {
             final int uid = mapUid(ws.getUid(i));
-            noteFullWifiLockAcquiredLocked(uid);
+            noteFullWifiLockAcquiredLocked(uid, elapsedRealtimeMs, uptimeMs);
         }
 
         final List<WorkChain> workChains = ws.getWorkChains();
@@ -6007,16 +6444,22 @@
             for (int i = 0; i < workChains.size(); ++i) {
                 final WorkChain workChain = workChains.get(i);
                 final int uid = mapUid(workChain.getAttributionUid());
-                noteFullWifiLockAcquiredLocked(uid);
+                noteFullWifiLockAcquiredLocked(uid, elapsedRealtimeMs, uptimeMs);
             }
         }
     }
 
     public void noteFullWifiLockReleasedFromSourceLocked(WorkSource ws) {
+        noteFullWifiLockReleasedFromSourceLocked(ws,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteFullWifiLockReleasedFromSourceLocked(WorkSource ws,
+            long elapsedRealtimeMs, long uptimeMs) {
         int N = ws.size();
         for (int i=0; i<N; i++) {
             final int uid = mapUid(ws.getUid(i));
-            noteFullWifiLockReleasedLocked(uid);
+            noteFullWifiLockReleasedLocked(uid, elapsedRealtimeMs, uptimeMs);
         }
 
         final List<WorkChain> workChains = ws.getWorkChains();
@@ -6024,16 +6467,21 @@
             for (int i = 0; i < workChains.size(); ++i) {
                 final WorkChain workChain = workChains.get(i);
                 final int uid = mapUid(workChain.getAttributionUid());
-                noteFullWifiLockReleasedLocked(uid);
+                noteFullWifiLockReleasedLocked(uid, elapsedRealtimeMs, uptimeMs);
             }
         }
     }
 
     public void noteWifiScanStartedFromSourceLocked(WorkSource ws) {
+        noteWifiScanStartedFromSourceLocked(ws, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteWifiScanStartedFromSourceLocked(WorkSource ws,
+            long elapsedRealtimeMs, long uptimeMs) {
         int N = ws.size();
         for (int i=0; i<N; i++) {
             final int uid = mapUid(ws.getUid(i));
-            noteWifiScanStartedLocked(uid);
+            noteWifiScanStartedLocked(uid, elapsedRealtimeMs, uptimeMs);
         }
 
         final List<WorkChain> workChains = ws.getWorkChains();
@@ -6041,16 +6489,21 @@
             for (int i = 0; i < workChains.size(); ++i) {
                 final WorkChain workChain = workChains.get(i);
                 final int uid = mapUid(workChain.getAttributionUid());
-                noteWifiScanStartedLocked(uid);
+                noteWifiScanStartedLocked(uid, elapsedRealtimeMs, uptimeMs);
             }
         }
     }
 
     public void noteWifiScanStoppedFromSourceLocked(WorkSource ws) {
+        noteWifiScanStoppedFromSourceLocked(ws, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteWifiScanStoppedFromSourceLocked(WorkSource ws,
+            long elapsedRealtimeMs, long uptimeMs) {
         int N = ws.size();
         for (int i=0; i<N; i++) {
             final int uid = mapUid(ws.getUid(i));
-            noteWifiScanStoppedLocked(uid);
+            noteWifiScanStoppedLocked(uid, elapsedRealtimeMs, uptimeMs);
         }
 
         final List<WorkChain> workChains = ws.getWorkChains();
@@ -6058,35 +6511,48 @@
             for (int i = 0; i < workChains.size(); ++i) {
                 final WorkChain workChain = workChains.get(i);
                 final int uid = mapUid(workChain.getAttributionUid());
-                noteWifiScanStoppedLocked(uid);
+                noteWifiScanStoppedLocked(uid, elapsedRealtimeMs, uptimeMs);
             }
         }
     }
 
     public void noteWifiBatchedScanStartedFromSourceLocked(WorkSource ws, int csph) {
+        noteWifiBatchedScanStartedFromSourceLocked(ws, csph,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteWifiBatchedScanStartedFromSourceLocked(WorkSource ws, int csph,
+            long elapsedRealtimeMs, long uptimeMs) {
         int N = ws.size();
         for (int i=0; i<N; i++) {
-            noteWifiBatchedScanStartedLocked(ws.getUid(i), csph);
+            noteWifiBatchedScanStartedLocked(ws.getUid(i), csph, elapsedRealtimeMs, uptimeMs);
         }
 
         final List<WorkChain> workChains = ws.getWorkChains();
         if (workChains != null) {
             for (int i = 0; i < workChains.size(); ++i) {
-                noteWifiBatchedScanStartedLocked(workChains.get(i).getAttributionUid(), csph);
+                noteWifiBatchedScanStartedLocked(workChains.get(i).getAttributionUid(), csph,
+                        elapsedRealtimeMs, uptimeMs);
             }
         }
     }
 
     public void noteWifiBatchedScanStoppedFromSourceLocked(WorkSource ws) {
+        noteWifiBatchedScanStoppedFromSourceLocked(ws,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+    public void noteWifiBatchedScanStoppedFromSourceLocked(WorkSource ws,
+            long elapsedRealtimeMs, long uptimeMs) {
         int N = ws.size();
         for (int i=0; i<N; i++) {
-            noteWifiBatchedScanStoppedLocked(ws.getUid(i));
+            noteWifiBatchedScanStoppedLocked(ws.getUid(i), elapsedRealtimeMs, uptimeMs);
         }
 
         final List<WorkChain> workChains = ws.getWorkChains();
         if (workChains != null) {
             for (int i = 0; i < workChains.size(); ++i) {
-                noteWifiBatchedScanStoppedLocked(workChains.get(i).getAttributionUid());
+                noteWifiBatchedScanStoppedLocked(workChains.get(i).getAttributionUid(),
+                        elapsedRealtimeMs, uptimeMs);
             }
         }
     }
@@ -6147,9 +6613,16 @@
      */
     public void noteBinderCallStats(int workSourceUid, long incrementalCallCount,
             Collection<BinderCallsStats.CallStat> callStats, int[] binderThreadNativeTids) {
+        noteBinderCallStats(workSourceUid, incrementalCallCount, callStats, binderThreadNativeTids,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public void noteBinderCallStats(int workSourceUid, long incrementalCallCount,
+            Collection<BinderCallsStats.CallStat> callStats, int[] binderThreadNativeTids,
+            long elapsedRealtimeMs, long uptimeMs) {
         synchronized (this) {
-            getUidStatsLocked(workSourceUid).noteBinderCallStatsLocked(incrementalCallCount,
-                    callStats);
+            getUidStatsLocked(workSourceUid, elapsedRealtimeMs, uptimeMs)
+                    .noteBinderCallStatsLocked(incrementalCallCount, callStats);
             mSystemServerCpuThreadReader.setBinderThreadNativeTids(binderThreadNativeTids);
         }
     }
@@ -6182,17 +6655,17 @@
         for (int i = 0; i < mUidStats.size(); i++) {
             Uid uid = mUidStats.valueAt(i);
 
-            long totalTimeForUid = 0;
+            long totalTimeForUidUs = 0;
             int totalCallCountForUid = 0;
             ArraySet<BinderCallStats> binderCallStats = uid.mBinderCallStats;
             for (int j = binderCallStats.size() - 1; j >= 0; j--) {
                 BinderCallStats stats = binderCallStats.valueAt(j);
                 totalCallCountForUid += stats.callCount;
                 if (stats.recordedCallCount > 0) {
-                    totalTimeForUid +=
+                    totalTimeForUidUs +=
                             stats.callCount * stats.recordedCpuTimeMicros / stats.recordedCallCount;
                 } else if (totalRecordedCallCount > 0) {
-                    totalTimeForUid +=
+                    totalTimeForUidUs +=
                             stats.callCount * totalRecordedCallTimeMicros / totalRecordedCallCount;
                 }
             }
@@ -6200,13 +6673,13 @@
             if (totalCallCountForUid < uid.mBinderCallCount && totalRecordedCallCount > 0) {
                 // Estimate remaining calls, which were not tracked because of binder call
                 // stats sampling
-                totalTimeForUid +=
+                totalTimeForUidUs +=
                         (uid.mBinderCallCount - totalCallCountForUid) * totalRecordedCallTimeMicros
                                 / totalRecordedCallCount;
             }
 
-            uid.mSystemServiceTimeUs = totalTimeForUid;
-            totalSystemServiceTimeMicros += totalTimeForUid;
+            uid.mSystemServiceTimeUs = totalTimeForUidUs;
+            totalSystemServiceTimeMicros += totalTimeForUidUs;
         }
 
         for (int i = 0; i < mUidStats.size(); i++) {
@@ -6296,9 +6769,9 @@
     @Override public long getLongestDeviceIdleModeTime(int mode) {
         switch (mode) {
             case DEVICE_IDLE_MODE_LIGHT:
-                return mLongestLightIdleTime;
+                return mLongestLightIdleTimeMs;
             case DEVICE_IDLE_MODE_DEEP:
-                return mLongestFullIdleTime;
+                return mLongestFullIdleTimeMs;
         }
         return 0;
     }
@@ -6328,12 +6801,12 @@
     }
 
     @Override public long getGpsSignalQualityTime(int strengthBin,
-        long elapsedRealtimeUs, int which) {
+            long elapsedRealtimeUs, int which) {
         if (strengthBin < 0 || strengthBin >= GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS) {
             return 0;
         }
         return mGpsSignalQualityTimer[strengthBin].getTotalTimeLocked(
-            elapsedRealtimeUs, which);
+                elapsedRealtimeUs, which);
     }
 
     @Override public long getGpsBatteryDrainMaMs() {
@@ -6344,11 +6817,11 @@
         }
         double energyUsedMaMs = 0.0;
         final int which = STATS_SINCE_CHARGED;
-        final long rawRealtime = SystemClock.elapsedRealtime() * 1000;
+        final long rawRealtimeUs = SystemClock.elapsedRealtime() * 1000;
         for(int i=0; i < GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
             energyUsedMaMs
-                += mPowerProfile.getAveragePower(PowerProfile.POWER_GPS_SIGNAL_QUALITY_BASED, i)
-                * (getGpsSignalQualityTime(i, rawRealtime, which) / 1000);
+                    += mPowerProfile.getAveragePower(PowerProfile.POWER_GPS_SIGNAL_QUALITY_BASED, i)
+                    * (getGpsSignalQualityTime(i, rawRealtimeUs, which) / 1000);
         }
         return (long) energyUsedMaMs;
     }
@@ -6562,18 +7035,18 @@
     }
 
     @Override public long getStartClockTime() {
-        final long currentTime = System.currentTimeMillis();
-        if ((currentTime > MILLISECONDS_IN_YEAR
-                && mStartClockTime < (currentTime - MILLISECONDS_IN_YEAR))
-                || (mStartClockTime > currentTime)) {
+        final long currentTimeMs = System.currentTimeMillis();
+        if ((currentTimeMs > MILLISECONDS_IN_YEAR
+                && mStartClockTimeMs < (currentTimeMs - MILLISECONDS_IN_YEAR))
+                || (mStartClockTimeMs > currentTimeMs)) {
             // If the start clock time has changed by more than a year, then presumably
             // the previous time was completely bogus.  So we are going to figure out a
             // new time based on how much time has elapsed since we started counting.
-            recordCurrentTimeChangeLocked(currentTime, mClocks.elapsedRealtime(),
+            recordCurrentTimeChangeLocked(currentTimeMs, mClocks.elapsedRealtime(),
                     mClocks.uptimeMillis());
-            return currentTime - (mClocks.elapsedRealtime() - (mRealtimeStart / 1000));
+            return currentTimeMs - (mClocks.elapsedRealtime() - (mRealtimeStartUs / 1000));
         }
-        return mStartClockTime;
+        return mStartClockTimeMs;
     }
 
     @Override public String getStartPlatformVersion() {
@@ -6597,29 +7070,32 @@
         return mUidStats;
     }
 
-    private static <T extends TimeBaseObs> boolean resetIfNotNull(T t, boolean detachIfReset) {
+    private static <T extends TimeBaseObs> boolean resetIfNotNull(T t, boolean detachIfReset,
+            long elapsedRealtimeUs) {
         if (t != null) {
-            return t.reset(detachIfReset);
+            return t.reset(detachIfReset, elapsedRealtimeUs);
         }
         return true;
     }
 
-    private static <T extends TimeBaseObs> boolean resetIfNotNull(T[] t, boolean detachIfReset) {
+    private static <T extends TimeBaseObs> boolean resetIfNotNull(T[] t, boolean detachIfReset,
+            long elapsedRealtimeUs) {
         if (t != null) {
             boolean ret = true;
             for (int i = 0; i < t.length; i++) {
-                ret &= resetIfNotNull(t[i], detachIfReset);
+                ret &= resetIfNotNull(t[i], detachIfReset, elapsedRealtimeUs);
             }
             return ret;
         }
         return true;
     }
 
-    private static <T extends TimeBaseObs> boolean resetIfNotNull(T[][] t, boolean detachIfReset) {
+    private static <T extends TimeBaseObs> boolean resetIfNotNull(T[][] t, boolean detachIfReset,
+            long elapsedRealtimeUs) {
         if (t != null) {
             boolean ret = true;
             for (int i = 0; i < t.length; i++) {
-                ret &= resetIfNotNull(t[i], detachIfReset);
+                ret &= resetIfNotNull(t[i], detachIfReset, elapsedRealtimeUs);
             }
             return ret;
         }
@@ -6627,9 +7103,9 @@
     }
 
     private static boolean resetIfNotNull(ControllerActivityCounterImpl counter,
-            boolean detachIfReset) {
+            boolean detachIfReset, long elapsedRealtimeUs) {
         if (counter != null) {
-            counter.reset(detachIfReset);
+            counter.reset(detachIfReset, elapsedRealtimeUs);
         }
         return true;
     }
@@ -6812,10 +7288,10 @@
         /**
          * The CPU times we had at the last history details update.
          */
-        long mLastStepUserTime;
-        long mLastStepSystemTime;
-        long mCurStepUserTime;
-        long mCurStepSystemTime;
+        long mLastStepUserTimeMs;
+        long mLastStepSystemTimeMs;
+        long mCurStepUserTimeMs;
+        long mCurStepSystemTimeMs;
 
         LongSamplingCounter mUserCpuTime;
         LongSamplingCounter mSystemCpuTime;
@@ -6915,17 +7391,19 @@
         private double mProportionalSystemServiceUsage;
 
         public Uid(BatteryStatsImpl bsi, int uid) {
+            this(bsi, uid, bsi.mClocks.elapsedRealtime(), bsi.mClocks.uptimeMillis());
+        }
+
+        public Uid(BatteryStatsImpl bsi, int uid, long elapsedRealtimeMs, long uptimeMs) {
             mBsi = bsi;
             mUid = uid;
 
             /* Observer list of TimeBase object in Uid is short */
             mOnBatteryBackgroundTimeBase = new TimeBase(false);
-            mOnBatteryBackgroundTimeBase.init(mBsi.mClocks.uptimeMillis() * 1000,
-                    mBsi.mClocks.elapsedRealtime() * 1000);
+            mOnBatteryBackgroundTimeBase.init(uptimeMs * 1000, elapsedRealtimeMs * 1000);
             /* Observer list of TimeBase object in Uid is short */
             mOnBatteryScreenOffBackgroundTimeBase = new TimeBase(false);
-            mOnBatteryScreenOffBackgroundTimeBase.init(mBsi.mClocks.uptimeMillis() * 1000,
-                    mBsi.mClocks.elapsedRealtime() * 1000);
+            mOnBatteryScreenOffBackgroundTimeBase.init(uptimeMs * 1000, elapsedRealtimeMs * 1000);
 
             mUserCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
             mSystemCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
@@ -7520,13 +7998,13 @@
             return mVibratorOnTimer;
         }
 
-        public void noteVibratorOnLocked(long durationMillis) {
-            createVibratorOnTimerLocked().addDuration(mBsi, durationMillis);
+        public void noteVibratorOnLocked(long durationMillis, long elapsedRealtimeMs) {
+            createVibratorOnTimerLocked().addDuration(mBsi, durationMillis, elapsedRealtimeMs);
         }
 
-        public void noteVibratorOffLocked() {
+        public void noteVibratorOffLocked(long elapsedRealtimeMs) {
             if (mVibratorOnTimer != null) {
-                mVibratorOnTimer.abortLastDuration(mBsi);
+                mVibratorOnTimer.abortLastDuration(mBsi, elapsedRealtimeMs);
             }
         }
 
@@ -7962,58 +8440,58 @@
          * inactive so can be dropped.
          */
         @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-        public boolean reset(long uptime, long realtime) {
+        public boolean reset(long uptimeUs, long realtimeUs) {
             boolean active = false;
 
-            mOnBatteryBackgroundTimeBase.init(uptime, realtime);
-            mOnBatteryScreenOffBackgroundTimeBase.init(uptime, realtime);
+            mOnBatteryBackgroundTimeBase.init(uptimeUs, realtimeUs);
+            mOnBatteryScreenOffBackgroundTimeBase.init(uptimeUs, realtimeUs);
 
             if (mWifiRunningTimer != null) {
-                active |= !mWifiRunningTimer.reset(false);
+                active |= !mWifiRunningTimer.reset(false, realtimeUs);
                 active |= mWifiRunning;
             }
             if (mFullWifiLockTimer != null) {
-                active |= !mFullWifiLockTimer.reset(false);
+                active |= !mFullWifiLockTimer.reset(false, realtimeUs);
                 active |= mFullWifiLockOut;
             }
             if (mWifiScanTimer != null) {
-                active |= !mWifiScanTimer.reset(false);
+                active |= !mWifiScanTimer.reset(false, realtimeUs);
                 active |= mWifiScanStarted;
             }
             if (mWifiBatchedScanTimer != null) {
                 for (int i = 0; i < NUM_WIFI_BATCHED_SCAN_BINS; i++) {
                     if (mWifiBatchedScanTimer[i] != null) {
-                        active |= !mWifiBatchedScanTimer[i].reset(false);
+                        active |= !mWifiBatchedScanTimer[i].reset(false, realtimeUs);
                     }
                 }
                 active |= (mWifiBatchedScanBinStarted != NO_BATCHED_SCAN_STARTED);
             }
             if (mWifiMulticastTimer != null) {
-                active |= !mWifiMulticastTimer.reset(false);
+                active |= !mWifiMulticastTimer.reset(false, realtimeUs);
                 active |= (mWifiMulticastWakelockCount > 0);
             }
 
-            active |= !resetIfNotNull(mAudioTurnedOnTimer, false);
-            active |= !resetIfNotNull(mVideoTurnedOnTimer, false);
-            active |= !resetIfNotNull(mFlashlightTurnedOnTimer, false);
-            active |= !resetIfNotNull(mCameraTurnedOnTimer, false);
-            active |= !resetIfNotNull(mForegroundActivityTimer, false);
-            active |= !resetIfNotNull(mForegroundServiceTimer, false);
-            active |= !resetIfNotNull(mAggregatedPartialWakelockTimer, false);
-            active |= !resetIfNotNull(mBluetoothScanTimer, false);
-            active |= !resetIfNotNull(mBluetoothUnoptimizedScanTimer, false);
+            active |= !resetIfNotNull(mAudioTurnedOnTimer, false, realtimeUs);
+            active |= !resetIfNotNull(mVideoTurnedOnTimer, false, realtimeUs);
+            active |= !resetIfNotNull(mFlashlightTurnedOnTimer, false, realtimeUs);
+            active |= !resetIfNotNull(mCameraTurnedOnTimer, false, realtimeUs);
+            active |= !resetIfNotNull(mForegroundActivityTimer, false, realtimeUs);
+            active |= !resetIfNotNull(mForegroundServiceTimer, false, realtimeUs);
+            active |= !resetIfNotNull(mAggregatedPartialWakelockTimer, false, realtimeUs);
+            active |= !resetIfNotNull(mBluetoothScanTimer, false, realtimeUs);
+            active |= !resetIfNotNull(mBluetoothUnoptimizedScanTimer, false, realtimeUs);
 
-            resetIfNotNull(mBluetoothScanResultCounter, false);
-            resetIfNotNull(mBluetoothScanResultBgCounter, false);
+            resetIfNotNull(mBluetoothScanResultCounter, false, realtimeUs);
+            resetIfNotNull(mBluetoothScanResultBgCounter, false, realtimeUs);
 
             if (mProcessStateTimer != null) {
                 for (int i = 0; i < NUM_PROCESS_STATE; i++) {
-                    active |= !resetIfNotNull(mProcessStateTimer[i], false);
+                    active |= !resetIfNotNull(mProcessStateTimer[i], false, realtimeUs);
                 }
                 active |= (mProcessState != ActivityManager.PROCESS_STATE_NONEXISTENT);
             }
             if (mVibratorOnTimer != null) {
-                if (mVibratorOnTimer.reset(false)) {
+                if (mVibratorOnTimer.reset(false, realtimeUs)) {
                     mVibratorOnTimer.detach();
                     mVibratorOnTimer = null;
                 } else {
@@ -8021,80 +8499,81 @@
                 }
             }
 
-            resetIfNotNull(mUserActivityCounters, false);
+            resetIfNotNull(mUserActivityCounters, false, realtimeUs);
 
-            resetIfNotNull(mNetworkByteActivityCounters, false);
-            resetIfNotNull(mNetworkPacketActivityCounters, false);
-            resetIfNotNull(mMobileRadioActiveTime, false);
-            resetIfNotNull(mMobileRadioActiveCount, false);
+            resetIfNotNull(mNetworkByteActivityCounters, false, realtimeUs);
+            resetIfNotNull(mNetworkPacketActivityCounters, false, realtimeUs);
+            resetIfNotNull(mMobileRadioActiveTime, false, realtimeUs);
+            resetIfNotNull(mMobileRadioActiveCount, false, realtimeUs);
 
-            resetIfNotNull(mWifiControllerActivity, false);
-            resetIfNotNull(mBluetoothControllerActivity, false);
-            resetIfNotNull(mModemControllerActivity, false);
+            resetIfNotNull(mWifiControllerActivity, false, realtimeUs);
+            resetIfNotNull(mBluetoothControllerActivity, false, realtimeUs);
+            resetIfNotNull(mModemControllerActivity, false, realtimeUs);
 
-            resetIfNotNull(mUserCpuTime, false);
-            resetIfNotNull(mSystemCpuTime, false);
+            resetIfNotNull(mUserCpuTime, false, realtimeUs);
+            resetIfNotNull(mSystemCpuTime, false, realtimeUs);
 
-            resetIfNotNull(mCpuClusterSpeedTimesUs, false);
+            resetIfNotNull(mCpuClusterSpeedTimesUs, false, realtimeUs);
 
-            resetIfNotNull(mCpuFreqTimeMs, false);
-            resetIfNotNull(mScreenOffCpuFreqTimeMs, false);
+            resetIfNotNull(mCpuFreqTimeMs, false, realtimeUs /* unused */);
+            resetIfNotNull(mScreenOffCpuFreqTimeMs, false, realtimeUs /* unused */);
 
 
-            resetIfNotNull(mCpuActiveTimeMs, false);
-            resetIfNotNull(mCpuClusterTimesMs, false);
+            resetIfNotNull(mCpuActiveTimeMs, false, realtimeUs /* unused */);
+            resetIfNotNull(mCpuClusterTimesMs, false, realtimeUs /* unused */);
 
-            resetIfNotNull(mProcStateTimeMs, false);
+            resetIfNotNull(mProcStateTimeMs, false, realtimeUs /* unused */);
 
-            resetIfNotNull(mProcStateScreenOffTimeMs, false);
+            resetIfNotNull(mProcStateScreenOffTimeMs, false, realtimeUs /* unused */);
 
-            resetIfNotNull(mMobileRadioApWakeupCount, false);
+            resetIfNotNull(mMobileRadioApWakeupCount, false, realtimeUs);
 
-            resetIfNotNull(mWifiRadioApWakeupCount, false);
+            resetIfNotNull(mWifiRadioApWakeupCount, false, realtimeUs);
 
 
             final ArrayMap<String, Wakelock> wakeStats = mWakelockStats.getMap();
             for (int iw=wakeStats.size()-1; iw>=0; iw--) {
                 Wakelock wl = wakeStats.valueAt(iw);
-                if (wl.reset()) {
+                if (wl.reset(realtimeUs)) {
                     wakeStats.removeAt(iw);
                 } else {
                     active = true;
                 }
             }
-            mWakelockStats.cleanup();
+            final long realtimeMs = realtimeUs / 1000;
+            mWakelockStats.cleanup(realtimeMs);
             final ArrayMap<String, DualTimer> syncStats = mSyncStats.getMap();
             for (int is=syncStats.size()-1; is>=0; is--) {
                 DualTimer timer = syncStats.valueAt(is);
-                if (timer.reset(false)) {
+                if (timer.reset(false, realtimeUs)) {
                     syncStats.removeAt(is);
                     timer.detach();
                 } else {
                     active = true;
                 }
             }
-            mSyncStats.cleanup();
+            mSyncStats.cleanup(realtimeMs);
             final ArrayMap<String, DualTimer> jobStats = mJobStats.getMap();
             for (int ij=jobStats.size()-1; ij>=0; ij--) {
                 DualTimer timer = jobStats.valueAt(ij);
-                if (timer.reset(false)) {
+                if (timer.reset(false, realtimeUs)) {
                     jobStats.removeAt(ij);
                     timer.detach();
                 } else {
                     active = true;
                 }
             }
-            mJobStats.cleanup();
+            mJobStats.cleanup(realtimeMs);
             mJobCompletions.clear();
 
-            resetIfNotNull(mJobsDeferredEventCount, false);
-            resetIfNotNull(mJobsDeferredCount, false);
-            resetIfNotNull(mJobsFreshnessTimeMs, false);
-            resetIfNotNull(mJobsFreshnessBuckets, false);
+            resetIfNotNull(mJobsDeferredEventCount, false, realtimeUs);
+            resetIfNotNull(mJobsDeferredCount, false, realtimeUs);
+            resetIfNotNull(mJobsFreshnessTimeMs, false, realtimeUs /* unused */);
+            resetIfNotNull(mJobsFreshnessBuckets, false, realtimeUs);
 
             for (int ise = mSensorStats.size() - 1; ise >= 0; ise--) {
                 Sensor s = mSensorStats.valueAt(ise);
-                if (s.reset()) {
+                if (s.reset(realtimeUs)) {
                     mSensorStats.removeAt(ise);
                 } else {
                     active = true;
@@ -8128,8 +8607,8 @@
 
             mProportionalSystemServiceUsage = 0;
 
-            mLastStepUserTime = mLastStepSystemTime = 0;
-            mCurStepUserTime = mCurStepSystemTime = 0;
+            mLastStepUserTimeMs = mLastStepSystemTimeMs = 0;
+            mCurStepUserTimeMs = mCurStepSystemTimeMs = 0;
 
 
             return !active;
@@ -8943,13 +9422,13 @@
                 return new DualTimer(mBsi.mClocks, mUid, type, pool, timeBase, bgTimeBase, in);
             }
 
-            boolean reset() {
+            boolean reset(long elapsedRealtimeUs) {
                 boolean wlactive = false;
 
-                wlactive |= !resetIfNotNull(mTimerFull,false);
-                wlactive |= !resetIfNotNull(mTimerPartial,false);
-                wlactive |= !resetIfNotNull(mTimerWindow,false);
-                wlactive |= !resetIfNotNull(mTimerDraw,false);
+                wlactive |= !resetIfNotNull(mTimerFull, false, elapsedRealtimeUs);
+                wlactive |= !resetIfNotNull(mTimerPartial, false, elapsedRealtimeUs);
+                wlactive |= !resetIfNotNull(mTimerWindow, false, elapsedRealtimeUs);
+                wlactive |= !resetIfNotNull(mTimerDraw, false, elapsedRealtimeUs);
 
                 if (!wlactive) {
                     detachIfNotNull(mTimerFull);
@@ -9040,8 +9519,8 @@
                 return new DualTimer(mBsi.mClocks, mUid, 0, pool, timeBase, bgTimeBase, in);
             }
 
-            boolean reset() {
-                if (mTimer.reset(true)) {
+            boolean reset(long elapsedRealtimeUs) {
+                if (mTimer.reset(true, elapsedRealtimeUs)) {
                     mTimer = null;
                     return true;
                 }
@@ -9103,17 +9582,17 @@
             /**
              * Total time (in ms) spent executing in user code.
              */
-            long mUserTime;
+            long mUserTimeMs;
 
             /**
              * Total time (in ms) spent executing in kernel code.
              */
-            long mSystemTime;
+            long mSystemTimeMs;
 
             /**
              * Amount of time (in ms) the process was running in the foreground.
              */
-            long mForegroundTime;
+            long mForegroundTimeMs;
 
             /**
              * Number of times the process has been started.
@@ -9138,14 +9617,16 @@
                 mBsi.mOnBatteryTimeBase.add(this);
             }
 
-            public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
+            public void onTimeStarted(long elapsedRealtimeUs, long baseUptimeUs,
+                    long baseRealtimeUs) {
             }
 
-            public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
+            public void onTimeStopped(long elapsedRealtimeUs, long baseUptimeUs,
+                    long baseRealtimeUs) {
             }
 
             @Override
-            public boolean reset(boolean detachIfReset) {
+            public boolean reset(boolean detachIfReset, long elapsedRealtimeUs) {
                 if (detachIfReset) {
                     this.detach();
                 }
@@ -9169,14 +9650,14 @@
                 return null;
             }
 
-            public void addExcessiveCpu(long overTime, long usedTime) {
+            public void addExcessiveCpu(long overTimeMs, long usedTimeMs) {
                 if (mExcessivePower == null) {
                     mExcessivePower = new ArrayList<ExcessivePower>();
                 }
                 ExcessivePower ew = new ExcessivePower();
                 ew.type = ExcessivePower.TYPE_CPU;
-                ew.overTime = overTime;
-                ew.usedTime = usedTime;
+                ew.overTime = overTimeMs;
+                ew.usedTime = usedTimeMs;
                 mExcessivePower.add(ew);
             }
 
@@ -9219,9 +9700,9 @@
             }
 
             void writeToParcelLocked(Parcel out) {
-                out.writeLong(mUserTime);
-                out.writeLong(mSystemTime);
-                out.writeLong(mForegroundTime);
+                out.writeLong(mUserTimeMs);
+                out.writeLong(mSystemTimeMs);
+                out.writeLong(mForegroundTimeMs);
                 out.writeInt(mStarts);
                 out.writeInt(mNumCrashes);
                 out.writeInt(mNumAnrs);
@@ -9229,9 +9710,9 @@
             }
 
             void readFromParcelLocked(Parcel in) {
-                mUserTime = in.readLong();
-                mSystemTime = in.readLong();
-                mForegroundTime = in.readLong();
+                mUserTimeMs = in.readLong();
+                mSystemTimeMs = in.readLong();
+                mForegroundTimeMs = in.readLong();
                 mStarts = in.readInt();
                 mNumCrashes = in.readInt();
                 mNumAnrs = in.readInt();
@@ -9239,20 +9720,20 @@
             }
 
             @UnsupportedAppUsage
-            public void addCpuTimeLocked(int utime, int stime) {
-                addCpuTimeLocked(utime, stime, mBsi.mOnBatteryTimeBase.isRunning());
+            public void addCpuTimeLocked(int utimeMs, int stimeMs) {
+                addCpuTimeLocked(utimeMs, stimeMs, mBsi.mOnBatteryTimeBase.isRunning());
             }
 
-            public void addCpuTimeLocked(int utime, int stime, boolean isRunning) {
+            public void addCpuTimeLocked(int utimeMs, int stimeMs, boolean isRunning) {
                 if (isRunning) {
-                    mUserTime += utime;
-                    mSystemTime += stime;
+                    mUserTimeMs += utimeMs;
+                    mSystemTimeMs += stimeMs;
                 }
             }
 
             @UnsupportedAppUsage
-            public void addForegroundTimeLocked(long ttime) {
-                mForegroundTime += ttime;
+            public void addForegroundTimeLocked(long ttimeMs) {
+                mForegroundTimeMs += ttimeMs;
             }
 
             @UnsupportedAppUsage
@@ -9276,19 +9757,19 @@
             @Override
             @UnsupportedAppUsage
             public long getUserTime(int which) {
-                return mUserTime;
+                return mUserTimeMs;
             }
 
             @Override
             @UnsupportedAppUsage
             public long getSystemTime(int which) {
-                return mSystemTime;
+                return mSystemTimeMs;
             }
 
             @Override
             @UnsupportedAppUsage
             public long getForegroundTime(int which) {
-                return mForegroundTime;
+                return mForegroundTimeMs;
             }
 
             @Override
@@ -9333,14 +9814,16 @@
                 mBsi.mOnBatteryScreenOffTimeBase.add(this);
             }
 
-            public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
+            public void onTimeStarted(long elapsedRealtimeUs, long baseUptimeUs,
+                    long baseRealtimeUs) {
             }
 
-            public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
+            public void onTimeStopped(long elapsedRealtimeUs, long baseUptimeUs,
+                    long baseRealtimeUs) {
             }
 
             @Override
-            public boolean reset(boolean detachIfReset) {
+            public boolean reset(boolean detachIfReset, long elapsedRealtimeUs) {
                 if (detachIfReset) {
                     this.detach();
                 }
@@ -9430,13 +9913,13 @@
                 /**
                  * Total time (ms in battery uptime) the service has been left started.
                  */
-                protected long mStartTime;
+                protected long mStartTimeMs;
 
                 /**
                  * If service has been started and not yet stopped, this is
                  * when it was started.
                  */
-                protected long mRunningSince;
+                protected long mRunningSinceMs;
 
                 /**
                  * True if we are currently running.
@@ -9451,13 +9934,13 @@
                 /**
                  * Total time (ms in battery uptime) the service has been left launched.
                  */
-                protected long mLaunchedTime;
+                protected long mLaunchedTimeMs;
 
                 /**
                  * If service has been launched and not yet exited, this is
                  * when it was launched (ms in battery uptime).
                  */
-                protected long mLaunchedSince;
+                protected long mLaunchedSinceMs;
 
                 /**
                  * True if we are currently launched.
@@ -9477,16 +9960,16 @@
                     mBsi.mOnBatteryTimeBase.add(this);
                 }
 
-                public void onTimeStarted(long elapsedRealtime, long baseUptime,
-                        long baseRealtime) {
+                public void onTimeStarted(long elapsedRealtimeUs, long baseUptimeUs,
+                        long baseRealtimeUs) {
                 }
 
-                public void onTimeStopped(long elapsedRealtime, long baseUptime,
-                        long baseRealtime) {
+                public void onTimeStopped(long elapsedRealtimeUs, long baseUptimeUs,
+                        long baseRealtimeUs) {
                 }
 
                 @Override
-                public boolean reset(boolean detachIfReset) {
+                public boolean reset(boolean detachIfReset, long elapsedRealtimeUs) {
                     if (detachIfReset) {
                         this.detach();
                     }
@@ -9495,59 +9978,68 @@
 
                 /**
                  * Remove this Serv as a listener from the time base.
-                 */
+                 Ms*/
                 @Override
                 public void detach() {
                     mBsi.mOnBatteryTimeBase.remove(this);
                 }
 
                 public void readFromParcelLocked(Parcel in) {
-                    mStartTime = in.readLong();
-                    mRunningSince = in.readLong();
+                    mStartTimeMs = in.readLong();
+                    mRunningSinceMs = in.readLong();
                     mRunning = in.readInt() != 0;
                     mStarts = in.readInt();
-                    mLaunchedTime = in.readLong();
-                    mLaunchedSince = in.readLong();
+                    mLaunchedTimeMs = in.readLong();
+                    mLaunchedSinceMs = in.readLong();
                     mLaunched = in.readInt() != 0;
                     mLaunches = in.readInt();
                 }
 
                 public void writeToParcelLocked(Parcel out) {
-                    out.writeLong(mStartTime);
-                    out.writeLong(mRunningSince);
+                    out.writeLong(mStartTimeMs);
+                    out.writeLong(mRunningSinceMs);
                     out.writeInt(mRunning ? 1 : 0);
                     out.writeInt(mStarts);
-                    out.writeLong(mLaunchedTime);
-                    out.writeLong(mLaunchedSince);
+                    out.writeLong(mLaunchedTimeMs);
+                    out.writeLong(mLaunchedSinceMs);
                     out.writeInt(mLaunched ? 1 : 0);
                     out.writeInt(mLaunches);
                 }
 
-                public long getLaunchTimeToNowLocked(long batteryUptime) {
-                    if (!mLaunched) return mLaunchedTime;
-                    return mLaunchedTime + batteryUptime - mLaunchedSince;
+                public long getLaunchTimeToNowLocked(long batteryUptimeMs) {
+                    if (!mLaunched) return mLaunchedTimeMs;
+                    return mLaunchedTimeMs + batteryUptimeMs - mLaunchedSinceMs;
                 }
 
-                public long getStartTimeToNowLocked(long batteryUptime) {
-                    if (!mRunning) return mStartTime;
-                    return mStartTime + batteryUptime - mRunningSince;
+                public long getStartTimeToNowLocked(long batteryUptimeMs) {
+                    if (!mRunning) return mStartTimeMs;
+                    return mStartTimeMs + batteryUptimeMs - mRunningSinceMs;
                 }
 
                 @UnsupportedAppUsage
                 public void startLaunchedLocked() {
+                    startLaunchedLocked(mBsi.mClocks.uptimeMillis());
+                }
+
+                public void startLaunchedLocked(long uptimeMs) {
                     if (!mLaunched) {
                         mLaunches++;
-                        mLaunchedSince = mBsi.getBatteryUptimeLocked();
+                        mLaunchedSinceMs = mBsi.getBatteryUptimeLocked(uptimeMs) / 1000;
                         mLaunched = true;
                     }
                 }
 
                 @UnsupportedAppUsage
                 public void stopLaunchedLocked() {
+                    stopLaunchedLocked(mBsi.mClocks.uptimeMillis());
+                }
+
+                public void stopLaunchedLocked(long uptimeMs) {
                     if (mLaunched) {
-                        long time = mBsi.getBatteryUptimeLocked() - mLaunchedSince;
-                        if (time > 0) {
-                            mLaunchedTime += time;
+                        long timeMs = mBsi.getBatteryUptimeLocked(uptimeMs) / 1000
+                                - mLaunchedSinceMs;
+                        if (timeMs > 0) {
+                            mLaunchedTimeMs += timeMs;
                         } else {
                             mLaunches--;
                         }
@@ -9557,19 +10049,28 @@
 
                 @UnsupportedAppUsage
                 public void startRunningLocked() {
+                    startRunningLocked(mBsi.mClocks.uptimeMillis());
+                }
+
+                public void startRunningLocked(long uptimeMs) {
                     if (!mRunning) {
                         mStarts++;
-                        mRunningSince = mBsi.getBatteryUptimeLocked();
+                        mRunningSinceMs = mBsi.getBatteryUptimeLocked(uptimeMs) / 1000;
                         mRunning = true;
                     }
                 }
 
                 @UnsupportedAppUsage
                 public void stopRunningLocked() {
+                    stopRunningLocked(mBsi.mClocks.uptimeMillis());
+                }
+
+                public void stopRunningLocked(long uptimeMs) {
                     if (mRunning) {
-                        long time = mBsi.getBatteryUptimeLocked() - mRunningSince;
-                        if (time > 0) {
-                            mStartTime += time;
+                        long timeMs = mBsi.getBatteryUptimeLocked(uptimeMs) / 1000
+                                - mRunningSinceMs;
+                        if (timeMs > 0) {
+                            mStartTimeMs += timeMs;
                         } else {
                             mStarts--;
                         }
@@ -9619,6 +10120,12 @@
 
         @GuardedBy("mBsi")
         public void updateUidProcessStateLocked(int procState) {
+            updateUidProcessStateLocked(procState,
+                    mBsi.mClocks.elapsedRealtime(), mBsi.mClocks.uptimeMillis());
+        }
+
+        public void updateUidProcessStateLocked(int procState,
+                long elapsedRealtimeMs, long uptimeMs) {
             int uidRunningState;
             // Make special note of Foreground Services
             final boolean userAwareService =
@@ -9629,10 +10136,7 @@
                 return;
             }
 
-            final long elapsedRealtimeMs = mBsi.mClocks.elapsedRealtime();
             if (mProcessState != uidRunningState) {
-                final long uptimeMs = mBsi.mClocks.uptimeMillis();
-
                 if (mProcessState != ActivityManager.PROCESS_STATE_NONEXISTENT) {
                     mProcessStateTimer[mProcessState].stopRunningLocked(elapsedRealtimeMs);
 
@@ -9789,28 +10293,28 @@
         }
 
         public void noteStartSyncLocked(String name, long elapsedRealtimeMs) {
-            DualTimer t = mSyncStats.startObject(name);
+            DualTimer t = mSyncStats.startObject(name, elapsedRealtimeMs);
             if (t != null) {
                 t.startRunningLocked(elapsedRealtimeMs);
             }
         }
 
         public void noteStopSyncLocked(String name, long elapsedRealtimeMs) {
-            DualTimer t = mSyncStats.stopObject(name);
+            DualTimer t = mSyncStats.stopObject(name, elapsedRealtimeMs);
             if (t != null) {
                 t.stopRunningLocked(elapsedRealtimeMs);
             }
         }
 
         public void noteStartJobLocked(String name, long elapsedRealtimeMs) {
-            DualTimer t = mJobStats.startObject(name);
+            DualTimer t = mJobStats.startObject(name, elapsedRealtimeMs);
             if (t != null) {
                 t.startRunningLocked(elapsedRealtimeMs);
             }
         }
 
         public void noteStopJobLocked(String name, long elapsedRealtimeMs, int stopReason) {
-            DualTimer t = mJobStats.stopObject(name);
+            DualTimer t = mJobStats.stopObject(name, elapsedRealtimeMs);
             if (t != null) {
                 t.stopRunningLocked(elapsedRealtimeMs);
             }
@@ -9873,7 +10377,7 @@
         }
 
         public void noteStartWakeLocked(int pid, String name, int type, long elapsedRealtimeMs) {
-            Wakelock wl = mWakelockStats.startObject(name);
+            Wakelock wl = mWakelockStats.startObject(name, elapsedRealtimeMs);
             if (wl != null) {
                 getWakelockTimerLocked(wl, type).startRunningLocked(elapsedRealtimeMs);
             }
@@ -9889,7 +10393,7 @@
         }
 
         public void noteStopWakeLocked(int pid, String name, int type, long elapsedRealtimeMs) {
-            Wakelock wl = mWakelockStats.stopObject(name);
+            Wakelock wl = mWakelockStats.stopObject(name, elapsedRealtimeMs);
             if (wl != null) {
                 StopwatchTimer wlt = getWakelockTimerLocked(wl, type);
                 wlt.stopRunningLocked(elapsedRealtimeMs);
@@ -9910,10 +10414,10 @@
             }
         }
 
-        public void reportExcessiveCpuLocked(String proc, long overTime, long usedTime) {
+        public void reportExcessiveCpuLocked(String proc, long overTimeMs, long usedTimeMs) {
             Proc p = getProcessStatsLocked(proc);
             if (p != null) {
-                p.addExcessiveCpu(overTime, usedTime);
+                p.addExcessiveCpu(overTimeMs, usedTimeMs);
             }
         }
 
@@ -10041,16 +10545,16 @@
         mDischargeDeepDozeCounter = new LongSamplingCounter(mOnBatteryTimeBase);
         mDischargeCounter = new LongSamplingCounter(mOnBatteryTimeBase);
         mOnBattery = mOnBatteryInternal = false;
-        long uptime = mClocks.uptimeMillis() * 1000;
-        long realtime = mClocks.elapsedRealtime() * 1000;
-        initTimes(uptime, realtime);
+        long uptimeUs = mClocks.uptimeMillis() * 1000;
+        long realtimeUs = mClocks.elapsedRealtime() * 1000;
+        initTimes(uptimeUs, realtimeUs);
         mStartPlatformVersion = mEndPlatformVersion = Build.ID;
         mDischargeStartLevel = 0;
         mDischargeUnplugLevel = 0;
         mDischargePlugLevel = -1;
         mDischargeCurrentLevel = 0;
         mCurrentBatteryLevel = 0;
-        initDischarge();
+        initDischarge(realtimeUs);
         clearHistoryLocked();
         updateDailyDeadlineLocked();
         mPlatformIdleStateCallback = cb;
@@ -10110,9 +10614,9 @@
         mCallback = cb;
     }
 
-    public void setRadioScanningTimeoutLocked(long timeout) {
+    public void setRadioScanningTimeoutLocked(long timeoutUs) {
         if (mPhoneSignalScanningTimer != null) {
-            mPhoneSignalScanningTimer.setTimeout(timeout);
+            mPhoneSignalScanningTimer.setTimeout(timeoutUs);
         }
     }
 
@@ -10122,9 +10626,9 @@
 
     public void updateDailyDeadlineLocked() {
         // Get the current time.
-        long currentTime = mDailyStartTime = System.currentTimeMillis();
+        long currentTimeMs = mDailyStartTimeMs = System.currentTimeMillis();
         Calendar calDeadline = Calendar.getInstance();
-        calDeadline.setTimeInMillis(currentTime);
+        calDeadline.setTimeInMillis(currentTimeMs);
 
         // Move time up to the next day, ranging from 1am to 3pm.
         calDeadline.set(Calendar.DAY_OF_YEAR, calDeadline.get(Calendar.DAY_OF_YEAR) + 1);
@@ -10132,25 +10636,24 @@
         calDeadline.set(Calendar.SECOND, 0);
         calDeadline.set(Calendar.MINUTE, 0);
         calDeadline.set(Calendar.HOUR_OF_DAY, 1);
-        mNextMinDailyDeadline = calDeadline.getTimeInMillis();
+        mNextMinDailyDeadlineMs = calDeadline.getTimeInMillis();
         calDeadline.set(Calendar.HOUR_OF_DAY, 3);
-        mNextMaxDailyDeadline = calDeadline.getTimeInMillis();
+        mNextMaxDailyDeadlineMs = calDeadline.getTimeInMillis();
     }
 
-    public void recordDailyStatsIfNeededLocked(boolean settled) {
-        long currentTime = System.currentTimeMillis();
-        if (currentTime >= mNextMaxDailyDeadline) {
+    public void recordDailyStatsIfNeededLocked(boolean settled, long currentTimeMs) {
+        if (currentTimeMs >= mNextMaxDailyDeadlineMs) {
             recordDailyStatsLocked();
-        } else if (settled && currentTime >= mNextMinDailyDeadline) {
+        } else if (settled && currentTimeMs >= mNextMinDailyDeadlineMs) {
             recordDailyStatsLocked();
-        } else if (currentTime < (mDailyStartTime-(1000*60*60*24))) {
+        } else if (currentTimeMs < (mDailyStartTimeMs - (1000 * 60 * 60 * 24))) {
             recordDailyStatsLocked();
         }
     }
 
     public void recordDailyStatsLocked() {
         DailyItem item = new DailyItem();
-        item.mStartTime = mDailyStartTime;
+        item.mStartTime = mDailyStartTimeMs;
         item.mEndTime = System.currentTimeMillis();
         boolean hasData = false;
         if (mDailyDischargeStepTracker.mNumStepDurations > 0) {
@@ -10175,7 +10678,7 @@
         updateDailyDeadlineLocked();
 
         if (hasData) {
-            final long startTime = SystemClock.uptimeMillis();
+            final long startTimeMs = SystemClock.uptimeMillis();
             mDailyItems.add(item);
             while (mDailyItems.size() > MAX_DAILY_ITEMS) {
                 mDailyItems.remove(0);
@@ -10185,12 +10688,12 @@
                 XmlSerializer out = new FastXmlSerializer();
                 out.setOutput(memStream, StandardCharsets.UTF_8.name());
                 writeDailyItemsLocked(out);
-                final long initialTime = SystemClock.uptimeMillis() - startTime;
+                final long initialTimeMs = SystemClock.uptimeMillis() - startTimeMs;
                 BackgroundThread.getHandler().post(new Runnable() {
                     @Override
                     public void run() {
                         synchronized (mCheckinFile) {
-                            final long startTime2 = SystemClock.uptimeMillis();
+                            final long startTimeMs2 = SystemClock.uptimeMillis();
                             FileOutputStream stream = null;
                             try {
                                 stream = mDailyFile.startWrite();
@@ -10199,7 +10702,7 @@
                                 mDailyFile.finishWrite(stream);
                                 com.android.internal.logging.EventLogTags.writeCommitSysConfigFile(
                                         "batterystats-daily",
-                                        initialTime + SystemClock.uptimeMillis() - startTime2);
+                                        initialTimeMs + SystemClock.uptimeMillis() - startTimeMs2);
                             } catch (IOException e) {
                                 Slog.w("BatteryStats",
                                         "Error writing battery daily items", e);
@@ -10431,17 +10934,17 @@
 
     @Override
     public long getCurrentDailyStartTime() {
-        return mDailyStartTime;
+        return mDailyStartTimeMs;
     }
 
     @Override
     public long getNextMinDailyDeadline() {
-        return mNextMinDailyDeadline;
+        return mNextMinDailyDeadlineMs;
     }
 
     @Override
     public long getNextMaxDailyDeadline() {
-        return mNextMaxDailyDeadline;
+        return mNextMaxDailyDeadlineMs;
     }
 
     @Override
@@ -10554,12 +11057,12 @@
         if (p == null) {
             return false;
         }
-        final long lastRealtime = out.time;
-        final long lastWalltime = out.currentTime;
+        final long lastRealtimeMs = out.time;
+        final long lastWalltimeMs = out.currentTime;
         readHistoryDelta(p, out);
         if (out.cmd != HistoryItem.CMD_CURRENT_TIME
-                && out.cmd != HistoryItem.CMD_RESET && lastWalltime != 0) {
-            out.currentTime = lastWalltime + (out.time - lastRealtime);
+                && out.cmd != HistoryItem.CMD_RESET && lastWalltimeMs != 0) {
+            out.currentTime = lastWalltimeMs + (out.time - lastRealtimeMs);
         }
         return true;
     }
@@ -10574,7 +11077,7 @@
 
     @Override
     public long getHistoryBaseTime() {
-        return mHistoryBaseTime;
+        return mHistoryBaseTimeMs;
     }
 
     @Override
@@ -10604,17 +11107,17 @@
         return state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND;
     }
 
-    void initTimes(long uptime, long realtime) {
-        mStartClockTime = System.currentTimeMillis();
-        mOnBatteryTimeBase.init(uptime, realtime);
-        mOnBatteryScreenOffTimeBase.init(uptime, realtime);
-        mRealtime = 0;
-        mUptime = 0;
-        mRealtimeStart = realtime;
-        mUptimeStart = uptime;
+    void initTimes(long uptimeUs, long realtimeUs) {
+        mStartClockTimeMs = System.currentTimeMillis();
+        mOnBatteryTimeBase.init(uptimeUs, realtimeUs);
+        mOnBatteryScreenOffTimeBase.init(uptimeUs, realtimeUs);
+        mRealtimeUs = 0;
+        mUptimeUs = 0;
+        mRealtimeStartUs = realtimeUs;
+        mUptimeStartUs = uptimeUs;
     }
 
-    void initDischarge() {
+    void initDischarge(long elapsedRealtimeUs) {
         mLowDischargeAmountSinceCharge = 0;
         mHighDischargeAmountSinceCharge = 0;
         mDischargeAmountScreenOn = 0;
@@ -10625,26 +11128,26 @@
         mDischargeAmountScreenDozeSinceCharge = 0;
         mDischargeStepTracker.init();
         mChargeStepTracker.init();
-        mDischargeScreenOffCounter.reset(false);
-        mDischargeScreenDozeCounter.reset(false);
-        mDischargeLightDozeCounter.reset(false);
-        mDischargeDeepDozeCounter.reset(false);
-        mDischargeCounter.reset(false);
+        mDischargeScreenOffCounter.reset(false, elapsedRealtimeUs);
+        mDischargeScreenDozeCounter.reset(false, elapsedRealtimeUs);
+        mDischargeLightDozeCounter.reset(false, elapsedRealtimeUs);
+        mDischargeDeepDozeCounter.reset(false, elapsedRealtimeUs);
+        mDischargeCounter.reset(false, elapsedRealtimeUs);
     }
 
     public void resetAllStatsCmdLocked() {
-        resetAllStatsLocked();
         final long mSecUptime = mClocks.uptimeMillis();
-        long uptime = mSecUptime * 1000;
+        long uptimeUs = mSecUptime * 1000;
         long mSecRealtime = mClocks.elapsedRealtime();
-        long realtime = mSecRealtime * 1000;
+        long realtimeUs = mSecRealtime * 1000;
+        resetAllStatsLocked(mSecUptime, mSecRealtime);
         mDischargeStartLevel = mHistoryCur.batteryLevel;
         pullPendingStateUpdatesLocked();
         addHistoryRecordLocked(mSecRealtime, mSecUptime);
         mDischargeCurrentLevel = mDischargeUnplugLevel = mDischargePlugLevel
                 = mCurrentBatteryLevel = mHistoryCur.batteryLevel;
-        mOnBatteryTimeBase.reset(uptime, realtime);
-        mOnBatteryScreenOffTimeBase.reset(uptime, realtime);
+        mOnBatteryTimeBase.reset(uptimeUs, realtimeUs);
+        mOnBatteryScreenOffTimeBase.reset(uptimeUs, realtimeUs);
         if ((mHistoryCur.states&HistoryItem.STATE_BATTERY_PLUGGED_FLAG) == 0) {
             if (isScreenOn(mScreenState)) {
                 mDischargeScreenOnUnplugLevel = mHistoryCur.batteryLevel;
@@ -10666,15 +11169,15 @@
         initActiveHistoryEventsLocked(mSecRealtime, mSecUptime);
     }
 
-    private void resetAllStatsLocked() {
-        final long uptimeMillis = mClocks.uptimeMillis();
-        final long elapsedRealtimeMillis = mClocks.elapsedRealtime();
+    private void resetAllStatsLocked(long uptimeMillis, long elapsedRealtimeMillis) {
+        final long uptimeUs = uptimeMillis * 1000;
+        final long elapsedRealtimeUs = elapsedRealtimeMillis * 1000;
         mStartCount = 0;
-        initTimes(uptimeMillis * 1000, elapsedRealtimeMillis * 1000);
-        mScreenOnTimer.reset(false);
-        mScreenDozeTimer.reset(false);
+        initTimes(uptimeUs, elapsedRealtimeUs);
+        mScreenOnTimer.reset(false, uptimeUs);
+        mScreenDozeTimer.reset(false, elapsedRealtimeUs);
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
-            mScreenBrightnessTimer[i].reset(false);
+            mScreenBrightnessTimer[i].reset(false, elapsedRealtimeUs);
         }
 
         if (mPowerProfile != null) {
@@ -10684,60 +11187,60 @@
         }
         mMinLearnedBatteryCapacity = -1;
         mMaxLearnedBatteryCapacity = -1;
-        mInteractiveTimer.reset(false);
-        mPowerSaveModeEnabledTimer.reset(false);
-        mLastIdleTimeStart = elapsedRealtimeMillis;
-        mLongestLightIdleTime = 0;
-        mLongestFullIdleTime = 0;
-        mDeviceIdleModeLightTimer.reset(false);
-        mDeviceIdleModeFullTimer.reset(false);
-        mDeviceLightIdlingTimer.reset(false);
-        mDeviceIdlingTimer.reset(false);
-        mPhoneOnTimer.reset(false);
-        mAudioOnTimer.reset(false);
-        mVideoOnTimer.reset(false);
-        mFlashlightOnTimer.reset(false);
-        mCameraOnTimer.reset(false);
-        mBluetoothScanTimer.reset(false);
+        mInteractiveTimer.reset(false, elapsedRealtimeUs);
+        mPowerSaveModeEnabledTimer.reset(false, elapsedRealtimeUs);
+        mLastIdleTimeStartMs = elapsedRealtimeMillis;
+        mLongestLightIdleTimeMs = 0;
+        mLongestFullIdleTimeMs = 0;
+        mDeviceIdleModeLightTimer.reset(false, elapsedRealtimeUs);
+        mDeviceIdleModeFullTimer.reset(false, elapsedRealtimeUs);
+        mDeviceLightIdlingTimer.reset(false, elapsedRealtimeUs);
+        mDeviceIdlingTimer.reset(false, elapsedRealtimeUs);
+        mPhoneOnTimer.reset(false, elapsedRealtimeUs);
+        mAudioOnTimer.reset(false, elapsedRealtimeUs);
+        mVideoOnTimer.reset(false, elapsedRealtimeUs);
+        mFlashlightOnTimer.reset(false, elapsedRealtimeUs);
+        mCameraOnTimer.reset(false, elapsedRealtimeUs);
+        mBluetoothScanTimer.reset(false, elapsedRealtimeUs);
         for (int i = 0; i < CellSignalStrength.getNumSignalStrengthLevels(); i++) {
-            mPhoneSignalStrengthsTimer[i].reset(false);
+            mPhoneSignalStrengthsTimer[i].reset(false, elapsedRealtimeUs);
         }
-        mPhoneSignalScanningTimer.reset(false);
+        mPhoneSignalScanningTimer.reset(false, elapsedRealtimeUs);
         for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
-            mPhoneDataConnectionsTimer[i].reset(false);
+            mPhoneDataConnectionsTimer[i].reset(false, elapsedRealtimeUs);
         }
         for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
-            mNetworkByteActivityCounters[i].reset(false);
-            mNetworkPacketActivityCounters[i].reset(false);
+            mNetworkByteActivityCounters[i].reset(false, elapsedRealtimeUs);
+            mNetworkPacketActivityCounters[i].reset(false, elapsedRealtimeUs);
         }
-        mMobileRadioActiveTimer.reset(false);
-        mMobileRadioActivePerAppTimer.reset(false);
-        mMobileRadioActiveAdjustedTime.reset(false);
-        mMobileRadioActiveUnknownTime.reset(false);
-        mMobileRadioActiveUnknownCount.reset(false);
-        mWifiOnTimer.reset(false);
-        mGlobalWifiRunningTimer.reset(false);
+        mMobileRadioActiveTimer.reset(false, elapsedRealtimeUs);
+        mMobileRadioActivePerAppTimer.reset(false, elapsedRealtimeUs);
+        mMobileRadioActiveAdjustedTime.reset(false, elapsedRealtimeUs);
+        mMobileRadioActiveUnknownTime.reset(false, elapsedRealtimeUs);
+        mMobileRadioActiveUnknownCount.reset(false, elapsedRealtimeUs);
+        mWifiOnTimer.reset(false, elapsedRealtimeUs);
+        mGlobalWifiRunningTimer.reset(false, elapsedRealtimeUs);
         for (int i=0; i<NUM_WIFI_STATES; i++) {
-            mWifiStateTimer[i].reset(false);
+            mWifiStateTimer[i].reset(false, elapsedRealtimeUs);
         }
         for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
-            mWifiSupplStateTimer[i].reset(false);
+            mWifiSupplStateTimer[i].reset(false, elapsedRealtimeUs);
         }
         for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
-            mWifiSignalStrengthsTimer[i].reset(false);
+            mWifiSignalStrengthsTimer[i].reset(false, elapsedRealtimeUs);
         }
-        mWifiMulticastWakelockTimer.reset(false);
-        mWifiActiveTimer.reset(false);
-        mWifiActivity.reset(false);
+        mWifiMulticastWakelockTimer.reset(false, elapsedRealtimeUs);
+        mWifiActiveTimer.reset(false, elapsedRealtimeUs);
+        mWifiActivity.reset(false, elapsedRealtimeUs);
         for (int i=0; i< GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
-            mGpsSignalQualityTimer[i].reset(false);
+            mGpsSignalQualityTimer[i].reset(false, elapsedRealtimeUs);
         }
-        mBluetoothActivity.reset(false);
-        mModemActivity.reset(false);
+        mBluetoothActivity.reset(false, elapsedRealtimeUs);
+        mModemActivity.reset(false, elapsedRealtimeUs);
         mNumConnectivityChange = 0;
 
         for (int i=0; i<mUidStats.size(); i++) {
-            if (mUidStats.valueAt(i).reset(uptimeMillis * 1000, elapsedRealtimeMillis * 1000)) {
+            if (mUidStats.valueAt(i).reset(uptimeUs, elapsedRealtimeUs)) {
                 mUidStats.valueAt(i).detachFromTimeBase();
                 mUidStats.remove(mUidStats.keyAt(i));
                 i--;
@@ -10780,25 +11283,25 @@
 
         mTmpRailStats.reset();
 
-        resetIfNotNull(mSystemServerThreadCpuTimesUs, false);
-        resetIfNotNull(mBinderThreadCpuTimesUs, false);
+        resetIfNotNull(mSystemServerThreadCpuTimesUs, false, elapsedRealtimeUs);
+        resetIfNotNull(mBinderThreadCpuTimesUs, false, elapsedRealtimeUs);
 
         mLastHistoryStepDetails = null;
-        mLastStepCpuUserTime = mLastStepCpuSystemTime = 0;
-        mCurStepCpuUserTime = mCurStepCpuSystemTime = 0;
-        mLastStepCpuUserTime = mCurStepCpuUserTime = 0;
-        mLastStepCpuSystemTime = mCurStepCpuSystemTime = 0;
-        mLastStepStatUserTime = mCurStepStatUserTime = 0;
-        mLastStepStatSystemTime = mCurStepStatSystemTime = 0;
-        mLastStepStatIOWaitTime = mCurStepStatIOWaitTime = 0;
-        mLastStepStatIrqTime = mCurStepStatIrqTime = 0;
-        mLastStepStatSoftIrqTime = mCurStepStatSoftIrqTime = 0;
-        mLastStepStatIdleTime = mCurStepStatIdleTime = 0;
+        mLastStepCpuUserTimeMs = mLastStepCpuSystemTimeMs = 0;
+        mCurStepCpuUserTimeMs = mCurStepCpuSystemTimeMs = 0;
+        mLastStepCpuUserTimeMs = mCurStepCpuUserTimeMs = 0;
+        mLastStepCpuSystemTimeMs = mCurStepCpuSystemTimeMs = 0;
+        mLastStepStatUserTimeMs = mCurStepStatUserTimeMs = 0;
+        mLastStepStatSystemTimeMs = mCurStepStatSystemTimeMs = 0;
+        mLastStepStatIOWaitTimeMs = mCurStepStatIOWaitTimeMs = 0;
+        mLastStepStatIrqTimeMs = mCurStepStatIrqTimeMs = 0;
+        mLastStepStatSoftIrqTimeMs = mCurStepStatSoftIrqTimeMs = 0;
+        mLastStepStatIdleTimeMs = mCurStepStatIdleTimeMs = 0;
 
         mNumAllUidCpuTimeReads = 0;
         mNumUidsRemoved = 0;
 
-        initDischarge();
+        initDischarge(elapsedRealtimeUs);
 
         clearHistoryLocked();
         mBatteryStatsHistory.resetAllFiles();
@@ -10915,6 +11418,14 @@
      * @param info The energy information from the WiFi controller.
      */
     public void updateWifiState(@Nullable final WifiActivityEnergyInfo info) {
+        updateWifiState(info, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    /**
+     * @see #updateWifiState(WifiActivityEnergyInfo)
+     */
+    public void updateWifiState(@Nullable final WifiActivityEnergyInfo info,
+            long elapsedRealtimeMs, long uptimeMs) {
         if (DEBUG_ENERGY) {
             Slog.d(TAG, "Updating wifi stats: " + Arrays.toString(mWifiIfaces));
         }
@@ -10939,7 +11450,6 @@
                 return;
             }
 
-            final long elapsedRealtimeMs = mClocks.elapsedRealtime();
             SparseLongArray rxPackets = new SparseLongArray();
             SparseLongArray txPackets = new SparseLongArray();
             long totalTxPackets = 0;
@@ -10961,7 +11471,7 @@
                         continue;
                     }
 
-                    final Uid u = getUidStatsLocked(mapUid(entry.uid));
+                    final Uid u = getUidStatsLocked(mapUid(entry.uid), elapsedRealtimeMs, uptimeMs);
                     if (entry.rxBytes != 0) {
                         u.noteNetworkActivityLocked(NETWORK_WIFI_RX_DATA, entry.rxBytes,
                                 entry.rxPackets);
@@ -11127,7 +11637,8 @@
                 // Distribute the remaining Tx power appropriately between all apps that transmitted
                 // packets.
                 for (int i = 0; i < txPackets.size(); i++) {
-                    final Uid uid = getUidStatsLocked(txPackets.keyAt(i));
+                    final Uid uid = getUidStatsLocked(txPackets.keyAt(i),
+                            elapsedRealtimeMs, uptimeMs);
                     final long myTxTimeMs = (txPackets.valueAt(i) * leftOverTxTimeMs)
                             / totalTxPackets;
                     if (DEBUG_ENERGY) {
@@ -11140,7 +11651,8 @@
                 // Distribute the remaining Rx power appropriately between all apps that received
                 // packets.
                 for (int i = 0; i < rxPackets.size(); i++) {
-                    final Uid uid = getUidStatsLocked(rxPackets.keyAt(i));
+                    final Uid uid = getUidStatsLocked(rxPackets.keyAt(i),
+                            elapsedRealtimeMs, uptimeMs);
                     final long myRxTimeMs = (rxPackets.valueAt(i) * leftOverRxTimeMs)
                             / totalRxPackets;
                     if (DEBUG_ENERGY) {
@@ -11179,7 +11691,7 @@
                         monitoredRailChargeConsumedMaMs);
                 mHistoryCur.wifiRailChargeMah +=
                         (monitoredRailChargeConsumedMaMs / MILLISECONDS_IN_HOUR);
-                addHistoryRecordLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+                addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
                 mTmpRailStats.resetWifiTotalEnergyUsed();
             }
         }
@@ -11210,13 +11722,21 @@
      * Distribute Cell radio energy info and network traffic to apps.
      */
     public void updateMobileRadioState(@Nullable final ModemActivityInfo activityInfo) {
+        updateMobileRadioState(activityInfo, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    /**
+     * @see #updateMobileRadioState(ModemActivityInfo)
+     */
+    public void updateMobileRadioState(@Nullable final ModemActivityInfo activityInfo,
+            long elapsedRealtimeMs, long uptimeMs) {
         if (DEBUG_ENERGY) {
             Slog.d(TAG, "Updating mobile radio stats with " + activityInfo);
         }
         ModemActivityInfo deltaInfo = getDeltaModemActivityInfo(activityInfo);
 
         // Add modem tx power to history.
-        addModemTxPowerToHistory(deltaInfo);
+        addModemTxPowerToHistory(deltaInfo, elapsedRealtimeMs, uptimeMs);
 
         // Grab a separate lock to acquire the network stats, which may do I/O.
         NetworkStats delta = null;
@@ -11279,12 +11799,11 @@
                             monitoredRailChargeConsumedMaMs);
                     mHistoryCur.modemRailChargeMah +=
                             (monitoredRailChargeConsumedMaMs / MILLISECONDS_IN_HOUR);
-                    addHistoryRecordLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+                    addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
                     mTmpRailStats.resetCellularTotalEnergyUsed();
                 }
             }
-            final long elapsedRealtimeMs = mClocks.elapsedRealtime();
-            long radioTime = mMobileRadioActivePerAppTimer.getTimeSinceMarkLocked(
+            long radioTimeUs = mMobileRadioActivePerAppTimer.getTimeSinceMarkLocked(
                     elapsedRealtimeMs * 1000);
             mMobileRadioActivePerAppTimer.setMark(elapsedRealtimeMs);
 
@@ -11308,7 +11827,7 @@
                     totalRxPackets += entry.rxPackets;
                     totalTxPackets += entry.txPackets;
 
-                    final Uid u = getUidStatsLocked(mapUid(entry.uid));
+                    final Uid u = getUidStatsLocked(mapUid(entry.uid), elapsedRealtimeMs, uptimeMs);
                     u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_DATA, entry.rxBytes,
                             entry.rxPackets);
                     u.noteNetworkActivityLocked(NETWORK_MOBILE_TX_DATA, entry.txBytes,
@@ -11339,16 +11858,17 @@
                             continue;
                         }
 
-                        final Uid u = getUidStatsLocked(mapUid(entry.uid));
+                        final Uid u = getUidStatsLocked(mapUid(entry.uid),
+                                elapsedRealtimeMs, uptimeMs);
 
                         // Distribute total radio active time in to this app.
                         final long appPackets = entry.rxPackets + entry.txPackets;
-                        final long appRadioTime = (radioTime * appPackets) / totalPackets;
-                        u.noteMobileRadioActiveTimeLocked(appRadioTime);
+                        final long appRadioTimeUs = (radioTimeUs * appPackets) / totalPackets;
+                        u.noteMobileRadioActiveTimeLocked(appRadioTimeUs);
 
                         // Remove this app from the totals, so that we don't lose any time
                         // due to rounding.
-                        radioTime -= appRadioTime;
+                        radioTimeUs -= appRadioTimeUs;
                         totalPackets -= appPackets;
 
                         if (deltaInfo != null) {
@@ -11373,9 +11893,9 @@
                     }
                 }
 
-                if (radioTime > 0) {
+                if (radioTimeUs > 0) {
                     // Whoops, there is some radio time we can't blame on an app!
-                    mMobileRadioActiveUnknownTime.addCountLocked(radioTime);
+                    mMobileRadioActiveUnknownTime.addCountLocked(radioTimeUs);
                     mMobileRadioActiveUnknownCount.addCountLocked(1);
                 }
 
@@ -11391,7 +11911,8 @@
      * time at the highest power level.
      * @param activityInfo
      */
-    private synchronized void addModemTxPowerToHistory(final ModemActivityInfo activityInfo) {
+    private synchronized void addModemTxPowerToHistory(final ModemActivityInfo activityInfo,
+            long elapsedRealtimeMs, long uptimeMs) {
         if (activityInfo == null) {
             return;
         }
@@ -11399,8 +11920,6 @@
         if (txPowerInfo == null || txPowerInfo.size() != ModemActivityInfo.TX_POWER_LEVELS) {
             return;
         }
-        final long elapsedRealtime = mClocks.elapsedRealtime();
-        final long uptime = mClocks.uptimeMillis();
         int levelMaxTimeSpent = 0;
         for (int i = 1; i < txPowerInfo.size(); i++) {
             if (txPowerInfo.get(i).getTimeInMillis() > txPowerInfo.get(levelMaxTimeSpent)
@@ -11410,7 +11929,7 @@
         }
         if (levelMaxTimeSpent == ModemActivityInfo.TX_POWER_LEVELS - 1) {
             mHistoryCur.states2 |= HistoryItem.STATE2_CELLULAR_HIGH_TX_POWER_FLAG;
-            addHistoryRecordLocked(elapsedRealtime, uptime);
+            addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
         }
     }
 
@@ -11446,6 +11965,14 @@
      * @param info The energy information from the bluetooth controller.
      */
     public void updateBluetoothStateLocked(@Nullable final BluetoothActivityEnergyInfo info) {
+        updateBluetoothStateLocked(info, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    /**
+     * @see #updateBluetoothStateLocked(BluetoothActivityEnergyInfo)
+     */
+    public void updateBluetoothStateLocked(@Nullable final BluetoothActivityEnergyInfo info,
+            long elapsedRealtimeMs, long uptimeMs) {
         if (DEBUG_ENERGY) {
             Slog.d(TAG, "Updating bluetooth stats: " + info);
         }
@@ -11456,7 +11983,6 @@
 
         mHasBluetoothReporting = true;
 
-        final long elapsedRealtimeMs = mClocks.elapsedRealtime();
         final long rxTimeMs =
                 info.getControllerRxTimeMillis() - mLastBluetoothActivityInfo.rxTimeMs;
         final long txTimeMs =
@@ -11560,7 +12086,7 @@
             mNetworkByteActivityCounters[NETWORK_BT_TX_DATA].addCountLocked(txBytes);
 
             // Add to the UID counters.
-            final Uid u = getUidStatsLocked(mapUid(traffic.getUid()));
+            final Uid u = getUidStatsLocked(mapUid(traffic.getUid()), elapsedRealtimeMs, uptimeMs);
             u.noteNetworkActivityLocked(NETWORK_BT_RX_DATA, rxBytes, 0);
             u.noteNetworkActivityLocked(NETWORK_BT_TX_DATA, txBytes, 0);
 
@@ -11579,7 +12105,7 @@
                 final long txBytes =
                         traffic.getTxBytes() - mLastBluetoothActivityInfo.uidTxBytes.get(uid);
 
-                final Uid u = getUidStatsLocked(mapUid(uid));
+                final Uid u = getUidStatsLocked(mapUid(uid), elapsedRealtimeMs, uptimeMs);
                 final ControllerActivityCounterImpl counter =
                         u.getOrCreateBluetoothControllerActivityLocked();
 
@@ -11623,6 +12149,13 @@
      * instead of fetching it anew.
      */
     public void updateRpmStatsLocked() {
+        updateRpmStatsLocked(mClocks.elapsedRealtime() * 1000);
+    }
+
+    /**
+     * @see #updateRpmStatsLocked()
+     */
+    public void updateRpmStatsLocked(long elapsedRealtimeUs) {
         if (mPlatformIdleStateCallback == null) return;
         long now = SystemClock.elapsedRealtime();
         if (now - mLastRpmStatsUpdateTimeMs >= RPM_STATS_UPDATE_FREQ_MS) {
@@ -11637,9 +12170,9 @@
             final String pName = pstate.getKey();
             final long pTimeUs = pstate.getValue().mTimeMs * 1000;
             final int pCount = pstate.getValue().mCount;
-            getRpmTimerLocked(pName).update(pTimeUs, pCount);
+            getRpmTimerLocked(pName).update(pTimeUs, pCount, elapsedRealtimeUs);
             if (SCREEN_OFF_RPM_STATS_ENABLED) {
-                getScreenOffRpmTimerLocked(pName).update(pTimeUs, pCount);
+                getScreenOffRpmTimerLocked(pName).update(pTimeUs, pCount, elapsedRealtimeUs);
             }
 
             // Update values for each voter of this platform state.
@@ -11648,9 +12181,9 @@
                 final String vName = pName + "." + voter.getKey();
                 final long vTimeUs = voter.getValue().mTimeMs * 1000;
                 final int vCount = voter.getValue().mCount;
-                getRpmTimerLocked(vName).update(vTimeUs, vCount);
+                getRpmTimerLocked(vName).update(vTimeUs, vCount, elapsedRealtimeUs);
                 if (SCREEN_OFF_RPM_STATS_ENABLED) {
-                    getScreenOffRpmTimerLocked(vName).update(vTimeUs, vCount);
+                    getScreenOffRpmTimerLocked(vName).update(vTimeUs, vCount, elapsedRealtimeUs);
                 }
             }
         }
@@ -11664,9 +12197,9 @@
                 final String name = subsysName + "." + sstate.getKey();
                 final long timeUs = sstate.getValue().mTimeMs * 1000;
                 final int count = sstate.getValue().mCount;
-                getRpmTimerLocked(name).update(timeUs, count);
+                getRpmTimerLocked(name).update(timeUs, count, elapsedRealtimeUs);
                 if (SCREEN_OFF_RPM_STATS_ENABLED) {
-                    getScreenOffRpmTimerLocked(name).update(timeUs, count);
+                    getScreenOffRpmTimerLocked(name).update(timeUs, count, elapsedRealtimeUs);
                 }
             }
         }
@@ -11686,6 +12219,13 @@
      * Read and distribute kernel wake lock use across apps.
      */
     public void updateKernelWakelocksLocked() {
+        updateKernelWakelocksLocked(mClocks.elapsedRealtime() * 1000);
+    }
+
+    /**
+     * @see #updateKernelWakelocksLocked()
+     */
+    public void updateKernelWakelocksLocked(long elapsedRealtimeUs) {
         final KernelWakelockStats wakelockStats = mKernelWakelockReader.readKernelWakelockStats(
                 mTmpWakelockStats);
         if (wakelockStats == null) {
@@ -11704,7 +12244,7 @@
                 mKernelWakelockStats.put(name, kwlt);
             }
 
-            kwlt.update(kws.mTotalTime, kws.mCount);
+            kwlt.update(kws.mTotalTime, kws.mCount, elapsedRealtimeUs);
             kwlt.setUpdateVersion(kws.mVersion);
         }
 
@@ -11714,7 +12254,7 @@
         for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
             SamplingTimer st = ent.getValue();
             if (st.getUpdateVersion() != wakelockStats.kernelWakelockVersion) {
-                st.endSample();
+                st.endSample(elapsedRealtimeUs);
                 numWakelocksSetStale++;
             }
         }
@@ -11742,6 +12282,10 @@
      * Reads the newest memory stats from the kernel.
      */
     public void updateKernelMemoryBandwidthLocked() {
+        updateKernelMemoryBandwidthLocked(mClocks.elapsedRealtime() * 1000);
+    }
+
+    public void updateKernelMemoryBandwidthLocked(long elapsedRealtimeUs) {
         mKernelMemoryBandwidthStats.updateStats();
         LongSparseLongArray bandwidthEntries = mKernelMemoryBandwidthStats.getBandwidthEntries();
         final int bandwidthEntryCount = bandwidthEntries.size();
@@ -11754,12 +12298,12 @@
                 timer = new SamplingTimer(mClocks, mOnBatteryTimeBase);
                 mKernelMemoryStats.put(bandwidthEntries.keyAt(i), timer);
             }
-            timer.update(bandwidthEntries.valueAt(i), 1);
+            timer.update(bandwidthEntries.valueAt(i), 1, elapsedRealtimeUs);
             if (DEBUG_MEMORY) {
                 Slog.d(TAG, String.format("Added entry %d and updated timer to: "
-                        + "mUnpluggedReportedTotalTime %d size %d", bandwidthEntries.keyAt(i),
+                        + "mUnpluggedReportedTotalTimeUs %d size %d", bandwidthEntries.keyAt(i),
                         mKernelMemoryStats.get(
-                                bandwidthEntries.keyAt(i)).mUnpluggedReportedTotalTime,
+                                bandwidthEntries.keyAt(i)).mUnpluggedReportedTotalTimeUs,
                         mKernelMemoryStats.size()));
             }
         }
@@ -11898,8 +12442,8 @@
         }
         if (DEBUG_BINDER_STATS) {
             Slog.d(TAG, "System server threads per CPU cluster (binder threads/total threads/%)");
-            long binderThreadTime = 0;
-            long totalThreadTime = 0;
+            long binderThreadTimeMs = 0;
+            long totalThreadTimeMs = 0;
             int cpuIndex = 0;
             for (int cluster = 0; cluster < numCpuClusters; cluster++) {
                 StringBuilder sb = new StringBuilder();
@@ -11909,26 +12453,27 @@
                     if (speed != 0) {
                         sb.append(", ");
                     }
-                    long totalCount = mSystemServerThreadCpuTimesUs[cluster][speed].getCountLocked(
-                            0) / 1000;
-                    long binderCount = mBinderThreadCpuTimesUs[cluster][speed].getCountLocked(0)
+                    long totalCountMs =
+                            mSystemServerThreadCpuTimesUs[cluster][speed].getCountLocked(0) / 1000;
+                    long binderCountMs = mBinderThreadCpuTimesUs[cluster][speed].getCountLocked(0)
                             / 1000;
                     sb.append(String.format("%d/%d(%.1f%%)",
-                            binderCount,
-                            totalCount,
-                            totalCount != 0 ? (double) binderCount * 100 / totalCount : 0));
+                            binderCountMs,
+                            totalCountMs,
+                            totalCountMs != 0 ? (double) binderCountMs * 100 / totalCountMs : 0));
 
-                    totalThreadTime += totalCount;
-                    binderThreadTime += binderCount;
+                    totalThreadTimeMs += totalCountMs;
+                    binderThreadTimeMs += binderCountMs;
                     index++;
                 }
                 cpuIndex += mPowerProfile.getNumCoresInCpuCluster(cluster);
                 Slog.d(TAG, sb.toString());
             }
-            Slog.d(TAG, "Total system server thread time (ms): " + totalThreadTime);
+            Slog.d(TAG, "Total system server thread time (ms): " + totalThreadTimeMs);
             Slog.d(TAG, String.format("Total Binder thread time (ms): %d (%.1f%%)",
-                    binderThreadTime,
-                    binderThreadTime != 0 ? (double) binderThreadTime * 100 / totalThreadTime : 0));
+                    binderThreadTimeMs,
+                    binderThreadTimeMs != 0
+                            ? (double) binderThreadTimeMs * 100 / totalThreadTimeMs : 0));
         }
     }
 
@@ -11985,8 +12530,10 @@
             // So, we distribute total time spent by an uid to different cpu freqs based on the
             // amount of time cpu was running at that freq.
             final int updatedUidsCount = updatedUids.size();
+            final long elapsedRealtimeMs = mClocks.elapsedRealtime();
+            final long uptimeMs = mClocks.uptimeMillis();
             for (int i = 0; i < updatedUidsCount; ++i) {
-                final Uid u = getUidStatsLocked(updatedUids.keyAt(i));
+                final Uid u = getUidStatsLocked(updatedUids.keyAt(i), elapsedRealtimeMs, uptimeMs);
                 final long appCpuTimeUs = updatedUids.valueAt(i);
                 // Add the cpu speeds to this UID.
                 final int numClusters = mPowerProfile.getNumCpuClusters();
@@ -12031,6 +12578,7 @@
         mTempTotalCpuUserTimeUs = mTempTotalCpuSystemTimeUs = 0;
         final int numWakelocks = partialTimers == null ? 0 : partialTimers.size();
         final long startTimeMs = mClocks.uptimeMillis();
+        final long elapsedRealtimeMs = mClocks.elapsedRealtime();
 
         mCpuUidUserSysTimeReader.readDelta((uid, timesUs) -> {
             long userTimeUs = timesUs[0], systemTimeUs = timesUs[1];
@@ -12048,7 +12596,7 @@
                 mCpuUidUserSysTimeReader.removeUid(uid);
                 return;
             }
-            final Uid u = getUidStatsLocked(uid);
+            final Uid u = getUidStatsLocked(uid, elapsedRealtimeMs, startTimeMs);
 
             // Accumulate the total system and user time.
             mTempTotalCpuUserTimeUs += userTimeUs;
@@ -12144,6 +12692,7 @@
         final int numClusters = mPowerProfile.getNumCpuClusters();
         mWakeLockAllocationsUs = null;
         final long startTimeMs = mClocks.uptimeMillis();
+        final long elapsedRealtimeMs = mClocks.elapsedRealtime();
         mCpuUidFreqTimeReader.readDelta((uid, cpuFreqTimeMs) -> {
             uid = mapUid(uid);
             if (Process.isIsolated(uid)) {
@@ -12156,7 +12705,7 @@
                 mCpuUidFreqTimeReader.removeUid(uid);
                 return;
             }
-            final Uid u = getUidStatsLocked(uid);
+            final Uid u = getUidStatsLocked(uid, elapsedRealtimeMs, startTimeMs);
             if (u.mCpuFreqTimeMs == null || u.mCpuFreqTimeMs.getSize() != cpuFreqTimeMs.length) {
                 detachIfNotNull(u.mCpuFreqTimeMs);
                 u.mCpuFreqTimeMs = new LongSamplingCounterArray(mOnBatteryTimeBase);
@@ -12257,6 +12806,7 @@
     @VisibleForTesting
     public void readKernelUidCpuActiveTimesLocked(boolean onBattery) {
         final long startTimeMs = mClocks.uptimeMillis();
+        final long elapsedRealtimeMs = mClocks.elapsedRealtime();
         mCpuUidActiveTimeReader.readDelta((uid, cpuActiveTimesMs) -> {
             uid = mapUid(uid);
             if (Process.isIsolated(uid)) {
@@ -12269,7 +12819,7 @@
                 mCpuUidActiveTimeReader.removeUid(uid);
                 return;
             }
-            final Uid u = getUidStatsLocked(uid);
+            final Uid u = getUidStatsLocked(uid, elapsedRealtimeMs, startTimeMs);
             u.mCpuActiveTimeMs.addCountLocked(cpuActiveTimesMs, onBattery);
         });
 
@@ -12286,6 +12836,7 @@
     @VisibleForTesting
     public void readKernelUidCpuClusterTimesLocked(boolean onBattery) {
         final long startTimeMs = mClocks.uptimeMillis();
+        final long elapsedRealtimeMs = mClocks.elapsedRealtime();
         mCpuUidClusterTimeReader.readDelta((uid, cpuClusterTimesMs) -> {
             uid = mapUid(uid);
             if (Process.isIsolated(uid)) {
@@ -12298,7 +12849,7 @@
                 mCpuUidClusterTimeReader.removeUid(uid);
                 return;
             }
-            final Uid u = getUidStatsLocked(uid);
+            final Uid u = getUidStatsLocked(uid, elapsedRealtimeMs, startTimeMs);
             u.mCpuClusterTimesMs.addCountLocked(cpuClusterTimesMs, onBattery);
         });
 
@@ -12338,8 +12889,8 @@
         m.arg1 = onBattery ? 1 : 0;
         mHandler.sendMessage(m);
 
-        final long uptime = mSecUptime * 1000;
-        final long realtime = mSecRealtime * 1000;
+        final long uptimeUs = mSecUptime * 1000;
+        final long realtimeUs = mSecRealtime * 1000;
         final int screenState = mScreenState;
         if (onBattery) {
             // We will reset our status if we are unplugging after the
@@ -12358,14 +12909,14 @@
                 // stats to be reported in the next checkin.  Only do this if we have
                 // a sufficient amount of data to make it interesting.
                 if (getLowDischargeAmountSinceCharge() >= 20) {
-                    final long startTime = SystemClock.uptimeMillis();
+                    final long startTimeMs = SystemClock.uptimeMillis();
                     final Parcel parcel = Parcel.obtain();
                     writeSummaryToParcel(parcel, true);
-                    final long initialTime = SystemClock.uptimeMillis() - startTime;
+                    final long initialTimeMs = SystemClock.uptimeMillis() - startTimeMs;
                     BackgroundThread.getHandler().post(new Runnable() {
                         @Override public void run() {
                             synchronized (mCheckinFile) {
-                                final long startTime2 = SystemClock.uptimeMillis();
+                                final long startTimeMs2 = SystemClock.uptimeMillis();
                                 FileOutputStream stream = null;
                                 try {
                                     stream = mCheckinFile.startWrite();
@@ -12373,8 +12924,8 @@
                                     stream.flush();
                                     mCheckinFile.finishWrite(stream);
                                     com.android.internal.logging.EventLogTags.writeCommitSysConfigFile(
-                                            "batterystats-checkin",
-                                            initialTime + SystemClock.uptimeMillis() - startTime2);
+                                            "batterystats-checkin", initialTimeMs
+                                            + SystemClock.uptimeMillis() - startTimeMs2);
                                 } catch (IOException e) {
                                     Slog.w("BatteryStats",
                                             "Error writing checkin battery statistics", e);
@@ -12387,7 +12938,7 @@
                     });
                 }
                 doWrite = true;
-                resetAllStatsLocked();
+                resetAllStatsLocked(mSecUptime, mSecRealtime);
                 if (chargeUAh > 0 && level > 0) {
                     // Only use the reported coulomb charge value if it is supported and reported.
                     mEstimatedBatteryCapacity = (int) ((chargeUAh / 1000) / (level / 100.0));
@@ -12434,7 +12985,7 @@
             mDischargeAmountScreenOn = 0;
             mDischargeAmountScreenDoze = 0;
             mDischargeAmountScreenOff = 0;
-            updateTimeBasesLocked(true, screenState, uptime, realtime);
+            updateTimeBasesLocked(true, screenState, uptimeUs, realtimeUs);
         } else {
             mLastChargingStateLevel = level;
             mOnBattery = mOnBatteryInternal = false;
@@ -12450,14 +13001,14 @@
                 mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
             }
             updateDischargeScreenLevelsLocked(screenState, screenState);
-            updateTimeBasesLocked(false, screenState, uptime, realtime);
+            updateTimeBasesLocked(false, screenState, uptimeUs, realtimeUs);
             mChargeStepTracker.init();
             mLastChargeStepLevel = level;
             mMaxChargeStepLevel = level;
             mInitStepMode = mCurStepMode;
             mModStepMode = 0;
         }
-        if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
+        if (doWrite || (mLastWriteTimeMs + (60 * 1000)) < mSecRealtime) {
             if (mStatsFile != null && mBatteryStatsHistory.getActiveFile() != null) {
                 writeAsyncLocked();
             }
@@ -12477,18 +13028,18 @@
         }
     }
 
-    private void recordCurrentTimeChangeLocked(final long currentTime, final long elapsedRealtimeMs,
-            final long uptimeMs) {
+    private void recordCurrentTimeChangeLocked(final long currentTimeMs,
+            final long elapsedRealtimeMs, final long uptimeMs) {
         if (mRecordingHistory) {
-            mHistoryCur.currentTime = currentTime;
+            mHistoryCur.currentTime = currentTimeMs;
             addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_CURRENT_TIME, mHistoryCur);
             mHistoryCur.currentTime = 0;
         }
     }
 
-    private void recordShutdownLocked(final long elapsedRealtimeMs, final long uptimeMs) {
+    private void recordShutdownLocked(final long currentTimeMs, final long elapsedRealtimeMs) {
         if (mRecordingHistory) {
-            mHistoryCur.currentTime = System.currentTimeMillis();
+            mHistoryCur.currentTime = currentTimeMs;
             addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_SHUTDOWN, mHistoryCur);
             mHistoryCur.currentTime = 0;
         }
@@ -12507,6 +13058,15 @@
     public void setBatteryStateLocked(final int status, final int health, final int plugType,
             final int level, /* not final */ int temp, final int volt, final int chargeUAh,
             final int chargeFullUAh, final long chargeTimeToFullSeconds) {
+        setBatteryStateLocked(status, health, plugType, level, temp, volt, chargeUAh,
+                chargeFullUAh, chargeTimeToFullSeconds,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis(), System.currentTimeMillis());
+    }
+
+    public void setBatteryStateLocked(final int status, final int health, final int plugType,
+            final int level, /* not final */ int temp, final int volt, final int chargeUAh,
+            final int chargeFullUAh, final long chargeTimeToFullSeconds,
+            final long elapsedRealtimeMs, final long uptimeMs, final long currentTimeMs) {
         // Temperature is encoded without the signed bit, so clamp any negative temperatures to 0.
         temp = Math.max(0, temp);
 
@@ -12514,8 +13074,6 @@
                 status, plugType, level);
 
         final boolean onBattery = isOnBattery(plugType, status);
-        final long uptime = mClocks.uptimeMillis();
-        final long elapsedRealtime = mClocks.elapsedRealtime();
         if (!mHaveBatteryLevel) {
             mHaveBatteryLevel = true;
             // We start out assuming that the device is plugged in (not
@@ -12538,20 +13096,20 @@
                     mLastChargeStepLevel = mLastDischargeStepLevel = level;
             mLastChargingStateLevel = level;
         } else if (mCurrentBatteryLevel != level || mOnBattery != onBattery) {
-            recordDailyStatsIfNeededLocked(level >= 100 && onBattery);
+            recordDailyStatsIfNeededLocked(level >= 100 && onBattery, currentTimeMs);
         }
         int oldStatus = mHistoryCur.batteryStatus;
         if (onBattery) {
             mDischargeCurrentLevel = level;
             if (!mRecordingHistory) {
                 mRecordingHistory = true;
-                startRecordingHistory(elapsedRealtime, uptime, true);
+                startRecordingHistory(elapsedRealtimeMs, uptimeMs, true);
             }
         } else if (level < 96 &&
                 status != BatteryManager.BATTERY_STATUS_UNKNOWN) {
             if (!mRecordingHistory) {
                 mRecordingHistory = true;
-                startRecordingHistory(elapsedRealtime, uptime, true);
+                startRecordingHistory(elapsedRealtimeMs, uptimeMs, true);
             }
         }
         mCurrentBatteryLevel = level;
@@ -12581,7 +13139,7 @@
                 }
             }
             mHistoryCur.batteryChargeUAh = chargeUAh;
-            setOnBatteryLocked(elapsedRealtime, uptime, onBattery, oldStatus, level, chargeUAh);
+            setOnBatteryLocked(elapsedRealtimeMs, uptimeMs, onBattery, oldStatus, level, chargeUAh);
         } else {
             boolean changed = false;
             if (mHistoryCur.batteryLevel != level) {
@@ -12641,9 +13199,9 @@
                 changed |= setChargingLocked(false);
                 if (mLastDischargeStepLevel != level && mMinDischargeStepLevel > level) {
                     mDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level,
-                            modeBits, elapsedRealtime);
+                            modeBits, elapsedRealtimeMs);
                     mDailyDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level,
-                            modeBits, elapsedRealtime);
+                            modeBits, elapsedRealtimeMs);
                     mLastDischargeStepLevel = level;
                     mMinDischargeStepLevel = level;
                     mInitStepMode = mCurStepMode;
@@ -12681,9 +13239,9 @@
                 }
                 if (mLastChargeStepLevel != level && mMaxChargeStepLevel < level) {
                     mChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel,
-                            modeBits, elapsedRealtime);
+                            modeBits, elapsedRealtimeMs);
                     mDailyChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel,
-                            modeBits, elapsedRealtime);
+                            modeBits, elapsedRealtimeMs);
                     mMaxChargeStepLevel = level;
                     mInitStepMode = mCurStepMode;
                     mModStepMode = 0;
@@ -12691,7 +13249,7 @@
                 mLastChargeStepLevel = level;
             }
             if (changed) {
-                addHistoryRecordLocked(elapsedRealtime, uptime);
+                addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
             }
         }
         if (!onBattery &&
@@ -12737,7 +13295,7 @@
     public long getAwakeTimeBattery() {
         // This previously evaluated to mOnBatteryTimeBase.getUptime(getBatteryUptimeLocked());
         // for over a decade, but surely that was a mistake.
-        return getBatteryUptimeLocked();
+        return getBatteryUptimeLocked(mClocks.uptimeMillis());
     }
 
     @UnsupportedAppUsage
@@ -12746,35 +13304,35 @@
     }
 
     @Override
-    public long computeUptime(long curTime, int which) {
-        return mUptime + (curTime - mUptimeStart);
+    public long computeUptime(long curTimeUs, int which) {
+        return mUptimeUs + (curTimeUs - mUptimeStartUs);
     }
 
     @Override
-    public long computeRealtime(long curTime, int which) {
-        return mRealtime + (curTime - mRealtimeStart);
+    public long computeRealtime(long curTimeUs, int which) {
+        return mRealtimeUs + (curTimeUs - mRealtimeStartUs);
     }
 
     @Override
     @UnsupportedAppUsage
-    public long computeBatteryUptime(long curTime, int which) {
-        return mOnBatteryTimeBase.computeUptime(curTime, which);
+    public long computeBatteryUptime(long curTimeUs, int which) {
+        return mOnBatteryTimeBase.computeUptime(curTimeUs, which);
     }
 
     @Override
     @UnsupportedAppUsage
-    public long computeBatteryRealtime(long curTime, int which) {
-        return mOnBatteryTimeBase.computeRealtime(curTime, which);
+    public long computeBatteryRealtime(long curTimeUs, int which) {
+        return mOnBatteryTimeBase.computeRealtime(curTimeUs, which);
     }
 
     @Override
-    public long computeBatteryScreenOffUptime(long curTime, int which) {
-        return mOnBatteryScreenOffTimeBase.computeUptime(curTime, which);
+    public long computeBatteryScreenOffUptime(long curTimeUs, int which) {
+        return mOnBatteryScreenOffTimeBase.computeUptime(curTimeUs, which);
     }
 
     @Override
-    public long computeBatteryScreenOffRealtime(long curTime, int which) {
-        return mOnBatteryScreenOffTimeBase.computeRealtime(curTime, which);
+    public long computeBatteryScreenOffRealtime(long curTimeUs, int which) {
+        return mOnBatteryScreenOffTimeBase.computeRealtime(curTimeUs, which);
     }
 
     private long computeTimePerLevel(long[] steps, int numSteps) {
@@ -12877,7 +13435,7 @@
     /*@hide */
     public CellularBatteryStats getCellularBatteryStats() {
         final int which = STATS_SINCE_CHARGED;
-        final long rawRealTime = SystemClock.elapsedRealtime() * 1000;
+        final long rawRealTimeUs = SystemClock.elapsedRealtime() * 1000;
         final ControllerActivityCounter counter = getModemControllerActivity();
         final long sleepTimeMs = counter.getSleepTimeCounter().getCountLocked(which);
         final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(which);
@@ -12887,13 +13445,13 @@
                 counter.getMonitoredRailChargeConsumedMaMs().getCountLocked(which);
         long[] timeInRatMs = new long[BatteryStats.NUM_DATA_CONNECTION_TYPES];
         for (int i = 0; i < timeInRatMs.length; i++) {
-           timeInRatMs[i] = getPhoneDataConnectionTime(i, rawRealTime, which) / 1000;
+            timeInRatMs[i] = getPhoneDataConnectionTime(i, rawRealTimeUs, which) / 1000;
         }
         long[] timeInRxSignalStrengthLevelMs =
                 new long[CellSignalStrength.getNumSignalStrengthLevels()];
         for (int i = 0; i < timeInRxSignalStrengthLevelMs.length; i++) {
-           timeInRxSignalStrengthLevelMs[i]
-               = getPhoneSignalStrengthTime(i, rawRealTime, which) / 1000;
+            timeInRxSignalStrengthLevelMs[i] =
+                getPhoneSignalStrengthTime(i, rawRealTimeUs, which) / 1000;
         }
         long[] txTimeMs = new long[Math.min(ModemActivityInfo.TX_POWER_LEVELS,
             counter.getTxTimeCounters().length)];
@@ -12903,8 +13461,8 @@
             totalTxTimeMs += txTimeMs[i];
         }
 
-        return new CellularBatteryStats(computeBatteryRealtime(rawRealTime, which) / 1000,
-                getMobileRadioActiveTime(rawRealTime, which) / 1000,
+        return new CellularBatteryStats(computeBatteryRealtime(rawRealTimeUs, which) / 1000,
+                getMobileRadioActiveTime(rawRealTimeUs, which) / 1000,
                 getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which),
                 getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which),
                 getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which),
@@ -12917,7 +13475,7 @@
     /*@hide */
     public WifiBatteryStats getWifiBatteryStats() {
         final int which = STATS_SINCE_CHARGED;
-        final long rawRealTime = SystemClock.elapsedRealtime() * 1000;
+        final long rawRealTimeUs = SystemClock.elapsedRealtime() * 1000;
         final ControllerActivityCounter counter = getWifiControllerActivity();
         final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(which);
         final long scanTimeMs = counter.getScanTimeCounter().getCountLocked(which);
@@ -12936,19 +13494,19 @@
         }
         long[] timeInStateMs = new long[NUM_WIFI_STATES];
         for (int i=0; i<NUM_WIFI_STATES; i++) {
-            timeInStateMs[i] = getWifiStateTime(i, rawRealTime, which) / 1000;
+            timeInStateMs[i] = getWifiStateTime(i, rawRealTimeUs, which) / 1000;
         }
         long[] timeInSupplStateMs = new long[NUM_WIFI_SUPPL_STATES];
         for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
-            timeInSupplStateMs[i] = getWifiSupplStateTime(i, rawRealTime, which) / 1000;
+            timeInSupplStateMs[i] = getWifiSupplStateTime(i, rawRealTimeUs, which) / 1000;
         }
         long[] timeSignalStrengthTimeMs = new long[NUM_WIFI_SIGNAL_STRENGTH_BINS];
         for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
-            timeSignalStrengthTimeMs[i] = getWifiSignalStrengthTime(i, rawRealTime, which) / 1000;
+            timeSignalStrengthTimeMs[i] = getWifiSignalStrengthTime(i, rawRealTimeUs, which) / 1000;
         }
         return new WifiBatteryStats(
-                computeBatteryRealtime(rawRealTime, which) / 1000,
-                getWifiActiveTime(rawRealTime, which) / 1000,
+                computeBatteryRealtime(rawRealTimeUs, which) / 1000,
+                getWifiActiveTime(rawRealTimeUs, which) / 1000,
                 getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which),
                 getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which),
                 getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which),
@@ -12962,12 +13520,12 @@
     public GpsBatteryStats getGpsBatteryStats() {
         GpsBatteryStats s = new GpsBatteryStats();
         final int which = STATS_SINCE_CHARGED;
-        final long rawRealTime = SystemClock.elapsedRealtime() * 1000;
-        s.setLoggingDurationMs(computeBatteryRealtime(rawRealTime, which) / 1000);
+        final long rawRealTimeUs = SystemClock.elapsedRealtime() * 1000;
+        s.setLoggingDurationMs(computeBatteryRealtime(rawRealTimeUs, which) / 1000);
         s.setEnergyConsumedMaMs(getGpsBatteryDrainMaMs());
         long[] time = new long[GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS];
         for (int i=0; i<time.length; i++) {
-            time[i] = getGpsSignalQualityTime(i, rawRealTime, which) / 1000;
+            time[i] = getGpsSignalQualityTime(i, rawRealTimeUs, which) / 1000;
         }
         s.setTimeInGpsSignalQualityLevel(time);
         return s;
@@ -12988,19 +13546,29 @@
         return mDailyPackageChanges;
     }
 
+    /**
+     * @return battery uptime in microseconds
+     */
     protected long getBatteryUptimeLocked() {
-        return mOnBatteryTimeBase.getUptime(mClocks.uptimeMillis() * 1000);
+        return getBatteryUptimeLocked(mClocks.uptimeMillis());
+    }
+
+    /**
+     * @return battery uptime in microseconds
+     */
+    protected long getBatteryUptimeLocked(long uptimeMs) {
+        return mOnBatteryTimeBase.getUptime(uptimeMs * 1000);
     }
 
     @Override
-    public long getBatteryUptime(long curTime) {
-        return mOnBatteryTimeBase.getUptime(curTime);
+    public long getBatteryUptime(long curTimeUs) {
+        return mOnBatteryTimeBase.getUptime(curTimeUs);
     }
 
     @Override
     @UnsupportedAppUsage
-    public long getBatteryRealtime(long curTime) {
-        return mOnBatteryTimeBase.getRealtime(curTime);
+    public long getBatteryRealtime(long curTimeUs) {
+        return mOnBatteryTimeBase.getRealtime(curTimeUs);
     }
 
     @Override
@@ -13188,22 +13756,22 @@
             return 0;
         }
 
-        final long uidTimeAtCpuSpeed = systemUid.getTimeAtCpuSpeed(cluster, step,
+        final long uidTimeAtCpuSpeedUs = systemUid.getTimeAtCpuSpeed(cluster, step,
                 BatteryStats.STATS_SINCE_CHARGED);
-        if (uidTimeAtCpuSpeed == 0) {
+        if (uidTimeAtCpuSpeedUs == 0) {
             return 0;
         }
 
-        final long uidThreadTime =
+        final long uidThreadTimeUs =
                 threadTimesForCluster[step].getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
 
-        if (uidThreadTime == 0) {
+        if (uidThreadTimeUs == 0) {
             return 0;
         }
 
-        final long binderThreadTime = mBinderThreadCpuTimesUs[cluster][step].getCountLocked(
+        final long binderThreadTimeUs = mBinderThreadCpuTimesUs[cluster][step].getCountLocked(
                 BatteryStats.STATS_SINCE_CHARGED);
-        return uidTimeAtCpuSpeed * binderThreadTime / uidThreadTime;
+        return uidTimeAtCpuSpeedUs * binderThreadTimeUs / uidThreadTimeUs;
     }
 
     /**
@@ -13211,9 +13779,13 @@
      */
     @UnsupportedAppUsage
     public Uid getUidStatsLocked(int uid) {
+        return getUidStatsLocked(uid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public Uid getUidStatsLocked(int uid, long elapsedRealtimeMs, long uptimeMs) {
         Uid u = mUidStats.get(uid);
         if (u == null) {
-            u = new Uid(this, uid);
+            u = new Uid(this, uid, elapsedRealtimeMs, uptimeMs);
             mUidStats.put(uid, u);
         }
         return u;
@@ -13229,10 +13801,14 @@
     }
 
     public void onCleanupUserLocked(int userId) {
+        onCleanupUserLocked(userId, mClocks.elapsedRealtime());
+    }
+
+    public void onCleanupUserLocked(int userId, long elapsedRealtimeMs) {
         final int firstUidForUser = UserHandle.getUid(userId, 0);
         final int lastUidForUser = UserHandle.getUid(userId, UserHandle.PER_USER_RANGE - 1);
         mPendingRemovedUids.add(
-                new UidToRemove(firstUidForUser, lastUidForUser, mClocks.elapsedRealtime()));
+                new UidToRemove(firstUidForUser, lastUidForUser, elapsedRealtimeMs));
     }
 
     public void onUserRemovedLocked(int userId) {
@@ -13256,12 +13832,19 @@
      */
     @UnsupportedAppUsage
     public void removeUidStatsLocked(int uid) {
+        removeUidStatsLocked(uid, mClocks.elapsedRealtime());
+    }
+
+    /**
+     * @see #removeUidStatsLocked(int)
+     */
+    public void removeUidStatsLocked(int uid, long elapsedRealtimeMs) {
         final Uid u = mUidStats.get(uid);
         if (u != null) {
             u.detachFromTimeBase();
         }
         mUidStats.remove(uid);
-        mPendingRemovedUids.add(new UidToRemove(uid, mClocks.elapsedRealtime()));
+        mPendingRemovedUids.add(new UidToRemove(uid, elapsedRealtimeMs));
     }
 
     /**
@@ -13270,8 +13853,16 @@
      */
     @UnsupportedAppUsage
     public Uid.Proc getProcessStatsLocked(int uid, String name) {
+        return getProcessStatsLocked(uid, name, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    /**
+     * @see #getProcessStatsLocked(int, String)
+     */
+    public Uid.Proc getProcessStatsLocked(int uid, String name,
+            long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
-        Uid u = getUidStatsLocked(uid);
+        Uid u = getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs);
         return u.getProcessStatsLocked(name);
     }
 
@@ -13281,8 +13872,16 @@
      */
     @UnsupportedAppUsage
     public Uid.Pkg getPackageStatsLocked(int uid, String pkg) {
+        return getPackageStatsLocked(uid, pkg, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    /**
+     * @see getPackageStatsLocked(int, String)
+     */
+    public Uid.Pkg getPackageStatsLocked(int uid, String pkg,
+            long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
-        Uid u = getUidStatsLocked(uid);
+        Uid u = getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs);
         return u.getPackageStatsLocked(pkg);
     }
 
@@ -13292,13 +13891,19 @@
      */
     @UnsupportedAppUsage
     public Uid.Pkg.Serv getServiceStatsLocked(int uid, String pkg, String name) {
+        return getServiceStatsLocked(uid, pkg, name,
+                mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+    }
+
+    public Uid.Pkg.Serv getServiceStatsLocked(int uid, String pkg, String name,
+            long elapsedRealtimeMs, long uptimeMs) {
         uid = mapUid(uid);
-        Uid u = getUidStatsLocked(uid);
+        Uid u = getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs);
         return u.getServiceStatsLocked(pkg, name);
     }
 
     public void shutdownLocked() {
-        recordShutdownLocked(mClocks.elapsedRealtime(), mClocks.uptimeMillis());
+        recordShutdownLocked(System.currentTimeMillis(), mClocks.elapsedRealtime());
         writeSyncLocked();
         mShuttingDown = true;
     }
@@ -13462,7 +14067,7 @@
 
                 mNumSingleUidCpuTimeReads = 0;
                 mNumBatchedSingleUidCpuTimeReads = 0;
-                mCpuTimeReadsTrackingStartTime = mClocks.uptimeMillis();
+                mCpuTimeReadsTrackingStartTimeMs = mClocks.uptimeMillis();
             }
         }
 
@@ -13471,7 +14076,7 @@
             if (oldDelayMillis != newDelayMillis) {
                 mNumSingleUidCpuTimeReads = 0;
                 mNumBatchedSingleUidCpuTimeReads = 0;
-                mCpuTimeReadsTrackingStartTime = mClocks.uptimeMillis();
+                mCpuTimeReadsTrackingStartTimeMs = mClocks.uptimeMillis();
             }
         }
 
@@ -13569,11 +14174,11 @@
                 Uid uid = mUidStats.get(u);
                 double proportionalSystemServiceUsage = uid.getProportionalSystemServiceUsage();
 
-                long time = 0;
+                long timeUs = 0;
                 for (int cluster = 0; cluster < mSystemServerThreadCpuTimesUs.length; cluster++) {
                     int numSpeeds = mSystemServerThreadCpuTimesUs[cluster].length;
                     for (int speed = 0; speed < numSpeeds; speed++) {
-                        time += getSystemServiceTimeAtCpuSpeed(cluster, speed)
+                        timeUs += getSystemServiceTimeAtCpuSpeed(cluster, speed)
                                 * proportionalSystemServiceUsage;
                     }
                 }
@@ -13581,7 +14186,7 @@
                 pw.print("  ");
                 pw.print(u);
                 pw.print(": ");
-                pw.println(time);
+                pw.println(timeUs / 1000);
             }
         }
     }
@@ -13616,7 +14221,7 @@
             Slog.d(TAG, "writeSummaryToParcel duration ms:"
                     + (SystemClock.uptimeMillis() - start) + " bytes:" + p.dataSize());
         }
-        mLastWriteTime = mClocks.elapsedRealtime();
+        mLastWriteTimeMs = mClocks.elapsedRealtime();
         writeParcelToFileLocked(p, mStatsFile, sync);
     }
 
@@ -13657,18 +14262,18 @@
         mWriteLock.lock();
         FileOutputStream fos = null;
         try {
-            final long startTime = SystemClock.uptimeMillis();
+            final long startTimeMs = SystemClock.uptimeMillis();
             fos = file.startWrite();
             fos.write(p.marshall());
             fos.flush();
             file.finishWrite(fos);
             if (DEBUG) {
                 Slog.d(TAG, "commitPendingDataToDisk file:" + file.getBaseFile().getPath()
-                        + " duration ms:" + (SystemClock.uptimeMillis() - startTime)
+                        + " duration ms:" + (SystemClock.uptimeMillis() - startTimeMs)
                         + " bytes:" + p.dataSize());
             }
             com.android.internal.logging.EventLogTags.writeCommitSysConfigFile(
-                    "batterystats", SystemClock.uptimeMillis() - startTime);
+                    "batterystats", SystemClock.uptimeMillis() - startTimeMs);
         } catch (IOException e) {
             Slog.w(TAG, "Error writing battery statistics", e);
             file.failWrite(fos);
@@ -13714,7 +14319,7 @@
             }
         } catch (Exception e) {
             Slog.e(TAG, "Error reading battery statistics", e);
-            resetAllStatsLocked();
+            resetAllStatsLocked(SystemClock.uptimeMillis(), SystemClock.elapsedRealtime());
         } finally {
             stats.recycle();
         }
@@ -13749,16 +14354,17 @@
         if (mHistoryBuffer.dataPosition() > 0
                 || mBatteryStatsHistory.getFilesNumbers().size() > 1) {
             mRecordingHistory = true;
-            final long elapsedRealtime = mClocks.elapsedRealtime();
-            final long uptime = mClocks.uptimeMillis();
+            final long elapsedRealtimeMs = mClocks.elapsedRealtime();
+            final long uptimeMs = mClocks.uptimeMillis();
             if (USE_OLD_HISTORY) {
-                addHistoryRecordLocked(elapsedRealtime, uptime, HistoryItem.CMD_START, mHistoryCur);
+                addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs,
+                        HistoryItem.CMD_START, mHistoryCur);
             }
-            addHistoryBufferLocked(elapsedRealtime, HistoryItem.CMD_START, mHistoryCur);
-            startRecordingHistory(elapsedRealtime, uptime, false);
+            addHistoryBufferLocked(elapsedRealtimeMs, HistoryItem.CMD_START, mHistoryCur);
+            startRecordingHistory(elapsedRealtimeMs, uptimeMs, false);
         }
 
-        recordDailyStatsIfNeededLocked(false);
+        recordDailyStatsIfNeededLocked(false, System.currentTimeMillis());
     }
 
     public int describeContents() {
@@ -13799,27 +14405,27 @@
 
         if (DEBUG_HISTORY) {
             StringBuilder sb = new StringBuilder(128);
-            sb.append("****************** OLD mHistoryBaseTime: ");
-            TimeUtils.formatDuration(mHistoryBaseTime, sb);
+            sb.append("****************** OLD mHistoryBaseTimeMs: ");
+            TimeUtils.formatDuration(mHistoryBaseTimeMs, sb);
             Slog.i(TAG, sb.toString());
         }
-        mHistoryBaseTime = historyBaseTime;
+        mHistoryBaseTimeMs = historyBaseTime;
         if (DEBUG_HISTORY) {
             StringBuilder sb = new StringBuilder(128);
-            sb.append("****************** NEW mHistoryBaseTime: ");
-            TimeUtils.formatDuration(mHistoryBaseTime, sb);
+            sb.append("****************** NEW mHistoryBaseTimeMs: ");
+            TimeUtils.formatDuration(mHistoryBaseTimeMs, sb);
             Slog.i(TAG, sb.toString());
         }
 
         // We are just arbitrarily going to insert 1 minute from the sample of
         // the last run until samples in this run.
-        if (mHistoryBaseTime > 0) {
+        if (mHistoryBaseTimeMs > 0) {
             long oldnow = mClocks.elapsedRealtime();
-            mHistoryBaseTime = mHistoryBaseTime - oldnow + 1;
+            mHistoryBaseTimeMs = mHistoryBaseTimeMs - oldnow + 1;
             if (DEBUG_HISTORY) {
                 StringBuilder sb = new StringBuilder(128);
-                sb.append("****************** ADJUSTED mHistoryBaseTime: ");
-                TimeUtils.formatDuration(mHistoryBaseTime, sb);
+                sb.append("****************** ADJUSTED mHistoryBaseTimeMs: ");
+                TimeUtils.formatDuration(mHistoryBaseTimeMs, sb);
                 Slog.i(TAG, sb.toString());
             }
         }
@@ -13839,14 +14445,14 @@
     void writeHistoryBuffer(Parcel out, boolean inclData, boolean andOldHistory) {
         if (DEBUG_HISTORY) {
             StringBuilder sb = new StringBuilder(128);
-            sb.append("****************** WRITING mHistoryBaseTime: ");
-            TimeUtils.formatDuration(mHistoryBaseTime, sb);
-            sb.append(" mLastHistoryElapsedRealtime: ");
-            TimeUtils.formatDuration(mLastHistoryElapsedRealtime, sb);
+            sb.append("****************** WRITING mHistoryBaseTimeMs: ");
+            TimeUtils.formatDuration(mHistoryBaseTimeMs, sb);
+            sb.append(" mLastHistoryElapsedRealtimeMs: ");
+            TimeUtils.formatDuration(mLastHistoryElapsedRealtimeMs, sb);
             Slog.i(TAG, sb.toString());
         }
         out.writeInt(VERSION);
-        out.writeLong(mHistoryBaseTime + mLastHistoryElapsedRealtime);
+        out.writeLong(mHistoryBaseTimeMs + mLastHistoryElapsedRealtimeMs);
         if (!inclData) {
             out.writeInt(0);
             out.writeInt(0);
@@ -13913,9 +14519,9 @@
         }
 
         mStartCount = in.readInt();
-        mUptime = in.readLong();
-        mRealtime = in.readLong();
-        mStartClockTime = in.readLong();
+        mUptimeUs = in.readLong();
+        mRealtimeUs = in.readLong();
+        mStartClockTimeMs = in.readLong();
         mStartPlatformVersion = in.readString();
         mEndPlatformVersion = in.readString();
         mOnBatteryTimeBase.readSummaryFromParcel(in);
@@ -13955,9 +14561,9 @@
         } else {
             mDailyPackageChanges = null;
         }
-        mDailyStartTime = in.readLong();
-        mNextMinDailyDeadline = in.readLong();
-        mNextMaxDailyDeadline = in.readLong();
+        mDailyStartTimeMs = in.readLong();
+        mNextMinDailyDeadlineMs = in.readLong();
+        mNextMaxDailyDeadlineMs = in.readLong();
 
         mStartCount++;
 
@@ -13971,8 +14577,8 @@
         mInteractiveTimer.readSummaryFromParcelLocked(in);
         mPhoneOn = false;
         mPowerSaveModeEnabledTimer.readSummaryFromParcelLocked(in);
-        mLongestLightIdleTime = in.readLong();
-        mLongestFullIdleTime = in.readLong();
+        mLongestLightIdleTimeMs = in.readLong();
+        mLongestFullIdleTimeMs = in.readLong();
         mDeviceIdleModeLightTimer.readSummaryFromParcelLocked(in);
         mDeviceIdleModeFullTimer.readSummaryFromParcelLocked(in);
         mDeviceLightIdlingTimer.readSummaryFromParcelLocked(in);
@@ -14084,9 +14690,11 @@
         if (NU > 10000) {
             throw new ParcelFormatException("File corrupt: too many uids " + NU);
         }
+        final long elapsedRealtimeMs = mClocks.elapsedRealtime();
+        final long uptimeMs = mClocks.uptimeMillis();
         for (int iu = 0; iu < NU; iu++) {
             int uid = in.readInt();
-            Uid u = new Uid(this, uid);
+            Uid u = new Uid(this, uid, elapsedRealtimeMs, uptimeMs);
             mUidStats.put(uid, u);
 
             u.mOnBatteryBackgroundTimeBase.readSummaryFromParcel(in);
@@ -14329,9 +14937,9 @@
             for (int ip = 0; ip < NP; ip++) {
                 String procName = in.readString();
                 Uid.Proc p = u.getProcessStatsLocked(procName);
-                p.mUserTime = in.readLong();
-                p.mSystemTime = in.readLong();
-                p.mForegroundTime = in.readLong();
+                p.mUserTimeMs = in.readLong();
+                p.mSystemTimeMs = in.readLong();
+                p.mForegroundTimeMs = in.readLong();
                 p.mStarts = in.readInt();
                 p.mNumCrashes = in.readInt();
                 p.mNumAnrs = in.readInt();
@@ -14364,7 +14972,7 @@
                 for (int is = 0; is < NS; is++) {
                     String servName = in.readString();
                     Uid.Pkg.Serv s = u.getServiceStatsLocked(pkgName, servName);
-                    s.mStartTime = in.readLong();
+                    s.mStartTimeMs = in.readLong();
                     s.mStarts = in.readInt();
                     s.mLaunches = in.readInt();
                 }
@@ -14407,7 +15015,7 @@
         out.writeInt(mStartCount);
         out.writeLong(computeUptime(NOW_SYS, STATS_SINCE_CHARGED));
         out.writeLong(computeRealtime(NOWREAL_SYS, STATS_SINCE_CHARGED));
-        out.writeLong(mStartClockTime);
+        out.writeLong(mStartClockTimeMs);
         out.writeString(mStartPlatformVersion);
         out.writeString(mEndPlatformVersion);
         mOnBatteryTimeBase.writeSummaryToParcel(out, NOW_SYS, NOWREAL_SYS);
@@ -14445,9 +15053,9 @@
         } else {
             out.writeInt(0);
         }
-        out.writeLong(mDailyStartTime);
-        out.writeLong(mNextMinDailyDeadline);
-        out.writeLong(mNextMaxDailyDeadline);
+        out.writeLong(mDailyStartTimeMs);
+        out.writeLong(mNextMinDailyDeadlineMs);
+        out.writeLong(mNextMaxDailyDeadlineMs);
 
         mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         mScreenDozeTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
@@ -14456,8 +15064,8 @@
         }
         mInteractiveTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         mPowerSaveModeEnabledTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
-        out.writeLong(mLongestLightIdleTime);
-        out.writeLong(mLongestFullIdleTime);
+        out.writeLong(mLongestLightIdleTimeMs);
+        out.writeLong(mLongestFullIdleTimeMs);
         mDeviceIdleModeLightTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         mDeviceIdleModeFullTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         mDeviceLightIdlingTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
@@ -14852,9 +15460,9 @@
             for (int ip=0; ip<NP; ip++) {
                 out.writeString(u.mProcessStats.keyAt(ip));
                 Uid.Proc ps = u.mProcessStats.valueAt(ip);
-                out.writeLong(ps.mUserTime);
-                out.writeLong(ps.mSystemTime);
-                out.writeLong(ps.mForegroundTime);
+                out.writeLong(ps.mUserTimeMs);
+                out.writeLong(ps.mSystemTimeMs);
+                out.writeLong(ps.mForegroundTimeMs);
                 out.writeInt(ps.mStarts);
                 out.writeInt(ps.mNumCrashes);
                 out.writeInt(ps.mNumAnrs);
@@ -14880,7 +15488,7 @@
                         out.writeString(ps.mServiceStats.keyAt(is));
                         BatteryStatsImpl.Uid.Pkg.Serv ss = ps.mServiceStats.valueAt(is);
                         long time = ss.getStartTimeToNowLocked(
-                                mOnBatteryTimeBase.getUptime(NOW_SYS));
+                                mOnBatteryTimeBase.getUptime(NOW_SYS) / 1000);
                         out.writeLong(time);
                         out.writeInt(ss.mStarts);
                         out.writeInt(ss.mLaunches);
@@ -14904,13 +15512,13 @@
         mBatteryStatsHistory.readFromParcel(in);
 
         mStartCount = in.readInt();
-        mStartClockTime = in.readLong();
+        mStartClockTimeMs = in.readLong();
         mStartPlatformVersion = in.readString();
         mEndPlatformVersion = in.readString();
-        mUptime = in.readLong();
-        mUptimeStart = in.readLong();
-        mRealtime = in.readLong();
-        mRealtimeStart = in.readLong();
+        mUptimeUs = in.readLong();
+        mUptimeStartUs = in.readLong();
+        mRealtimeUs = in.readLong();
+        mRealtimeStartUs = in.readLong();
         mOnBattery = in.readInt() != 0;
         mEstimatedBatteryCapacity = in.readInt();
         mMinLearnedBatteryCapacity = in.readInt();
@@ -14931,8 +15539,8 @@
         mPhoneOn = false;
         mPowerSaveModeEnabledTimer = new StopwatchTimer(mClocks, null, -2, null,
                 mOnBatteryTimeBase, in);
-        mLongestLightIdleTime = in.readLong();
-        mLongestFullIdleTime = in.readLong();
+        mLongestLightIdleTimeMs = in.readLong();
+        mLongestFullIdleTimeMs = in.readLong();
         mDeviceIdleModeLightTimer = new StopwatchTimer(mClocks, null, -14, null,
                 mOnBatteryTimeBase, in);
         mDeviceIdleModeFullTimer = new StopwatchTimer(mClocks, null, -11, null,
@@ -15030,7 +15638,7 @@
         mDischargeScreenDozeCounter = new LongSamplingCounter(mOnBatteryTimeBase, in);
         mDischargeLightDozeCounter = new LongSamplingCounter(mOnBatteryTimeBase, in);
         mDischargeDeepDozeCounter = new LongSamplingCounter(mOnBatteryTimeBase, in);
-        mLastWriteTime = in.readLong();
+        mLastWriteTimeMs = in.readLong();
 
         mRpmStats.clear();
         int NRPMS = in.readInt();
@@ -15096,9 +15704,11 @@
 
         int numUids = in.readInt();
         mUidStats.clear();
+        final long elapsedRealtimeMs = mClocks.elapsedRealtime();
+        final long uptimeMs = mClocks.uptimeMillis();
         for (int i = 0; i < numUids; i++) {
             int uid = in.readInt();
-            Uid u = new Uid(this, uid);
+            Uid u = new Uid(this, uid, elapsedRealtimeMs, uptimeMs);
             u.readFromParcelLocked(mOnBatteryTimeBase, mOnBatteryScreenOffTimeBase, in);
             mUidStats.append(uid, u);
         }
@@ -15137,13 +15747,13 @@
         mBatteryStatsHistory.writeToParcel(out);
 
         out.writeInt(mStartCount);
-        out.writeLong(mStartClockTime);
+        out.writeLong(mStartClockTimeMs);
         out.writeString(mStartPlatformVersion);
         out.writeString(mEndPlatformVersion);
-        out.writeLong(mUptime);
-        out.writeLong(mUptimeStart);
-        out.writeLong(mRealtime);
-        out.writeLong(mRealtimeStart);
+        out.writeLong(mUptimeUs);
+        out.writeLong(mUptimeStartUs);
+        out.writeLong(mRealtimeUs);
+        out.writeLong(mRealtimeStartUs);
         out.writeInt(mOnBattery ? 1 : 0);
         out.writeInt(mEstimatedBatteryCapacity);
         out.writeInt(mMinLearnedBatteryCapacity);
@@ -15158,8 +15768,8 @@
         }
         mInteractiveTimer.writeToParcel(out, uSecRealtime);
         mPowerSaveModeEnabledTimer.writeToParcel(out, uSecRealtime);
-        out.writeLong(mLongestLightIdleTime);
-        out.writeLong(mLongestFullIdleTime);
+        out.writeLong(mLongestLightIdleTimeMs);
+        out.writeLong(mLongestFullIdleTimeMs);
         mDeviceIdleModeLightTimer.writeToParcel(out, uSecRealtime);
         mDeviceIdleModeFullTimer.writeToParcel(out, uSecRealtime);
         mDeviceLightIdlingTimer.writeToParcel(out, uSecRealtime);
@@ -15227,7 +15837,7 @@
         mDischargeScreenDozeCounter.writeToParcel(out);
         mDischargeLightDozeCounter.writeToParcel(out);
         mDischargeDeepDozeCounter.writeToParcel(out);
-        out.writeLong(mLastWriteTime);
+        out.writeLong(mLastWriteTimeMs);
 
         out.writeInt(mRpmStats.size());
         for (Map.Entry<String, SamplingTimer> ent : mRpmStats.entrySet()) {
@@ -15472,7 +16082,7 @@
         pw.print("Batched cpu time reads: ");
         pw.println(mNumBatchedSingleUidCpuTimeReads);
         pw.print("Batching Duration (min): ");
-        pw.println((mClocks.uptimeMillis() - mCpuTimeReadsTrackingStartTime) / (60 * 1000));
+        pw.println((mClocks.uptimeMillis() - mCpuTimeReadsTrackingStartTimeMs) / (60 * 1000));
         pw.print("All UID cpu time reads since the later of device start or stats reset: ");
         pw.println(mNumAllUidCpuTimeReads);
         pw.print("UIDs removed since the later of device start or stats reset: ");
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 32e7fdc..5948e7e 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -86,9 +86,10 @@
  */
 public class ZygoteInit {
 
-    // TODO (chriswailes): Change this so it is set with Zygote or ZygoteSecondary as appropriate
     private static final String TAG = "Zygote";
 
+    private static final boolean LOGGING_DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
     private static final String PROPERTY_DISABLE_GRAPHICS_DRIVER_PRELOADING =
             "ro.zygote.disable_gl_preload";
 
@@ -284,6 +285,7 @@
                     new BufferedReader(new InputStreamReader(is), Zygote.SOCKET_BUFFER_SIZE);
 
             int count = 0;
+            int missingLambdaCount = 0;
             String line;
             while ((line = br.readLine()) != null) {
                 // Skip comments and blank lines.
@@ -302,24 +304,33 @@
                     Class.forName(line, true, null);
                     count++;
                 } catch (ClassNotFoundException e) {
-                    Log.w(TAG, "Class not found for preloading: " + line);
+                    if (line.contains("$$Lambda$")) {
+                        if (LOGGING_DEBUG) {
+                            missingLambdaCount++;
+                        }
+                    } else {
+                        Log.w(TAG, "Class not found for preloading: " + line);
+                    }
                 } catch (UnsatisfiedLinkError e) {
                     Log.w(TAG, "Problem preloading " + line + ": " + e);
                 } catch (Throwable t) {
                     Log.e(TAG, "Error preloading " + line + ".", t);
                     if (t instanceof Error) {
                         throw (Error) t;
-                    }
-                    if (t instanceof RuntimeException) {
+                    } else if (t instanceof RuntimeException) {
                         throw (RuntimeException) t;
+                    } else {
+                        throw new RuntimeException(t);
                     }
-                    throw new RuntimeException(t);
                 }
                 Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
             }
 
             Log.i(TAG, "...preloaded " + count + " classes in "
                     + (SystemClock.uptimeMillis() - startTime) + "ms.");
+            if (LOGGING_DEBUG && missingLambdaCount != 0) {
+                Log.i(TAG, "Unresolved lambda preloads: " + missingLambdaCount);
+            }
         } catch (IOException e) {
             Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
         } finally {
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 7f3eb45..d5f54a1 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -18,13 +18,11 @@
 
 import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Point;
-import android.graphics.Rect;
 import android.hardware.input.InputManager;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.util.MergedConfiguration;
-import android.view.DisplayCutout;
 import android.view.DragEvent;
 import android.view.IScrollCaptureController;
 import android.view.IWindow;
@@ -33,6 +31,7 @@
 import android.view.InsetsState;
 import android.view.PointerIcon;
 import android.view.WindowInsets.Type.InsetsType;
+import android.window.ClientWindowFrames;
 
 import com.android.internal.os.IResultReceiver;
 
@@ -51,11 +50,9 @@
     }
 
     @Override
-    public void resized(Rect frame, Rect contentInsets, Rect visibleInsets,
-            Rect stableInsets, boolean reportDraw,
-            MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
-            boolean alwaysConsumeSystemBars, int displayId,
-            DisplayCutout.ParcelableWrapper displayCutout) {
+    public void resized(ClientWindowFrames frames, boolean reportDraw,
+            MergedConfiguration mergedConfiguration, boolean forceLayout,
+            boolean alwaysConsumeSystemBars, int displayId) {
         if (reportDraw) {
             try {
                 mSession.finishDrawing(this, null /* postDrawTransaction */);
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 3d12d07..7f743ef 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -219,6 +219,8 @@
 
     optional SettingProto enhanced_voice_privacy_enabled = 23 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
+    optional SettingProto force_bold_text = 85 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
     message Gesture {
         optional SettingProto aware_enabled = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
@@ -615,5 +617,5 @@
 
     // Please insert fields in alphabetical order and group them into messages
     // if possible (to avoid reaching the method limit).
-    // Next tag = 85;
+    // Next tag = 86;
 }
diff --git a/core/proto/android/wifi/enums.proto b/core/proto/android/wifi/enums.proto
index 315c579..e676fef 100644
--- a/core/proto/android/wifi/enums.proto
+++ b/core/proto/android/wifi/enums.proto
@@ -48,3 +48,65 @@
      */
     WIFI_MODE_FULL_LOW_LATENCY = 4;
 }
+
+/**
+ * Wifi authentication type.
+ */
+enum WifiAuthType {
+    AUTH_TYPE_NONE = 0;
+
+    // WPA pre-shared key.
+    AUTH_TYPE_WPA_PSK = 1;
+    // WPA using EAP authentication. Generally used with an external authentication server.
+    AUTH_TYPE_WPA_EAP = 2;
+    // IEEE 802.1X using EAP authentication and (optionally) dynamically generated WEP keys.
+    AUTH_TYPE_IEEE8021X = 3;
+    // WPA2 pre-shared key for use with soft access point.
+    AUTH_TYPE_WPA2_PSK = 4;
+    // Hotspot 2.0 r2 OSEN.
+    AUTH_TYPE_OSEN = 5;
+    // IEEE 802.11r Fast BSS Transition with PSK authentication.
+    AUTH_TYPE_FT_PSK = 6;
+    // IEEE 802.11r Fast BSS Transition with EAP authentication.
+    AUTH_TYPE_FT_EAP = 7;
+    // Simultaneous Authentication of Equals.
+    AUTH_TYPE_SAE = 8;
+    // Opportunistic Wireless Encryption.
+    AUTH_TYPE_OWE = 9;
+    // SUITE_B_192 192 bit level
+    AUTH_TYPE_SUITE_B_192 = 10;
+    // WPA pre-shared key with stronger SHA256-based algorithms.
+    AUTH_TYPE_WPA_PSK_SHA256 = 11;
+    // WPA using EAP authentication with stronger SHA256-based algorithms.
+    AUTH_TYPE_WPA_EAP_SHA256 = 12;
+    // WAPI pre-shared key.
+    AUTH_TYPE_WAPI_PSK = 13;
+    // WAPI certificate to be specified.
+    AUTH_TYPE_WAPI_CERT = 14;
+    // IEEE 802.11ai FILS SK with SHA256.
+    AUTH_TYPE_FILS_SHA256 = 15;
+    // IEEE 802.11ai FILS SK with SHA384.
+    AUTH_TYPE_FILS_SHA384 = 16;
+}
+
+/**
+ * Bucketed wifi band.
+ */
+enum WifiBandBucket {
+    BAND_UNKNOWN = 0;
+
+    // All of 2.4GHz band
+    BAND_2G = 1;
+    // Frequencies in the range of [5150, 5250) GHz
+    BAND_5G_LOW = 2;
+    // Frequencies in the range of [5250, 5725) GHz
+    BAND_5G_MIDDLE = 3;
+    // Frequencies in the range of [5725, 5850) GHz
+    BAND_5G_HIGH = 4;
+    // Frequencies in the range of [5925, 6425) GHz
+    BAND_6G_LOW = 5;
+    // Frequencies in the range of [6425, 6875) GHz
+    BAND_6G_MIDDLE = 6;
+    // Frequencies in the range of [6875, 7125) GHz
+    BAND_6G_HIGH = 7;
+}
\ No newline at end of file
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c9cecdd..560e3c1 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4691,6 +4691,12 @@
     <permission android:name="android.permission.HANDLE_CAR_MODE_CHANGES"
                 android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows the holder to send category_car notifications.
+        @hide -->
+    <permission
+        android:name="android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS"
+        android:protectionLevel="signature|privileged" />
+
     <!-- The system process is explicitly the only one allowed to launch the
          confirmation UI for full backup/restore -->
     <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index e17c312..6ae6faa 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -50,6 +50,7 @@
     <uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
     <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
     <uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
+    <uses-permission android:name="android.permission.DEVICE_POWER"/>
     <uses-permission android:name="android.permission.DOWNLOAD_CACHE_NON_PURGEABLE" />
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 0490678..88faa0a 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -574,16 +574,16 @@
 
         InstallParams(String outFileName, int rawResId) throws PackageParserException {
             this.pkg = getParsedPackage(outFileName, rawResId);
-            this.packageURI = Uri.fromFile(new File(pkg.getCodePath()));
+            this.packageURI = Uri.fromFile(new File(pkg.getPath()));
         }
 
         InstallParams(ParsingPackage pkg) {
-            this.packageURI = Uri.fromFile(new File(pkg.getCodePath()));
+            this.packageURI = Uri.fromFile(new File(pkg.getPath()));
             this.pkg = pkg;
         }
 
         long getApkSize() {
-            File file = new File(pkg.getCodePath());
+            File file = new File(pkg.getPath());
             return file.length();
         }
     }
@@ -1003,7 +1003,7 @@
         try {
             cleanUpInstall(ip.pkg.getPackageName());
         } finally {
-            File outFile = new File(ip.pkg.getCodePath());
+            File outFile = new File(ip.pkg.getPath());
             if (outFile != null && outFile.exists()) {
                 outFile.delete();
             }
diff --git a/core/tests/coretests/src/com/android/internal/content/OverlayConfigIterationRule.java b/core/tests/coretests/src/com/android/internal/content/OverlayConfigIterationRule.java
index fbf75df..a01459f 100644
--- a/core/tests/coretests/src/com/android/internal/content/OverlayConfigIterationRule.java
+++ b/core/tests/coretests/src/com/android/internal/content/OverlayConfigIterationRule.java
@@ -146,7 +146,7 @@
                         when(a.getTargetSdkVersion()).thenReturn(info.targetSdkVersion);
                         when(a.isOverlayIsStatic()).thenReturn(info.isStatic);
                         when(a.getOverlayPriority()).thenReturn(info.priority);
-                        when(a.getBaseCodePath()).thenReturn(info.path.getPath());
+                        when(a.getBaseApkPath()).thenReturn(info.path.getPath());
                         f.accept(a, !info.path.getPath().contains("data/overlay"));
                     }
                     return null;
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryInputSuspendTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryInputSuspendTest.java
new file mode 100644
index 0000000..e870d60
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryInputSuspendTest.java
@@ -0,0 +1,130 @@
+/*
+ * 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 org.junit.Assert.assertTrue;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
+import android.os.Build;
+import android.os.ConditionVariable;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.SystemUtil;
+
+import com.google.android.collect.Sets;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+public class BatteryInputSuspendTest {
+
+    public static final Set<String> SUPPORTED_DEVICES = Sets.newArraySet(
+            "blueline",
+            "crosshatch",
+            "coral"
+    );
+
+    private ChargerStateMonitor mChargerStateMonitor;
+
+    @Before
+    public void verifyCharging() {
+        if (!SUPPORTED_DEVICES.contains(Build.DEVICE)) {
+            return;
+        }
+
+        mChargerStateMonitor = new ChargerStateMonitor();
+
+        assertTrue("Device must be connected to USB", mChargerStateMonitor.isCharging());
+    }
+
+    @Test
+    public void testSuspendInput() {
+        if (!SUPPORTED_DEVICES.contains(Build.DEVICE)) {
+            return;
+        }
+
+        SystemUtil.runShellCommand("dumpsys battery suspend_input");
+
+        mChargerStateMonitor.waitForChargerState(/* isPluggedIn */false);
+    }
+
+    @After
+    public void reenableCharging() {
+        if (!SUPPORTED_DEVICES.contains(Build.DEVICE)) {
+            return;
+        }
+
+        mChargerStateMonitor.reset();
+
+        SystemUtil.runShellCommand("dumpsys battery reset");
+
+        mChargerStateMonitor.waitForChargerState(/* isPluggedIn */true);
+    }
+
+    private static class ChargerStateMonitor {
+        private final Intent mBatteryMonitor;
+        private final ConditionVariable mReady = new ConditionVariable();
+        private boolean mExpectedChargingState;
+
+        ChargerStateMonitor() {
+            Context context = InstrumentationRegistry.getInstrumentation().getContext();
+            mBatteryMonitor = context.registerReceiver(new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    if (isCharging(intent) == mExpectedChargingState) {
+                        mReady.open();
+                    }
+                }
+            }, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+        }
+
+        public boolean isCharging() {
+            return isCharging(mBatteryMonitor);
+        }
+
+        private boolean isCharging(Intent batteryMonitor) {
+            return batteryMonitor.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) != 0;
+        }
+
+        void waitForChargerState(boolean isPluggedIn) {
+            mExpectedChargingState = isPluggedIn;
+
+            boolean charging = isCharging();
+            if (charging == mExpectedChargingState) {
+                return;
+            }
+
+            boolean success = mReady.block(100000);
+            assertTrue("Timed out waiting for charging state to change", success);
+        }
+
+        void reset() {
+            mReady.close();
+        }
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
index 61d20df..3b27f18 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
@@ -18,6 +18,7 @@
 
 import android.os.BatteryStats;
 import android.os.Parcel;
+import android.os.SystemClock;
 
 import androidx.test.filters.SmallTest;
 
@@ -36,9 +37,9 @@
         timer.onTimeStarted(100, 100, 100);
 
         // First update is absorbed.
-        timer.update(10, 1);
+        timer.update(10, 1, SystemClock.elapsedRealtime() * 1000);
 
-        timer.update(20, 2);
+        timer.update(20, 2, SystemClock.elapsedRealtime() * 1000);
 
         assertEquals(1, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
         assertEquals(10, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
@@ -62,7 +63,7 @@
                 timeBase);
 
         // First once is absorbed.
-        timer.update(10, 1);
+        timer.update(10, 1, SystemClock.elapsedRealtime() * 1000);
 
         timer.add(10, 1);
 
@@ -71,7 +72,7 @@
 
         // This is less than we currently have, so we will end the sample. Time isn't running, so
         // nothing should happen.
-        timer.update(0, 0);
+        timer.update(0, 0, SystemClock.elapsedRealtime() * 1000);
 
         assertEquals(0, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
         assertEquals(0, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
@@ -86,7 +87,7 @@
 
         // This is less than we currently have, so we should end our sample and continue with the
         // entire amount updated here.
-        timer.update(50, 5);
+        timer.update(50, 5, SystemClock.elapsedRealtime() * 1000);
 
         assertEquals(150, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
         assertEquals(15, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
@@ -106,7 +107,7 @@
 
         // This should be absorbed because it is our first update and we don't know what
         // was being counted before.
-        timer.update(10, 1);
+        timer.update(10, 1, SystemClock.elapsedRealtime() * 1000);
 
         assertEquals(0, timer.getTotalTimeLocked(10, BatteryStats.STATS_SINCE_CHARGED));
         assertEquals(0, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
@@ -115,7 +116,7 @@
         timer.onTimeStarted(100, 100, 100);
 
         // This should be absorbed.
-        timer.update(10, 1);
+        timer.update(10, 1, SystemClock.elapsedRealtime() * 1000);
 
         assertEquals(0, timer.getTotalTimeLocked(100, BatteryStats.STATS_SINCE_CHARGED));
         assertEquals(0, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
@@ -206,13 +207,13 @@
 
         // Now, just like with a fresh timer, the first update should be absorbed to account for
         // data being collected when we weren't recording.
-        unparceledOnBatteryTimer.update(10, 10);
+        unparceledOnBatteryTimer.update(10, 10, SystemClock.elapsedRealtime() * 1000);
 
         assertEquals(10, unparceledOnBatteryTimer.getTotalTimeLocked(0,
                 BatteryStats.STATS_SINCE_CHARGED));
         assertEquals(1, unparceledOnBatteryTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
 
-        unparceledOffBatteryTimer.update(10, 10);
+        unparceledOffBatteryTimer.update(10, 10, SystemClock.elapsedRealtime() * 1000);
 
         assertEquals(10, unparceledOffBatteryTimer.getTotalTimeLocked(0,
                 BatteryStats.STATS_SINCE_CHARGED));
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java
index df549c5..80e066c 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java
@@ -36,22 +36,22 @@
         }
 
         void populate() {
-            mStartTime = 1010;
-            mRunningSince = 2021;
+            mStartTimeMs = 1010;
+            mRunningSinceMs = 2021;
             mRunning = true;
             mStarts = 4042;
-            mLaunchedTime = 5053;
-            mLaunchedSince = 6064;
+            mLaunchedTimeMs = 5053;
+            mLaunchedSinceMs = 6064;
             mLaunched = true;
             mLaunches = 8085;
         }
 
         long getStartTime() {
-            return mStartTime;
+            return mStartTimeMs;
         }
 
         long getRunningSince() {
-            return mRunningSince;
+            return mRunningSinceMs;
         }
 
         void setRunning(boolean val) {
@@ -67,11 +67,11 @@
         }
 
         long getLaunchedTime() {
-            return mLaunchedTime;
+            return mLaunchedTimeMs;
         }
 
         long getLaunchedSince() {
-            return mLaunchedSince;
+            return mLaunchedSinceMs;
         }
 
         void setLaunched(boolean val) {
@@ -173,7 +173,12 @@
         MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
             @Override
             public long getBatteryUptimeLocked() {
-                return 777777L;
+                return 777777L * 1000; // microseconds
+            }
+
+            @Override
+            public long getBatteryUptimeLocked(long uptimeMs) {
+                return 777777L * 1000; // microseconds
             }
         };
 
@@ -202,7 +207,12 @@
         MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
             @Override
             public long getBatteryUptimeLocked() {
-                return 777777L;
+                return 777777L * 1000; // microseconds
+            }
+
+            @Override
+            public long getBatteryUptimeLocked(long uptimeMs) {
+                return 777777L * 1000; // microseconds
             }
         };
 
@@ -229,7 +239,12 @@
         MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
             @Override
             public long getBatteryUptimeLocked() {
-                return 777777L;
+                return 777777L * 1000; // microseconds
+            }
+
+            @Override
+            public long getBatteryUptimeLocked(long uptimeMs) {
+                return 777777L * 1000; // microseconds
             }
         };
         TestServ serv = new TestServ(bsi);
@@ -259,7 +274,12 @@
         MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
             @Override
             public long getBatteryUptimeLocked() {
-                return 777777L;
+                return 777777L * 1000; // microseconds
+            }
+
+            @Override
+            public long getBatteryUptimeLocked(long uptimeMs) {
+                return 777777L * 1000; // microseconds
             }
         };
         TestServ serv = new TestServ(bsi);
@@ -316,7 +336,12 @@
         MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
             @Override
             public long getBatteryUptimeLocked() {
-                return 777777L;
+                return 777777L * 1000; // microseconds
+            }
+
+            @Override
+            public long getBatteryUptimeLocked(long uptimeMs) {
+                return 777777L * 1000; // microseconds
             }
         };
         TestServ serv = new TestServ(bsi);
@@ -345,7 +370,12 @@
         MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
             @Override
             public long getBatteryUptimeLocked() {
-                return 777777L;
+                return 777777L * 1000; // microseconds
+            }
+
+            @Override
+            public long getBatteryUptimeLocked(long uptimeMs) {
+                return 777777L * 1000; // microseconds
             }
         };
         TestServ serv = new TestServ(bsi);
@@ -374,7 +404,12 @@
         MockBatteryStatsImpl bsi = new MockBatteryStatsImpl() {
             @Override
             public long getBatteryUptimeLocked() {
-                return 777777L;
+                return 777777L * 1000; // microseconds
+            }
+
+            @Override
+            public long getBatteryUptimeLocked(long uptimeMs) {
+                return 777777L * 1000; // microseconds
             }
         };
         TestServ serv = new TestServ(bsi);
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java
index e5441c0..f016e75a 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java
@@ -41,29 +41,29 @@
         public void populate(long uptime, long realtime, boolean running, long pastUptime,
                 long uptimeStart, long pastRealtime, long realtimeStart,
                 long unpluggedUptime, long unpluggedRealtime) {
-            mUptime = uptime;
-            mRealtime = realtime;
+            mUptimeUs = uptime;
+            mRealtimeUs = realtime;
             mRunning = running;
-            mPastUptime = pastUptime;
-            mUptimeStart = uptimeStart;
-            mPastRealtime = pastRealtime;
-            mRealtimeStart = realtimeStart;
-            mUnpluggedUptime = unpluggedUptime;
-            mUnpluggedRealtime = unpluggedRealtime;
+            mPastUptimeUs = pastUptime;
+            mUptimeStartUs = uptimeStart;
+            mPastRealtimeUs = pastRealtime;
+            mRealtimeStartUs = realtimeStart;
+            mUnpluggedUptimeUs = unpluggedUptime;
+            mUnpluggedRealtimeUs = unpluggedRealtime;
         }
 
         public void verify(long uptime, long realtime, boolean running, long pastUptime,
                 long uptimeStart, long pastRealtime, long realtimeStart,
                 long unpluggedUptime, long unpluggedRealtime) {
-            Assert.assertEquals(uptime, mUptime);
-            Assert.assertEquals(realtime, mRealtime);
+            Assert.assertEquals(uptime, mUptimeUs);
+            Assert.assertEquals(realtime, mRealtimeUs);
             Assert.assertEquals(running, mRunning);
-            Assert.assertEquals(pastUptime, mPastUptime);
-            Assert.assertEquals(uptimeStart, mUptimeStart);
-            Assert.assertEquals(pastRealtime, mPastRealtime);
-            Assert.assertEquals(realtimeStart, mRealtimeStart);
-            Assert.assertEquals(unpluggedUptime, mUnpluggedUptime);
-            Assert.assertEquals(unpluggedRealtime, mUnpluggedRealtime);
+            Assert.assertEquals(pastUptime, mPastUptimeUs);
+            Assert.assertEquals(uptimeStart, mUptimeStartUs);
+            Assert.assertEquals(pastRealtime, mPastRealtimeUs);
+            Assert.assertEquals(realtimeStart, mRealtimeStartUs);
+            Assert.assertEquals(unpluggedUptime, mUnpluggedUptimeUs);
+            Assert.assertEquals(unpluggedRealtime, mUnpluggedRealtimeUs);
         }
     }
 
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
index 40e3a5f..11a01b3 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
@@ -49,7 +49,8 @@
             super(clocks, type, timeBase);
         }
 
-        protected long computeRunTimeLocked(long curBatteryRealtime) {
+        @Override
+        protected long computeRunTimeLocked(long curBatteryRealtime, long elapsedRealtimeUs) {
             lastComputeRunTimeRealtime = curBatteryRealtime;
             return nextComputeRunTime;
         }
@@ -67,19 +68,19 @@
         }
 
         public long getTotalTime() {
-            return mTotalTime;
+            return mTotalTimeUs;
         }
 
         public void setTotalTime(long val) {
-            mTotalTime = val;
+            mTotalTimeUs = val;
         }
 
         public long getTimeBeforeMark() {
-            return mTimeBeforeMark;
+            return mTimeBeforeMarkUs;
         }
 
         public void setTimeBeforeMark(long val) {
-            mTimeBeforeMark = val;
+            mTimeBeforeMarkUs = val;
         }
     }
 
diff --git a/core/tests/coretests/src/com/android/internal/util/HexDumpTest.java b/core/tests/coretests/src/com/android/internal/util/HexDumpTest.java
index 4f0becc..f1cd89b 100644
--- a/core/tests/coretests/src/com/android/internal/util/HexDumpTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/HexDumpTest.java
@@ -160,8 +160,9 @@
     private static void assertThrows(Class<? extends RuntimeException> clazz, Runnable runnable) {
         try {
             runnable.run();
-        } catch (RuntimeException exception) {
-            assertEquals(toStrackTrace(exception), clazz, exception.getClass());
+            fail();
+        } catch (RuntimeException expected) {
+            assertEquals(toStrackTrace(expected), clazz, expected.getClass());
         }
     }
 
diff --git a/data/etc/car/com.google.android.car.kitchensink.xml b/data/etc/car/com.google.android.car.kitchensink.xml
index 7292e07..59aa45e 100644
--- a/data/etc/car/com.google.android.car.kitchensink.xml
+++ b/data/etc/car/com.google.android.car.kitchensink.xml
@@ -40,6 +40,7 @@
         <permission name="android.permission.REAL_GET_TASKS"/>
         <permission name="android.permission.READ_LOGS"/>
         <permission name="android.permission.REBOOT"/>
+        <permission name="android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS"/>
         <!-- use for CarServiceTest -->
         <permission name="android.permission.SET_ACTIVITY_WATCHER"/>
         <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index 8abe9ee..b4620e27 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -22,7 +22,6 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Point;
-import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -32,7 +31,6 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
-import android.view.DisplayCutout;
 import android.view.DragEvent;
 import android.view.IScrollCaptureController;
 import android.view.IWindow;
@@ -47,6 +45,7 @@
 import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.view.WindowlessWindowManager;
+import android.window.ClientWindowFrames;
 
 import com.android.internal.os.IResultReceiver;
 
@@ -274,22 +273,20 @@
         @Override
         public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
                 int requestedWidth, int requestedHeight, int viewVisibility, int flags,
-                long frameNumber, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
-                Rect outVisibleInsets, Rect outStableInsets,
-                DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration,
+                long frameNumber, ClientWindowFrames outFrames,
+                MergedConfiguration mergedConfiguration,
                 SurfaceControl outSurfaceControl, InsetsState outInsetsState,
                 InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
                 SurfaceControl outBLASTSurfaceControl) {
             int res = super.relayout(window, seq, attrs, requestedWidth, requestedHeight,
-                    viewVisibility, flags, frameNumber, outFrame, outOverscanInsets,
-                    outContentInsets, outVisibleInsets, outStableInsets,
-                    cutout, mergedConfiguration, outSurfaceControl, outInsetsState,
+                    viewVisibility, flags, frameNumber, outFrames,
+                    mergedConfiguration, outSurfaceControl, outInsetsState,
                     outActiveControls, outSurfaceSize, outBLASTSurfaceControl);
             if (res != 0) {
                 return res;
             }
             DisplayLayout dl = mDisplayController.getDisplayLayout(mDisplayId);
-            outStableInsets.set(dl.stableInsets());
+            outFrames.stableInsets.set(dl.stableInsets());
             return 0;
         }
 
@@ -314,10 +311,9 @@
         ContainerWindow() {}
 
         @Override
-        public void resized(Rect frame, Rect contentInsets, Rect visibleInsets, Rect stableInsets,
-                boolean reportDraw, MergedConfiguration newMergedConfiguration, Rect backDropFrame,
-                boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
-                DisplayCutout.ParcelableWrapper displayCutout) {}
+        public void resized(ClientWindowFrames frames, boolean reportDraw,
+                MergedConfiguration newMergedConfiguration, boolean forceLayout,
+                boolean alwaysConsumeSystemBars, int displayId) {}
 
         @Override
         public void locationInParentDisplayChanged(Point offset) {}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java
index 015707e..25827cd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java
@@ -194,7 +194,7 @@
      */
     boolean applyEnterSplit(SplitScreenTaskOrganizer tiles, SplitDisplayLayout layout) {
         // Set launchtile first so that any stack created after
-        // getAllStackInfos and before reparent (even if unlikely) are placed
+        // getAllRootTaskInfos and before reparent (even if unlikely) are placed
         // correctly.
         mTaskOrganizer.setLaunchRoot(DEFAULT_DISPLAY, tiles.mSecondary.token);
         List<ActivityManager.RunningTaskInfo> rootTasks =
diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp
index 5879022..d7afa0e 100644
--- a/libs/WindowManager/Shell/tests/flicker/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/Android.bp
@@ -18,7 +18,7 @@
     name: "WMShellFlickerTests",
     srcs: ["src/**/*.java", "src/**/*.kt"],
     manifest: "AndroidManifest.xml",
-    test_config: "AndroidTest.xml",
+    test_config: "AndroidTestPhysicalDevices.xml",
     platform_apis: true,
     certificate: "platform",
     test_suites: ["device-tests"],
@@ -32,3 +32,21 @@
         "launcher-aosp-tapl"
     ],
 }
+
+android_test {
+    name: "WMShellFlickerTestsVirtual",
+    srcs: ["src/**/*.java", "src/**/*.kt"],
+    manifest: "AndroidManifest.xml",
+    test_config: "AndroidTestVirtualDevices.xml",
+    platform_apis: true,
+    certificate: "platform",
+    libs: ["android.test.runner"],
+    static_libs: [
+        "androidx.test.ext.junit",
+        "flickerlib",
+        "truth-prebuilt",
+        "app-helpers-core",
+        "launcher-helper-lib",
+        "launcher-aosp-tapl"
+    ],
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTestPhysicalDevices.xml
similarity index 95%
copy from libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
copy to libs/WindowManager/Shell/tests/flicker/AndroidTestPhysicalDevices.xml
index 526fc50..9dd9f42 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTestPhysicalDevices.xml
@@ -27,6 +27,7 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest">
         <option name="package" value="com.android.wm.shell.flicker"/>
+        <option name="include-annotation" value="androidx.test.filters.RequiresDevice" />
         <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
         <option name="shell-timeout" value="6600s" />
         <option name="test-timeout" value="6000s" />
@@ -37,4 +38,4 @@
         <option name="collect-on-run-ended-only" value="true" />
         <option name="clean-up" value="true" />
     </metrics_collector>
-</configuration>
+</configuration>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTestVirtualDevices.xml
similarity index 95%
rename from libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
rename to libs/WindowManager/Shell/tests/flicker/AndroidTestVirtualDevices.xml
index 526fc50..afb1166 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTestVirtualDevices.xml
@@ -27,6 +27,7 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest">
         <option name="package" value="com.android.wm.shell.flicker"/>
+        <option name="exclude-annotation" value="androidx.test.filters.RequiresDevice" />
         <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
         <option name="shell-timeout" value="6600s" />
         <option name="test-timeout" value="6000s" />
@@ -37,4 +38,4 @@
         <option name="collect-on-run-ended-only" value="true" />
         <option name="clean-up" value="true" />
     </metrics_collector>
-</configuration>
+</configuration>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt
index 308a36e..47a62ce 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt
@@ -18,7 +18,7 @@
 
 import android.app.Instrumentation
 import android.support.test.launcherhelper.ILauncherStrategy
-import com.android.server.wm.flicker.StandardAppHelper
+import com.android.server.wm.flicker.helpers.StandardAppHelper
 
 abstract class FlickerAppHelper(
     instr: Instrumentation,
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index 4b04449..c3c576d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -18,7 +18,7 @@
 
 import android.view.Surface
 import androidx.test.filters.FlakyTest
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.dsl.flicker
 import com.android.server.wm.flicker.helpers.closePipWindow
 import com.android.server.wm.flicker.helpers.expandPipWindow
@@ -41,7 +41,7 @@
  * Test Pip launch.
  * To run this test: `atest FlickerTests:PipToAppTest`
  */
-@LargeTest
+@RequiresDevice
 @RunWith(Parameterized::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @FlakyTest(bugId = 152738416)
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 549e793..624607b 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -828,9 +828,10 @@
         }
 
         /**
-         * Gets the UID of this token.
+         * Gets the UID of the application that created the media session.
          * @hide
          */
+        @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
         public int getUid() {
             return mUid;
         }
diff --git a/non-updatable-api/module-lib-current.txt b/non-updatable-api/module-lib-current.txt
index 1bbbf98..f7f42d0 100644
--- a/non-updatable-api/module-lib-current.txt
+++ b/non-updatable-api/module-lib-current.txt
@@ -57,6 +57,10 @@
     field public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 65536; // 0x10000
   }
 
+  public static final class MediaSession.Token implements android.os.Parcelable {
+    method public int getUid();
+  }
+
   public final class MediaSessionManager {
     method public void dispatchMediaKeyEventAsSystemService(@NonNull android.view.KeyEvent);
     method public boolean dispatchMediaKeyEventAsSystemService(@NonNull android.media.session.MediaSession.Token, @NonNull android.view.KeyEvent);
diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt
index ff3999f..b807d1b 100644
--- a/non-updatable-api/system-current.txt
+++ b/non-updatable-api/system-current.txt
@@ -205,6 +205,7 @@
     field public static final String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS";
     field public static final String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS";
     field public static final String SECURE_ELEMENT_PRIVILEGED_OPERATION = "android.permission.SECURE_ELEMENT_PRIVILEGED_OPERATION";
+    field public static final String SEND_CATEGORY_CAR_NOTIFICATIONS = "android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS";
     field public static final String SEND_DEVICE_CUSTOMIZATION_READY = "android.permission.SEND_DEVICE_CUSTOMIZATION_READY";
     field public static final String SEND_SHOW_SUSPENDED_APP_DETAILS = "android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS";
     field public static final String SEND_SMS_NO_CONFIRMATION = "android.permission.SEND_SMS_NO_CONFIRMATION";
@@ -6812,6 +6813,8 @@
     field public static final int BSS_CAPABILITY_CF_POLL_REQUEST = 8; // 0x8
     field public static final int BSS_CAPABILITY_CHANNEL_AGILITY = 128; // 0x80
     field public static final int BSS_CAPABILITY_DELAYED_BLOCK_ACK = 16384; // 0x4000
+    field public static final int BSS_CAPABILITY_DMG_ESS = 3; // 0x3
+    field public static final int BSS_CAPABILITY_DMG_IBSS = 1; // 0x1
     field public static final int BSS_CAPABILITY_DSSS_OFDM = 8192; // 0x2000
     field public static final int BSS_CAPABILITY_ESS = 1; // 0x1
     field public static final int BSS_CAPABILITY_IBSS = 2; // 0x2
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
index dadbc22..3af7507 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
@@ -30,7 +30,6 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardViewController;
 import com.android.keyguard.ViewMediatorCallback;
-import com.android.keyguard.dagger.KeyguardBouncerComponent;
 import com.android.systemui.R;
 import com.android.systemui.car.CarServiceProvider;
 import com.android.systemui.car.navigationbar.CarNavigationBarController;
@@ -40,6 +39,7 @@
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.statusbar.phone.BiometricUnlockController;
 import com.android.systemui.statusbar.phone.KeyguardBouncer;
+import com.android.systemui.statusbar.phone.KeyguardBouncer.Factory;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.NotificationPanelViewController;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -66,7 +66,7 @@
     private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
     private final ViewMediatorCallback mViewMediatorCallback;
     private final CarNavigationBarController mCarNavigationBarController;
-    private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
+    private final Factory mKeyguardBouncerFactory;
     // Needed to instantiate mBouncer.
     private final KeyguardBouncer.BouncerExpansionCallback
             mExpansionCallback = new KeyguardBouncer.BouncerExpansionCallback() {
@@ -107,7 +107,7 @@
             Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
             ViewMediatorCallback viewMediatorCallback,
             CarNavigationBarController carNavigationBarController,
-            KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) {
+            KeyguardBouncer.Factory keyguardBouncerFactory) {
 
         super(R.id.keyguard_stub, overlayViewGlobalStateController);
 
@@ -118,7 +118,7 @@
         mBiometricUnlockControllerLazy = biometricUnlockControllerLazy;
         mViewMediatorCallback = viewMediatorCallback;
         mCarNavigationBarController = carNavigationBarController;
-        mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory;
+        mKeyguardBouncerFactory = keyguardBouncerFactory;
 
         registerUserSwitchedListener();
     }
@@ -130,9 +130,8 @@
 
     @Override
     public void onFinishInflate() {
-        mBouncer = mKeyguardBouncerComponentFactory
-                .build(getLayout().findViewById(R.id.keyguard_container), mExpansionCallback)
-                .createKeyguardBouncer();
+        mBouncer = mKeyguardBouncerFactory
+                .create(getLayout().findViewById(R.id.keyguard_container), mExpansionCallback);
         mBiometricUnlockControllerLazy.get().setKeyguardViewController(this);
     }
 
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/ButtonSelectionStateController.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/ButtonSelectionStateController.java
index aa6da89..2dc4756 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/ButtonSelectionStateController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/ButtonSelectionStateController.java
@@ -16,7 +16,7 @@
 
 package com.android.systemui.car.navigationbar;
 
-import android.app.ActivityManager;
+import android.app.ActivityTaskManager.RootTaskInfo;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -97,27 +97,27 @@
      * The StackInfo is expected to be supplied in order of recency and StackInfo will only be used
      * for consideration if it has the same displayId as the CarNavigationButton.
      *
-     * @param stackInfoList of the currently running application
+     * @param taskInfoList of the currently running application
      * @param validDisplay index of the valid display
      */
 
-    protected void taskChanged(List<ActivityManager.StackInfo> stackInfoList, int validDisplay) {
-        ActivityManager.StackInfo validStackInfo = null;
-        for (ActivityManager.StackInfo stackInfo : stackInfoList) {
+    protected void taskChanged(List<RootTaskInfo> taskInfoList, int validDisplay) {
+        RootTaskInfo validTaskInfo = null;
+        for (RootTaskInfo taskInfo : taskInfoList) {
             // Find the first stack info with a topActivity in the primary display.
             // TODO: We assume that CarFacetButton will launch an app only in the primary display.
             // We need to extend the functionality to handle the multiple display properly.
-            if (stackInfo.topActivity != null && stackInfo.displayId == validDisplay) {
-                validStackInfo = stackInfo;
+            if (taskInfo.topActivity != null && taskInfo.displayId == validDisplay) {
+                validTaskInfo = taskInfo;
                 break;
             }
         }
 
-        if (validStackInfo == null) {
+        if (validTaskInfo == null) {
             // No stack was found that was on the same display as the buttons thus return
             return;
         }
-        int displayId = validStackInfo.displayId;
+        int displayId = validTaskInfo.displayId;
 
         mSelectedButtons.forEach(carNavigationButton -> {
             if (carNavigationButton.getDisplayId() == displayId) {
@@ -126,7 +126,7 @@
         });
         mSelectedButtons.clear();
 
-        HashSet<CarNavigationButton> selectedButtons = findSelectedButtons(validStackInfo);
+        HashSet<CarNavigationButton> selectedButtons = findSelectedButtons(validTaskInfo);
 
         if (selectedButtons != null) {
             selectedButtons.forEach(carNavigationButton -> {
@@ -141,10 +141,10 @@
     /**
      * Defaults to Display.DEFAULT_DISPLAY when no parameter is provided for the validDisplay.
      *
-     * @param stackInfoList
+     * @param taskInfoList
      */
-    protected void taskChanged(List<ActivityManager.StackInfo> stackInfoList) {
-        taskChanged(stackInfoList, Display.DEFAULT_DISPLAY);
+    protected void taskChanged(List<RootTaskInfo> taskInfoList) {
+        taskChanged(taskInfoList, Display.DEFAULT_DISPLAY);
     }
 
     /**
@@ -171,12 +171,11 @@
         mRegisteredViews.add(carNavigationButton);
     }
 
-    private HashSet<CarNavigationButton> findSelectedButtons(
-            ActivityManager.StackInfo validStackInfo) {
-        String packageName = validStackInfo.topActivity.getPackageName();
+    private HashSet<CarNavigationButton> findSelectedButtons(RootTaskInfo validTaskInfo) {
+        String packageName = validTaskInfo.topActivity.getPackageName();
 
         HashSet<CarNavigationButton> selectedButtons =
-                findButtonsByComponentName(validStackInfo.topActivity);
+                findButtonsByComponentName(validTaskInfo.topActivity);
         if (selectedButtons == null) {
             selectedButtons = mButtonsByPackage.get(packageName);
         }
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/ButtonSelectionStateListener.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/ButtonSelectionStateListener.java
index d6216ba..f74bd4f 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/ButtonSelectionStateListener.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/ButtonSelectionStateListener.java
@@ -43,9 +43,9 @@
     public void onTaskStackChanged() {
         try {
             mButtonSelectionStateController.taskChanged(
-                    ActivityTaskManager.getService().getAllStackInfos());
+                    ActivityTaskManager.getService().getAllRootTaskInfos());
         } catch (Exception e) {
-            Log.e(TAG, "Getting StackInfo from activity manager failed", e);
+            Log.e(TAG, "Getting RootTaskInfo from activity task manager failed", e);
         }
     }
 
@@ -53,9 +53,9 @@
     public void onTaskDisplayChanged(int taskId, int newDisplayId) {
         try {
             mButtonSelectionStateController.taskChanged(
-                    ActivityTaskManager.getService().getAllStackInfos());
+                    ActivityTaskManager.getService().getAllRootTaskInfos());
         } catch (Exception e) {
-            Log.e(TAG, "Getting StackInfo from activity manager failed", e);
+            Log.e(TAG, "Getting RootTaskInfo from activity task manager failed", e);
         }
 
     }
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppDetector.java b/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppDetector.java
index eb32edb..f96ee0f 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppDetector.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppDetector.java
@@ -17,7 +17,7 @@
 package com.android.systemui.car.sideloaded;
 
 import android.annotation.NonNull;
-import android.app.ActivityManager;
+import android.app.ActivityTaskManager.RootTaskInfo;
 import android.content.ComponentName;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.InstallSourceInfo;
@@ -78,10 +78,10 @@
         return false;
     }
 
-    boolean isSafe(@NonNull ActivityManager.StackInfo stackInfo) {
-        ComponentName componentName = stackInfo.topActivity;
+    boolean isSafe(@NonNull RootTaskInfo taskInfo) {
+        ComponentName componentName = taskInfo.topActivity;
         if (componentName == null) {
-            Log.w(TAG, "Stack info does not have top activity: " + stackInfo.stackId);
+            Log.w(TAG, "Task info does not have top activity: " + taskInfo.taskId);
             return false;
         }
         return isSafe(componentName.getPackageName());
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppListener.java b/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppListener.java
index c8c1a40..db7718b 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppListener.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppListener.java
@@ -16,8 +16,7 @@
 
 package com.android.systemui.car.sideloaded;
 
-import android.app.ActivityManager;
-import android.app.ActivityManager.StackInfo;
+import android.app.ActivityTaskManager.RootTaskInfo;
 import android.app.IActivityTaskManager;
 import android.app.TaskStackListener;
 import android.content.ComponentName;
@@ -56,15 +55,15 @@
     public void onTaskCreated(int taskId, ComponentName componentName) throws RemoteException {
         super.onTaskCreated(taskId, componentName);
 
-        List<StackInfo> stackInfoList = mActivityTaskManager.getAllStackInfos();
-        ActivityManager.StackInfo stackInfo = getStackInfo(stackInfoList, taskId);
-        if (stackInfo == null) {
+        List<RootTaskInfo> taskInfoList = mActivityTaskManager.getAllRootTaskInfos();
+        RootTaskInfo taskInfo = getStackInfo(taskInfoList, taskId);
+        if (taskInfo == null) {
             Log.e(TAG, "Stack info was not available for taskId: " + taskId);
             return;
         }
 
-        if (!mSideLoadedAppDetector.isSafe(stackInfo)) {
-            Display display = mDisplayManager.getDisplay(stackInfo.displayId);
+        if (!mSideLoadedAppDetector.isSafe(taskInfo)) {
+            Display display = mDisplayManager.getDisplay(taskInfo.displayId);
             mSideLoadedAppStateController.onUnsafeTaskCreatedOnDisplay(display);
         }
     }
@@ -75,18 +74,18 @@
 
         Display[] displays = mDisplayManager.getDisplays();
         for (Display display : displays) {
-            // Note that the stackInfoList is ordered by recency.
-            List<StackInfo> stackInfoList =
-                    mActivityTaskManager.getAllStackInfosOnDisplay(display.getDisplayId());
+            // Note that the taskInfoList is ordered by recency.
+            List<RootTaskInfo> taskInfoList =
+                    mActivityTaskManager.getAllRootTaskInfosOnDisplay(display.getDisplayId());
 
-            if (stackInfoList == null) {
+            if (taskInfoList == null) {
                 continue;
             }
-            StackInfo stackInfo = getTopVisibleStackInfo(stackInfoList);
-            if (stackInfo == null) {
+            RootTaskInfo taskInfo = getTopVisibleStackInfo(taskInfoList);
+            if (taskInfo == null) {
                 continue;
             }
-            if (mSideLoadedAppDetector.isSafe(stackInfo)) {
+            if (mSideLoadedAppDetector.isSafe(taskInfo)) {
                 mSideLoadedAppStateController.onSafeTaskDisplayedOnDisplay(display);
             } else {
                 mSideLoadedAppStateController.onUnsafeTaskDisplayedOnDisplay(display);
@@ -97,18 +96,17 @@
     /**
      * Returns stack info for a given taskId.
      */
-    private ActivityManager.StackInfo getStackInfo(
-            List<ActivityManager.StackInfo> stackInfoList, int taskId) {
-        if (stackInfoList == null) {
+    private RootTaskInfo getStackInfo(List<RootTaskInfo> taskInfoList, int taskId) {
+        if (taskInfoList == null) {
             return null;
         }
-        for (ActivityManager.StackInfo stackInfo : stackInfoList) {
-            if (stackInfo.taskIds == null) {
+        for (RootTaskInfo taskInfo : taskInfoList) {
+            if (taskInfo.childTaskIds == null) {
                 continue;
             }
-            for (int stackTaskId : stackInfo.taskIds) {
-                if (taskId == stackTaskId) {
-                    return stackInfo;
+            for (int taskTaskId : taskInfo.childTaskIds) {
+                if (taskId == taskTaskId) {
+                    return taskInfo;
                 }
             }
         }
@@ -118,11 +116,10 @@
     /**
      * Returns the first visible stackInfo.
      */
-    private ActivityManager.StackInfo getTopVisibleStackInfo(
-            List<ActivityManager.StackInfo> stackInfoList) {
-        for (ActivityManager.StackInfo stackInfo : stackInfoList) {
-            if (stackInfo.visible) {
-                return stackInfo;
+    private RootTaskInfo getTopVisibleStackInfo(List<RootTaskInfo> taskInfoList) {
+        for (RootTaskInfo taskInfo : taskInfoList) {
+            if (taskInfo.visible) {
+                return taskInfo;
             }
         }
         return null;
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
index 63d4004..062ab41 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
@@ -36,7 +36,6 @@
 
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.ViewMediatorCallback;
-import com.android.keyguard.dagger.KeyguardBouncerComponent;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.car.CarServiceProvider;
@@ -67,9 +66,7 @@
     @Mock
     private CarKeyguardViewController.OnKeyguardCancelClickedListener mCancelClickedListener;
     @Mock
-    private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
-    @Mock
-    private KeyguardBouncerComponent mKeyguardBouncerComponent;
+    private KeyguardBouncer.Factory mKeyguardBouncerFactory;
     @Mock
     private KeyguardBouncer mBouncer;
 
@@ -77,11 +74,10 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
-        when(mKeyguardBouncerComponentFactory.build(
+        when(mKeyguardBouncerFactory.create(
                 any(ViewGroup.class),
                 any(KeyguardBouncer.BouncerExpansionCallback.class)))
-                .thenReturn(mKeyguardBouncerComponent);
-        when(mKeyguardBouncerComponent.createKeyguardBouncer()).thenReturn(mBouncer);
+                .thenReturn(mBouncer);
 
         mCarKeyguardViewController = new CarKeyguardViewController(
                 Handler.getMain(),
@@ -92,7 +88,7 @@
                 () -> mock(BiometricUnlockController.class),
                 mock(ViewMediatorCallback.class),
                 mock(CarNavigationBarController.class),
-                mKeyguardBouncerComponentFactory
+                mKeyguardBouncerFactory
         );
         mCarKeyguardViewController.inflate((ViewGroup) LayoutInflater.from(mContext).inflate(
                 R.layout.sysui_overlay_window, /* root= */ null));
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonSelectionStateControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonSelectionStateControllerTest.java
index f623c26..bd017cd 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonSelectionStateControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonSelectionStateControllerTest.java
@@ -18,7 +18,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import android.app.ActivityManager;
+import android.app.ActivityTaskManager.RootTaskInfo;
 import android.content.ComponentName;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -71,7 +71,7 @@
     public void onTaskChanged_buttonDetectableByComponentName_selectsAssociatedButton() {
         CarNavigationButton testButton = mTestView.findViewById(R.id.detectable_by_component_name);
         mComponentName = new ComponentName(TEST_COMPONENT_NAME_PACKAGE, TEST_COMPONENT_NAME_CLASS);
-        List<ActivityManager.StackInfo> testStack = createTestStack(mComponentName);
+        List<RootTaskInfo> testStack = createTestStack(mComponentName);
         testButton.setSelected(false);
         mButtonSelectionStateController.taskChanged(testStack, /* validDisplay= */ -1);
 
@@ -82,7 +82,7 @@
     public void onTaskChanged_buttonDetectableByCategory_selectsAssociatedButton() {
         CarNavigationButton testButton = mTestView.findViewById(R.id.detectable_by_category);
         mComponentName = new ComponentName(TEST_CATEGORY, TEST_CATEGORY_CLASS);
-        List<ActivityManager.StackInfo> testStack = createTestStack(mComponentName);
+        List<RootTaskInfo> testStack = createTestStack(mComponentName);
         testButton.setSelected(false);
         mButtonSelectionStateController.taskChanged(testStack, /* validDisplay= */ -1);
 
@@ -93,7 +93,7 @@
     public void onTaskChanged_buttonDetectableByPackage_selectsAssociatedButton() {
         CarNavigationButton testButton = mTestView.findViewById(R.id.detectable_by_package);
         mComponentName = new ComponentName(TEST_PACKAGE, TEST_PACKAGE_CLASS);
-        List<ActivityManager.StackInfo> testStack = createTestStack(mComponentName);
+        List<RootTaskInfo> testStack = createTestStack(mComponentName);
         testButton.setSelected(false);
         mButtonSelectionStateController.taskChanged(testStack, /* validDisplay= */ -1);
 
@@ -104,12 +104,12 @@
     public void onTaskChanged_deselectsPreviouslySelectedButton() {
         CarNavigationButton oldButton = mTestView.findViewById(R.id.detectable_by_component_name);
         mComponentName = new ComponentName(TEST_COMPONENT_NAME_PACKAGE, TEST_COMPONENT_NAME_CLASS);
-        List<ActivityManager.StackInfo> oldStack = createTestStack(mComponentName);
+        List<RootTaskInfo> oldStack = createTestStack(mComponentName);
         oldButton.setSelected(false);
         mButtonSelectionStateController.taskChanged(oldStack, /* validDisplay= */ -1);
 
         mComponentName = new ComponentName(TEST_PACKAGE, TEST_PACKAGE_CLASS);
-        List<ActivityManager.StackInfo> newStack = createTestStack(mComponentName);
+        List<RootTaskInfo> newStack = createTestStack(mComponentName);
         mButtonSelectionStateController.taskChanged(newStack, /* validDisplay= */ -1);
 
         assertButtonUnselected(oldButton);
@@ -125,12 +125,12 @@
         assertThat(button.getAlpha()).isEqualTo(CarNavigationButton.DEFAULT_UNSELECTED_ALPHA);
     }
 
-    private List<ActivityManager.StackInfo> createTestStack(ComponentName componentName) {
-        ActivityManager.StackInfo validStackInfo = new ActivityManager.StackInfo();
+    private List<RootTaskInfo> createTestStack(ComponentName componentName) {
+        RootTaskInfo validStackInfo = new RootTaskInfo();
         validStackInfo.displayId = -1; // No display is assigned to this test view
         validStackInfo.topActivity = componentName;
 
-        List<ActivityManager.StackInfo> testStack = new ArrayList<>();
+        List<RootTaskInfo> testStack = new ArrayList<>();
         testStack.add(validStackInfo);
 
         return testStack;
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppDetectorTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppDetectorTest.java
index 421e210..bf9ac30 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppDetectorTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppDetectorTest.java
@@ -23,7 +23,7 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.when;
 
-import android.app.ActivityManager;
+import android.app.ActivityTaskManager.RootTaskInfo;
 import android.content.ComponentName;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.InstallSourceInfo;
@@ -79,8 +79,8 @@
 
     @Test
     public void isSafe_systemApp_returnsTrue() throws Exception {
-        ActivityManager.StackInfo stackInfo = new ActivityManager.StackInfo();
-        stackInfo.topActivity = new ComponentName(APP_PACKAGE_NAME, APP_CLASS_NAME);
+        RootTaskInfo taskInfo = new RootTaskInfo();
+        taskInfo.topActivity = new ComponentName(APP_PACKAGE_NAME, APP_CLASS_NAME);
 
         ApplicationInfo applicationInfo = new ApplicationInfo();
         applicationInfo.packageName = APP_PACKAGE_NAME;
@@ -89,13 +89,13 @@
         when(mPackageManager.getApplicationInfoAsUser(eq(APP_PACKAGE_NAME), anyInt(), any()))
                 .thenReturn(applicationInfo);
 
-        assertThat(mSideLoadedAppDetector.isSafe(stackInfo)).isTrue();
+        assertThat(mSideLoadedAppDetector.isSafe(taskInfo)).isTrue();
     }
 
     @Test
     public void isSafe_updatedSystemApp_returnsTrue() throws Exception {
-        ActivityManager.StackInfo stackInfo = new ActivityManager.StackInfo();
-        stackInfo.topActivity = new ComponentName(APP_PACKAGE_NAME, APP_CLASS_NAME);
+        RootTaskInfo taskInfo = new RootTaskInfo();
+        taskInfo.topActivity = new ComponentName(APP_PACKAGE_NAME, APP_CLASS_NAME);
 
         ApplicationInfo applicationInfo = new ApplicationInfo();
         applicationInfo.packageName = APP_PACKAGE_NAME;
@@ -104,7 +104,7 @@
         when(mPackageManager.getApplicationInfoAsUser(eq(APP_PACKAGE_NAME), anyInt(), any()))
                 .thenReturn(applicationInfo);
 
-        assertThat(mSideLoadedAppDetector.isSafe(stackInfo)).isTrue();
+        assertThat(mSideLoadedAppDetector.isSafe(taskInfo)).isTrue();
     }
 
     @Test
@@ -113,8 +113,8 @@
                 /* initiatingPackageSigningInfo= */null,
                 /* originatingPackageName= */ null,
                 /* installingPackageName= */ null);
-        ActivityManager.StackInfo stackInfo = new ActivityManager.StackInfo();
-        stackInfo.topActivity = new ComponentName(APP_PACKAGE_NAME, APP_CLASS_NAME);
+        RootTaskInfo taskInfo = new RootTaskInfo();
+        taskInfo.topActivity = new ComponentName(APP_PACKAGE_NAME, APP_CLASS_NAME);
 
         ApplicationInfo applicationInfo = new ApplicationInfo();
         applicationInfo.packageName = APP_PACKAGE_NAME;
@@ -123,7 +123,7 @@
                 .thenReturn(applicationInfo);
         when(mPackageManager.getInstallSourceInfo(APP_PACKAGE_NAME)).thenReturn(sourceInfo);
 
-        assertThat(mSideLoadedAppDetector.isSafe(stackInfo)).isTrue();
+        assertThat(mSideLoadedAppDetector.isSafe(taskInfo)).isTrue();
     }
 
     @Test
@@ -132,8 +132,8 @@
                 /* initiatingPackageSigningInfo= */null,
                 /* originatingPackageName= */ null,
                 /* installingPackageName= */ null);
-        ActivityManager.StackInfo stackInfo = new ActivityManager.StackInfo();
-        stackInfo.topActivity = new ComponentName(APP_PACKAGE_NAME, APP_CLASS_NAME);
+        RootTaskInfo taskInfo = new RootTaskInfo();
+        taskInfo.topActivity = new ComponentName(APP_PACKAGE_NAME, APP_CLASS_NAME);
 
         ApplicationInfo applicationInfo = new ApplicationInfo();
         applicationInfo.packageName = APP_PACKAGE_NAME;
@@ -142,7 +142,7 @@
                 .thenReturn(applicationInfo);
         when(mPackageManager.getInstallSourceInfo(APP_PACKAGE_NAME)).thenReturn(sourceInfo);
 
-        assertThat(mSideLoadedAppDetector.isSafe(stackInfo)).isFalse();
+        assertThat(mSideLoadedAppDetector.isSafe(taskInfo)).isFalse();
     }
 
     @Test
@@ -151,8 +151,8 @@
                 /* initiatingPackageSigningInfo= */null,
                 /* originatingPackageName= */ null,
                 /* installingPackageName= */ null);
-        ActivityManager.StackInfo stackInfo = new ActivityManager.StackInfo();
-        stackInfo.topActivity = new ComponentName(APP_PACKAGE_NAME, APP_CLASS_NAME);
+        RootTaskInfo taskInfo = new RootTaskInfo();
+        taskInfo.topActivity = new ComponentName(APP_PACKAGE_NAME, APP_CLASS_NAME);
 
         ApplicationInfo applicationInfo = new ApplicationInfo();
         applicationInfo.packageName = APP_PACKAGE_NAME;
@@ -161,6 +161,6 @@
                 .thenReturn(applicationInfo);
         when(mPackageManager.getInstallSourceInfo(APP_PACKAGE_NAME)).thenReturn(sourceInfo);
 
-        assertThat(mSideLoadedAppDetector.isSafe(stackInfo)).isFalse();
+        assertThat(mSideLoadedAppDetector.isSafe(taskInfo)).isFalse();
     }
 }
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java
index 67f222b..0b5f68f 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java
@@ -21,7 +21,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.app.ActivityManager.StackInfo;
+import android.app.ActivityTaskManager.RootTaskInfo;
 import android.app.IActivityTaskManager;
 import android.content.ComponentName;
 import android.hardware.display.DisplayManager;
@@ -81,22 +81,22 @@
         int displayId = 123;
         ComponentName componentName = new ComponentName(APP_PACKAGE_NAME, APP_CLASS_NAME);
 
-        StackInfo stackInfo1 = createTask(1, /* isVisible= */ true);
-        stackInfo1.taskIds = new int[] { 11, 22, 33 };
+        RootTaskInfo taskInfo1 = createTask(1, /* isVisible= */ true);
+        taskInfo1.childTaskIds = new int[] { 11, 22, 33 };
 
-        StackInfo stackInfo2 = createTask(2, /* isVisible= */ true);
-        stackInfo2.taskIds = new int[] { 111, 222, 333, taskId };
-        stackInfo2.displayId = displayId;
+        RootTaskInfo taskInfo2 = createTask(2, /* isVisible= */ true);
+        taskInfo2.childTaskIds = new int[] { 111, 222, 333, taskId };
+        taskInfo2.displayId = displayId;
 
-        List<StackInfo> stackInfoList = Arrays.asList(stackInfo1, stackInfo2);
+        List<RootTaskInfo> taskInfoList = Arrays.asList(taskInfo1, taskInfo2);
 
-        when(mActivityTaskManager.getAllStackInfos()).thenReturn(stackInfoList);
-        when(mSideLoadedAppDetector.isSafe(stackInfo2)).thenReturn(true);
+        when(mActivityTaskManager.getAllRootTaskInfos()).thenReturn(taskInfoList);
+        when(mSideLoadedAppDetector.isSafe(taskInfo2)).thenReturn(true);
 
         mSideLoadedAppListener.onTaskCreated(taskId, componentName);
 
-        verify(mSideLoadedAppDetector, never()).isSafe(stackInfo1);
-        verify(mSideLoadedAppDetector).isSafe(stackInfo2);
+        verify(mSideLoadedAppDetector, never()).isSafe(taskInfo1);
+        verify(mSideLoadedAppDetector).isSafe(taskInfo2);
 
         verify(mSideLoadedAppStateController, never()).onUnsafeTaskCreatedOnDisplay(any());
         verify(mSideLoadedAppStateController, never()).onSafeTaskDisplayedOnDisplay(any());
@@ -109,23 +109,23 @@
         int displayId = 123;
         ComponentName componentName = new ComponentName(APP_PACKAGE_NAME, APP_CLASS_NAME);
 
-        StackInfo stackInfo1 = createTask(1, /* isVisible= */ true);
-        stackInfo1.taskIds = new int[] { 11, 22, 33 };
-        StackInfo stackInfo2 = createTask(2, /* isVisible= */ true);
-        stackInfo2.taskIds = new int[] { 111, 222, 333, taskId };
-        stackInfo2.displayId = displayId;
-        List<StackInfo> stackInfoList = Arrays.asList(stackInfo1, stackInfo2);
+        RootTaskInfo taskInfo1 = createTask(1, /* isVisible= */ true);
+        taskInfo1.childTaskIds = new int[] { 11, 22, 33 };
+        RootTaskInfo taskInfo2 = createTask(2, /* isVisible= */ true);
+        taskInfo2.childTaskIds = new int[] { 111, 222, 333, taskId };
+        taskInfo2.displayId = displayId;
+        List<RootTaskInfo> taskInfoList = Arrays.asList(taskInfo1, taskInfo2);
 
         Display display = createDisplay(displayId);
 
-        when(mActivityTaskManager.getAllStackInfos()).thenReturn(stackInfoList);
-        when(mSideLoadedAppDetector.isSafe(stackInfo2)).thenReturn(false);
+        when(mActivityTaskManager.getAllRootTaskInfos()).thenReturn(taskInfoList);
+        when(mSideLoadedAppDetector.isSafe(taskInfo2)).thenReturn(false);
         when(mDisplayManager.getDisplay(displayId)).thenReturn(display);
 
         mSideLoadedAppListener.onTaskCreated(taskId, componentName);
 
-        verify(mSideLoadedAppDetector, never()).isSafe(stackInfo1);
-        verify(mSideLoadedAppDetector).isSafe(stackInfo2);
+        verify(mSideLoadedAppDetector, never()).isSafe(taskInfo1);
+        verify(mSideLoadedAppDetector).isSafe(taskInfo2);
 
         verify(mSideLoadedAppStateController).onUnsafeTaskCreatedOnDisplay(display);
         verify(mSideLoadedAppStateController, never()).onSafeTaskDisplayedOnDisplay(any());
@@ -135,21 +135,21 @@
     @Test
     public void onTaskStackChanged_safeTask_callsSafeTaskDisplayed() throws Exception {
         Display display = createDisplay(123);
-        StackInfo stackInfo1 = createTask(1, /* isVisible= */ false);
-        StackInfo stackInfo2 = createTask(2, /* isVisible= */ true);
-        StackInfo stackInfo3 = createTask(3, /* isVisible= */ true);
-        List<StackInfo> stackInfoList = Arrays.asList(stackInfo1, stackInfo2, stackInfo3);
+        RootTaskInfo taskInfo1 = createTask(1, /* isVisible= */ false);
+        RootTaskInfo taskInfo2 = createTask(2, /* isVisible= */ true);
+        RootTaskInfo taskInfo3 = createTask(3, /* isVisible= */ true);
+        List<RootTaskInfo> taskInfoList = Arrays.asList(taskInfo1, taskInfo2, taskInfo3);
 
-        when(mActivityTaskManager.getAllStackInfosOnDisplay(display.getDisplayId()))
-                .thenReturn(stackInfoList);
-        when(mSideLoadedAppDetector.isSafe(stackInfo2)).thenReturn(true);
+        when(mActivityTaskManager.getAllRootTaskInfosOnDisplay(display.getDisplayId()))
+                .thenReturn(taskInfoList);
+        when(mSideLoadedAppDetector.isSafe(taskInfo2)).thenReturn(true);
         when(mDisplayManager.getDisplays()).thenReturn(new Display[] { display });
 
         mSideLoadedAppListener.onTaskStackChanged();
 
-        verify(mSideLoadedAppDetector, never()).isSafe(stackInfo1);
-        verify(mSideLoadedAppDetector).isSafe(stackInfo2);
-        verify(mSideLoadedAppDetector, never()).isSafe(stackInfo3);
+        verify(mSideLoadedAppDetector, never()).isSafe(taskInfo1);
+        verify(mSideLoadedAppDetector).isSafe(taskInfo2);
+        verify(mSideLoadedAppDetector, never()).isSafe(taskInfo3);
 
         verify(mSideLoadedAppStateController, never()).onUnsafeTaskCreatedOnDisplay(any());
         verify(mSideLoadedAppStateController).onSafeTaskDisplayedOnDisplay(display);
@@ -159,21 +159,21 @@
     @Test
     public void onTaskStackChanged_unsafeTask_callsUnsafeTaskDisplayed() throws Exception {
         Display display = createDisplay(123);
-        StackInfo stackInfo1 = createTask(1, /* isVisible= */ false);
-        StackInfo stackInfo2 = createTask(2, /* isVisible= */ true);
-        StackInfo stackInfo3 = createTask(3, /* isVisible= */ true);
-        List<StackInfo> stackInfoList = Arrays.asList(stackInfo1, stackInfo2, stackInfo3);
+        RootTaskInfo taskInfo1 = createTask(1, /* isVisible= */ false);
+        RootTaskInfo taskInfo2 = createTask(2, /* isVisible= */ true);
+        RootTaskInfo taskInfo3 = createTask(3, /* isVisible= */ true);
+        List<RootTaskInfo> taskInfoList = Arrays.asList(taskInfo1, taskInfo2, taskInfo3);
 
-        when(mActivityTaskManager.getAllStackInfosOnDisplay(display.getDisplayId()))
-                .thenReturn(stackInfoList);
-        when(mSideLoadedAppDetector.isSafe(stackInfo2)).thenReturn(false);
+        when(mActivityTaskManager.getAllRootTaskInfosOnDisplay(display.getDisplayId()))
+                .thenReturn(taskInfoList);
+        when(mSideLoadedAppDetector.isSafe(taskInfo2)).thenReturn(false);
         when(mDisplayManager.getDisplays()).thenReturn(new Display[] { display });
 
         mSideLoadedAppListener.onTaskStackChanged();
 
-        verify(mSideLoadedAppDetector, never()).isSafe(stackInfo1);
-        verify(mSideLoadedAppDetector).isSafe(stackInfo2);
-        verify(mSideLoadedAppDetector, never()).isSafe(stackInfo3);
+        verify(mSideLoadedAppDetector, never()).isSafe(taskInfo1);
+        verify(mSideLoadedAppDetector).isSafe(taskInfo2);
+        verify(mSideLoadedAppDetector, never()).isSafe(taskInfo3);
 
         verify(mSideLoadedAppStateController, never()).onUnsafeTaskCreatedOnDisplay(any());
         verify(mSideLoadedAppStateController, never()).onSafeTaskDisplayedOnDisplay(any());
@@ -183,40 +183,40 @@
     @Test
     public void onTaskStackChanged_multiDisplay_callsTasksDisplayed() throws Exception {
         Display display1 = createDisplay(1);
-        StackInfo stackInfo1 = createTask(1, /* isVisible= */ false);
-        StackInfo stackInfo2 = createTask(2, /* isVisible= */ true);
-        StackInfo stackInfo3 = createTask(3, /* isVisible= */ true);
-        List<StackInfo> display1Stack = Arrays.asList(stackInfo1, stackInfo2, stackInfo3);
+        RootTaskInfo taskInfo1 = createTask(1, /* isVisible= */ false);
+        RootTaskInfo taskInfo2 = createTask(2, /* isVisible= */ true);
+        RootTaskInfo taskInfo3 = createTask(3, /* isVisible= */ true);
+        List<RootTaskInfo> display1Tasks = Arrays.asList(taskInfo1, taskInfo2, taskInfo3);
 
         Display display2 = createDisplay(2);
-        StackInfo stackInfo4 = createTask(4, /* isVisible= */ true);
-        List<StackInfo> display2Stack = Collections.singletonList(stackInfo4);
+        RootTaskInfo taskInfo4 = createTask(4, /* isVisible= */ true);
+        List<RootTaskInfo> display2Tasks = Collections.singletonList(taskInfo4);
 
         Display display3 = createDisplay(3);
-        StackInfo stackInfo5 = createTask(5, /* isVisible= */ true);
-        List<StackInfo> display3Stack = Collections.singletonList(stackInfo5);
+        RootTaskInfo taskInfo5 = createTask(5, /* isVisible= */ true);
+        List<RootTaskInfo> display3Tasks = Collections.singletonList(taskInfo5);
 
-        when(mActivityTaskManager.getAllStackInfosOnDisplay(display1.getDisplayId()))
-                .thenReturn(display1Stack);
-        when(mActivityTaskManager.getAllStackInfosOnDisplay(display2.getDisplayId()))
-                .thenReturn(display2Stack);
-        when(mActivityTaskManager.getAllStackInfosOnDisplay(display3.getDisplayId()))
-                .thenReturn(display3Stack);
+        when(mActivityTaskManager.getAllRootTaskInfosOnDisplay(display1.getDisplayId()))
+                .thenReturn(display1Tasks);
+        when(mActivityTaskManager.getAllRootTaskInfosOnDisplay(display2.getDisplayId()))
+                .thenReturn(display2Tasks);
+        when(mActivityTaskManager.getAllRootTaskInfosOnDisplay(display3.getDisplayId()))
+                .thenReturn(display3Tasks);
 
-        when(mSideLoadedAppDetector.isSafe(stackInfo2)).thenReturn(true);
-        when(mSideLoadedAppDetector.isSafe(stackInfo4)).thenReturn(false);
-        when(mSideLoadedAppDetector.isSafe(stackInfo5)).thenReturn(true);
+        when(mSideLoadedAppDetector.isSafe(taskInfo2)).thenReturn(true);
+        when(mSideLoadedAppDetector.isSafe(taskInfo4)).thenReturn(false);
+        when(mSideLoadedAppDetector.isSafe(taskInfo5)).thenReturn(true);
 
         when(mDisplayManager.getDisplays())
                 .thenReturn(new Display[] { display1, display2, display3});
 
         mSideLoadedAppListener.onTaskStackChanged();
 
-        verify(mSideLoadedAppDetector, never()).isSafe(stackInfo1);
-        verify(mSideLoadedAppDetector).isSafe(stackInfo2);
-        verify(mSideLoadedAppDetector, never()).isSafe(stackInfo3);
-        verify(mSideLoadedAppDetector).isSafe(stackInfo4);
-        verify(mSideLoadedAppDetector).isSafe(stackInfo5);
+        verify(mSideLoadedAppDetector, never()).isSafe(taskInfo1);
+        verify(mSideLoadedAppDetector).isSafe(taskInfo2);
+        verify(mSideLoadedAppDetector, never()).isSafe(taskInfo3);
+        verify(mSideLoadedAppDetector).isSafe(taskInfo4);
+        verify(mSideLoadedAppDetector).isSafe(taskInfo5);
 
         verify(mSideLoadedAppStateController, never()).onUnsafeTaskCreatedOnDisplay(any());
         verify(mSideLoadedAppStateController).onSafeTaskDisplayedOnDisplay(display1);
@@ -234,10 +234,10 @@
                 DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
     }
 
-    private StackInfo createTask(int id, boolean isVisible) {
-        StackInfo stackInfo = new StackInfo();
-        stackInfo.stackId = id;
-        stackInfo.visible = isVisible;
-        return stackInfo;
+    private RootTaskInfo createTask(int id, boolean isVisible) {
+        RootTaskInfo taskInfo = new RootTaskInfo();
+        taskInfo.taskId = id;
+        taskInfo.visible = isVisible;
+        return taskInfo;
     }
 }
diff --git a/packages/DynamicSystemInstallationService/res/values-nl/strings.xml b/packages/DynamicSystemInstallationService/res/values-nl/strings.xml
index 47eeb83..2b9fa41 100644
--- a/packages/DynamicSystemInstallationService/res/values-nl/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-nl/strings.xml
@@ -2,7 +2,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="keyguard_description" msgid="8582605799129954556">"Geef je wachtwoord op en ga door naar \'Dynamische systeemupdates\'"</string>
-    <string name="notification_install_completed" msgid="6252047868415172643">"Dynamisch systeem is gereed. Start je apparaat opnieuw op om het te gebruiken."</string>
+    <string name="notification_install_completed" msgid="6252047868415172643">"Dynamisch systeem is klaar. Start je apparaat opnieuw op om het te gebruiken."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"Installatie wordt uitgevoerd"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"Installatie mislukt"</string>
     <string name="notification_image_validation_failed" msgid="2720357826403917016">"Valideren van afbeelding mislukt. Installatie afbreken."</string>
diff --git a/packages/PackageInstaller/res/values-nl/strings.xml b/packages/PackageInstaller/res/values-nl/strings.xml
index 108c86f..d3a9589 100644
--- a/packages/PackageInstaller/res/values-nl/strings.xml
+++ b/packages/PackageInstaller/res/values-nl/strings.xml
@@ -18,7 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="7488448184431507488">"Pakket-installatie"</string>
     <string name="install" msgid="711829760615509273">"Installeren"</string>
-    <string name="done" msgid="6632441120016885253">"Gereed"</string>
+    <string name="done" msgid="6632441120016885253">"Klaar"</string>
     <string name="cancel" msgid="1018267193425558088">"Annuleren"</string>
     <string name="installing" msgid="4921993079741206516">"Installeren…"</string>
     <string name="installing_app" msgid="1165095864863849422">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> installeren…"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 8f71509..7f6237d 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -212,7 +212,7 @@
     <string name="adb_wireless_settings" msgid="2295017847215680229">"Адладка па Wi-Fi"</string>
     <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Каб праглядаць і выкарыстоўваць даступныя прылады, уключыце адладку па Wi-Fi"</string>
     <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Спалучыць прыладу з дапамогай QR-кода"</string>
-    <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Спалучаць новыя прылады з дапамогай сканера QR-кода"</string>
+    <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Спалучаць новыя прылады з дапамогай сканера QR-кодаў"</string>
     <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Спалучыць прыладу з дапамогай кода спалучэння"</string>
     <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Спалучаць новыя прылады з дапамогай шасцізначнага кода"</string>
     <string name="adb_paired_devices_title" msgid="5268997341526217362">"Спалучаныя прылады"</string>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index fbd8876..dd2aa3b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1777,6 +1777,9 @@
                 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
                 SecureSettingsProto.Accessibility.HIGH_TEXT_CONTRAST_ENABLED);
         dumpSetting(s, p,
+                Settings.Secure.FORCE_BOLD_TEXT,
+                SecureSettingsProto.FORCE_BOLD_TEXT);
+        dumpSetting(s, p,
                 Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
                 SecureSettingsProto.Accessibility.LARGE_POINTER_ICON);
         dumpSetting(s, p,
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 211a27c..0a36dae 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -1067,6 +1067,8 @@
     <string name="controls_added_tooltip" msgid="4842812921719153085">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‏‏‎‏‎‏‎‎‏‎‎‎‎‎‏‎‏‏‎‎‎‏‏‎‏‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‏‎‎‎‎‏‏‎‏‏‏‏‎‏‎Hold Power button to see new controls‎‏‎‎‏‎"</string>
     <string name="controls_menu_add" msgid="4447246119229920050">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‏‏‎‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‏‎‎‎‎‏‏‎‏‏‎‏‎‏‏‎‏‏‏‏‎‎‎‏‎‎‏‏‎‎‏‏‎‎‏‎‎Add controls‎‏‎‎‏‎"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‏‎‏‏‏‎‎‎‎‏‎‎‎‎‏‏‏‎‎‏‏‎‎‎‎‏‎‎‎‏‎‏‎‏‎‏‏‎‏‎‏‎‏‏‎‏‏‎‏‏‏‎‏‏‎‎Edit controls‎‏‎‎‏‎"</string>
-    <string name="one_handed_tutorial_title" msgid="6312198435090726656">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‏‏‎‎‏‎‏‏‎‏‏‏‏‎‎‎‎‏‎‎‎‏‎‎‎‎‎‏‏‎‏‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‎Using one-handed mode‎‏‎‎‏‎"</string>
-    <string name="one_handed_tutorial_description" msgid="7674850272340517174">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‏‎‏‎‎‎‏‎‏‏‏‎‏‎‏‎‎‎‏‏‎‏‏‎‏‏‎‎‏‎‏‎‏‎‏‎‏‎‎‎‎‏‎‎‏‏‎‏‏‎‎To exit, swipe up from the bottom of the screen or tap anywhere above the app‎‏‎‎‏‎"</string>
+    <!-- no translation found for one_handed_tutorial_title (6312198435090726656) -->
+    <skip />
+    <!-- no translation found for one_handed_tutorial_description (7674850272340517174) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 4e9347c..79c2fbd 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -395,7 +395,7 @@
     <string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"Conectado (<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería)"</string>
     <string name="quick_settings_connecting" msgid="2381969772953268809">"Conectando..."</string>
     <string name="quick_settings_tethering_label" msgid="5257299852322475780">"Compartir conexión"</string>
-    <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Zona Wi-Fi"</string>
+    <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Punto de acceso"</string>
     <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Activando…"</string>
     <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"Ahorro de datos activado"</string>
     <plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="3142308865165871976">
@@ -660,7 +660,7 @@
     <string name="alarm_template" msgid="2234991538018805736">"a las <xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="alarm_template_far" msgid="3561752195856839456">"el <xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Ajustes rápidos, <xliff:g id="TITLE">%s</xliff:g>."</string>
-    <string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Zona Wi-Fi"</string>
+    <string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Punto de acceso"</string>
     <string name="accessibility_managed_profile" msgid="4703836746209377356">"Perfil de trabajo"</string>
     <string name="tuner_warning_title" msgid="7721976098452135267">"Diversión solo para algunos"</string>
     <string name="tuner_warning" msgid="1861736288458481650">"El configurador de UI del sistema te ofrece otras formas de modificar y personalizar la interfaz de usuario de Android. Estas funciones experimentales pueden cambiar, fallar o desaparecer en futuras versiones. Te recomendamos que tengas cuidado."</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index b02be5d..01d3fec 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -390,7 +390,7 @@
     <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Kleuren omkeren"</string>
     <string name="quick_settings_color_space_label" msgid="537528291083575559">"Modus voor kleurcorrectie"</string>
     <string name="quick_settings_more_settings" msgid="2878235926753776694">"Meer instellingen"</string>
-    <string name="quick_settings_done" msgid="2163641301648855793">"Gereed"</string>
+    <string name="quick_settings_done" msgid="2163641301648855793">"Klaar"</string>
     <string name="quick_settings_connected" msgid="3873605509184830379">"Verbonden"</string>
     <string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"Verbonden, batterij <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
     <string name="quick_settings_connecting" msgid="2381969772953268809">"Verbinding maken…"</string>
@@ -692,7 +692,7 @@
     <string name="notification_channel_silenced" msgid="1995937493874511359">"Deze meldingen worden zonder geluid weergegeven"</string>
     <string name="notification_channel_unsilenced" msgid="94878840742161152">"Deze meldingen stellen je op de hoogte"</string>
     <string name="inline_blocking_helper" msgid="2891486013649543452">"Meestal sluit je deze meldingen. \nWil je ze blijven weergeven?"</string>
-    <string name="inline_done_button" msgid="6043094985588909584">"Gereed"</string>
+    <string name="inline_done_button" msgid="6043094985588909584">"Klaar"</string>
     <string name="inline_ok_button" msgid="603075490581280343">"Toepassen"</string>
     <string name="inline_keep_showing" msgid="8736001253507073497">"Deze meldingen blijven weergeven?"</string>
     <string name="inline_stop_button" msgid="2453460935438696090">"Meldingen stoppen"</string>
@@ -747,7 +747,7 @@
     <string name="notification_channel_switch_accessibility" msgid="8979885820432540252">"Meldingen van dit kanaal toestaan"</string>
     <string name="notification_more_settings" msgid="4936228656989201793">"Meer instellingen"</string>
     <string name="notification_app_settings" msgid="8963648463858039377">"Aanpassen"</string>
-    <string name="notification_done" msgid="6215117625922713976">"Gereed"</string>
+    <string name="notification_done" msgid="6215117625922713976">"Klaar"</string>
     <string name="inline_undo" msgid="9026953267645116526">"Ongedaan maken"</string>
     <string name="demote" msgid="6225813324237153980">"Deze melding markeren als geen gesprek"</string>
     <string name="notification_conversation_favorite" msgid="1905240206975921907">"Belangrijk gesprek"</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
index 57b3761..08e9cf6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
@@ -16,32 +16,11 @@
 
 package com.android.keyguard;
 
-import android.app.ActivityManager;
 import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
 import android.graphics.Canvas;
-import android.media.AudioManager;
-import android.os.SystemClock;
-import android.service.trust.TrustAgentService;
-import android.telephony.TelephonyManager;
 import android.util.AttributeSet;
-import android.util.Log;
-import android.view.KeyEvent;
 import android.widget.FrameLayout;
 
-import androidx.annotation.VisibleForTesting;
-
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.settingslib.Utils;
-import com.android.systemui.Dependency;
-import com.android.systemui.R;
-import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
-
-import java.io.File;
-
 /**
  * Base class for keyguard view.  {@link #reset} is where you should
  * reset the state of your view.  Use the {@link KeyguardViewCallback} via
@@ -51,59 +30,10 @@
  * Handles intercepting of media keys that still work when the keyguard is
  * showing.
  */
-public class KeyguardHostView extends FrameLayout implements SecurityCallback {
+public class KeyguardHostView extends FrameLayout {
 
-    private AudioManager mAudioManager;
-    private TelephonyManager mTelephonyManager = null;
     protected ViewMediatorCallback mViewMediatorCallback;
-    protected LockPatternUtils mLockPatternUtils;
-    private OnDismissAction mDismissAction;
-    private Runnable mCancelAction;
 
-    private final KeyguardUpdateMonitorCallback mUpdateCallback =
-            new KeyguardUpdateMonitorCallback() {
-
-        @Override
-        public void onUserSwitchComplete(int userId) {
-            getSecurityContainer().showPrimarySecurityScreen(false /* turning off */);
-        }
-
-        @Override
-        public void onTrustGrantedWithFlags(int flags, int userId) {
-            if (userId != KeyguardUpdateMonitor.getCurrentUser()) return;
-            if (!isAttachedToWindow()) return;
-            boolean bouncerVisible = isVisibleToUser();
-            boolean initiatedByUser =
-                    (flags & TrustAgentService.FLAG_GRANT_TRUST_INITIATED_BY_USER) != 0;
-            boolean dismissKeyguard =
-                    (flags & TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD) != 0;
-
-            if (initiatedByUser || dismissKeyguard) {
-                if (mViewMediatorCallback.isScreenOn() && (bouncerVisible || dismissKeyguard)) {
-                    if (!bouncerVisible) {
-                        // The trust agent dismissed the keyguard without the user proving
-                        // that they are present (by swiping up to show the bouncer). That's fine if
-                        // the user proved presence via some other way to the trust agent.
-                        Log.i(TAG, "TrustAgent dismissed Keyguard.");
-                    }
-                    dismiss(false /* authenticated */, userId,
-                            /* bypassSecondaryLockScreen */ false);
-                } else {
-                    mViewMediatorCallback.playTrustedSound();
-                }
-            }
-        }
-    };
-
-    // Whether the volume keys should be handled by keyguard. If true, then
-    // they will be handled here for specific media types such as music, otherwise
-    // the audio service will bring up the volume dialog.
-    private static final boolean KEYGUARD_MANAGES_VOLUME = false;
-    public static final boolean DEBUG = KeyguardConstants.DEBUG;
-    private static final String TAG = "KeyguardViewBase";
-
-    @VisibleForTesting
-    protected KeyguardSecurityContainer mSecurityContainer;
 
     public KeyguardHostView(Context context) {
         this(context, null);
@@ -111,7 +41,6 @@
 
     public KeyguardHostView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        Dependency.get(KeyguardUpdateMonitor.class).registerCallback(mUpdateCallback);
     }
 
     @Override
@@ -122,337 +51,7 @@
         }
     }
 
-    /**
-     * Sets an action to run when keyguard finishes.
-     *
-     * @param action
-     */
-    public void setOnDismissAction(OnDismissAction action, Runnable cancelAction) {
-        if (mCancelAction != null) {
-            mCancelAction.run();
-            mCancelAction = null;
-        }
-        mDismissAction = action;
-        mCancelAction = cancelAction;
-    }
-
-    public boolean hasDismissActions() {
-        return mDismissAction != null || mCancelAction != null;
-    }
-
-    public void cancelDismissAction() {
-        setOnDismissAction(null, null);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        mSecurityContainer =
-                findViewById(R.id.keyguard_security_container);
-        mLockPatternUtils = new LockPatternUtils(mContext);
-        mSecurityContainer.setLockPatternUtils(mLockPatternUtils);
-        mSecurityContainer.setSecurityCallback(this);
-        mSecurityContainer.showPrimarySecurityScreen(false);
-    }
-
-    /**
-     * Called when the view needs to be shown.
-     */
-    public void showPrimarySecurityScreen() {
-        if (DEBUG) Log.d(TAG, "show()");
-        mSecurityContainer.showPrimarySecurityScreen(false);
-    }
-
-    public KeyguardSecurityView getCurrentSecurityView() {
-        return mSecurityContainer != null ? mSecurityContainer.getCurrentSecurityView() : null;
-    }
-
-    /**
-     * Show a string explaining why the security view needs to be solved.
-     *
-     * @param reason a flag indicating which string should be shown, see
-     *               {@link KeyguardSecurityView#PROMPT_REASON_NONE},
-     *               {@link KeyguardSecurityView#PROMPT_REASON_RESTART},
-     *               {@link KeyguardSecurityView#PROMPT_REASON_TIMEOUT}, and
-     *               {@link KeyguardSecurityView#PROMPT_REASON_PREPARE_FOR_UPDATE}.
-     */
-    public void showPromptReason(int reason) {
-        mSecurityContainer.showPromptReason(reason);
-    }
-
-    public void showMessage(CharSequence message, ColorStateList colorState) {
-        mSecurityContainer.showMessage(message, colorState);
-    }
-
-    public void showErrorMessage(CharSequence message) {
-        showMessage(message, Utils.getColorError(mContext));
-    }
-
-    /**
-     * Dismisses the keyguard by going to the next screen or making it gone.
-     * @param targetUserId a user that needs to be the foreground user at the dismissal completion.
-     * @return True if the keyguard is done.
-     */
-    public boolean dismiss(int targetUserId) {
-        return dismiss(false, targetUserId, false);
-    }
-
-    public boolean handleBackKey() {
-        if (mSecurityContainer.getCurrentSecuritySelection() != SecurityMode.None) {
-            mSecurityContainer.dismiss(false, KeyguardUpdateMonitor.getCurrentUser());
-            return true;
-        }
-        return false;
-    }
-
-    protected KeyguardSecurityContainer getSecurityContainer() {
-        return mSecurityContainer;
-    }
-
-    @Override
-    public boolean dismiss(boolean authenticated, int targetUserId,
-            boolean bypassSecondaryLockScreen) {
-        return mSecurityContainer.showNextSecurityScreenOrFinish(authenticated, targetUserId,
-                bypassSecondaryLockScreen);
-    }
-
-    /**
-     * Authentication has happened and it's time to dismiss keyguard. This function
-     * should clean up and inform KeyguardViewMediator.
-     *
-     * @param strongAuth whether the user has authenticated with strong authentication like
-     *                   pattern, password or PIN but not by trust agents or fingerprint
-     * @param targetUserId a user that needs to be the foreground user at the dismissal completion.
-     */
-    @Override
-    public void finish(boolean strongAuth, int targetUserId) {
-        // If there's a pending runnable because the user interacted with a widget
-        // and we're leaving keyguard, then run it.
-        boolean deferKeyguardDone = false;
-        if (mDismissAction != null) {
-            deferKeyguardDone = mDismissAction.onDismiss();
-            mDismissAction = null;
-            mCancelAction = null;
-        }
-        if (mViewMediatorCallback != null) {
-            if (deferKeyguardDone) {
-                mViewMediatorCallback.keyguardDonePending(strongAuth, targetUserId);
-            } else {
-                mViewMediatorCallback.keyguardDone(strongAuth, targetUserId);
-            }
-        }
-    }
-
-    @Override
-    public void reset() {
-        mViewMediatorCallback.resetKeyguard();
-    }
-
-    @Override
-    public void onCancelClicked() {
-        mViewMediatorCallback.onCancelClicked();
-    }
-
-    public void resetSecurityContainer() {
-        mSecurityContainer.reset();
-    }
-
-    @Override
-    public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) {
-        if (mViewMediatorCallback != null) {
-            mViewMediatorCallback.setNeedsInput(needsInput);
-        }
-    }
-
-    public CharSequence getAccessibilityTitleForCurrentMode() {
-        return mSecurityContainer.getTitle();
-    }
-
-    public void userActivity() {
-        if (mViewMediatorCallback != null) {
-            mViewMediatorCallback.userActivity();
-        }
-    }
-
-    /**
-     * Called when the Keyguard is not actively shown anymore on the screen.
-     */
-    public void onPause() {
-        if (DEBUG) Log.d(TAG, String.format("screen off, instance %s at %s",
-                Integer.toHexString(hashCode()), SystemClock.uptimeMillis()));
-        mSecurityContainer.showPrimarySecurityScreen(true);
-        mSecurityContainer.onPause();
-        clearFocus();
-    }
-
-    /**
-     * Called when the Keyguard is actively shown on the screen.
-     */
-    public void onResume() {
-        if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
-        mSecurityContainer.onResume(KeyguardSecurityView.SCREEN_ON);
-        requestFocus();
-    }
-
-    /**
-     * Starts the animation when the Keyguard gets shown.
-     */
-    public void startAppearAnimation() {
-        mSecurityContainer.startAppearAnimation();
-    }
-
-    public void startDisappearAnimation(Runnable finishRunnable) {
-        if (!mSecurityContainer.startDisappearAnimation(finishRunnable) && finishRunnable != null) {
-            finishRunnable.run();
-        }
-    }
-
-    /**
-     * Called before this view is being removed.
-     */
-    public void cleanUp() {
-        getSecurityContainer().onPause();
-    }
-
-    @Override
-    public boolean dispatchKeyEvent(KeyEvent event) {
-        if (interceptMediaKey(event)) {
-            return true;
-        }
-        return super.dispatchKeyEvent(event);
-    }
-
-    /**
-     * Allows the media keys to work when the keyguard is showing.
-     * The media keys should be of no interest to the actual keyguard view(s),
-     * so intercepting them here should not be of any harm.
-     * @param event The key event
-     * @return whether the event was consumed as a media key.
-     */
-    public boolean interceptMediaKey(KeyEvent event) {
-        final int keyCode = event.getKeyCode();
-        if (event.getAction() == KeyEvent.ACTION_DOWN) {
-            switch (keyCode) {
-                case KeyEvent.KEYCODE_MEDIA_PLAY:
-                case KeyEvent.KEYCODE_MEDIA_PAUSE:
-                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
-                    /* Suppress PLAY/PAUSE toggle when phone is ringing or
-                     * in-call to avoid music playback */
-                    if (mTelephonyManager == null) {
-                        mTelephonyManager = (TelephonyManager) getContext().getSystemService(
-                                Context.TELEPHONY_SERVICE);
-                    }
-                    if (mTelephonyManager != null &&
-                            mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) {
-                        return true;  // suppress key event
-                    }
-                case KeyEvent.KEYCODE_MUTE:
-                case KeyEvent.KEYCODE_HEADSETHOOK:
-                case KeyEvent.KEYCODE_MEDIA_STOP:
-                case KeyEvent.KEYCODE_MEDIA_NEXT:
-                case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
-                case KeyEvent.KEYCODE_MEDIA_REWIND:
-                case KeyEvent.KEYCODE_MEDIA_RECORD:
-                case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
-                case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
-                    handleMediaKeyEvent(event);
-                    return true;
-                }
-
-                case KeyEvent.KEYCODE_VOLUME_UP:
-                case KeyEvent.KEYCODE_VOLUME_DOWN:
-                case KeyEvent.KEYCODE_VOLUME_MUTE: {
-                    if (KEYGUARD_MANAGES_VOLUME) {
-                        synchronized (this) {
-                            if (mAudioManager == null) {
-                                mAudioManager = (AudioManager) getContext().getSystemService(
-                                        Context.AUDIO_SERVICE);
-                            }
-                        }
-                        // Volume buttons should only function for music (local or remote).
-                        // TODO: Actually handle MUTE.
-                        mAudioManager.adjustSuggestedStreamVolume(
-                                keyCode == KeyEvent.KEYCODE_VOLUME_UP
-                                        ? AudioManager.ADJUST_RAISE
-                                        : AudioManager.ADJUST_LOWER /* direction */,
-                                AudioManager.STREAM_MUSIC /* stream */, 0 /* flags */);
-                        // Don't execute default volume behavior
-                        return true;
-                    } else {
-                        return false;
-                    }
-                }
-            }
-        } else if (event.getAction() == KeyEvent.ACTION_UP) {
-            switch (keyCode) {
-                case KeyEvent.KEYCODE_MUTE:
-                case KeyEvent.KEYCODE_HEADSETHOOK:
-                case KeyEvent.KEYCODE_MEDIA_PLAY:
-                case KeyEvent.KEYCODE_MEDIA_PAUSE:
-                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
-                case KeyEvent.KEYCODE_MEDIA_STOP:
-                case KeyEvent.KEYCODE_MEDIA_NEXT:
-                case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
-                case KeyEvent.KEYCODE_MEDIA_REWIND:
-                case KeyEvent.KEYCODE_MEDIA_RECORD:
-                case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
-                case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
-                    handleMediaKeyEvent(event);
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    private void handleMediaKeyEvent(KeyEvent keyEvent) {
-        synchronized (this) {
-            if (mAudioManager == null) {
-                mAudioManager = (AudioManager) getContext().getSystemService(
-                        Context.AUDIO_SERVICE);
-            }
-        }
-        mAudioManager.dispatchMediaKeyEvent(keyEvent);
-    }
-
-    /**
-     * In general, we enable unlocking the insecure keyguard with the menu key. However, there are
-     * some cases where we wish to disable it, notably when the menu button placement or technology
-     * is prone to false positives.
-     *
-     * @return true if the menu key should be enabled
-     */
-    private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
-    public boolean shouldEnableMenuKey() {
-        final Resources res = getResources();
-        final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
-        final boolean isTestHarness = ActivityManager.isRunningInTestHarness();
-        final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
-        return !configDisabled || isTestHarness || fileOverride;
-    }
-
     public void setViewMediatorCallback(ViewMediatorCallback viewMediatorCallback) {
         mViewMediatorCallback = viewMediatorCallback;
-        // Update ViewMediator with the current input method requirements
-        mViewMediatorCallback.setNeedsInput(mSecurityContainer.needsInput());
-    }
-
-    public void setLockPatternUtils(LockPatternUtils utils) {
-        mLockPatternUtils = utils;
-        mSecurityContainer.setLockPatternUtils(utils);
-    }
-
-    public SecurityMode getSecurityMode() {
-        return mSecurityContainer.getSecurityMode();
-    }
-
-    public SecurityMode getCurrentSecurityMode() {
-        return mSecurityContainer.getCurrentSecurityMode();
-    }
-
-    /**
-     * When bouncer was visible and is starting to become hidden.
-     */
-    public void onStartingToHide() {
-        mSecurityContainer.onStartingToHide();
     }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
new file mode 100644
index 0000000..7aabb17
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
@@ -0,0 +1,460 @@
+/*
+ * 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.keyguard;
+
+import android.app.ActivityManager;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.media.AudioManager;
+import android.os.SystemClock;
+import android.service.trust.TrustAgentService;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import android.util.MathUtils;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.View.OnKeyListener;
+import android.view.ViewTreeObserver;
+
+import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.keyguard.dagger.KeyguardBouncerScope;
+import com.android.settingslib.Utils;
+import com.android.systemui.R;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.phone.KeyguardBouncer;
+import com.android.systemui.util.ViewController;
+
+import java.io.File;
+
+import javax.inject.Inject;
+
+/** Controller for a {@link KeyguardHostView}. */
+@KeyguardBouncerScope
+public class KeyguardHostViewController extends ViewController<KeyguardHostView> {
+    private static final String TAG = "KeyguardViewBase";
+    public static final boolean DEBUG = KeyguardConstants.DEBUG;
+    // Whether the volume keys should be handled by keyguard. If true, then
+    // they will be handled here for specific media types such as music, otherwise
+    // the audio service will bring up the volume dialog.
+    private static final boolean KEYGUARD_MANAGES_VOLUME = false;
+
+    private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
+
+    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private final KeyguardSecurityContainerController mKeyguardSecurityContainerController;
+    private final TelephonyManager mTelephonyManager;
+    private final ViewMediatorCallback mViewMediatorCallback;
+    private final AudioManager mAudioManager;
+
+    private ActivityStarter.OnDismissAction mDismissAction;
+    private Runnable mCancelAction;
+
+    private final KeyguardUpdateMonitorCallback mUpdateCallback =
+            new KeyguardUpdateMonitorCallback() {
+                @Override
+                public void onUserSwitchComplete(int userId) {
+                    mKeyguardSecurityContainerController.showPrimarySecurityScreen(
+                            false /* turning off */);
+                }
+
+                @Override
+                public void onTrustGrantedWithFlags(int flags, int userId) {
+                    if (userId != KeyguardUpdateMonitor.getCurrentUser()) return;
+                    boolean bouncerVisible = mView.isVisibleToUser();
+                    boolean initiatedByUser =
+                            (flags & TrustAgentService.FLAG_GRANT_TRUST_INITIATED_BY_USER) != 0;
+                    boolean dismissKeyguard =
+                            (flags & TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD) != 0;
+
+                    if (initiatedByUser || dismissKeyguard) {
+                        if (mViewMediatorCallback.isScreenOn()
+                                && (bouncerVisible || dismissKeyguard)) {
+                            if (!bouncerVisible) {
+                                // The trust agent dismissed the keyguard without the user proving
+                                // that they are present (by swiping up to show the bouncer). That's
+                                // fine if the user proved presence via some other way to the trust
+                                //agent.
+                                Log.i(TAG, "TrustAgent dismissed Keyguard.");
+                            }
+                            mSecurityCallback.dismiss(false /* authenticated */, userId,
+                                    /* bypassSecondaryLockScreen */ false);
+                        } else {
+                            mViewMediatorCallback.playTrustedSound();
+                        }
+                    }
+                }
+            };
+
+    private final SecurityCallback mSecurityCallback = new SecurityCallback() {
+
+        @Override
+        public boolean dismiss(boolean authenticated, int targetUserId,
+                boolean bypassSecondaryLockScreen) {
+            return mKeyguardSecurityContainerController.showNextSecurityScreenOrFinish(
+                    authenticated, targetUserId, bypassSecondaryLockScreen);
+        }
+
+        @Override
+        public void userActivity() {
+            mViewMediatorCallback.userActivity();
+        }
+
+        @Override
+        public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) {
+            mViewMediatorCallback.setNeedsInput(needsInput);
+        }
+
+        /**
+         * Authentication has happened and it's time to dismiss keyguard. This function
+         * should clean up and inform KeyguardViewMediator.
+         *
+         * @param strongAuth whether the user has authenticated with strong authentication like
+         *                   pattern, password or PIN but not by trust agents or fingerprint
+         * @param targetUserId a user that needs to be the foreground user at the dismissal
+         *                    completion.
+         */
+        @Override
+        public void finish(boolean strongAuth, int targetUserId) {
+            // If there's a pending runnable because the user interacted with a widget
+            // and we're leaving keyguard, then run it.
+            boolean deferKeyguardDone = false;
+            if (mDismissAction != null) {
+                deferKeyguardDone = mDismissAction.onDismiss();
+                mDismissAction = null;
+                mCancelAction = null;
+            }
+            if (mViewMediatorCallback != null) {
+                if (deferKeyguardDone) {
+                    mViewMediatorCallback.keyguardDonePending(strongAuth, targetUserId);
+                } else {
+                    mViewMediatorCallback.keyguardDone(strongAuth, targetUserId);
+                }
+            }
+        }
+
+        @Override
+        public void reset() {
+            mViewMediatorCallback.resetKeyguard();
+        }
+
+        @Override
+        public void onCancelClicked() {
+            mViewMediatorCallback.onCancelClicked();
+        }
+    };
+
+    private OnKeyListener mOnKeyListener = (v, keyCode, event) -> interceptMediaKey(event);
+
+    @Inject
+    public KeyguardHostViewController(KeyguardHostView view,
+            KeyguardUpdateMonitor keyguardUpdateMonitor,
+            KeyguardSecurityContainerController keyguardSecurityContainerController,
+            AudioManager audioManager,
+            TelephonyManager telephonyManager,
+            ViewMediatorCallback viewMediatorCallback) {
+        super(view);
+        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+        mKeyguardSecurityContainerController = keyguardSecurityContainerController;
+        mAudioManager = audioManager;
+        mTelephonyManager = telephonyManager;
+        mViewMediatorCallback = viewMediatorCallback;
+    }
+
+    /** Initialize the Controller. */
+    public void init() {
+        super.init();
+        mView.setViewMediatorCallback(mViewMediatorCallback);
+        // Update ViewMediator with the current input method requirements
+        mViewMediatorCallback.setNeedsInput(mKeyguardSecurityContainerController.needsInput());
+        mKeyguardSecurityContainerController.init();
+        mKeyguardSecurityContainerController.setSecurityCallback(mSecurityCallback);
+        mKeyguardSecurityContainerController.showPrimarySecurityScreen(false);
+    }
+
+    @Override
+    protected void onViewAttached() {
+        mKeyguardUpdateMonitor.registerCallback(mUpdateCallback);
+        mView.setOnKeyListener(mOnKeyListener);
+    }
+
+    @Override
+    protected void onViewDetached() {
+        mKeyguardUpdateMonitor.removeCallback(mUpdateCallback);
+        mView.setOnKeyListener(null);
+    }
+
+     /** Called before this view is being removed. */
+    public void cleanUp() {
+        mKeyguardSecurityContainerController.onPause();
+    }
+
+    public void resetSecurityContainer() {
+        mKeyguardSecurityContainerController.reset();
+    }
+
+    /**
+     * Dismisses the keyguard by going to the next screen or making it gone.
+     * @param targetUserId a user that needs to be the foreground user at the dismissal completion.
+     * @return True if the keyguard is done.
+     */
+    public boolean dismiss(int targetUserId) {
+        return mSecurityCallback.dismiss(false, targetUserId, false);
+    }
+
+    /**
+     * Called when the Keyguard is actively shown on the screen.
+     */
+    public void onResume() {
+        if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
+        mKeyguardSecurityContainerController.onResume(KeyguardSecurityView.SCREEN_ON);
+        mView.requestFocus();
+    }
+
+    public CharSequence getAccessibilityTitleForCurrentMode() {
+        return mKeyguardSecurityContainerController.getTitle();
+    }
+
+    /**
+     * Starts the animation when the Keyguard gets shown.
+     */
+    public void appear(int statusBarHeight) {
+        // We might still be collapsed and the view didn't have time to layout yet or still
+        // be small, let's wait on the predraw to do the animation in that case.
+        if (mView.getHeight() != 0 && mView.getHeight() != statusBarHeight) {
+            mKeyguardSecurityContainerController.startAppearAnimation();
+        } else {
+            mView.getViewTreeObserver().addOnPreDrawListener(
+                    new ViewTreeObserver.OnPreDrawListener() {
+                        @Override
+                        public boolean onPreDraw() {
+                            mView.getViewTreeObserver().removeOnPreDrawListener(this);
+                            mKeyguardSecurityContainerController.startAppearAnimation();
+                            return true;
+                        }
+                    });
+            mView.requestLayout();
+        }
+    }
+
+    /**
+     * Show a string explaining why the security view needs to be solved.
+     *
+     * @param reason a flag indicating which string should be shown, see
+     *               {@link KeyguardSecurityView#PROMPT_REASON_NONE},
+     *               {@link KeyguardSecurityView#PROMPT_REASON_RESTART},
+     *               {@link KeyguardSecurityView#PROMPT_REASON_TIMEOUT}, and
+     *               {@link KeyguardSecurityView#PROMPT_REASON_PREPARE_FOR_UPDATE}.
+     */
+    public void showPromptReason(int reason) {
+        mKeyguardSecurityContainerController.showPromptReason(reason);
+    }
+
+    public void showMessage(CharSequence message, ColorStateList colorState) {
+        mKeyguardSecurityContainerController.showMessage(message, colorState);
+    }
+
+    public void showErrorMessage(CharSequence customMessage) {
+        showMessage(customMessage, Utils.getColorError(mView.getContext()));
+    }
+
+    /**
+     * Sets an action to run when keyguard finishes.
+     *
+     * @param action
+     */
+    public void setOnDismissAction(ActivityStarter.OnDismissAction action, Runnable cancelAction) {
+        if (mCancelAction != null) {
+            mCancelAction.run();
+            mCancelAction = null;
+        }
+        mDismissAction = action;
+        mCancelAction = cancelAction;
+    }
+
+    public void cancelDismissAction() {
+        setOnDismissAction(null, null);
+    }
+
+    public void startDisappearAnimation(Runnable finishRunnable) {
+        if (!mKeyguardSecurityContainerController.startDisappearAnimation(finishRunnable)
+                && finishRunnable != null) {
+            finishRunnable.run();
+        }
+    }
+
+    /**
+     * Called when the Keyguard is not actively shown anymore on the screen.
+     */
+    public void onPause() {
+        if (DEBUG) {
+            Log.d(TAG, String.format("screen off, instance %s at %s",
+                    Integer.toHexString(hashCode()), SystemClock.uptimeMillis()));
+        }
+        mKeyguardSecurityContainerController.showPrimarySecurityScreen(true);
+        mKeyguardSecurityContainerController.onPause();
+        mView.clearFocus();
+    }
+
+    /**
+     * Called when the view needs to be shown.
+     */
+    public void showPrimarySecurityScreen() {
+        if (DEBUG) Log.d(TAG, "show()");
+        mKeyguardSecurityContainerController.showPrimarySecurityScreen(false);
+    }
+
+    public void setExpansion(float fraction) {
+        float alpha = MathUtils.map(KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1, 1, 0, fraction);
+        mView.setAlpha(MathUtils.constrain(alpha, 0f, 1f));
+        mView.setTranslationY(fraction * mView.getHeight());
+    }
+
+    /**
+     * When bouncer was visible and is starting to become hidden.
+     */
+    public void onStartingToHide() {
+        mKeyguardSecurityContainerController.onStartingToHide();
+    }
+
+    public boolean hasDismissActions() {
+        return mDismissAction != null || mCancelAction != null;
+    }
+
+    public SecurityMode getCurrentSecurityMode() {
+        return mKeyguardSecurityContainerController.getCurrentSecurityMode();
+    }
+
+    public int getTop() {
+        int top = mView.getTop();
+        // The password view has an extra top padding that should be ignored.
+        if (getCurrentSecurityMode() == SecurityMode.Password) {
+            View messageArea = mView.findViewById(R.id.keyguard_message_area);
+            top += messageArea.getTop();
+        }
+        return top;
+    }
+
+    public boolean handleBackKey() {
+        if (mKeyguardSecurityContainerController.getCurrentSecuritySelection()
+                != SecurityMode.None) {
+            mKeyguardSecurityContainerController.dismiss(
+                    false, KeyguardUpdateMonitor.getCurrentUser());
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * In general, we enable unlocking the insecure keyguard with the menu key. However, there are
+     * some cases where we wish to disable it, notably when the menu button placement or technology
+     * is prone to false positives.
+     *
+     * @return true if the menu key should be enabled
+     */
+    public boolean shouldEnableMenuKey() {
+        final Resources res = mView.getResources();
+        final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
+        final boolean isTestHarness = ActivityManager.isRunningInTestHarness();
+        final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
+        return !configDisabled || isTestHarness || fileOverride;
+    }
+
+    /**
+     * Allows the media keys to work when the keyguard is showing.
+     * The media keys should be of no interest to the actual keyguard view(s),
+     * so intercepting them here should not be of any harm.
+     * @param event The key event
+     * @return whether the event was consumed as a media key.
+     */
+    public boolean interceptMediaKey(KeyEvent event) {
+        int keyCode = event.getKeyCode();
+        if (event.getAction() == KeyEvent.ACTION_DOWN) {
+            switch (keyCode) {
+                case KeyEvent.KEYCODE_MEDIA_PLAY:
+                case KeyEvent.KEYCODE_MEDIA_PAUSE:
+                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+                    /* Suppress PLAY/PAUSE toggle when phone is ringing or
+                     * in-call to avoid music playback */
+                    if (mTelephonyManager != null &&
+                            mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) {
+                        return true;  // suppress key event
+                    }
+                case KeyEvent.KEYCODE_MUTE:
+                case KeyEvent.KEYCODE_HEADSETHOOK:
+                case KeyEvent.KEYCODE_MEDIA_STOP:
+                case KeyEvent.KEYCODE_MEDIA_NEXT:
+                case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+                case KeyEvent.KEYCODE_MEDIA_REWIND:
+                case KeyEvent.KEYCODE_MEDIA_RECORD:
+                case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+                case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
+                    handleMediaKeyEvent(event);
+                    return true;
+                }
+
+                case KeyEvent.KEYCODE_VOLUME_UP:
+                case KeyEvent.KEYCODE_VOLUME_DOWN:
+                case KeyEvent.KEYCODE_VOLUME_MUTE: {
+                    if (KEYGUARD_MANAGES_VOLUME) {
+                        // Volume buttons should only function for music (local or remote).
+                        // TODO: Actually handle MUTE.
+                        mAudioManager.adjustSuggestedStreamVolume(
+                                keyCode == KeyEvent.KEYCODE_VOLUME_UP
+                                        ? AudioManager.ADJUST_RAISE
+                                        : AudioManager.ADJUST_LOWER /* direction */,
+                                AudioManager.STREAM_MUSIC /* stream */, 0 /* flags */);
+                        // Don't execute default volume behavior
+                        return true;
+                    } else {
+                        return false;
+                    }
+                }
+            }
+        } else if (event.getAction() == KeyEvent.ACTION_UP) {
+            switch (keyCode) {
+                case KeyEvent.KEYCODE_MUTE:
+                case KeyEvent.KEYCODE_HEADSETHOOK:
+                case KeyEvent.KEYCODE_MEDIA_PLAY:
+                case KeyEvent.KEYCODE_MEDIA_PAUSE:
+                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+                case KeyEvent.KEYCODE_MEDIA_STOP:
+                case KeyEvent.KEYCODE_MEDIA_NEXT:
+                case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+                case KeyEvent.KEYCODE_MEDIA_REWIND:
+                case KeyEvent.KEYCODE_MEDIA_RECORD:
+                case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+                case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
+                    handleMediaKeyEvent(event);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+
+    private void handleMediaKeyEvent(KeyEvent keyEvent) {
+        mAudioManager.dispatchMediaKeyEvent(keyEvent);
+    }
+
+    public void finish(boolean strongAuth, int currentUser) {
+        mSecurityCallback.finish(strongAuth, currentUser);
+    }
+
+
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
new file mode 100644
index 0000000..f056bdb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
@@ -0,0 +1,68 @@
+/*
+ * 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.keyguard;
+
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.util.ViewController;
+
+import javax.inject.Inject;
+
+/** Controller for a {@link KeyguardMessageAreaController}. */
+public class KeyguardMessageAreaController extends ViewController<KeyguardMessageArea> {
+    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private final ConfigurationController mConfigurationController;
+
+    private KeyguardMessageAreaController(KeyguardMessageArea view,
+            KeyguardUpdateMonitor keyguardUpdateMonitor,
+            ConfigurationController configurationController) {
+        super(view);
+
+        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+        mConfigurationController = configurationController;
+    }
+
+    @Override
+    protected void onViewAttached() {
+        //mConfigurationController.addCallback();
+        //mKeyguardUpdateMonitor.registerCallback();
+    }
+
+    @Override
+    protected void onViewDetached() {
+        //mConfigurationController.removeCallback();
+        //mKeyguardUpdateMonitor.removeCallback();
+    }
+
+    /** Factory for createing {@link com.android.keyguard.KeyguardMessageAreaController}. */
+    public static class Factory {
+        private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+        private final ConfigurationController mConfigurationController;
+
+        @Inject
+        public Factory(KeyguardUpdateMonitor keyguardUpdateMonitor,
+                ConfigurationController configurationController) {
+            mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+            mConfigurationController = configurationController;
+        }
+
+        /** Build a new {@link KeyguardMessageAreaController}. */
+        public KeyguardMessageAreaController create(KeyguardMessageArea view) {
+            return new KeyguardMessageAreaController(
+                    view, mKeyguardUpdateMonitor, mConfigurationController);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardRootViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardRootViewController.java
new file mode 100644
index 0000000..5c125fc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardRootViewController.java
@@ -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.
+ */
+
+package com.android.keyguard;
+
+import android.view.ViewGroup;
+
+import com.android.keyguard.dagger.KeyguardBouncerScope;
+import com.android.keyguard.dagger.RootView;
+import com.android.systemui.statusbar.phone.KeyguardBouncer;
+import com.android.systemui.util.ViewController;
+
+import javax.inject.Inject;
+/** Controller for a {@link KeyguardBouncer}'s Root view. */
+@KeyguardBouncerScope
+public class KeyguardRootViewController extends ViewController<ViewGroup> {
+    @Inject
+    public KeyguardRootViewController(@RootView ViewGroup view) {
+        super(view);
+    }
+
+    public ViewGroup getView() {
+        return mView;
+    }
+
+    @Override
+    protected void onViewAttached() {
+
+    }
+
+    @Override
+    protected void onViewDetached() {
+
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
new file mode 100644
index 0000000..17f25bd08ef
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.content.res.ColorStateList;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.systemui.util.ViewController;
+
+import javax.inject.Inject;
+
+/** Controller for {@link KeyguardSecurityContainer} */
+public class KeyguardSecurityContainerController extends ViewController<KeyguardSecurityContainer> {
+
+    private final LockPatternUtils mLockPatternUtils;
+    private final KeyguardSecurityViewController.Factory mKeyguardSecurityViewControllerFactory;
+
+    @Inject
+    KeyguardSecurityContainerController(KeyguardSecurityContainer view,
+            LockPatternUtils lockPatternUtils,
+            KeyguardSecurityViewController.Factory keyguardSecurityViewControllerFactory) {
+        super(view);
+        mLockPatternUtils = lockPatternUtils;
+        view.setLockPatternUtils(mLockPatternUtils);
+        mKeyguardSecurityViewControllerFactory = keyguardSecurityViewControllerFactory;
+    }
+
+    @Override
+    protected void onViewAttached() {
+    }
+
+    @Override
+    protected void onViewDetached() {
+    }
+
+    /** */
+    public void onPause() {
+        mView.onPause();
+    }
+
+    public void showPrimarySecurityScreen(boolean turningOff) {
+        mView.showPrimarySecurityScreen(turningOff);
+    }
+
+    public void showPromptReason(int reason) {
+        mView.showPromptReason(reason);
+    }
+
+    public void showMessage(CharSequence message, ColorStateList colorState) {
+        mView.showMessage(message, colorState);
+    }
+
+    public SecurityMode getCurrentSecuritySelection() {
+        return mView.getCurrentSecuritySelection();
+    }
+
+    public void dismiss(boolean authenticated, int targetUserId) {
+        mView.dismiss(authenticated, targetUserId);
+    }
+
+    public void reset() {
+        mView.reset();
+    }
+
+    public CharSequence getTitle() {
+        return mView.getTitle();
+    }
+
+    public void onResume(int screenOn) {
+        mView.onResume(screenOn);
+    }
+
+    public void startAppearAnimation() {
+        mView.startAppearAnimation();
+    }
+
+    public boolean startDisappearAnimation(Runnable onFinishRunnable) {
+        return mView.startDisappearAnimation(onFinishRunnable);
+    }
+
+    public void onStartingToHide() {
+        mView.onStartingToHide();
+    }
+
+    public void setSecurityCallback(SecurityCallback securityCallback) {
+        mView.setSecurityCallback(securityCallback);
+    }
+
+    public boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId,
+            boolean bypassSecondaryLockScreen) {
+        return mView.showNextSecurityScreenOrFinish(
+                authenticated, targetUserId, bypassSecondaryLockScreen);
+    }
+
+    public boolean needsInput() {
+        return mView.needsInput();
+    }
+
+    public SecurityMode getCurrentSecurityMode() {
+        return mView.getCurrentSecurityMode();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java
new file mode 100644
index 0000000..ef9ba19
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java
@@ -0,0 +1,58 @@
+/*
+ * 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.keyguard;
+
+import android.view.View;
+
+import com.android.systemui.util.ViewController;
+
+import javax.inject.Inject;
+
+
+/** Controller for a {@link KeyguardSecurityView}. */
+public class KeyguardSecurityViewController extends ViewController<View> {
+
+    private final KeyguardSecurityView mView;
+
+    private KeyguardSecurityViewController(KeyguardSecurityView view) {
+        super((View) view);
+        // KeyguardSecurityView isn't actually a View, so we need to track it ourselves.
+        mView = view;
+    }
+
+    @Override
+    protected void onViewAttached() {
+
+    }
+
+    @Override
+    protected void onViewDetached() {
+
+    }
+
+    /** Factory for a {@link KeyguardSecurityViewController}. */
+    public static class Factory {
+        @Inject
+        public Factory() {
+        }
+
+        /** Create a new {@link KeyguardSecurityViewController}. */
+        public KeyguardSecurityViewController create(KeyguardSecurityView view) {
+            return new KeyguardSecurityViewController(view);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 1027329..76090f8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -36,6 +36,7 @@
 import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
+import android.app.ActivityTaskManager.RootTaskInfo;
 import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.app.UserSwitchObserver;
@@ -2783,7 +2784,7 @@
         @Override
         public void onTaskStackChangedBackground() {
             try {
-                ActivityManager.StackInfo info = ActivityTaskManager.getService().getStackInfo(
+                RootTaskInfo info = ActivityTaskManager.getService().getRootTaskInfo(
                         WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_ASSISTANT);
                 if (info == null) {
                     return;
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
index 84deaca..5160b7e 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
@@ -16,27 +16,27 @@
 
 package com.android.keyguard.dagger;
 
-import android.view.ViewGroup;
-
+import com.android.keyguard.KeyguardHostViewController;
+import com.android.keyguard.KeyguardRootViewController;
 import com.android.systemui.statusbar.phone.KeyguardBouncer;
 
-import dagger.BindsInstance;
 import dagger.Subcomponent;
 
 /**
  * Dagger Subcomponent for the {@link KeyguardBouncer}.
  */
-@Subcomponent
+@Subcomponent(modules = {KeyguardBouncerModule.class})
 @KeyguardBouncerScope
 public interface KeyguardBouncerComponent {
     /** Simple factory for {@link KeyguardBouncerComponent}. */
     @Subcomponent.Factory
     interface Factory {
-        KeyguardBouncerComponent build(
-                @BindsInstance @ContainerView ViewGroup container,
-                @BindsInstance KeyguardBouncer.BouncerExpansionCallback bouncerExpansionCallback);
+        KeyguardBouncerComponent create();
     }
 
-    /** */
-    KeyguardBouncer createKeyguardBouncer();
+    /** Returns a {@link KeyguardRootViewController}. */
+    KeyguardRootViewController getKeyguardRootViewController();
+
+    /** Returns a {@link KeyguardHostViewController}. */
+    KeyguardHostViewController getKeyguardHostViewController();
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
new file mode 100644
index 0000000..b6010c8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
@@ -0,0 +1,64 @@
+/*
+ * 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.keyguard.dagger;
+
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import com.android.keyguard.KeyguardHostView;
+import com.android.keyguard.KeyguardMessageArea;
+import com.android.keyguard.KeyguardSecurityContainer;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.KeyguardBouncer;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Module to create and access view related to the {@link KeyguardBouncer}.
+ */
+@Module
+public interface KeyguardBouncerModule {
+    /** */
+    @Provides
+    @KeyguardBouncerScope
+    @RootView
+    static ViewGroup providesRootView(LayoutInflater layoutInflater) {
+        return (ViewGroup) layoutInflater.inflate(R.layout.keyguard_bouncer, null);
+    }
+
+    /** */
+    @Provides
+    @KeyguardBouncerScope
+    static KeyguardMessageArea providesKeyguardMessageArea(@RootView ViewGroup viewGroup) {
+        return viewGroup.findViewById(R.id.keyguard_message_area);
+    }
+
+    /** */
+    @Provides
+    @KeyguardBouncerScope
+    static KeyguardHostView providesKeyguardHostView(@RootView ViewGroup rootView) {
+        return rootView.findViewById(R.id.keyguard_host_view);
+    }
+
+    /** */
+    @Provides
+    @KeyguardBouncerScope
+    static KeyguardSecurityContainer preovidesKeyguardSecurityContainer(KeyguardHostView hostView) {
+        return hostView.findViewById(R.id.keyguard_security_container);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/ContainerView.java b/packages/SystemUI/src/com/android/keyguard/dagger/RootView.java
similarity index 96%
rename from packages/SystemUI/src/com/android/keyguard/dagger/ContainerView.java
rename to packages/SystemUI/src/com/android/keyguard/dagger/RootView.java
index e65f19d..5ebff09 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/ContainerView.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/RootView.java
@@ -26,5 +26,5 @@
 @Qualifier
 @Documented
 @Retention(RUNTIME)
-public @interface ContainerView {
+public @interface RootView {
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessController.kt
index 9dcc3bb..a7d17e1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessController.kt
@@ -177,7 +177,7 @@
                     userDefinedBrightness = systemSettings.getFloat(SCREEN_BRIGHTNESS_FLOAT)
                 }
             })
-        userDefinedBrightness = systemSettings.getFloat(SCREEN_BRIGHTNESS_FLOAT)
+        userDefinedBrightness = systemSettings.getFloat(SCREEN_BRIGHTNESS_FLOAT, 1f)
     }
 
     override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
index b464e8ad..89b5c38 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
@@ -22,8 +22,8 @@
 import static android.view.Surface.ROTATION_0;
 import static android.view.Surface.ROTATION_180;
 
-import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
+import android.app.ActivityTaskManager.RootTaskInfo;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
@@ -328,14 +328,14 @@
             return false;
         }
 
-        // Bail early if the pinned stack is staled.
-        final ActivityManager.StackInfo pinnedStackInfo;
+        // Bail early if the pinned task is staled.
+        final RootTaskInfo pinnedTaskInfo;
         try {
-            pinnedStackInfo = ActivityTaskManager.getService()
-                    .getStackInfo(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
-            if (pinnedStackInfo == null) return false;
+            pinnedTaskInfo = ActivityTaskManager.getService()
+                    .getRootTaskInfo(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
+            if (pinnedTaskInfo == null) return false;
         } catch (RemoteException e) {
-            Log.e(TAG, "Failed to get StackInfo for pinned stack", e);
+            Log.e(TAG, "Failed to get RootTaskInfo for pinned task", e);
             return false;
         }
 
@@ -362,7 +362,7 @@
 
         getInsetBounds(outInsetBounds);
         outBounds.set(postChangeStackBounds);
-        t.setBounds(pinnedStackInfo.stackToken, outBounds);
+        t.setBounds(pinnedTaskInfo.token, outBounds);
         return true;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 5793cdd..a5ee3a0 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -99,6 +99,36 @@
     private static final int MSG_FINISH_RESIZE = 4;
     private static final int MSG_RESIZE_USER = 5;
 
+    // Not a complete set of states but serves what we want right now.
+    private enum State {
+        UNDEFINED(0),
+        TASK_APPEARED(1),
+        ENTERING_PIP(2),
+        EXITING_PIP(3);
+
+        private final int mStateValue;
+
+        State(int value) {
+            mStateValue = value;
+        }
+
+        private boolean isInPip() {
+            return mStateValue >= TASK_APPEARED.mStateValue
+                    && mStateValue != EXITING_PIP.mStateValue;
+        }
+
+        /**
+         * Resize request can be initiated in other component, ignore if we are no longer in PIP,
+         * still waiting for animation or we're exiting from it.
+         *
+         * @return {@code true} if the resize request should be blocked/ignored.
+         */
+        private boolean shouldBlockResizeRequest() {
+            return mStateValue < ENTERING_PIP.mStateValue
+                    || mStateValue == EXITING_PIP.mStateValue;
+        }
+    }
+
     private final Context mContext;
     private final Handler mMainHandler;
     private final Handler mUpdateHandler;
@@ -200,8 +230,7 @@
     private ActivityManager.RunningTaskInfo mTaskInfo;
     private WindowContainerToken mToken;
     private SurfaceControl mLeash;
-    private boolean mInPip;
-    private boolean mExitingPip;
+    private State mState = State.UNDEFINED;
     private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS;
     private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
             mSurfaceControlTransactionFactory;
@@ -253,11 +282,11 @@
     }
 
     public boolean isInPip() {
-        return mInPip;
+        return mState.isInPip();
     }
 
     public boolean isDeferringEnterPipAnimation() {
-        return mInPip && mShouldDeferEnteringPip;
+        return mState.isInPip() && mShouldDeferEnteringPip;
     }
 
     /**
@@ -286,9 +315,9 @@
      * @param animationDurationMs duration in millisecond for the exiting PiP transition
      */
     public void exitPip(int animationDurationMs) {
-        if (!mInPip || mExitingPip || mToken == null) {
+        if (!mState.isInPip() || mState == State.EXITING_PIP || mToken == null) {
             Log.wtf(TAG, "Not allowed to exitPip in current state"
-                    + " mInPip=" + mInPip + " mExitingPip=" + mExitingPip + " mToken=" + mToken);
+                    + " mState=" + mState + " mToken=" + mToken);
             return;
         }
 
@@ -303,6 +332,7 @@
                 ? TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
                 : TRANSITION_DIRECTION_LEAVE_PIP;
         if (orientationDiffers) {
+            mState = State.EXITING_PIP;
             // Send started callback though animation is ignored.
             sendOnPipTransitionStarted(direction);
             // Don't bother doing an animation if the display rotation differs or if it's in
@@ -311,7 +341,6 @@
             mTaskOrganizer.applyTransaction(wct);
             // Send finished callback though animation is ignored.
             sendOnPipTransitionFinished(direction);
-            mInPip = false;
         } else {
             final SurfaceControl.Transaction tx =
                     mSurfaceControlTransactionFactory.getTransaction();
@@ -333,11 +362,10 @@
                     scheduleAnimateResizePip(mLastReportedBounds, destinationBounds,
                             null /* sourceHintRect */, direction, animationDurationMs,
                             null /* updateBoundsCallback */);
-                    mInPip = false;
+                    mState = State.EXITING_PIP;
                 }
             });
         }
-        mExitingPip = true;
     }
 
     private void applyWindowingModeChangeOnExit(WindowContainerTransaction wct, int direction) {
@@ -356,9 +384,9 @@
      * Removes PiP immediately.
      */
     public void removePip() {
-        if (!mInPip || mExitingPip ||  mToken == null) {
+        if (!mState.isInPip() ||  mToken == null) {
             Log.wtf(TAG, "Not allowed to removePip in current state"
-                    + " mInPip=" + mInPip + " mExitingPip=" + mExitingPip + " mToken=" + mToken);
+                    + " mState=" + mState + " mToken=" + mToken);
             return;
         }
 
@@ -370,7 +398,7 @@
                 .setDuration(mEnterExitAnimationDuration)
                 .start());
         mInitialState.remove(mToken.asBinder());
-        mExitingPip = true;
+        mState = State.EXITING_PIP;
     }
 
     private void removePipImmediately() {
@@ -392,8 +420,7 @@
         Objects.requireNonNull(info, "Requires RunningTaskInfo");
         mTaskInfo = info;
         mToken = mTaskInfo.token;
-        mInPip = true;
-        mExitingPip = false;
+        mState = State.TASK_APPEARED;
         mLeash = leash;
         mInitialState.put(mToken.asBinder(), new Configuration(mTaskInfo.configuration));
         mPictureInPictureParams = mTaskInfo.pictureInPictureParams;
@@ -423,6 +450,7 @@
             scheduleAnimateResizePip(currentBounds, destinationBounds, sourceHintRect,
                     TRANSITION_DIRECTION_TO_PIP, mEnterExitAnimationDuration,
                     null /* updateBoundsCallback */);
+            mState = State.ENTERING_PIP;
         } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
             enterPipWithAlphaAnimation(destinationBounds, mEnterExitAnimationDuration);
             mOneShotAnimationType = ANIM_TYPE_BOUNDS;
@@ -468,6 +496,9 @@
                         .setPipAnimationCallback(mPipAnimationCallback)
                         .setDuration(durationMs)
                         .start());
+                // mState is set right after the animation is kicked off to block any resize
+                // requests such as offsetPip that may have been called prior to the transition.
+                mState = State.ENTERING_PIP;
             }
         });
     }
@@ -560,7 +591,7 @@
      */
     @Override
     public void onTaskVanished(ActivityManager.RunningTaskInfo info) {
-        if (!mInPip) {
+        if (!mState.isInPip()) {
             return;
         }
         final WindowContainerToken token = info.token;
@@ -571,8 +602,7 @@
         }
         mShouldDeferEnteringPip = false;
         mPictureInPictureParams = null;
-        mInPip = false;
-        mExitingPip = false;
+        mState = State.UNDEFINED;
         mPipUiEventLoggerLogger.setTaskInfo(null);
     }
 
@@ -600,7 +630,7 @@
 
     @Override
     public void onFixedRotationFinished(int displayId) {
-        if (mShouldDeferEnteringPip && mInPip) {
+        if (mShouldDeferEnteringPip && mState.isInPip()) {
             final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
                     mTaskInfo.topActivity, getAspectRatioOrDefault(mPictureInPictureParams),
                     null /* bounds */, getMinimalSize(mTaskInfo.topActivityInfo));
@@ -623,7 +653,7 @@
                 mPipAnimationController.getCurrentAnimator();
         if (animator == null || !animator.isRunning()
                 || animator.getTransitionDirection() != TRANSITION_DIRECTION_TO_PIP) {
-            if (mInPip && fromRotation) {
+            if (mState.isInPip() && fromRotation) {
                 // If we are rotating while there is a current animation, immediately cancel the
                 // animation (remove the listeners so we don't trigger the normal finish resize
                 // call that should only happen on the update thread)
@@ -712,10 +742,10 @@
     private void scheduleAnimateResizePip(Rect currentBounds, Rect destinationBounds,
             Rect sourceHintRect, @PipAnimationController.TransitionDirection int direction,
             int durationMs, Consumer<Rect> updateBoundsCallback) {
-        if (!mInPip) {
+        if (!mState.isInPip()) {
             // TODO: tend to use shouldBlockResizeRequest here as well but need to consider
             // the fact that when in exitPip, scheduleAnimateResizePip is executed in the window
-            // container transaction callback and we want to set the mExitingPip immediately.
+            // container transaction callback and we want to set the mState immediately.
             return;
         }
 
@@ -772,7 +802,7 @@
     private void scheduleFinishResizePip(Rect destinationBounds,
             @PipAnimationController.TransitionDirection int direction,
             Consumer<Rect> updateBoundsCallback) {
-        if (shouldBlockResizeRequest()) {
+        if (mState.shouldBlockResizeRequest()) {
             return;
         }
 
@@ -791,7 +821,7 @@
         mSurfaceTransactionHelper
                 .crop(tx, mLeash, destinationBounds)
                 .resetScale(tx, mLeash, destinationBounds)
-                .round(tx, mLeash, mInPip);
+                .round(tx, mLeash, mState.isInPip());
         return tx;
     }
 
@@ -800,7 +830,7 @@
      */
     public void scheduleOffsetPip(Rect originalBounds, int offset, int duration,
             Consumer<Rect> updateBoundsCallback) {
-        if (shouldBlockResizeRequest()) {
+        if (mState.shouldBlockResizeRequest()) {
             return;
         }
         if (mShouldDeferEnteringPip) {
@@ -845,7 +875,7 @@
         final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
         mSurfaceTransactionHelper
                 .crop(tx, mLeash, destinationBounds)
-                .round(tx, mLeash, mInPip);
+                .round(tx, mLeash, mState.isInPip());
         tx.apply();
     }
 
@@ -983,16 +1013,6 @@
     }
 
     /**
-     * Resize request can be initiated in other component, ignore if we are no longer in PIP
-     * or we're exiting from it.
-     *
-     * @return {@code true} if the resize request should be blocked/ignored.
-     */
-    private boolean shouldBlockResizeRequest() {
-        return !mInPip || mExitingPip;
-    }
-
-    /**
      * Sync with {@link SplitScreen} on destination bounds if PiP is going to split screen.
      *
      * @param destinationBoundsOut contain the updated destination bounds if applicable
@@ -1026,7 +1046,7 @@
         pw.println(innerPrefix + "mToken=" + mToken
                 + " binder=" + (mToken != null ? mToken.asBinder() : null));
         pw.println(innerPrefix + "mLeash=" + mLeash);
-        pw.println(innerPrefix + "mInPip=" + mInPip);
+        pw.println(innerPrefix + "mState=" + mState);
         pw.println(innerPrefix + "mOneShotAnimationType=" + mOneShotAnimationType);
         pw.println(innerPrefix + "mPictureInPictureParams=" + mPictureInPictureParams);
         pw.println(innerPrefix + "mLastReportedBounds=" + mLastReportedBounds);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipController.java
index 6998e90..4f225e2 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipController.java
@@ -25,6 +25,7 @@
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
+import android.app.ActivityTaskManager.RootTaskInfo;
 import android.app.IActivityManager;
 import android.app.RemoteAction;
 import android.content.ComponentName;
@@ -324,9 +325,9 @@
         configController.addCallback(mOverlayChangedListener);
 
         try {
-            ActivityManager.StackInfo stackInfo = ActivityTaskManager.getService().getStackInfo(
+            RootTaskInfo taskInfo = ActivityTaskManager.getService().getRootTaskInfo(
                     WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
-            if (stackInfo != null) {
+            if (taskInfo != null) {
                 // If SystemUI restart, and it already existed a pinned stack,
                 // register the pip input consumer to ensure touch can send to it.
                 mInputConsumerController.registerInputConsumer(true /* withSfVsync */);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index 873ba26..d308172 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -19,8 +19,8 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 
-import android.app.ActivityManager.StackInfo;
 import android.app.ActivityTaskManager;
+import android.app.ActivityTaskManager.RootTaskInfo;
 import android.app.RemoteAction;
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
@@ -312,10 +312,10 @@
             // Fetch the pinned stack bounds
             Rect stackBounds = null;
             try {
-                StackInfo pinnedStackInfo = ActivityTaskManager.getService().getStackInfo(
+                RootTaskInfo pinnedTaskInfo = ActivityTaskManager.getService().getRootTaskInfo(
                         WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
-                if (pinnedStackInfo != null) {
-                    stackBounds = pinnedStackInfo.bounds;
+                if (pinnedTaskInfo != null) {
+                    stackBounds = pinnedTaskInfo.bounds;
                 }
             } catch (RemoteException e) {
                 Log.e(TAG, "Error showing PIP menu", e);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java
index 993bfe0..c66f442 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java
@@ -475,12 +475,10 @@
         final Pair<ComponentName, Integer> topPipActivityInfo =
                 PipUtils.getTopPipActivity(mContext, ActivityManager.getService());
         if (topPipActivityInfo.first != null) {
-            final UserHandle user = UserHandle.of(topPipActivityInfo.second);
             final Intent settingsIntent = new Intent(ACTION_PICTURE_IN_PICTURE_SETTINGS,
                     Uri.fromParts("package", topPipActivityInfo.first.getPackageName(), null));
-            settingsIntent.putExtra(Intent.EXTRA_USER_HANDLE, user);
             settingsIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
-            mContext.startActivity(settingsIntent);
+            mContext.startActivityAsUser(settingsIntent, UserHandle.CURRENT);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java
index 4cfec01..baa8f11 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java
@@ -19,8 +19,8 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 
-import android.app.ActivityManager.StackInfo;
 import android.app.ActivityTaskManager;
+import android.app.ActivityTaskManager.RootTaskInfo;
 import android.app.IActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -40,15 +40,15 @@
             IActivityManager activityManager) {
         try {
             final String sysUiPackageName = context.getPackageName();
-            final StackInfo pinnedStackInfo = ActivityTaskManager.getService().getStackInfo(
+            final RootTaskInfo pinnedTaskInfo = ActivityTaskManager.getService().getRootTaskInfo(
                     WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
-            if (pinnedStackInfo != null && pinnedStackInfo.taskIds != null &&
-                    pinnedStackInfo.taskIds.length > 0) {
-                for (int i = pinnedStackInfo.taskNames.length - 1; i >= 0; i--) {
+            if (pinnedTaskInfo != null && pinnedTaskInfo.childTaskIds != null
+                    && pinnedTaskInfo.childTaskIds.length > 0) {
+                for (int i = pinnedTaskInfo.childTaskNames.length - 1; i >= 0; i--) {
                     ComponentName cn = ComponentName.unflattenFromString(
-                            pinnedStackInfo.taskNames[i]);
+                            pinnedTaskInfo.childTaskNames[i]);
                     if (cn != null && !cn.getPackageName().equals(sysUiPackageName)) {
-                        return new Pair<>(cn, pinnedStackInfo.taskUserIds[i]);
+                        return new Pair<>(cn, pinnedTaskInfo.childTaskUserIds[i]);
                     }
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java
index 3b3235f..12a545a 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java
@@ -21,8 +21,8 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 
 import android.app.ActivityManager.RunningTaskInfo;
-import android.app.ActivityManager.StackInfo;
 import android.app.ActivityTaskManager;
+import android.app.ActivityTaskManager.RootTaskInfo;
 import android.app.IActivityTaskManager;
 import android.app.RemoteAction;
 import android.content.BroadcastReceiver;
@@ -289,7 +289,7 @@
         //   1. Configuration changed due to the language change (RTL <-> RTL)
         //   2. SystemUI restarts after the crash
         mPipBounds = mDefaultPipBounds;
-        resizePinnedStack(getPinnedStackInfo() == null ? STATE_NO_PIP : STATE_PIP);
+        resizePinnedStack(getPinnedTaskInfo() == null ? STATE_NO_PIP : STATE_PIP);
     }
 
     /**
@@ -505,15 +505,15 @@
         return mState != STATE_NO_PIP;
     }
 
-    private StackInfo getPinnedStackInfo() {
-        StackInfo stackInfo = null;
+    private RootTaskInfo getPinnedTaskInfo() {
+        RootTaskInfo taskInfo = null;
         try {
-            stackInfo = ActivityTaskManager.getService().getStackInfo(
+            taskInfo = ActivityTaskManager.getService().getRootTaskInfo(
                     WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
         } catch (RemoteException e) {
-            Log.e(TAG, "getStackInfo failed", e);
+            Log.e(TAG, "getRootTaskInfo failed", e);
         }
-        return stackInfo;
+        return taskInfo;
     }
 
     private void handleMediaResourceGranted(String[] packageNames) {
@@ -611,14 +611,14 @@
             if (getState() != STATE_NO_PIP) {
                 boolean hasPip = false;
 
-                StackInfo stackInfo = getPinnedStackInfo();
-                if (stackInfo == null || stackInfo.taskIds == null) {
+                RootTaskInfo taskInfo = getPinnedTaskInfo();
+                if (taskInfo == null || taskInfo.childTaskIds == null) {
                     Log.w(TAG, "There is nothing in pinned stack");
                     closePipInternal(false);
                     return;
                 }
-                for (int i = stackInfo.taskIds.length - 1; i >= 0; --i) {
-                    if (stackInfo.taskIds[i] == mPipTaskId) {
+                for (int i = taskInfo.childTaskIds.length - 1; i >= 0; --i) {
+                    if (taskInfo.childTaskIds[i] == mPipTaskId) {
                         // PIP task is still alive.
                         hasPip = true;
                         break;
@@ -642,16 +642,16 @@
         public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
             if (DEBUG) Log.d(TAG, "onActivityPinned()");
 
-            StackInfo stackInfo = getPinnedStackInfo();
-            if (stackInfo == null) {
+            RootTaskInfo taskInfo = getPinnedTaskInfo();
+            if (taskInfo == null) {
                 Log.w(TAG, "Cannot find pinned stack");
                 return;
             }
-            if (DEBUG) Log.d(TAG, "PINNED_STACK:" + stackInfo);
-            mPinnedStackId = stackInfo.stackId;
-            mPipTaskId = stackInfo.taskIds[stackInfo.taskIds.length - 1];
+            if (DEBUG) Log.d(TAG, "PINNED_STACK:" + taskInfo);
+            mPinnedStackId = taskInfo.taskId;
+            mPipTaskId = taskInfo.childTaskIds[taskInfo.childTaskIds.length - 1];
             mPipComponentName = ComponentName.unflattenFromString(
-                    stackInfo.taskNames[stackInfo.taskNames.length - 1]);
+                    taskInfo.childTaskNames[taskInfo.childTaskNames.length - 1]);
             // Set state to STATE_PIP so we show it when the pinned stack animation ends.
             mState = STATE_PIP;
             mMediaSessionManager.addOnActiveSessionsChangedListener(
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
index 4d6d71c..0fbd73b 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
@@ -86,9 +86,9 @@
                 ALL_INDICATORS, DEFAULT_ALL_INDICATORS)
     }
 
+    // TODO(b/168209929) Remove hardcode
     private fun isMicCameraEnabled(): Boolean {
-        return deviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
-                MIC_CAMERA, DEFAULT_MIC_CAMERA)
+        return true
     }
 
     private var currentUserIds = emptyList<Int>()
@@ -124,11 +124,11 @@
                             DEFAULT_ALL_INDICATORS)
                     callbacks.forEach { it.get()?.onFlagAllChanged(allIndicatorsAvailable) }
                 }
-
-                if (properties.keyset.contains(MIC_CAMERA)) {
-                    micCameraAvailable = properties.getBoolean(MIC_CAMERA, DEFAULT_MIC_CAMERA)
-                    callbacks.forEach { it.get()?.onFlagMicCameraChanged(micCameraAvailable) }
-                }
+                // TODO(b/168209929) Uncomment
+//                if (properties.keyset.contains(MIC_CAMERA)) {
+//                    micCameraAvailable = properties.getBoolean(MIC_CAMERA, DEFAULT_MIC_CAMERA)
+//                    callbacks.forEach { it.get()?.onFlagMicCameraChanged(micCameraAvailable) }
+//                }
                 internalUiExecutor.updateListeningState()
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
index 6f7b32b..363a085 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
@@ -26,6 +26,7 @@
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
+import android.app.ActivityTaskManager.RootTaskInfo;
 import android.app.AppGlobals;
 import android.app.Notification;
 import android.app.NotificationManager;
@@ -161,16 +162,16 @@
                 () -> {
                     ArraySet<Pair<String, Integer>> notifs = new ArraySet<>(mCurrentNotifs);
                     try {
-                        final ActivityManager.StackInfo focusedStack =
-                                ActivityTaskManager.getService().getFocusedStackInfo();
-                        if (focusedStack != null) {
+                        final RootTaskInfo focusedTask =
+                                ActivityTaskManager.getService().getFocusedRootTaskInfo();
+                        if (focusedTask != null) {
                             final int windowingMode =
-                                    focusedStack.configuration.windowConfiguration
+                                    focusedTask.configuration.windowConfiguration
                                             .getWindowingMode();
                             if (windowingMode == WINDOWING_MODE_FULLSCREEN
                                     || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
                                     || windowingMode == WINDOWING_MODE_FREEFORM) {
-                                checkAndPostForStack(focusedStack, notifs, noMan, pm);
+                                checkAndPostForStack(focusedTask, notifs, noMan, pm);
                             }
                         }
                         if (mDockedStackExists) {
@@ -205,10 +206,8 @@
             @NonNull NotificationManager noMan,
             @NonNull IPackageManager pm) {
         try {
-            final ActivityManager.StackInfo info =
-                    ActivityTaskManager.getService()
-                            .getStackInfo(
-                                    WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED);
+            final RootTaskInfo info = ActivityTaskManager.getService().getRootTaskInfo(
+                    WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED);
             checkAndPostForStack(info, notifs, noMan, pm);
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
@@ -221,7 +220,7 @@
      * exists, this method removes it from {@code notifs} in the arguments.
      */
     private void checkAndPostForStack(
-            @Nullable ActivityManager.StackInfo info,
+            @Nullable RootTaskInfo info,
             @NonNull ArraySet<Pair<String, Integer>> notifs,
             @NonNull NotificationManager noMan,
             @NonNull IPackageManager pm) {
@@ -241,7 +240,7 @@
                             info.userId,
                             appInfo,
                             noMan,
-                            info.taskIds[info.taskIds.length - 1]);
+                            info.childTaskIds[info.childTaskIds.length - 1]);
                 }
             }
         } catch (RemoteException e) {
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 09034c0..3665c39 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -25,26 +25,21 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Log;
-import android.util.MathUtils;
 import android.view.KeyEvent;
-import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
 import android.view.WindowInsets;
 
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardHostView;
+import com.android.keyguard.KeyguardHostViewController;
+import com.android.keyguard.KeyguardRootViewController;
 import com.android.keyguard.KeyguardSecurityModel;
 import com.android.keyguard.KeyguardSecurityView;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.keyguard.ViewMediatorCallback;
-import com.android.keyguard.dagger.ContainerView;
-import com.android.keyguard.dagger.KeyguardBouncerScope;
+import com.android.keyguard.dagger.KeyguardBouncerComponent;
+import com.android.keyguard.dagger.RootView;
 import com.android.systemui.DejankUtils;
-import com.android.systemui.Dependency;
-import com.android.systemui.R;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.shared.system.SysUiStatsLog;
@@ -57,18 +52,16 @@
 /**
  * A class which manages the bouncer on the lockscreen.
  */
-@KeyguardBouncerScope
 public class KeyguardBouncer {
 
     private static final String TAG = "KeyguardBouncer";
     static final long BOUNCER_FACE_DELAY = 1200;
-    static final float ALPHA_EXPANSION_THRESHOLD = 0.95f;
+    public static final float ALPHA_EXPANSION_THRESHOLD = 0.95f;
     static final float EXPANSION_HIDDEN = 1f;
     static final float EXPANSION_VISIBLE = 0f;
 
     protected final Context mContext;
     protected final ViewMediatorCallback mCallback;
-    protected final LockPatternUtils mLockPatternUtils;
     protected final ViewGroup mContainer;
     private final FalsingManager mFalsingManager;
     private final DismissCallbackRegistry mDismissCallbackRegistry;
@@ -76,6 +69,8 @@
     private final BouncerExpansionCallback mExpansionCallback;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final KeyguardStateController mKeyguardStateController;
+    private final KeyguardSecurityModel mKeyguardSecurityModel;
+    private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
     private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
             new KeyguardUpdateMonitorCallback() {
                 @Override
@@ -85,32 +80,33 @@
             };
     private final Runnable mRemoveViewRunnable = this::removeView;
     private final KeyguardBypassController mKeyguardBypassController;
-    protected KeyguardHostView mKeyguardView;
+    private KeyguardHostViewController mKeyguardViewController;
     private final Runnable mResetRunnable = ()-> {
-        if (mKeyguardView != null) {
-            mKeyguardView.resetSecurityContainer();
+        if (mKeyguardViewController != null) {
+            mKeyguardViewController.resetSecurityContainer();
         }
     };
 
     private int mStatusBarHeight;
     private float mExpansion = EXPANSION_HIDDEN;
     protected ViewGroup mRoot;
+    private KeyguardRootViewController mRootViewController;
     private boolean mShowingSoon;
     private int mBouncerPromptReason;
     private boolean mIsAnimatingAway;
     private boolean mIsScrimmed;
 
-    @Inject
-    public KeyguardBouncer(Context context, ViewMediatorCallback callback,
-            LockPatternUtils lockPatternUtils, @ContainerView ViewGroup container,
+    private KeyguardBouncer(Context context, ViewMediatorCallback callback,
+            ViewGroup container,
             DismissCallbackRegistry dismissCallbackRegistry, FalsingManager falsingManager,
             BouncerExpansionCallback expansionCallback,
             KeyguardStateController keyguardStateController,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
-            KeyguardBypassController keyguardBypassController, Handler handler) {
+            KeyguardBypassController keyguardBypassController, Handler handler,
+            KeyguardSecurityModel keyguardSecurityModel,
+            KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) {
         mContext = context;
         mCallback = callback;
-        mLockPatternUtils = lockPatternUtils;
         mContainer = container;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mFalsingManager = falsingManager;
@@ -118,6 +114,8 @@
         mExpansionCallback = expansionCallback;
         mHandler = handler;
         mKeyguardStateController = keyguardStateController;
+        mKeyguardSecurityModel = keyguardSecurityModel;
+        mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory;
         mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
         mKeyguardBypassController = keyguardBypassController;
     }
@@ -168,7 +166,7 @@
 
         // If allowed, try to dismiss the Keyguard. If no security auth (password/pin/pattern) is
         // set, this will dismiss the whole Keyguard. Otherwise, show the bouncer.
-        if (allowDismissKeyguard && mKeyguardView.dismiss(activeUserId)) {
+        if (allowDismissKeyguard && mKeyguardViewController.dismiss(activeUserId)) {
             return;
         }
 
@@ -204,12 +202,13 @@
      */
     private void onFullyShown() {
         mFalsingManager.onBouncerShown();
-        if (mKeyguardView == null) {
+        if (mKeyguardViewController == null) {
             Log.wtf(TAG, "onFullyShown when view was null");
         } else {
-            mKeyguardView.onResume();
+            mKeyguardViewController.onResume();
             if (mRoot != null) {
-                mRoot.announceForAccessibility(mKeyguardView.getAccessibilityTitleForCurrentMode());
+                mRoot.announceForAccessibility(
+                        mKeyguardViewController.getAccessibilityTitleForCurrentMode());
             }
         }
     }
@@ -233,28 +232,13 @@
             showPromptReason(mBouncerPromptReason);
             final CharSequence customMessage = mCallback.consumeCustomMessage();
             if (customMessage != null) {
-                mKeyguardView.showErrorMessage(customMessage);
+                mKeyguardViewController.showErrorMessage(customMessage);
             }
-            // We might still be collapsed and the view didn't have time to layout yet or still
-            // be small, let's wait on the predraw to do the animation in that case.
-            if (mKeyguardView.getHeight() != 0 && mKeyguardView.getHeight() != mStatusBarHeight) {
-                mKeyguardView.startAppearAnimation();
-            } else {
-                mKeyguardView.getViewTreeObserver().addOnPreDrawListener(
-                        new ViewTreeObserver.OnPreDrawListener() {
-                            @Override
-                            public boolean onPreDraw() {
-                                mKeyguardView.getViewTreeObserver().removeOnPreDrawListener(this);
-                                mKeyguardView.startAppearAnimation();
-                                return true;
-                            }
-                        });
-                mKeyguardView.requestLayout();
-            }
+            mKeyguardViewController.appear(mStatusBarHeight);
             mShowingSoon = false;
             if (mExpansion == EXPANSION_VISIBLE) {
-                mKeyguardView.onResume();
-                mKeyguardView.resetSecurityContainer();
+                mKeyguardViewController.onResume();
+                mKeyguardViewController.resetSecurityContainer();
                 showPromptReason(mBouncerPromptReason);
             }
             SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED,
@@ -270,16 +254,16 @@
      *               and {@link KeyguardSecurityView#PROMPT_REASON_RESTART}
      */
     public void showPromptReason(int reason) {
-        if (mKeyguardView != null) {
-            mKeyguardView.showPromptReason(reason);
+        if (mKeyguardViewController != null) {
+            mKeyguardViewController.showPromptReason(reason);
         } else {
             Log.w(TAG, "Trying to show prompt reason on empty bouncer");
         }
     }
 
     public void showMessage(String message, ColorStateList colorState) {
-        if (mKeyguardView != null) {
-            mKeyguardView.showMessage(message, colorState);
+        if (mKeyguardViewController != null) {
+            mKeyguardViewController.showMessage(message, colorState);
         } else {
             Log.w(TAG, "Trying to show message on empty bouncer");
         }
@@ -293,7 +277,7 @@
 
     public void showWithDismissAction(OnDismissAction r, Runnable cancelAction) {
         ensureView();
-        mKeyguardView.setOnDismissAction(r, cancelAction);
+        mKeyguardViewController.setOnDismissAction(r, cancelAction);
         show(false /* resetSecuritySelection */);
     }
 
@@ -307,9 +291,9 @@
         mFalsingManager.onBouncerHidden();
         mCallback.onBouncerVisiblityChanged(false /* shown */);
         cancelShowRunnable();
-        if (mKeyguardView != null) {
-            mKeyguardView.cancelDismissAction();
-            mKeyguardView.cleanUp();
+        if (mKeyguardViewController != null) {
+            mKeyguardViewController.cancelDismissAction();
+            mKeyguardViewController.cleanUp();
         }
         mIsAnimatingAway = false;
         if (mRoot != null) {
@@ -328,8 +312,8 @@
      */
     public void startPreHideAnimation(Runnable runnable) {
         mIsAnimatingAway = true;
-        if (mKeyguardView != null) {
-            mKeyguardView.startDisappearAnimation(runnable);
+        if (mKeyguardViewController != null) {
+            mKeyguardViewController.startDisappearAnimation(runnable);
         } else if (runnable != null) {
             runnable.run();
         }
@@ -345,8 +329,9 @@
     }
 
     public void onScreenTurnedOff() {
-        if (mKeyguardView != null && mRoot != null && mRoot.getVisibility() == View.VISIBLE) {
-            mKeyguardView.onPause();
+        if (mKeyguardViewController != null
+                && mRoot != null && mRoot.getVisibility() == View.VISIBLE) {
+            mKeyguardViewController.onPause();
         }
     }
 
@@ -380,7 +365,7 @@
     }
 
     private void showPrimarySecurityScreen() {
-        mKeyguardView.showPrimarySecurityScreen();
+        mKeyguardViewController.showPrimarySecurityScreen();
     }
 
     /**
@@ -391,10 +376,8 @@
     public void setExpansion(float fraction) {
         float oldExpansion = mExpansion;
         mExpansion = fraction;
-        if (mKeyguardView != null && !mIsAnimatingAway) {
-            float alpha = MathUtils.map(ALPHA_EXPANSION_THRESHOLD, 1, 1, 0, fraction);
-            mKeyguardView.setAlpha(MathUtils.constrain(alpha, 0f, 1f));
-            mKeyguardView.setTranslationY(fraction * mKeyguardView.getHeight());
+        if (mKeyguardViewController != null && !mIsAnimatingAway) {
+            mKeyguardViewController.setExpansion(fraction);
         }
 
         if (fraction == EXPANSION_VISIBLE && oldExpansion != EXPANSION_VISIBLE) {
@@ -405,28 +388,22 @@
             mExpansionCallback.onFullyHidden();
         } else if (fraction != EXPANSION_VISIBLE && oldExpansion == EXPANSION_VISIBLE) {
             mExpansionCallback.onStartingToHide();
-            if (mKeyguardView != null) {
-                mKeyguardView.onStartingToHide();
+            if (mKeyguardViewController != null) {
+                mKeyguardViewController.onStartingToHide();
             }
         }
     }
 
     public boolean willDismissWithAction() {
-        return mKeyguardView != null && mKeyguardView.hasDismissActions();
+        return mKeyguardViewController != null && mKeyguardViewController.hasDismissActions();
     }
 
     public int getTop() {
-        if (mKeyguardView == null) {
+        if (mKeyguardViewController == null) {
             return 0;
         }
 
-        int top = mKeyguardView.getTop();
-        // The password view has an extra top padding that should be ignored.
-        if (mKeyguardView.getCurrentSecurityMode() == SecurityMode.Password) {
-            View messageArea = mKeyguardView.findViewById(R.id.keyguard_message_area);
-            top += messageArea.getTop();
-        }
-        return top;
+        return mKeyguardViewController.getTop();
     }
 
     protected void ensureView() {
@@ -442,10 +419,13 @@
     protected void inflateView() {
         removeView();
         mHandler.removeCallbacks(mRemoveViewRunnable);
-        mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null);
-        mKeyguardView = mRoot.findViewById(R.id.keyguard_host_view);
-        mKeyguardView.setLockPatternUtils(mLockPatternUtils);
-        mKeyguardView.setViewMediatorCallback(mCallback);
+        KeyguardBouncerComponent component = mKeyguardBouncerComponentFactory.create();
+        mRootViewController = component.getKeyguardRootViewController();
+        mRootViewController.init();
+        mRoot = mRootViewController.getView();  // TODO(b/166448040): Don't access root view here.
+        mKeyguardViewController = component.getKeyguardHostViewController();
+        mKeyguardViewController.init();
+
         mContainer.addView(mRoot, mContainer.getChildCount());
         mStatusBarHeight = mRoot.getResources().getDimensionPixelOffset(
                 com.android.systemui.R.dimen.status_bar_height);
@@ -465,7 +445,7 @@
     }
 
     public boolean onBackPressed() {
-        return mKeyguardView != null && mKeyguardView.handleBackKey();
+        return mKeyguardViewController != null && mKeyguardViewController.handleBackKey();
     }
 
     /**
@@ -473,7 +453,7 @@
      * notifications on Keyguard, like SIM PIN/PUK.
      */
     public boolean needsFullscreenBouncer() {
-        SecurityMode mode = Dependency.get(KeyguardSecurityModel.class).getSecurityMode(
+        SecurityMode mode = mKeyguardSecurityModel.getSecurityMode(
                 KeyguardUpdateMonitor.getCurrentUser());
         return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;
     }
@@ -483,8 +463,8 @@
      * makes this method much faster.
      */
     public boolean isFullscreenBouncer() {
-        if (mKeyguardView != null) {
-            SecurityMode mode = mKeyguardView.getCurrentSecurityMode();
+        if (mKeyguardViewController != null) {
+            SecurityMode mode = mKeyguardViewController.getCurrentSecurityMode();
             return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;
         }
         return false;
@@ -494,21 +474,22 @@
      * WARNING: This method might cause Binder calls.
      */
     public boolean isSecure() {
-        return mKeyguardView == null || mKeyguardView.getSecurityMode() != SecurityMode.None;
+        return mKeyguardSecurityModel.getSecurityMode(
+                KeyguardUpdateMonitor.getCurrentUser()) != SecurityMode.None;
     }
 
     public boolean shouldDismissOnMenuPressed() {
-        return mKeyguardView.shouldEnableMenuKey();
+        return mKeyguardViewController.shouldEnableMenuKey();
     }
 
     public boolean interceptMediaKey(KeyEvent event) {
         ensureView();
-        return mKeyguardView.interceptMediaKey(event);
+        return mKeyguardViewController.interceptMediaKey(event);
     }
 
     public void notifyKeyguardAuthenticated(boolean strongAuth) {
         ensureView();
-        mKeyguardView.finish(strongAuth, KeyguardUpdateMonitor.getCurrentUser());
+        mKeyguardViewController.finish(strongAuth, KeyguardUpdateMonitor.getCurrentUser());
     }
 
     public void dump(PrintWriter pw) {
@@ -516,8 +497,8 @@
         pw.println("  isShowing(): " + isShowing());
         pw.println("  mStatusBarHeight: " + mStatusBarHeight);
         pw.println("  mExpansion: " + mExpansion);
-        pw.println("  mKeyguardView; " + mKeyguardView);
-        pw.println("  mShowingSoon: " + mKeyguardView);
+        pw.println("  mKeyguardViewController; " + mKeyguardViewController);
+        pw.println("  mShowingSoon: " + mShowingSoon);
         pw.println("  mBouncerPromptReason: " + mBouncerPromptReason);
         pw.println("  mIsAnimatingAway: " + mIsAnimatingAway);
     }
@@ -528,4 +509,46 @@
         void onStartingToShow();
         void onFullyHidden();
     }
+
+    /** Create a {@link KeyguardBouncer} once a container and bouncer callback are available. */
+    public static class Factory {
+        private final Context mContext;
+        private final ViewMediatorCallback mCallback;
+        private final DismissCallbackRegistry mDismissCallbackRegistry;
+        private final FalsingManager mFalsingManager;
+        private final KeyguardStateController mKeyguardStateController;
+        private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+        private final KeyguardBypassController mKeyguardBypassController;
+        private final Handler mHandler;
+        private final KeyguardSecurityModel mKeyguardSecurityModel;
+        private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
+
+        @Inject
+        public Factory(Context context, ViewMediatorCallback callback,
+                DismissCallbackRegistry dismissCallbackRegistry, FalsingManager falsingManager,
+                KeyguardStateController keyguardStateController,
+                KeyguardUpdateMonitor keyguardUpdateMonitor,
+                KeyguardBypassController keyguardBypassController, Handler handler,
+                KeyguardSecurityModel keyguardSecurityModel,
+                KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) {
+            mContext = context;
+            mCallback = callback;
+            mDismissCallbackRegistry = dismissCallbackRegistry;
+            mFalsingManager = falsingManager;
+            mKeyguardStateController = keyguardStateController;
+            mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+            mKeyguardBypassController = keyguardBypassController;
+            mHandler = handler;
+            mKeyguardSecurityModel = keyguardSecurityModel;
+            mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory;
+        }
+
+        public KeyguardBouncer create(@RootView ViewGroup container,
+                BouncerExpansionCallback expansionCallback) {
+            return new KeyguardBouncer(mContext, mCallback, container,
+                    mDismissCallbackRegistry, mFalsingManager, expansionCallback,
+                    mKeyguardStateController, mKeyguardUpdateMonitor, mKeyguardBypassController,
+                    mHandler, mKeyguardSecurityModel, mKeyguardBouncerComponentFactory);
+        }
+    }
 }
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 b56993b..51209d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -44,7 +44,6 @@
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.keyguard.KeyguardViewController;
 import com.android.keyguard.ViewMediatorCallback;
-import com.android.keyguard.dagger.KeyguardBouncerComponent;
 import com.android.settingslib.animation.AppearAnimationUtils;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.dagger.SysUISingleton;
@@ -104,7 +103,7 @@
     private final NavigationModeController mNavigationModeController;
     private final NotificationShadeWindowController mNotificationShadeWindowController;
     private final Optional<FaceAuthScreenBrightnessController> mFaceAuthScreenBrightnessController;
-    private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
+    private final KeyguardBouncer.Factory mKeyguardBouncerFactory;
     private final BouncerExpansionCallback mExpansionCallback = new BouncerExpansionCallback() {
         @Override
         public void onFullyShown() {
@@ -216,7 +215,7 @@
             KeyguardStateController keyguardStateController,
             Optional<FaceAuthScreenBrightnessController> faceAuthScreenBrightnessController,
             NotificationMediaManager notificationMediaManager,
-            KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) {
+            KeyguardBouncer.Factory keyguardBouncerFactory) {
         mContext = context;
         mViewMediatorCallback = callback;
         mLockPatternUtils = lockPatternUtils;
@@ -229,7 +228,7 @@
         mStatusBarStateController = sysuiStatusBarStateController;
         mDockManager = dockManager;
         mFaceAuthScreenBrightnessController = faceAuthScreenBrightnessController;
-        mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory;
+        mKeyguardBouncerFactory = keyguardBouncerFactory;
     }
 
     @Override
@@ -246,9 +245,7 @@
             mLastLockVisible = mLockIconContainer.getVisibility() == View.VISIBLE;
         }
         mBiometricUnlockController = biometricUnlockController;
-        mBouncer = mKeyguardBouncerComponentFactory
-                .build(container, mExpansionCallback)
-                .createKeyguardBouncer();
+        mBouncer = mKeyguardBouncerFactory.create(container, mExpansionCallback);
         mNotificationPanelViewController = notificationPanelViewController;
         notificationPanelViewController.addExpansionListener(this);
         mBypassController = bypassController;
diff --git a/packages/SystemUI/src/com/android/systemui/util/ViewController.java b/packages/SystemUI/src/com/android/systemui/util/ViewController.java
new file mode 100644
index 0000000..64f8dbb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/ViewController.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.systemui.util;
+
+import android.view.View;
+import android.view.View.OnAttachStateChangeListener;
+
+/**
+ * Utility class that handles view lifecycle events for View Controllers.
+ *
+ * Implementations should handle setup and teardown related activities inside of
+ * {@link #onViewAttached()} and {@link  #onViewDetached()}.
+ *
+ * @param <T> View class that this ViewController is for.
+ */
+public abstract class ViewController<T extends View> {
+    protected final T mView;
+    private boolean mInited;
+
+    private OnAttachStateChangeListener mOnAttachStateListener = new OnAttachStateChangeListener() {
+        @Override
+        public void onViewAttachedToWindow(View v) {
+            ViewController.this.onViewAttached();
+        }
+
+        @Override
+        public void onViewDetachedFromWindow(View v) {
+            ViewController.this.onViewDetached();
+        }
+    };
+
+    protected ViewController(T view) {
+        mView = view;
+    }
+
+    /** Call immediately after constructing Controller in order to handle view lifecycle events. */
+    public void init() {
+        if (mInited) {
+            return;
+        }
+        mInited = true;
+
+        if (mView.isAttachedToWindow()) {
+            mOnAttachStateListener.onViewAttachedToWindow(mView);
+        }
+        mView.addOnAttachStateChangeListener(mOnAttachStateListener);
+    }
+
+    /**
+     * Called when the view is attached and a call to {@link #init()} has been made in either order.
+     */
+    protected abstract void onViewAttached();
+
+    /**
+     * Called when the view is detached.
+     */
+    protected abstract void onViewDetached();
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java
similarity index 61%
rename from packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewTest.java
rename to packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java
index dd5c833..54e879e 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardHostViewControllerTest.java
@@ -11,7 +11,7 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
 
 package com.android.keyguard;
@@ -19,11 +19,12 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 
+import android.media.AudioManager;
+import android.telephony.TelephonyManager;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
-import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 
@@ -39,41 +40,44 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
-public class KeyguardHostViewTest extends SysuiTestCase {
+public class KeyguardHostViewControllerTest extends SysuiTestCase {
 
     @Mock
-    private KeyguardSecurityContainer mSecurityContainer;
+    private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @Mock
-    private LockPatternUtils mLockPatternUtils;
+    private KeyguardHostView mKeyguardHostView;
+    @Mock
+    private KeyguardSecurityContainerController mKeyguardSecurityContainerController;
+    @Mock
+    private AudioManager mAudioManager;
+    @Mock
+    private TelephonyManager mTelephonyManager;
+    @Mock
+    private ViewMediatorCallback mViewMediatorCallback;
+
     @Rule
     public MockitoRule mMockitoRule = MockitoJUnit.rule();
 
-    private KeyguardHostView mKeyguardHostView;
+    private KeyguardHostViewController mKeyguardHostViewController;
 
     @Before
     public void setup() {
-        mDependency.injectMockDependency(KeyguardUpdateMonitor.class);
-        mKeyguardHostView = new KeyguardHostView(getContext()) {
-            @Override
-            protected void onFinishInflate() {
-                mSecurityContainer = KeyguardHostViewTest.this.mSecurityContainer;
-                mLockPatternUtils = KeyguardHostViewTest.this.mLockPatternUtils;
-            }
-        };
-        mKeyguardHostView.onFinishInflate();
+        mKeyguardHostViewController = new KeyguardHostViewController(
+                mKeyguardHostView, mKeyguardUpdateMonitor, mKeyguardSecurityContainerController,
+                mAudioManager, mTelephonyManager, mViewMediatorCallback);
     }
 
     @Test
     public void testHasDismissActions() {
-        Assert.assertFalse("Action not set yet", mKeyguardHostView.hasDismissActions());
-        mKeyguardHostView.setOnDismissAction(mock(OnDismissAction.class),
+        Assert.assertFalse("Action not set yet", mKeyguardHostViewController.hasDismissActions());
+        mKeyguardHostViewController.setOnDismissAction(mock(OnDismissAction.class),
                 null /* cancelAction */);
-        Assert.assertTrue("Action should exist", mKeyguardHostView.hasDismissActions());
+        Assert.assertTrue("Action should exist", mKeyguardHostViewController.hasDismissActions());
     }
 
     @Test
     public void testOnStartingToHide() {
-        mKeyguardHostView.onStartingToHide();
-        verify(mSecurityContainer).onStartingToHide();
+        mKeyguardHostViewController.onStartingToHide();
+        verify(mKeyguardSecurityContainerController).onStartingToHide();
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessControllerTest.kt
index 58cb032..73a7ca9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessControllerTest.kt
@@ -87,6 +87,8 @@
             override fun createAnimator(start: Float, end: Float) = animator
         }
         `when`(systemSettings.getFloat(eq(SCREEN_BRIGHTNESS_FLOAT))).thenReturn(INITIAL_BRIGHTNESS)
+        `when`(systemSettings.getFloat(eq(SCREEN_BRIGHTNESS_FLOAT), eq(1f)))
+                .thenReturn(INITIAL_BRIGHTNESS)
         faceAuthScreenBrightnessController.attach(whiteOverlay)
         verify(keyguardUpdateMonitor).registerCallback(capture(keyguardUpdateCallback))
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt
index 25fb7d3..1f10d01 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt
@@ -32,6 +32,7 @@
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
 import org.junit.Before
+import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
@@ -106,6 +107,7 @@
     }
 
     @Test
+    @Ignore // TODO(b/168209929)
     fun testMicCameraChanged() {
         changeMicCamera(false) // default is true
         executor.runAllReady()
@@ -129,6 +131,7 @@
     }
 
     @Test
+    @Ignore // TODO(b/168209929)
     fun testBothChanged() {
         changeAll(true)
         changeMicCamera(false)
@@ -150,6 +153,7 @@
     }
 
     @Test
+    @Ignore // TODO(b/168209929)
     fun testMicCamera_listening() {
         changeMicCamera(true)
         executor.runAllReady()
@@ -158,6 +162,7 @@
     }
 
     @Test
+    @Ignore // TODO(b/168209929)
     fun testAllFalse_notListening() {
         changeAll(true)
         executor.runAllReady()
@@ -169,6 +174,7 @@
     }
 
     @Test
+    @Ignore // TODO(b/168209929)
     fun testSomeListening_stillListening() {
         // Mic and camera are true by default
         changeAll(true)
@@ -180,6 +186,7 @@
     }
 
     @Test
+    @Ignore // TODO(b/168209929)
     fun testAllDeleted_micCameraFalse_stopListening() {
         changeMicCamera(false)
         changeAll(true)
@@ -191,6 +198,7 @@
     }
 
     @Test
+    @Ignore // TODO(b/168209929)
     fun testMicDeleted_stillListening() {
         changeMicCamera(true)
         executor.runAllReady()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
index f152a74..0a079b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
@@ -43,6 +43,7 @@
 import org.junit.Assert.assertThat
 import org.junit.Assert.assertTrue
 import org.junit.Before
+import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
@@ -271,6 +272,7 @@
     }
 
     @Test
+    @Ignore // TODO(b/168209929)
     fun testNotListeningWhenIndicatorsDisabled() {
         changeAll(false)
         changeMicCamera(false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index 0a041e4..1b05ad7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -38,16 +38,16 @@
 import android.testing.TestableLooper;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
 import android.widget.FrameLayout;
 
 import androidx.test.filters.SmallTest;
 
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardHostView;
+import com.android.keyguard.KeyguardHostViewController;
+import com.android.keyguard.KeyguardRootViewController;
 import com.android.keyguard.KeyguardSecurityModel;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.ViewMediatorCallback;
+import com.android.keyguard.dagger.KeyguardBouncerComponent;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
@@ -76,13 +76,9 @@
     @Mock
     private ViewMediatorCallback mViewMediatorCallback;
     @Mock
-    private LockPatternUtils mLockPatternUtils;
-    @Mock
     private DismissCallbackRegistry mDismissCallbackRegistry;
     @Mock
-    private KeyguardHostView mKeyguardHostView;
-    @Mock
-    private ViewTreeObserver mViewTreeObserver;
+    private KeyguardHostViewController mKeyguardHostViewController;
     @Mock
     private KeyguardBouncer.BouncerExpansionCallback mExpansionCallback;
     @Mock
@@ -96,7 +92,13 @@
     @Mock
     private KeyguardSecurityModel mKeyguardSecurityModel;
     @Mock
+    private KeyguardRootViewController mRootViewController;
+    @Mock
     private ViewGroup mRootView;
+    @Mock
+    private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
+    @Mock
+    private KeyguardBouncerComponent mKeyguardBouncerComponent;
     @Rule
     public MockitoRule mRule = MockitoJUnit.rule();
     private Integer mRootVisibility = View.INVISIBLE;
@@ -106,7 +108,6 @@
     public void setup() {
         allowTestableLooperAsMainThread();
         mDependency.injectTestDependency(KeyguardUpdateMonitor.class, mKeyguardUpdateMonitor);
-        mDependency.injectTestDependency(KeyguardSecurityModel.class, mKeyguardSecurityModel);
         mDependency.injectMockDependency(KeyguardStateController.class);
         when(mRootView.getVisibility()).thenAnswer((Answer<Integer>) invocation -> mRootVisibility);
         doAnswer(invocation -> {
@@ -116,19 +117,22 @@
         when(mKeyguardSecurityModel.getSecurityMode(anyInt()))
                 .thenReturn(KeyguardSecurityModel.SecurityMode.None);
         DejankUtils.setImmediate(true);
+        when(mKeyguardBouncerComponentFactory.create()).thenReturn(mKeyguardBouncerComponent);
+        when(mKeyguardBouncerComponent.getKeyguardHostViewController())
+                .thenReturn(mKeyguardHostViewController);
+        when(mKeyguardBouncerComponent.getKeyguardRootViewController())
+                .thenReturn(mRootViewController);
+
+        when(mRootViewController.getView()).thenReturn(mRootView);
+        when(mRootView.getResources()).thenReturn(mContext.getResources());
+
         final ViewGroup container = new FrameLayout(getContext());
-        when(mKeyguardHostView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
-        when(mKeyguardHostView.getHeight()).thenReturn(500);
-        mBouncer = new KeyguardBouncer(getContext(), mViewMediatorCallback,
-                mLockPatternUtils, container, mDismissCallbackRegistry, mFalsingManager,
-                mExpansionCallback, mKeyguardStateController, mKeyguardUpdateMonitor,
-                mKeyguardBypassController, mHandler) {
-            @Override
-            protected void inflateView() {
-                mKeyguardView = mKeyguardHostView;
-                mRoot = mRootView;
-            }
-        };
+        mBouncer = new KeyguardBouncer.Factory(getContext(), mViewMediatorCallback,
+                mDismissCallbackRegistry, mFalsingManager,
+                mKeyguardStateController, mKeyguardUpdateMonitor,
+                mKeyguardBypassController, mHandler, mKeyguardSecurityModel,
+                mKeyguardBouncerComponentFactory)
+                .create(container, mExpansionCallback);
     }
 
     @Test
@@ -154,12 +158,10 @@
         mBouncer.ensureView();
         mBouncer.setExpansion(1);
 
-        reset(mKeyguardHostView);
-        when(mKeyguardHostView.getHeight()).thenReturn(500);
+        reset(mKeyguardHostViewController);
 
         mBouncer.show(true);
-        verify(mKeyguardHostView).setAlpha(eq(1f));
-        verify(mKeyguardHostView).setTranslationY(eq(0f));
+        verify(mKeyguardHostViewController).setExpansion(0);
     }
 
     @Test
@@ -177,23 +179,23 @@
     @Test
     public void testShow_triesToDismissKeyguard() {
         mBouncer.show(true);
-        verify(mKeyguardHostView).dismiss(anyInt());
+        verify(mKeyguardHostViewController).dismiss(anyInt());
     }
 
     @Test
     public void testShow_resetsSecuritySelection() {
         mBouncer.show(false);
-        verify(mKeyguardHostView, never()).showPrimarySecurityScreen();
+        verify(mKeyguardHostViewController, never()).showPrimarySecurityScreen();
 
         mBouncer.hide(false);
         mBouncer.show(true);
-        verify(mKeyguardHostView).showPrimarySecurityScreen();
+        verify(mKeyguardHostViewController).showPrimarySecurityScreen();
     }
 
     @Test
     public void testShow_animatesKeyguardView() {
         mBouncer.show(true);
-        verify(mKeyguardHostView).startAppearAnimation();
+        verify(mKeyguardHostViewController).appear(anyInt());
     }
 
     @Test
@@ -201,7 +203,7 @@
         final String errorMessage = "an error message";
         when(mViewMediatorCallback.consumeCustomMessage()).thenReturn(errorMessage);
         mBouncer.show(true);
-        verify(mKeyguardHostView).showErrorMessage(eq(errorMessage));
+        verify(mKeyguardHostViewController).showErrorMessage(eq(errorMessage));
     }
 
     @Test
@@ -218,10 +220,10 @@
         verify(mExpansionCallback).onFullyShown();
 
         verify(mExpansionCallback, never()).onStartingToHide();
-        verify(mKeyguardHostView, never()).onStartingToHide();
+        verify(mKeyguardHostViewController, never()).onStartingToHide();
         mBouncer.setExpansion(0.9f);
         verify(mExpansionCallback).onStartingToHide();
-        verify(mKeyguardHostView).onStartingToHide();
+        verify(mKeyguardHostViewController).onStartingToHide();
     }
 
     @Test
@@ -230,7 +232,7 @@
         mBouncer.setExpansion(0.1f);
 
         mBouncer.setExpansion(0);
-        verify(mKeyguardHostView).onResume();
+        verify(mKeyguardHostViewController).onResume();
         verify(mRootView).announceForAccessibility(any());
     }
 
@@ -267,7 +269,7 @@
     public void testShowPromptReason_propagates() {
         mBouncer.ensureView();
         mBouncer.showPromptReason(1);
-        verify(mKeyguardHostView).showPromptReason(eq(1));
+        verify(mKeyguardHostViewController).showPromptReason(eq(1));
     }
 
     @Test
@@ -275,7 +277,8 @@
         final String message = "a message";
         mBouncer.ensureView();
         mBouncer.showMessage(message, ColorStateList.valueOf(Color.GREEN));
-        verify(mKeyguardHostView).showMessage(eq(message), eq(ColorStateList.valueOf(Color.GREEN)));
+        verify(mKeyguardHostViewController).showMessage(
+                eq(message), eq(ColorStateList.valueOf(Color.GREEN)));
     }
 
     @Test
@@ -283,7 +286,7 @@
         final OnDismissAction dismissAction = () -> false;
         final Runnable cancelAction = () -> {};
         mBouncer.showWithDismissAction(dismissAction, cancelAction);
-        verify(mKeyguardHostView).setOnDismissAction(dismissAction, cancelAction);
+        verify(mKeyguardHostViewController).setOnDismissAction(dismissAction, cancelAction);
         Assert.assertTrue("Should be showing", mBouncer.isShowing());
     }
 
@@ -297,7 +300,7 @@
         ran[0] = false;
         mBouncer.ensureView();
         mBouncer.startPreHideAnimation(r);
-        verify(mKeyguardHostView).startDisappearAnimation(r);
+        verify(mKeyguardHostViewController).startDisappearAnimation(r);
         Assert.assertFalse("Callback should have been deferred", ran[0]);
     }
 
@@ -322,16 +325,14 @@
     public void testSetExpansion() {
         mBouncer.ensureView();
         mBouncer.setExpansion(0.5f);
-        verify(mKeyguardHostView).setAlpha(anyFloat());
-        verify(mKeyguardHostView).setTranslationY(anyFloat());
+        verify(mKeyguardHostViewController).setExpansion(0.5f);
     }
 
     @Test
     public void testIsFullscreenBouncer_asksKeyguardView() {
         mBouncer.ensureView();
         mBouncer.isFullscreenBouncer();
-        verify(mKeyguardHostView).getCurrentSecurityMode();
-        verify(mKeyguardHostView, never()).getSecurityMode();
+        verify(mKeyguardHostViewController).getCurrentSecurityMode();
     }
 
     @Test
@@ -346,21 +347,18 @@
     @Test
     public void testIsHiding_skipsTranslation() {
         mBouncer.show(false /* reset */);
-        reset(mKeyguardHostView);
+        reset(mKeyguardHostViewController);
         mBouncer.startPreHideAnimation(null /* runnable */);
         mBouncer.setExpansion(0.5f);
-        verify(mKeyguardHostView, never()).setTranslationY(anyFloat());
-        verify(mKeyguardHostView, never()).setAlpha(anyFloat());
+        verify(mKeyguardHostViewController, never()).setExpansion(anyFloat());
     }
 
     @Test
     public void testIsSecure() {
-        Assert.assertTrue("Bouncer is secure before inflating views", mBouncer.isSecure());
-
         mBouncer.ensureView();
         for (KeyguardSecurityModel.SecurityMode mode : KeyguardSecurityModel.SecurityMode.values()){
-            reset(mKeyguardHostView);
-            when(mKeyguardHostView.getSecurityMode()).thenReturn(mode);
+            reset(mKeyguardSecurityModel);
+            when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(mode);
             Assert.assertEquals("Security doesn't match for mode: " + mode,
                     mBouncer.isSecure(), mode != KeyguardSecurityModel.SecurityMode.None);
         }
@@ -392,7 +390,7 @@
     public void testWillDismissWithAction() {
         mBouncer.ensureView();
         Assert.assertFalse("Action not set yet", mBouncer.willDismissWithAction());
-        when(mKeyguardHostView.hasDismissActions()).thenReturn(true);
+        when(mKeyguardHostViewController.hasDismissActions()).thenReturn(true);
         Assert.assertTrue("Action should exist", mBouncer.willDismissWithAction());
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 1083273..9832d31 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -39,7 +39,6 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.ViewMediatorCallback;
-import com.android.keyguard.dagger.KeyguardBouncerComponent;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
@@ -92,9 +91,7 @@
     @Mock
     private FaceAuthScreenBrightnessController mFaceAuthScreenBrightnessController;
     @Mock
-    private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
-    @Mock
-    private KeyguardBouncerComponent mKeyguardBouncerComponent;
+    private KeyguardBouncer.Factory mKeyguardBouncerFactory;
     @Mock
     private KeyguardBouncer mBouncer;
 
@@ -107,11 +104,10 @@
         when(mLockIconContainer.animate()).thenReturn(mock(ViewPropertyAnimator.class,
                 RETURNS_DEEP_STUBS));
 
-        when(mKeyguardBouncerComponentFactory.build(
+        when(mKeyguardBouncerFactory.create(
                 any(ViewGroup.class),
                 any(KeyguardBouncer.BouncerExpansionCallback.class)))
-                .thenReturn(mKeyguardBouncerComponent);
-        when(mKeyguardBouncerComponent.createKeyguardBouncer()).thenReturn(mBouncer);
+                .thenReturn(mBouncer);
 
         mStatusBarKeyguardViewManager = new StatusBarKeyguardViewManager(
                 getContext(),
@@ -126,7 +122,7 @@
                 mKeyguardStateController,
                 Optional.of(mFaceAuthScreenBrightnessController),
                 mock(NotificationMediaManager.class),
-                mKeyguardBouncerComponentFactory);
+                mKeyguardBouncerFactory);
         mStatusBarKeyguardViewManager.registerStatusBar(mStatusBar, mContainer,
                 mNotificationPanelView, mBiometrucUnlockController,
                 mLockIconContainer, mNotificationContainer, mBypassController);
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_notifications_alert.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_notifications_alert.xml
new file mode 100644
index 0000000..e66d920
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_notifications_alert.xml
@@ -0,0 +1,34 @@
+<?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:height="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M5.85,3.01C3.72,4.82,2.5,7.46,2.5,10.25C2.5,10.66,2.84,11,3.25,11S4,10.66,4,10.25c0-2.35,1.03-4.57,2.82-6.1 C7.14,3.88,7.17,3.41,6.91,3.1C6.64,2.78,6.17,2.74,5.85,3.01z" />
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M21.5,10.25c0-2.79-1.22-5.43-3.35-7.24c-0.32-0.27-0.79-0.23-1.06,0.08c-0.27,0.32-0.23,0.79,0.08,1.06 C18.97,5.68,20,7.9,20,10.25c0,0.41,0.34,0.75,0.75,0.75S21.5,10.66,21.5,10.25z" />
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M12,2.5c-0.83,0-1.5,0.67-1.5,1.5v0.7C7.91,5.36,6,7.71,6,10.5V15c0,0.55-0.45,1-1,1s-1,0.45-1,1v2h16v-2 c0-0.55-0.45-1-1-1s-1-0.45-1-1v-4.5c0-2.79-1.91-5.14-4.5-5.8V4C13.5,3.17,12.83,2.5,12,2.5z M16.5,10.5V15 c0,1.21,0.86,2.22,2,2.45v0.05h-13v-0.05c1.14-0.23,2-1.24,2-2.45v-4.5C7.5,8.02,9.52,6,12,6S16.5,8.02,16.5,10.5z" />
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M14,20h-4c0,1.1,0.9,2,2,2S14,21.1,14,20z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_notifications_alert.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_notifications_alert.xml
new file mode 100644
index 0000000..2f5bdb0e
--- /dev/null
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_notifications_alert.xml
@@ -0,0 +1,34 @@
+<?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:height="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M4.12,9.67C4.42,7.73,5.38,6,6.77,4.73C7.19,4.35,7.2,3.7,6.8,3.3c-0.39-0.39-1-0.39-1.4-0.03 C3.7,4.84,2.52,6.96,2.15,9.34c-0.1,0.61,0.37,1.16,0.99,1.16C3.63,10.5,4.04,10.15,4.12,9.67z" />
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M18.6,3.28c-0.4-0.37-1.02-0.36-1.4,0.02c-0.4,0.4-0.38,1.04,0.03,1.42c1.38,1.27,2.35,3,2.65,4.94 c0.08,0.49,0.5,0.84,0.98,0.84c0.61,0,1.09-0.55,0.99-1.16C21.47,6.96,20.29,4.84,18.6,3.28z" />
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M12,22c1.1,0,2-0.9,2-2h-4C10,21.1,10.9,22,12,22z" />
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M18,16v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-0.83-0.67-1.5-1.5-1.5S10.5,3.17,10.5,4v0.68C7.63,5.36,6,7.92,6,11v5 l-2.15,2.15c-0.19,0.2-0.19,0.51,0.01,0.71C3.95,18.95,4.07,19,4.2,19h15.6c0.45,0,0.67-0.54,0.35-0.85L18,16z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackKaiSettingsOverlay/res/drawable/ic_notifications_alert.xml b/packages/overlays/IconPackKaiSettingsOverlay/res/drawable/ic_notifications_alert.xml
new file mode 100644
index 0000000..c92bdf6
--- /dev/null
+++ b/packages/overlays/IconPackKaiSettingsOverlay/res/drawable/ic_notifications_alert.xml
@@ -0,0 +1,21 @@
+<!--
+   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 android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+  <path android:fillColor="@android:color/white" android:pathData="M6.81,3.81L5.75,2.75C3.45,4.76,2,7.71,2,11h1.5C3.5,8.13,4.79,5.55,6.81,3.81z"/>
+  <path android:fillColor="@android:color/white" android:pathData="M18.25,2.75l-1.06,1.06C19.21,5.55,20.5,8.13,20.5,11H22C22,7.71,20.55,4.76,18.25,2.75z"/>
+  <path android:fillColor="@android:color/white" android:pathData="M18,10.5c0-4.38-2.72-5.57-4.5-5.89V4c0-1.59-1.43-1.5-1.5-1.5c-0.05,0-1.5-0.09-1.5,1.5v0.62C8.72,4.94,6,6.14,6,10.5v7 H4V19h16v-1.5h-2V10.5z M16.5,17.5h-9v-7C7.5,7.57,8.94,5.95,12,6c3.07-0.05,4.5,1.55,4.5,4.5V17.5z"/>
+  <path android:fillColor="@android:color/white" android:pathData="M12,22c0.07,0,2,0.12,2-2h-4C10,22.12,11.91,22,12,22z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_notifications_alert.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_notifications_alert.xml
new file mode 100644
index 0000000..8f854e7
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_notifications_alert.xml
@@ -0,0 +1,34 @@
+<?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:height="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M14,20h-4c0,1.1,0.9,2,2,2S14,21.1,14,20z" />
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M12,2.5c-0.69,0-1.25,0.56-1.25,1.25v0.77C8.04,5.11,6,7.51,6,10.4V17H4.75C4.34,17,4,17.34,4,17.75s0.34,0.75,0.75,0.75 h14.5c0.41,0,0.75-0.34,0.75-0.75S19.66,17,19.25,17H18v-6.6c0-2.88-2.04-5.29-4.75-5.87V3.75C13.25,3.06,12.69,2.5,12,2.5z M16.5,10.4V17h-9v-6.6c0-2.48,2.02-4.5,4.5-4.5S16.5,7.91,16.5,10.4z" />
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M5.85,3.01C3.72,4.82,2.5,7.46,2.5,10.25C2.5,10.66,2.84,11,3.25,11S4,10.66,4,10.25c0-2.35,1.03-4.57,2.82-6.1 C7.14,3.88,7.17,3.41,6.91,3.1C6.64,2.78,6.17,2.74,5.85,3.01z" />
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M18.15,3.01c-0.32-0.27-0.79-0.23-1.06,0.08c-0.27,0.32-0.23,0.79,0.08,1.06C18.97,5.68,20,7.9,20,10.25 c0,0.41,0.34,0.75,0.75,0.75s0.75-0.34,0.75-0.75C21.5,7.46,20.28,4.82,18.15,3.01z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackSamSettingsOverlay/res/drawable/ic_notifications_alert.xml b/packages/overlays/IconPackSamSettingsOverlay/res/drawable/ic_notifications_alert.xml
new file mode 100644
index 0000000..e022c63
--- /dev/null
+++ b/packages/overlays/IconPackSamSettingsOverlay/res/drawable/ic_notifications_alert.xml
@@ -0,0 +1,21 @@
+<!--
+   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 android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+  <path android:fillColor="@android:color/white" android:pathData="M6.47,4.81c0.37-0.38,0.35-0.99-0.03-1.37c-0.4-0.4-1.05-0.39-1.44,0.02c-1.62,1.72-2.7,3.95-2.95,6.43 C2,10.48,2.46,11,3.05,11h0.01c0.51,0,0.93-0.38,0.98-0.88C4.24,8.07,5.13,6.22,6.47,4.81z"/>
+  <path android:fillColor="@android:color/white" android:pathData="M18.99,3.47c-0.39-0.41-1.04-0.42-1.44-0.02c-0.38,0.38-0.39,0.98-0.03,1.37c1.34,1.41,2.23,3.26,2.43,5.3 c0.05,0.5,0.48,0.88,0.98,0.88h0.01c0.59,0,1.05-0.52,0.99-1.11C21.69,7.42,20.61,5.19,18.99,3.47z"/>
+  <path android:fillColor="@android:color/white" android:pathData="M19,17h-1v-6c0-3.07-1.63-5.64-4.5-6.32V4c0-0.83-0.67-1.5-1.5-1.5c-0.83,0-1.5,0.67-1.5,1.5v0.68C7.64,5.36,6,7.92,6,11 v6H5c-0.55,0-1,0.45-1,1c0,0.55,0.45,1,1,1h14c0.55,0,1-0.45,1-1C20,17.45,19.55,17,19,17z"/>
+  <path android:fillColor="@android:color/white" android:pathData="M12,22c1.1,0,2-0.9,2-2h-4C10,21.1,10.9,22,12,22z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackVictorSettingsOverlay/res/drawable/ic_notifications_alert.xml b/packages/overlays/IconPackVictorSettingsOverlay/res/drawable/ic_notifications_alert.xml
new file mode 100644
index 0000000..1e25d27
--- /dev/null
+++ b/packages/overlays/IconPackVictorSettingsOverlay/res/drawable/ic_notifications_alert.xml
@@ -0,0 +1,21 @@
+<!--
+   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 android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+  <path android:fillColor="@android:color/white" android:pathData="M18,6.5L16.5,5H13V3h-2v2H7.5L6,6.5v11H4V19h16v-1.5h-2V6.5z M7.5,17.5v-11h9v11H7.5z"/>
+  <path android:fillColor="@android:color/white" android:pathData="M12,22c1.1,0,2-0.9,2-2h-4C10,21.1,10.9,22,12,22z"/>
+  <path android:fillColor="@android:color/white" android:pathData="M6.81,3.81L5.75,2.75C3.45,4.76,2,7.71,2,11h1.5C3.5,8.13,4.79,5.55,6.81,3.81z"/>
+  <path android:fillColor="@android:color/white" android:pathData="M18.25,2.75l-1.06,1.06C19.21,5.55,20.5,8.13,20.5,11H22C22,7.71,20.55,4.76,18.25,2.75z"/>
+</vector>
\ No newline at end of file
diff --git a/services/backup/java/com/android/server/backup/BackupManagerConstants.java b/services/backup/java/com/android/server/backup/BackupManagerConstants.java
index d8c5f6f..4bd987a 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerConstants.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerConstants.java
@@ -112,7 +112,7 @@
     }
 
     public String getSettingValue(ContentResolver resolver) {
-        return Settings.Secure.getString(resolver, SETTING);
+        return Settings.Secure.getStringForUser(resolver, SETTING, resolver.getUserId());
     }
 
     public synchronized void update(KeyValueListParser parser) {
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 65ac784..d92706d 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -39,6 +39,7 @@
 import android.os.BatteryProperty;
 import android.os.BatteryStats;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.DropBoxManager;
 import android.os.FileUtils;
@@ -59,6 +60,7 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.battery.BatteryServiceDumpProto;
+import android.sysprop.PowerProperties;
 import android.util.EventLog;
 import android.util.MutableInt;
 import android.util.Slog;
@@ -182,6 +184,7 @@
     private int mChargeStartLevel;
 
     private boolean mUpdatesStopped;
+    private boolean mBatteryInputSuspended;
 
     private Led mLed;
 
@@ -234,6 +237,8 @@
             invalidChargerObserver.startObserving(
                     "DEVPATH=/devices/virtual/switch/invalid_charger");
         }
+
+        mBatteryInputSuspended = PowerProperties.battery_input_suspended().orElse(false);
     }
 
     @Override
@@ -876,6 +881,10 @@
         pw.println("  reset [-f]");
         pw.println("    Unfreeze battery state, returning to current hardware values.");
         pw.println("    -f: force a battery change broadcast be sent, prints new sequence.");
+        if (Build.IS_DEBUGGABLE) {
+            pw.println("  disable_charge");
+            pw.println("    Suspend charging even if plugged in. ");
+        }
     }
 
     static final int OPTION_FORCE_UPDATE = 1<<0;
@@ -997,6 +1006,20 @@
                 } finally {
                     Binder.restoreCallingIdentity(ident);
                 }
+                if (mBatteryInputSuspended) {
+                    PowerProperties.battery_input_suspended(false);
+                    mBatteryInputSuspended = false;
+                }
+            } break;
+            case "suspend_input": {
+                if (!Build.IS_DEBUGGABLE) {
+                    throw new SecurityException(
+                            "battery suspend_input is only supported on debuggable builds");
+                }
+                getContext().enforceCallingOrSelfPermission(
+                        android.Manifest.permission.DEVICE_POWER, null);
+                PowerProperties.battery_input_suspended(true);
+                mBatteryInputSuspended = true;
             } break;
             default:
                 return shell.handleDefaultCommands(cmd);
diff --git a/services/core/java/com/android/server/NetworkScorerAppManager.java b/services/core/java/com/android/server/NetworkScorerAppManager.java
index 3bcb36f..4de4075 100644
--- a/services/core/java/com/android/server/NetworkScorerAppManager.java
+++ b/services/core/java/com/android/server/NetworkScorerAppManager.java
@@ -19,6 +19,7 @@
 import android.Manifest.permission;
 import android.annotation.Nullable;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.PermissionChecker;
@@ -404,7 +405,8 @@
         }
 
         public int getSecureInt(Context context, String name, int defaultValue) {
-            return Settings.Secure.getInt(context.getContentResolver(), name, defaultValue);
+            final ContentResolver cr = context.getContentResolver();
+            return Settings.Secure.getIntForUser(cr, name, defaultValue, cr.getUserId());
         }
     }
 }
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 27c5d4a..eb18da2 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -4687,14 +4687,19 @@
             }
         }
 
-        public void onAppOpsChanged(int code, int uid, @Nullable String packageName, int mode) {
+        public void onAppOpsChanged(int code, int uid, @Nullable String packageName, int mode,
+                int previousMode) {
             final long token = Binder.clearCallingIdentity();
             try {
                 // When using FUSE, we may need to kill the app if the op changes
                 switch(code) {
                     case OP_REQUEST_INSTALL_PACKAGES:
-                        // Always kill regardless of op change, to remount apps /storage
-                        killAppForOpChange(code, uid);
+                        if (previousMode == MODE_ALLOWED || mode == MODE_ALLOWED) {
+                            // If we transition to/from MODE_ALLOWED, kill the app to make
+                            // sure it has the correct view of /storage. Changing between
+                            // MODE_DEFAULT / MODE_ERRORED is a no-op
+                            killAppForOpChange(code, uid);
+                        }
                         return;
                     case OP_MANAGE_EXTERNAL_STORAGE:
                         if (mode != MODE_ALLOWED) {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 343e05d..c441bd6 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -768,9 +768,7 @@
         FrameworkStatsLog.write(FrameworkStatsLog.SERVICE_STATE_CHANGED, r.appInfo.uid,
                 r.name.getPackageName(), r.name.getClassName(),
                 FrameworkStatsLog.SERVICE_STATE_CHANGED__STATE__START);
-        synchronized (r.stats.getBatteryStats()) {
-            r.stats.startRunningLocked();
-        }
+        mAm.mBatteryStatsService.noteServiceStartRunning(r.stats);
         String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
         if (error != null) {
             return new ComponentName("!!", error);
@@ -809,9 +807,7 @@
         FrameworkStatsLog.write(FrameworkStatsLog.SERVICE_STATE_CHANGED, service.appInfo.uid,
                 service.name.getPackageName(), service.name.getClassName(),
                 FrameworkStatsLog.SERVICE_STATE_CHANGED__STATE__STOP);
-        synchronized (service.stats.getBatteryStats()) {
-            service.stats.stopRunningLocked();
-        }
+        mAm.mBatteryStatsService.noteServiceStopRunning(service.stats);
         service.startRequested = false;
         if (service.tracker != null) {
             service.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
@@ -970,9 +966,7 @@
             FrameworkStatsLog.write(FrameworkStatsLog.SERVICE_STATE_CHANGED, r.appInfo.uid,
                     r.name.getPackageName(), r.name.getClassName(),
                     FrameworkStatsLog.SERVICE_STATE_CHANGED__STATE__STOP);
-            synchronized (r.stats.getBatteryStats()) {
-                r.stats.stopRunningLocked();
-            }
+            mAm.mBatteryStatsService.noteServiceStopRunning(r.stats);
             r.startRequested = false;
             if (r.tracker != null) {
                 r.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
@@ -2518,7 +2512,8 @@
                     synchronized (stats) {
                         ss = stats.getServiceStatsLocked(
                                 sInfo.applicationInfo.uid, name.getPackageName(),
-                                name.getClassName());
+                                name.getClassName(), SystemClock.elapsedRealtime(),
+                                SystemClock.uptimeMillis());
                     }
                     r = new ServiceRecord(mAm, ss, className, name, definingPackageName,
                             definingUid, filter, sInfo, callingFromFg, res);
@@ -3056,9 +3051,7 @@
             }
             FrameworkStatsLog.write(FrameworkStatsLog.SERVICE_LAUNCH_REPORTED, r.appInfo.uid,
                     r.name.getPackageName(), r.name.getClassName());
-            synchronized (r.stats.getBatteryStats()) {
-                r.stats.startLaunchedLocked();
-            }
+            mAm.mBatteryStatsService.noteServiceStartLaunch(r.stats);
             mAm.notifyPackageUse(r.serviceInfo.packageName,
                                  PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
             app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
@@ -3402,9 +3395,7 @@
         smap.mDelayedStartList.remove(r);
 
         if (r.app != null) {
-            synchronized (r.stats.getBatteryStats()) {
-                r.stats.stopLaunchedLocked();
-            }
+            mAm.mBatteryStatsService.noteServiceStopLaunch(r.stats);
             r.app.stopService(r);
             r.app.updateBoundClientUids();
             if (r.whitelistManager) {
@@ -3940,9 +3931,7 @@
         // Clear app state from services.
         for (int i = app.numberOfRunningServices() - 1; i >= 0; i--) {
             ServiceRecord sr = app.getRunningServiceAt(i);
-            synchronized (sr.stats.getBatteryStats()) {
-                sr.stats.stopLaunchedLocked();
-            }
+            mAm.mBatteryStatsService.noteServiceStopLaunch(sr.stats);
             if (sr.app != app && sr.app != null && !sr.app.isPersistent()) {
                 sr.app.stopService(sr);
                 sr.app.updateBoundClientUids();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2746c2c..7e664966 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -133,7 +133,6 @@
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
 import static com.android.server.wm.ActivityTaskManagerService.relaunchReasonToString;
 
-
 import android.Manifest;
 import android.Manifest.permission;
 import android.annotation.BroadcastBehavior;
@@ -143,8 +142,8 @@
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningTaskInfo;
-import android.app.ActivityManager.StackInfo;
 import android.app.ActivityManagerInternal;
+import android.app.ActivityTaskManager.RootTaskInfo;
 import android.app.ActivityThread;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
@@ -342,7 +341,6 @@
 import com.android.server.ServiceThread;
 import com.android.server.SystemConfig;
 import com.android.server.SystemService;
-import com.android.server.SystemService.TargetUser;
 import com.android.server.SystemServiceManager;
 import com.android.server.ThreadPriorityBooster;
 import com.android.server.UserspaceRebootLogger;
@@ -2835,14 +2833,16 @@
             }
 
             final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
-            synchronized(bstats) {
-                synchronized(mPidsSelfLocked) {
-                    if (haveNewCpuStats) {
-                        if (bstats.startAddingCpuLocked()) {
-                            int totalUTime = 0;
-                            int totalSTime = 0;
-                            final int N = mProcessCpuTracker.countStats();
-                            for (int i=0; i<N; i++) {
+            synchronized (bstats) {
+                if (haveNewCpuStats) {
+                    if (bstats.startAddingCpuLocked()) {
+                        int totalUTime = 0;
+                        int totalSTime = 0;
+                        final int statsCount = mProcessCpuTracker.countStats();
+                        final long elapsedRealtime = SystemClock.elapsedRealtime();
+                        final long uptime = SystemClock.uptimeMillis();
+                        synchronized (mPidsSelfLocked) {
+                            for (int i = 0; i < statsCount; i++) {
                                 ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
                                 if (!st.working) {
                                     continue;
@@ -2854,7 +2854,8 @@
                                     BatteryStatsImpl.Uid.Proc ps = pr.curProcBatteryStats;
                                     if (ps == null || !ps.isActive()) {
                                         pr.curProcBatteryStats = ps = bstats.getProcessStatsLocked(
-                                                pr.info.uid, pr.processName);
+                                                pr.info.uid, pr.processName,
+                                                elapsedRealtime, uptime);
                                     }
                                     ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
                                     pr.curCpuTime += st.rel_utime + st.rel_stime;
@@ -2865,20 +2866,22 @@
                                     BatteryStatsImpl.Uid.Proc ps = st.batteryStats;
                                     if (ps == null || !ps.isActive()) {
                                         st.batteryStats = ps = bstats.getProcessStatsLocked(
-                                                bstats.mapUid(st.uid), st.name);
+                                                bstats.mapUid(st.uid), st.name,
+                                                elapsedRealtime, uptime);
                                     }
                                     ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
                                 }
                             }
-                            final int userTime = mProcessCpuTracker.getLastUserTime();
-                            final int systemTime = mProcessCpuTracker.getLastSystemTime();
-                            final int iowaitTime = mProcessCpuTracker.getLastIoWaitTime();
-                            final int irqTime = mProcessCpuTracker.getLastIrqTime();
-                            final int softIrqTime = mProcessCpuTracker.getLastSoftIrqTime();
-                            final int idleTime = mProcessCpuTracker.getLastIdleTime();
-                            bstats.finishAddingCpuLocked(totalUTime, totalSTime, userTime,
-                                    systemTime, iowaitTime, irqTime, softIrqTime, idleTime);
                         }
+
+                        final int userTime = mProcessCpuTracker.getLastUserTime();
+                        final int systemTime = mProcessCpuTracker.getLastSystemTime();
+                        final int iowaitTime = mProcessCpuTracker.getLastIoWaitTime();
+                        final int irqTime = mProcessCpuTracker.getLastIrqTime();
+                        final int softIrqTime = mProcessCpuTracker.getLastSoftIrqTime();
+                        final int idleTime = mProcessCpuTracker.getLastIdleTime();
+                        bstats.finishAddingCpuLocked(totalUTime, totalSTime, userTime,
+                                systemTime, iowaitTime, irqTime, softIrqTime, idleTime);
                     }
                 }
 
@@ -3076,18 +3079,8 @@
             Slog.d(TAG_SWITCH,
                     "updateBatteryStats: comp=" + activity + "res=" + resumed);
         }
-        final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
-        FrameworkStatsLog.write(FrameworkStatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED,
-                uid, activity.getPackageName(), activity.getShortClassName(),
-                resumed ? FrameworkStatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__FOREGROUND :
-                        FrameworkStatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__BACKGROUND);
-        synchronized (stats) {
-            if (resumed) {
-                stats.noteActivityResumedLocked(uid);
-            } else {
-                stats.noteActivityPausedLocked(uid);
-            }
-        }
+        mBatteryStatsService.updateBatteryStatsOnActivityUsage(activity.getPackageName(),
+                activity.getShortClassName(), uid, userId, resumed);
     }
 
     /**
@@ -3626,10 +3619,7 @@
             }
         }
 
-        BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
-        synchronized (stats) {
-            stats.noteProcessDiedLocked(app.info.uid, pid);
-        }
+        mBatteryStatsService.noteProcessDied(app.info.uid, pid);
 
         if (!app.killed) {
             if (!fromBinderDied) {
@@ -6418,8 +6408,8 @@
     }
 
     @Override
-    public List<StackInfo> getAllStackInfos() {
-        return mActivityTaskManager.getAllStackInfos();
+    public List<RootTaskInfo> getAllRootTaskInfos() {
+        return mActivityTaskManager.getAllRootTaskInfos();
     }
 
     @Override
@@ -14535,10 +14525,7 @@
                                         timeFormatPreferenceMsgValue, 0);
                         mHandler.sendMessage(updateTimePreferenceMsg);
                     }
-                    BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
-                    synchronized (stats) {
-                        stats.noteCurrentTimeChangedLocked();
-                    }
+                    mBatteryStatsService.noteCurrentTimeChanged();
                     break;
                 case Intent.ACTION_CLEAR_DNS_CACHE:
                     mHandler.sendEmptyMessage(CLEAR_DNS_CACHE_MSG);
@@ -15338,8 +15325,8 @@
     }
 
     @Override
-    public StackInfo getFocusedStackInfo() throws RemoteException {
-        return mActivityTaskManager.getFocusedStackInfo();
+    public RootTaskInfo getFocusedRootTaskInfo() throws RemoteException {
+        return mActivityTaskManager.getFocusedRootTaskInfo();
     }
 
     @Override
@@ -15910,7 +15897,6 @@
         updateCpuStatsNow();
 
         synchronized (this) {
-            BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
             boolean doCpuKills = true;
             if (mLastPowerCheckUptime == 0) {
                 doCpuKills = false;
@@ -15957,10 +15943,8 @@
                             cpuLimit = mConstants.POWER_CHECK_MAX_CPU_4;
                         }
                         if (((cputimeUsed * 100) / uptimeSince) >= cpuLimit) {
-                            synchronized (stats) {
-                                stats.reportExcessiveCpuLocked(app.info.uid, app.processName,
+                            mBatteryStatsService.reportExcessiveCpu(app.info.uid, app.processName,
                                         uptimeSince, cputimeUsed);
-                            }
                             app.kill("excessive cpu " + cputimeUsed + " during " + uptimeSince
                                     + " dur=" + checkDur + " limit=" + cpuLimit,
                                     ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE,
@@ -17466,19 +17450,7 @@
         @Override
         public void updateForegroundTimeIfOnBattery(
                 String packageName, int uid, long cpuTimeDiff) {
-            synchronized (ActivityManagerService.this) {
-                if (!mBatteryStatsService.isOnBattery()) {
-                    return;
-                }
-                final BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
-                synchronized (bsi) {
-                    final BatteryStatsImpl.Uid.Proc ps =
-                            bsi.getProcessStatsLocked(uid, packageName);
-                    if (ps != null) {
-                        ps.addForegroundTimeLocked(cpuTimeDiff);
-                    }
-                }
-            }
+            mBatteryStatsService.updateForegroundTimeIfOnBattery(packageName, uid, cpuTimeDiff);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index a512cca..9ce8b11 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -28,6 +28,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
+import android.app.ActivityTaskManager.RootTaskInfo;
 import android.app.AppGlobals;
 import android.app.BroadcastOptions;
 import android.app.IActivityController;
@@ -2586,7 +2587,7 @@
             case "list":
                 return runStackList(pw);
             case "info":
-                return runStackInfo(pw);
+                return runRootTaskInfo(pw);
             case "move-top-activity-to-pinned-stack":
                 return runMoveTopActivityToPinnedStack(pw);
             case "remove":
@@ -2668,17 +2669,17 @@
     }
 
     int runStackList(PrintWriter pw) throws RemoteException {
-        List<ActivityManager.StackInfo> stacks = mTaskInterface.getAllStackInfos();
-        for (ActivityManager.StackInfo info : stacks) {
+        List<RootTaskInfo> tasks = mTaskInterface.getAllRootTaskInfos();
+        for (RootTaskInfo info : tasks) {
             pw.println(info);
         }
         return 0;
     }
 
-    int runStackInfo(PrintWriter pw) throws RemoteException {
+    int runRootTaskInfo(PrintWriter pw) throws RemoteException {
         int windowingMode = Integer.parseInt(getNextArgRequired());
         int activityType = Integer.parseInt(getNextArgRequired());
-        ActivityManager.StackInfo info = mTaskInterface.getStackInfo(windowingMode, activityType);
+        RootTaskInfo info = mTaskInterface.getRootTaskInfo(windowingMode, activityType);
         pw.println(info);
         return 0;
     }
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 39f79ca..692b3f1 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -376,7 +376,8 @@
                     for (int uid : uidsToRemove) {
                         FrameworkStatsLog.write(FrameworkStatsLog.ISOLATED_UID_CHANGED, -1, uid,
                                 FrameworkStatsLog.ISOLATED_UID_CHANGED__EVENT__REMOVED);
-                        mStats.removeIsolatedUidLocked(uid);
+                        mStats.removeIsolatedUidLocked(uid, SystemClock.elapsedRealtime(),
+                                SystemClock.uptimeMillis());
                     }
                     mStats.clearPendingRemovedUids();
                 }
@@ -473,11 +474,15 @@
         final WifiActivityEnergyInfo wifiInfo = awaitControllerInfo(wifiReceiver);
         final BluetoothActivityEnergyInfo bluetoothInfo = awaitControllerInfo(bluetoothReceiver);
         final ModemActivityInfo modemInfo = awaitControllerInfo(modemReceiver);
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
+        final long uptime = SystemClock.uptimeMillis();
+        final long elapsedRealtimeUs = elapsedRealtime * 1000;
+        final long uptimeUs = uptime * 1000;
 
         synchronized (mStats) {
             mStats.addHistoryEventLocked(
-                    SystemClock.elapsedRealtime(),
-                    SystemClock.uptimeMillis(),
+                    elapsedRealtime,
+                    uptime,
                     BatteryStats.HistoryItem.EVENT_COLLECT_EXTERNAL_STATS,
                     reason, 0);
 
@@ -490,17 +495,17 @@
             }
 
             if ((updateFlags & UPDATE_ALL) != 0) {
-                mStats.updateKernelWakelocksLocked();
-                mStats.updateKernelMemoryBandwidthLocked();
+                mStats.updateKernelWakelocksLocked(elapsedRealtimeUs);
+                mStats.updateKernelMemoryBandwidthLocked(elapsedRealtimeUs);
             }
 
             if ((updateFlags & UPDATE_RPM) != 0) {
-                mStats.updateRpmStatsLocked();
+                mStats.updateRpmStatsLocked(elapsedRealtimeUs);
             }
 
             if (bluetoothInfo != null) {
                 if (bluetoothInfo.isValid()) {
-                    mStats.updateBluetoothStateLocked(bluetoothInfo);
+                    mStats.updateBluetoothStateLocked(bluetoothInfo, elapsedRealtime, uptime);
                 } else {
                     Slog.w(TAG, "bluetooth info is invalid: " + bluetoothInfo);
                 }
@@ -512,7 +517,7 @@
 
         if (wifiInfo != null) {
             if (wifiInfo.isValid()) {
-                mStats.updateWifiState(extractDeltaLocked(wifiInfo));
+                mStats.updateWifiState(extractDeltaLocked(wifiInfo), elapsedRealtime, uptime);
             } else {
                 Slog.w(TAG, "wifi info is invalid: " + wifiInfo);
             }
@@ -520,7 +525,7 @@
 
         if (modemInfo != null) {
             if (modemInfo.isValid()) {
-                mStats.updateMobileRadioState(modemInfo);
+                mStats.updateMobileRadioState(modemInfo, elapsedRealtime, uptime);
             } else {
                 Slog.w(TAG, "modem info is invalid: " + modemInfo);
             }
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index d72998b..f427532 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.os.BatteryStatsInternal;
 import android.os.Binder;
 import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
@@ -62,7 +63,9 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.ParseUtils;
+import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.LocalServices;
+import com.android.server.Watchdog;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -76,6 +79,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 
@@ -86,7 +90,8 @@
 public final class BatteryStatsService extends IBatteryStats.Stub
         implements PowerManagerInternal.LowPowerModeListener,
         BatteryStatsImpl.PlatformIdleStateCallback,
-        BatteryStatsImpl.RailEnergyDataCallback {
+        BatteryStatsImpl.RailEnergyDataCallback,
+        Watchdog.Monitor {
     static final String TAG = "BatteryStatsService";
     static final boolean DBG = false;
 
@@ -110,6 +115,10 @@
     private CharBuffer mUtf16BufferStat = CharBuffer.allocate(MAX_LOW_POWER_STATS_SIZE);
     private static final int MAX_LOW_POWER_STATS_SIZE = 4096;
 
+    private final HandlerThread mHandlerThread;
+    private final Handler mHandler;
+    private final Object mLock = new Object();
+
     /**
      * Replaces the information in the given rpmStats with up-to-date information.
      */
@@ -190,6 +199,9 @@
                 return (umi != null) ? umi.getUserIds() : null;
             }
         };
+        mHandlerThread = new HandlerThread("batterystats-handler");
+        mHandlerThread.start();
+        mHandler = new Handler(mHandlerThread.getLooper());
         mStats = new BatteryStatsImpl(systemDir, handler, this,
                 this, mUserManagerUserInfoProvider);
         mWorker = new BatteryExternalStatsWorker(context, mStats);
@@ -206,6 +218,7 @@
 
     public void systemServicesReady() {
         mStats.systemServicesReady(mContext);
+        Watchdog.getInstance().addMonitor(this);
     }
 
     private final class LocalService extends BatteryStatsInternal {
@@ -228,8 +241,20 @@
         @Override
         public void noteBinderCallStats(int workSourceUid, long incrementatCallCount,
                 Collection<BinderCallsStats.CallStat> callStats, int[] binderThreadNativeTids) {
-            mStats.noteBinderCallStats(workSourceUid, incrementatCallCount, callStats,
-                    binderThreadNativeTids);
+            synchronized (BatteryStatsService.this.mLock) {
+                mHandler.sendMessage(PooledLambda.obtainMessage(
+                        mStats::noteBinderCallStats, workSourceUid, incrementatCallCount,
+                        callStats, binderThreadNativeTids,
+                        SystemClock.elapsedRealtime(), SystemClock.uptimeMillis()));
+            }
+        }
+    }
+
+    @Override
+    public void monitor() {
+        synchronized (mLock) {
+        }
+        synchronized (mStats) {
         }
     }
 
@@ -250,6 +275,19 @@
         awaitUninterruptibly(mWorker.scheduleSync(reason, flags));
     }
 
+    private void awaitCompletion() {
+        synchronized (mLock) {
+            final CountDownLatch latch = new CountDownLatch(1);
+            mHandler.post(() -> {
+                latch.countDown();
+            });
+            try {
+                latch.await();
+            } catch (InterruptedException e) {
+            }
+        }
+    }
+
     /**
      * At the time when the constructor runs, the power manager has not yet been
      * initialized.  So we initialize the low power observer later.
@@ -259,8 +297,8 @@
         powerMgr.registerLowPowerModeObserver(this);
         synchronized (mStats) {
             mStats.notePowerSaveModeLocked(
-                    powerMgr.getLowPowerState(ServiceType.BATTERY_STATS)
-                            .batterySaverEnabled);
+                    powerMgr.getLowPowerState(ServiceType.BATTERY_STATS).batterySaverEnabled,
+                    SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
         }
         (new WakeupReasonThread()).start();
     }
@@ -268,6 +306,9 @@
     public void shutdown() {
         Slog.w("BatteryStats", "Writing battery stats before shutdown...");
 
+        // Drain the handler queue to make sure we've handled all pending works.
+        awaitCompletion();
+
         syncStats("shutdown", BatteryExternalStatsWorker.UPDATE_ALL);
 
         synchronized (mStats) {
@@ -293,9 +334,16 @@
     }
 
     @Override
-    public void onLowPowerModeChanged(PowerSaveState result) {
-        synchronized (mStats) {
-            mStats.notePowerSaveModeLocked(result.batterySaverEnabled);
+    public void onLowPowerModeChanged(final PowerSaveState result) {
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.notePowerSaveModeLocked(result.batterySaverEnabled,
+                            elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
@@ -313,7 +361,12 @@
      * object to update with the latest info, then write to disk.
      */
     public void scheduleWriteToDisk() {
-        mWorker.scheduleWrite();
+        synchronized (mLock) {
+            // We still schedule it on the handler so we'll have all existing pending works done.
+            mHandler.post(() -> {
+                mWorker.scheduleWrite();
+            });
+        }
     }
 
     // These are for direct use by the activity manager...
@@ -321,70 +374,124 @@
     /**
      * Remove a UID from the BatteryStats and BatteryStats' external dependencies.
      */
-    void removeUid(int uid) {
-        synchronized (mStats) {
-            mStats.removeUidStatsLocked(uid);
+    void removeUid(final int uid) {
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.removeUidStatsLocked(uid, elapsedRealtime);
+                }
+            });
         }
     }
 
-    void onCleanupUser(int userId) {
-        synchronized (mStats) {
-            mStats.onCleanupUserLocked(userId);
+    void onCleanupUser(final int userId) {
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.onCleanupUserLocked(userId, elapsedRealtime);
+                }
+            });
         }
     }
 
-    void onUserRemoved(int userId) {
-        synchronized (mStats) {
-            mStats.onUserRemovedLocked(userId);
+    void onUserRemoved(final int userId) {
+        synchronized (mLock) {
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.onUserRemovedLocked(userId);
+                }
+            });
         }
     }
 
-    void addIsolatedUid(int isolatedUid, int appUid) {
-        synchronized (mStats) {
-            mStats.addIsolatedUidLocked(isolatedUid, appUid);
+    void addIsolatedUid(final int isolatedUid, final int appUid) {
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.addIsolatedUidLocked(isolatedUid, appUid, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    void removeIsolatedUid(int isolatedUid, int appUid) {
-        synchronized (mStats) {
-            mStats.scheduleRemoveIsolatedUidLocked(isolatedUid, appUid);
+    void removeIsolatedUid(final int isolatedUid, final int appUid) {
+        synchronized (mLock) {
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.scheduleRemoveIsolatedUidLocked(isolatedUid, appUid);
+                }
+            });
         }
     }
 
-    void noteProcessStart(String name, int uid) {
-        synchronized (mStats) {
-            mStats.noteProcessStartLocked(name, uid);
-            FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED, uid, name,
-                    FrameworkStatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED__STATE__STARTED);
+    void noteProcessStart(final String name, final int uid) {
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteProcessStartLocked(name, uid, elapsedRealtime, uptime);
+                }
+            });
         }
+        FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED, uid, name,
+                FrameworkStatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED__STATE__STARTED);
     }
 
     void noteProcessCrash(String name, int uid) {
-        synchronized (mStats) {
-            mStats.noteProcessCrashLocked(name, uid);
-            FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED, uid, name,
-                    FrameworkStatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED__STATE__CRASHED);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteProcessCrashLocked(name, uid, elapsedRealtime, uptime);
+                }
+            });
         }
+        FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED, uid, name,
+                FrameworkStatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED__STATE__CRASHED);
     }
 
     void noteProcessAnr(String name, int uid) {
-        synchronized (mStats) {
-            mStats.noteProcessAnrLocked(name, uid);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteProcessAnrLocked(name, uid, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
     void noteProcessFinish(String name, int uid) {
-        synchronized (mStats) {
-            mStats.noteProcessFinishLocked(name, uid);
-            FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED, uid, name,
-                    FrameworkStatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED__STATE__FINISHED);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteProcessFinishLocked(name, uid, elapsedRealtime, uptime);
+                }
+            });
         }
+        FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED, uid, name,
+                FrameworkStatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED__STATE__FINISHED);
     }
 
     /** @param state Process state from ActivityManager.java. */
     void noteUidProcessState(int uid, int state) {
-        synchronized (mStats) {
-            mStats.noteUidProcessStateLocked(uid, state);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteUidProcessStateLocked(uid, state, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
@@ -396,6 +503,9 @@
         //Slog.i("foo", "SENDING BATTERY INFO:");
         //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
         Parcel out = Parcel.obtain();
+        // Drain the handler queue to make sure we've handled all pending works, so we'll get
+        // an accurate stats.
+        awaitCompletion();
         syncStats("get-stats", BatteryExternalStatsWorker.UPDATE_ALL);
         synchronized (mStats) {
             mStats.writeToParcel(out, 0);
@@ -411,6 +521,9 @@
         //Slog.i("foo", "SENDING BATTERY INFO:");
         //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
         Parcel out = Parcel.obtain();
+        // Drain the handler queue to make sure we've handled all pending works, so we'll get
+        // an accurate stats.
+        awaitCompletion();
         syncStats("get-stats", BatteryExternalStatsWorker.UPDATE_ALL);
         synchronized (mStats) {
             mStats.writeToParcel(out, 0);
@@ -446,579 +559,1015 @@
         }
     }
 
-    public void noteEvent(int code, String name, int uid) {
+    public void noteEvent(final int code, final String name, final int uid) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteEventLocked(code, name, uid);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteEventLocked(code, name, uid, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteSyncStart(String name, int uid) {
+    public void noteSyncStart(final String name, final int uid) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteSyncStartLocked(name, uid);
-            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SYNC_STATE_CHANGED, uid, null,
-                    name, FrameworkStatsLog.SYNC_STATE_CHANGED__STATE__ON);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteSyncStartLocked(name, uid, elapsedRealtime, uptime);
+                }
+                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SYNC_STATE_CHANGED, uid, null,
+                        name, FrameworkStatsLog.SYNC_STATE_CHANGED__STATE__ON);
+            });
         }
     }
 
-    public void noteSyncFinish(String name, int uid) {
+    public void noteSyncFinish(final String name, final int uid) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteSyncFinishLocked(name, uid);
-            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SYNC_STATE_CHANGED, uid, null,
-                    name, FrameworkStatsLog.SYNC_STATE_CHANGED__STATE__OFF);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteSyncFinishLocked(name, uid, elapsedRealtime, uptime);
+                }
+                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SYNC_STATE_CHANGED, uid, null,
+                        name, FrameworkStatsLog.SYNC_STATE_CHANGED__STATE__OFF);
+            });
         }
     }
 
     /** A scheduled job was started. */
-    public void noteJobStart(String name, int uid) {
+    public void noteJobStart(final String name, final int uid) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteJobStartLocked(name, uid);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteJobStartLocked(name, uid, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
     /** A scheduled job was finished. */
-    public void noteJobFinish(String name, int uid, int stopReason) {
+    public void noteJobFinish(final String name, final int uid, final int stopReason) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteJobFinishLocked(name, uid, stopReason);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteJobFinishLocked(name, uid, stopReason, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    void noteJobsDeferred(int uid, int numDeferred, long sinceLast) {
+    void noteJobsDeferred(final int uid, final int numDeferred, final long sinceLast) {
         // No need to enforce calling permission, as it is called from an internal interface
-        synchronized (mStats) {
-            mStats.noteJobsDeferredLocked(uid, numDeferred, sinceLast);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteJobsDeferredLocked(uid, numDeferred, sinceLast,
+                            elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteWakupAlarm(String name, int uid, WorkSource workSource, String tag) {
+    public void noteWakupAlarm(final String name, final int uid, final WorkSource workSource,
+            final String tag) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteWakupAlarmLocked(name, uid, workSource, tag);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteWakupAlarmLocked(name, uid, workSource, tag,
+                            elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteAlarmStart(String name, WorkSource workSource, int uid) {
+    public void noteAlarmStart(final String name, final WorkSource workSource, final int uid) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteAlarmStartLocked(name, workSource, uid);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteAlarmStartLocked(name, workSource, uid, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteAlarmFinish(String name, WorkSource workSource, int uid) {
+    public void noteAlarmFinish(final String name, final WorkSource workSource, final int uid) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteAlarmFinishLocked(name, workSource, uid);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteAlarmFinishLocked(name, workSource, uid, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteStartWakelock(int uid, int pid, String name, String historyName, int type,
-            boolean unimportantForLogging) {
+    public void noteStartWakelock(final int uid, final int pid, final String name,
+            final String historyName, final int type, final boolean unimportantForLogging) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteStartWakeLocked(uid, pid, null, name, historyName, type,
-                    unimportantForLogging, SystemClock.elapsedRealtime(),
-                    SystemClock.uptimeMillis());
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteStartWakeLocked(uid, pid, null, name, historyName, type,
+                            unimportantForLogging, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteStopWakelock(int uid, int pid, String name, String historyName, int type) {
+    public void noteStopWakelock(final int uid, final int pid, final String name,
+            final String historyName, final int type) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteStopWakeLocked(uid, pid, null, name, historyName, type,
-                    SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteStopWakeLocked(uid, pid, null, name, historyName, type,
+                            elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteStartWakelockFromSource(WorkSource ws, int pid, String name,
-            String historyName, int type, boolean unimportantForLogging) {
+    public void noteStartWakelockFromSource(final WorkSource ws, final int pid, final String name,
+            final String historyName, final int type, final boolean unimportantForLogging) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteStartWakeFromSourceLocked(ws, pid, name, historyName,
-                    type, unimportantForLogging);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteStartWakeFromSourceLocked(ws, pid, name, historyName,
+                            type, unimportantForLogging, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteChangeWakelockFromSource(WorkSource ws, int pid, String name,
-            String historyName, int type, WorkSource newWs, int newPid, String newName,
-            String newHistoryName, int newType, boolean newUnimportantForLogging) {
+    public void noteChangeWakelockFromSource(final WorkSource ws, final int pid, final String name,
+            final String historyName, final int type, final WorkSource newWs, final int newPid,
+            final String newName, final String newHistoryName, final int newType,
+            final boolean newUnimportantForLogging) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteChangeWakelockFromSourceLocked(ws, pid, name, historyName, type,
-                    newWs, newPid, newName, newHistoryName, newType, newUnimportantForLogging);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteChangeWakelockFromSourceLocked(ws, pid, name, historyName, type,
+                            newWs, newPid, newName, newHistoryName, newType,
+                            newUnimportantForLogging, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteStopWakelockFromSource(WorkSource ws, int pid, String name, String historyName,
-            int type) {
+    public void noteStopWakelockFromSource(final WorkSource ws, final int pid, final String name,
+            final String historyName, final int type) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteStopWakeFromSourceLocked(ws, pid, name, historyName, type);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteStopWakeFromSourceLocked(ws, pid, name, historyName, type,
+                            elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
     @Override
-    public void noteLongPartialWakelockStart(String name, String historyName, int uid) {
+    public void noteLongPartialWakelockStart(final String name, final String historyName,
+            final int uid) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteLongPartialWakelockStart(name, historyName, uid);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteLongPartialWakelockStart(name, historyName, uid,
+                            elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
     @Override
-    public void noteLongPartialWakelockStartFromSource(String name, String historyName,
-            WorkSource workSource) {
+    public void noteLongPartialWakelockStartFromSource(final String name, final String historyName,
+            final WorkSource workSource) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteLongPartialWakelockStartFromSource(name, historyName, workSource);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteLongPartialWakelockStartFromSource(name, historyName, workSource,
+                            elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
     @Override
-    public void noteLongPartialWakelockFinish(String name, String historyName, int uid) {
+    public void noteLongPartialWakelockFinish(final String name, final String historyName,
+            final int uid) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteLongPartialWakelockFinish(name, historyName, uid);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteLongPartialWakelockFinish(name, historyName, uid,
+                            elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
     @Override
-    public void noteLongPartialWakelockFinishFromSource(String name, String historyName,
-            WorkSource workSource) {
+    public void noteLongPartialWakelockFinishFromSource(final String name, final String historyName,
+            final WorkSource workSource) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteLongPartialWakelockFinishFromSource(name, historyName, workSource);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteLongPartialWakelockFinishFromSource(name, historyName, workSource,
+                            elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteStartSensor(int uid, int sensor) {
+    public void noteStartSensor(final int uid, final int sensor) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteStartSensorLocked(uid, sensor);
-            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SENSOR_STATE_CHANGED, uid, null,
-                    sensor, FrameworkStatsLog.SENSOR_STATE_CHANGED__STATE__ON);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteStartSensorLocked(uid, sensor, elapsedRealtime, uptime);
+                }
+                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SENSOR_STATE_CHANGED, uid,
+                        null, sensor, FrameworkStatsLog.SENSOR_STATE_CHANGED__STATE__ON);
+            });
         }
     }
 
-    public void noteStopSensor(int uid, int sensor) {
+    public void noteStopSensor(final int uid, final int sensor) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteStopSensorLocked(uid, sensor);
-            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SENSOR_STATE_CHANGED, uid, null,
-                    sensor, FrameworkStatsLog.SENSOR_STATE_CHANGED__STATE__OFF);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteStopSensorLocked(uid, sensor, elapsedRealtime, uptime);
+                }
+                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SENSOR_STATE_CHANGED, uid,
+                        null, sensor, FrameworkStatsLog.SENSOR_STATE_CHANGED__STATE__OFF);
+            });
         }
     }
 
-    public void noteVibratorOn(int uid, long durationMillis) {
+    public void noteVibratorOn(final int uid, final long durationMillis) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteVibratorOnLocked(uid, durationMillis);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteVibratorOnLocked(uid, durationMillis, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteVibratorOff(int uid) {
+    public void noteVibratorOff(final int uid) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteVibratorOffLocked(uid);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteVibratorOffLocked(uid, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
     @Override
-    public void noteGpsChanged(WorkSource oldWs, WorkSource newWs) {
+    public void noteGpsChanged(final WorkSource oldWs, final WorkSource newWs) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteGpsChangedLocked(oldWs, newWs);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteGpsChangedLocked(oldWs, newWs, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteGpsSignalQuality(int signalLevel) {
-        synchronized (mStats) {
-            mStats.noteGpsSignalQualityLocked(signalLevel);
+    public void noteGpsSignalQuality(final int signalLevel) {
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteGpsSignalQualityLocked(signalLevel, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteScreenState(int state) {
+    public void noteScreenState(final int state) {
         enforceCallingPermission();
-        if (DBG) Slog.d(TAG, "begin noteScreenState");
-        synchronized (mStats) {
-            FrameworkStatsLog.write(FrameworkStatsLog.SCREEN_STATE_CHANGED, state);
-
-            mStats.noteScreenStateLocked(state);
-        }
-        if (DBG) Slog.d(TAG, "end noteScreenState");
-    }
-
-    public void noteScreenBrightness(int brightness) {
-        enforceCallingPermission();
-        synchronized (mStats) {
-            FrameworkStatsLog.write(FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED, brightness);
-            mStats.noteScreenBrightnessLocked(brightness);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            final long currentTime = System.currentTimeMillis();
+            mHandler.post(() -> {
+                if (DBG) Slog.d(TAG, "begin noteScreenState");
+                synchronized (mStats) {
+                    mStats.noteScreenStateLocked(state, elapsedRealtime, uptime, currentTime);
+                }
+                FrameworkStatsLog.write(FrameworkStatsLog.SCREEN_STATE_CHANGED, state);
+                if (DBG) Slog.d(TAG, "end noteScreenState");
+            });
         }
     }
 
-    public void noteUserActivity(int uid, int event) {
+    public void noteScreenBrightness(final int brightness) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteUserActivityLocked(uid, event);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteScreenBrightnessLocked(brightness, elapsedRealtime, uptime);
+                }
+                FrameworkStatsLog.write(FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED, brightness);
+            });
         }
     }
 
-    public void noteWakeUp(String reason, int reasonUid) {
+    public void noteUserActivity(final int uid, final int event) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteWakeUpLocked(reason, reasonUid);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteUserActivityLocked(uid, event, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteInteractive(boolean interactive) {
+    public void noteWakeUp(final String reason, final int reasonUid) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteInteractiveLocked(interactive);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteWakeUpLocked(reason, reasonUid, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteConnectivityChanged(int type, String extra) {
+    public void noteInteractive(final boolean interactive) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteConnectivityChangedLocked(type, extra);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteInteractiveLocked(interactive, elapsedRealtime);
+                }
+            });
         }
     }
 
-    public void noteMobileRadioPowerState(int powerState, long timestampNs, int uid) {
+    public void noteConnectivityChanged(final int type, final String extra) {
         enforceCallingPermission();
-        final boolean update;
-        synchronized (mStats) {
-            update = mStats.noteMobileRadioPowerStateLocked(powerState, timestampNs, uid);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteConnectivityChangedLocked(type, extra, elapsedRealtime, uptime);
+                }
+            });
         }
+    }
 
-        if (update) {
-            mWorker.scheduleSync("modem-data", BatteryExternalStatsWorker.UPDATE_RADIO);
+    public void noteMobileRadioPowerState(final int powerState, final long timestampNs,
+            final int uid) {
+        enforceCallingPermission();
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                final boolean update;
+                synchronized (mStats) {
+                    update = mStats.noteMobileRadioPowerStateLocked(powerState, timestampNs, uid,
+                            elapsedRealtime, uptime);
+                }
+
+                if (update) {
+                    mWorker.scheduleSync("modem-data", BatteryExternalStatsWorker.UPDATE_RADIO);
+                }
+            });
         }
     }
 
     public void notePhoneOn() {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.notePhoneOnLocked();
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.notePhoneOnLocked(elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
     public void notePhoneOff() {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.notePhoneOffLocked();
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.notePhoneOffLocked(elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void notePhoneSignalStrength(SignalStrength signalStrength) {
+    public void notePhoneSignalStrength(final SignalStrength signalStrength) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.notePhoneSignalStrengthLocked(signalStrength);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.notePhoneSignalStrengthLocked(signalStrength, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void notePhoneDataConnectionState(int dataType, boolean hasData, int serviceType) {
+    public void notePhoneDataConnectionState(final int dataType, final boolean hasData,
+            final int serviceType) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.notePhoneDataConnectionStateLocked(dataType, hasData, serviceType);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.notePhoneDataConnectionStateLocked(dataType, hasData, serviceType,
+                            elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void notePhoneState(int state) {
+    public void notePhoneState(final int state) {
         enforceCallingPermission();
-        int simState = mContext.getSystemService(TelephonyManager.class).getSimState();
-        synchronized (mStats) {
-            mStats.notePhoneStateLocked(state, simState);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                int simState = mContext.getSystemService(TelephonyManager.class).getSimState();
+                synchronized (mStats) {
+                    mStats.notePhoneStateLocked(state, simState, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
     public void noteWifiOn() {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteWifiOnLocked();
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteWifiOnLocked(elapsedRealtime, uptime);
+                }
+                FrameworkStatsLog.write(FrameworkStatsLog.WIFI_ENABLED_STATE_CHANGED,
+                        FrameworkStatsLog.WIFI_ENABLED_STATE_CHANGED__STATE__ON);
+            });
         }
-        FrameworkStatsLog.write(FrameworkStatsLog.WIFI_ENABLED_STATE_CHANGED,
-                FrameworkStatsLog.WIFI_ENABLED_STATE_CHANGED__STATE__ON);
     }
 
     public void noteWifiOff() {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteWifiOffLocked();
-        }
-        FrameworkStatsLog.write(FrameworkStatsLog.WIFI_ENABLED_STATE_CHANGED,
-                FrameworkStatsLog.WIFI_ENABLED_STATE_CHANGED__STATE__OFF);
-    }
-
-    public void noteStartAudio(int uid) {
-        enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteAudioOnLocked(uid);
-            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.AUDIO_STATE_CHANGED, uid, null,
-                    FrameworkStatsLog.AUDIO_STATE_CHANGED__STATE__ON);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteWifiOffLocked(elapsedRealtime, uptime);
+                }
+                FrameworkStatsLog.write(FrameworkStatsLog.WIFI_ENABLED_STATE_CHANGED,
+                        FrameworkStatsLog.WIFI_ENABLED_STATE_CHANGED__STATE__OFF);
+            });
         }
     }
 
-    public void noteStopAudio(int uid) {
+    public void noteStartAudio(final int uid) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteAudioOffLocked(uid);
-            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.AUDIO_STATE_CHANGED, uid, null,
-                    FrameworkStatsLog.AUDIO_STATE_CHANGED__STATE__OFF);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteAudioOnLocked(uid, elapsedRealtime, uptime);
+                }
+                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.AUDIO_STATE_CHANGED, uid,
+                        null, FrameworkStatsLog.AUDIO_STATE_CHANGED__STATE__ON);
+            });
         }
     }
 
-    public void noteStartVideo(int uid) {
+    public void noteStopAudio(final int uid) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteVideoOnLocked(uid);
-            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED, uid,
-                    null, FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED__STATE__ON);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteAudioOffLocked(uid, elapsedRealtime, uptime);
+                }
+                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.AUDIO_STATE_CHANGED, uid,
+                        null, FrameworkStatsLog.AUDIO_STATE_CHANGED__STATE__OFF);
+            });
         }
     }
 
-    public void noteStopVideo(int uid) {
+    public void noteStartVideo(final int uid) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteVideoOffLocked(uid);
-            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED, uid,
-                    null, FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED__STATE__OFF);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteVideoOnLocked(uid, elapsedRealtime, uptime);
+                }
+                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED,
+                        uid, null, FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED__STATE__ON);
+            });
+        }
+    }
+
+    public void noteStopVideo(final int uid) {
+        enforceCallingPermission();
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteVideoOffLocked(uid, elapsedRealtime, uptime);
+                }
+                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED,
+                        uid, null, FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED__STATE__OFF);
+            });
         }
     }
 
     public void noteResetAudio() {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteResetAudioLocked();
-            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.AUDIO_STATE_CHANGED, -1, null,
-                    FrameworkStatsLog.AUDIO_STATE_CHANGED__STATE__RESET);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteResetAudioLocked(elapsedRealtime, uptime);
+                }
+                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.AUDIO_STATE_CHANGED, -1, null,
+                        FrameworkStatsLog.AUDIO_STATE_CHANGED__STATE__RESET);
+            });
         }
     }
 
     public void noteResetVideo() {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteResetVideoLocked();
-            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED, -1,
-                    null, FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED__STATE__RESET);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteResetVideoLocked(elapsedRealtime, uptime);
+                }
+                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED, -1,
+                        null, FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED__STATE__RESET);
+            });
         }
     }
 
-    public void noteFlashlightOn(int uid) {
+    public void noteFlashlightOn(final int uid) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteFlashlightOnLocked(uid);
-            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED, uid,
-                    null, FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED__STATE__ON);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteFlashlightOnLocked(uid, elapsedRealtime, uptime);
+                }
+                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED, uid,
+                        null, FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED__STATE__ON);
+            });
         }
     }
 
-    public void noteFlashlightOff(int uid) {
+    public void noteFlashlightOff(final int uid) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteFlashlightOffLocked(uid);
-            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED, uid,
-                    null, FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED__STATE__OFF);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteFlashlightOffLocked(uid, elapsedRealtime, uptime);
+                }
+                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED, uid,
+                        null, FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED__STATE__OFF);
+            });
         }
     }
 
-    public void noteStartCamera(int uid) {
+    public void noteStartCamera(final int uid) {
         enforceCallingPermission();
         if (DBG) Slog.d(TAG, "begin noteStartCamera");
-        synchronized (mStats) {
-            mStats.noteCameraOnLocked(uid);
-            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.CAMERA_STATE_CHANGED, uid, null,
-                    FrameworkStatsLog.CAMERA_STATE_CHANGED__STATE__ON);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteCameraOnLocked(uid, elapsedRealtime, uptime);
+                }
+                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.CAMERA_STATE_CHANGED, uid,
+                        null, FrameworkStatsLog.CAMERA_STATE_CHANGED__STATE__ON);
+            });
         }
         if (DBG) Slog.d(TAG, "end noteStartCamera");
     }
 
-    public void noteStopCamera(int uid) {
+    public void noteStopCamera(final int uid) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteCameraOffLocked(uid);
-            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.CAMERA_STATE_CHANGED, uid, null,
-                    FrameworkStatsLog.CAMERA_STATE_CHANGED__STATE__OFF);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteCameraOffLocked(uid, elapsedRealtime, uptime);
+                }
+                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.CAMERA_STATE_CHANGED, uid,
+                        null, FrameworkStatsLog.CAMERA_STATE_CHANGED__STATE__OFF);
+            });
         }
     }
 
     public void noteResetCamera() {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteResetCameraLocked();
-            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.CAMERA_STATE_CHANGED, -1, null,
-                    FrameworkStatsLog.CAMERA_STATE_CHANGED__STATE__RESET);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteResetCameraLocked(elapsedRealtime, uptime);
+                }
+                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.CAMERA_STATE_CHANGED, -1,
+                        null, FrameworkStatsLog.CAMERA_STATE_CHANGED__STATE__RESET);
+            });
         }
     }
 
     public void noteResetFlashlight() {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteResetFlashlightLocked();
-            FrameworkStatsLog.write_non_chained(FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED, -1,
-                    null, FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED__STATE__RESET);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteResetFlashlightLocked(elapsedRealtime, uptime);
+                }
+                FrameworkStatsLog.write_non_chained(FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED, -1,
+                        null, FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED__STATE__RESET);
+            });
         }
     }
 
     @Override
-    public void noteWifiRadioPowerState(int powerState, long tsNanos, int uid) {
+    public void noteWifiRadioPowerState(final int powerState, final long tsNanos, final int uid) {
         enforceCallingPermission();
-
-        // There was a change in WiFi power state.
-        // Collect data now for the past activity.
-        synchronized (mStats) {
-            if (mStats.isOnBattery()) {
-                final String type = (powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH ||
-                        powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM) ? "active"
-                        : "inactive";
-                mWorker.scheduleSync("wifi-data: " + type, BatteryExternalStatsWorker.UPDATE_WIFI);
-            }
-            mStats.noteWifiRadioPowerState(powerState, tsNanos, uid);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                // There was a change in WiFi power state.
+                // Collect data now for the past activity.
+                synchronized (mStats) {
+                    if (mStats.isOnBattery()) {
+                        final String type =
+                                (powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
+                                || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM)
+                                ? "active" : "inactive";
+                        mWorker.scheduleSync("wifi-data: " + type,
+                                BatteryExternalStatsWorker.UPDATE_WIFI);
+                    }
+                    mStats.noteWifiRadioPowerState(powerState, tsNanos, uid,
+                            elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteWifiRunning(WorkSource ws) {
+    public void noteWifiRunning(final WorkSource ws) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteWifiRunningLocked(ws);
-        }
-        // TODO: Log WIFI_RUNNING_STATE_CHANGED in a better spot to include Hotspot too.
-        FrameworkStatsLog.write(FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED,
-                ws, FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__ON);
-    }
-
-    public void noteWifiRunningChanged(WorkSource oldWs, WorkSource newWs) {
-        enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteWifiRunningChangedLocked(oldWs, newWs);
-        }
-        FrameworkStatsLog.write(FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED,
-                newWs, FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__ON);
-        FrameworkStatsLog.write(FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED,
-                oldWs, FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__OFF);
-    }
-
-    public void noteWifiStopped(WorkSource ws) {
-        enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteWifiStoppedLocked(ws);
-        }
-        FrameworkStatsLog.write(FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED,
-                ws, FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__OFF);
-    }
-
-    public void noteWifiState(int wifiState, String accessPoint) {
-        enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteWifiStateLocked(wifiState, accessPoint);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteWifiRunningLocked(ws, elapsedRealtime, uptime);
+                }
+                // TODO: Log WIFI_RUNNING_STATE_CHANGED in a better spot to include Hotspot too.
+                FrameworkStatsLog.write(FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED,
+                        ws, FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__ON);
+            });
         }
     }
 
-    public void noteWifiSupplicantStateChanged(int supplState, boolean failedAuth) {
+    public void noteWifiRunningChanged(final WorkSource oldWs, final WorkSource newWs) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteWifiSupplicantStateChangedLocked(supplState, failedAuth);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteWifiRunningChangedLocked(oldWs, newWs, elapsedRealtime, uptime);
+                }
+                FrameworkStatsLog.write(FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED,
+                        newWs, FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__ON);
+                FrameworkStatsLog.write(FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED,
+                        oldWs, FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__OFF);
+            });
         }
     }
 
-    public void noteWifiRssiChanged(int newRssi) {
+    public void noteWifiStopped(final WorkSource ws) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteWifiRssiChangedLocked(newRssi);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteWifiStoppedLocked(ws, elapsedRealtime, uptime);
+                }
+                FrameworkStatsLog.write(FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED,
+                        ws, FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__OFF);
+            });
         }
     }
 
-    public void noteFullWifiLockAcquired(int uid) {
+    public void noteWifiState(final int wifiState, final String accessPoint) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteFullWifiLockAcquiredLocked(uid);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteWifiStateLocked(wifiState, accessPoint, elapsedRealtime);
+                }
+            });
         }
     }
 
-    public void noteFullWifiLockReleased(int uid) {
+    public void noteWifiSupplicantStateChanged(final int supplState, final boolean failedAuth) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteFullWifiLockReleasedLocked(uid);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteWifiSupplicantStateChangedLocked(supplState, failedAuth,
+                            elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteWifiScanStarted(int uid) {
+    public void noteWifiRssiChanged(final int newRssi) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteWifiScanStartedLocked(uid);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteWifiRssiChangedLocked(newRssi, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteWifiScanStopped(int uid) {
+    public void noteFullWifiLockAcquired(final int uid) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteWifiScanStoppedLocked(uid);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteFullWifiLockAcquiredLocked(uid, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteWifiMulticastEnabled(int uid) {
+    public void noteFullWifiLockReleased(final int uid) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteWifiMulticastEnabledLocked(uid);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteFullWifiLockReleasedLocked(uid, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteWifiMulticastDisabled(int uid) {
+    public void noteWifiScanStarted(final int uid) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteWifiMulticastDisabledLocked(uid);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteWifiScanStartedLocked(uid, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteFullWifiLockAcquiredFromSource(WorkSource ws) {
+    public void noteWifiScanStopped(final int uid) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteFullWifiLockAcquiredFromSourceLocked(ws);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteWifiScanStoppedLocked(uid, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteFullWifiLockReleasedFromSource(WorkSource ws) {
+    public void noteWifiMulticastEnabled(final int uid) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteFullWifiLockReleasedFromSourceLocked(ws);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteWifiMulticastEnabledLocked(uid, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteWifiScanStartedFromSource(WorkSource ws) {
+    public void noteWifiMulticastDisabled(final int uid) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteWifiScanStartedFromSourceLocked(ws);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteWifiMulticastDisabledLocked(uid, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteWifiScanStoppedFromSource(WorkSource ws) {
+    public void noteFullWifiLockAcquiredFromSource(final WorkSource ws) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteWifiScanStoppedFromSourceLocked(ws);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteFullWifiLockAcquiredFromSourceLocked(ws, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteWifiBatchedScanStartedFromSource(WorkSource ws, int csph) {
+    public void noteFullWifiLockReleasedFromSource(final WorkSource ws) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteWifiBatchedScanStartedFromSourceLocked(ws, csph);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteFullWifiLockReleasedFromSourceLocked(ws, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
-    public void noteWifiBatchedScanStoppedFromSource(WorkSource ws) {
+    public void noteWifiScanStartedFromSource(final WorkSource ws) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteWifiBatchedScanStoppedFromSourceLocked(ws);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteWifiScanStartedFromSourceLocked(ws, elapsedRealtime, uptime);
+                }
+            });
+        }
+    }
+
+    public void noteWifiScanStoppedFromSource(final WorkSource ws) {
+        enforceCallingPermission();
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteWifiScanStoppedFromSourceLocked(ws, elapsedRealtime, uptime);
+                }
+            });
+        }
+    }
+
+    public void noteWifiBatchedScanStartedFromSource(final WorkSource ws, final int csph) {
+        enforceCallingPermission();
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteWifiBatchedScanStartedFromSourceLocked(ws, csph,
+                            elapsedRealtime, uptime);
+                }
+            });
+        }
+    }
+
+    public void noteWifiBatchedScanStoppedFromSource(final WorkSource ws) {
+        enforceCallingPermission();
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteWifiBatchedScanStoppedFromSourceLocked(ws, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
     @Override
-    public void noteNetworkInterfaceType(String iface, int networkType) {
+    public void noteNetworkInterfaceType(final String iface, final int networkType) {
         enforceCallingPermission();
-        mStats.noteNetworkInterfaceType(iface, networkType);
+        synchronized (mLock) {
+            mHandler.post(() -> {
+                mStats.noteNetworkInterfaceType(iface, networkType);
+            });
+        }
     }
 
     @Override
@@ -1027,66 +1576,119 @@
         // During device boot, qtaguid isn't enabled until after the inital
         // loading of battery stats. Now that they're enabled, take our initial
         // snapshot for future delta calculation.
-        mWorker.scheduleSync("network-stats-enabled",
-                BatteryExternalStatsWorker.UPDATE_RADIO | BatteryExternalStatsWorker.UPDATE_WIFI);
-    }
-
-    @Override
-    public void noteDeviceIdleMode(int mode, String activeReason, int activeUid) {
-        enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteDeviceIdleModeLocked(mode, activeReason, activeUid);
-        }
-    }
-
-    public void notePackageInstalled(String pkgName, long versionCode) {
-        enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.notePackageInstalledLocked(pkgName, versionCode);
-        }
-    }
-
-    public void notePackageUninstalled(String pkgName) {
-        enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.notePackageUninstalledLocked(pkgName);
+        synchronized (mLock) {
+            // Still schedule it on the handler to make sure we have existing pending works done
+            mHandler.post(() -> {
+                mWorker.scheduleSync("network-stats-enabled",
+                        BatteryExternalStatsWorker.UPDATE_RADIO
+                        | BatteryExternalStatsWorker.UPDATE_WIFI);
+            });
         }
     }
 
     @Override
-    public void noteBleScanStarted(WorkSource ws, boolean isUnoptimized) {
+    public void noteDeviceIdleMode(final int mode, final String activeReason, final int activeUid) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteBluetoothScanStartedFromSourceLocked(ws, isUnoptimized);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteDeviceIdleModeLocked(mode, activeReason, activeUid,
+                            elapsedRealtime, uptime);
+                }
+            });
+        }
+    }
+
+    public void notePackageInstalled(final String pkgName, final long versionCode) {
+        enforceCallingPermission();
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.notePackageInstalledLocked(pkgName, versionCode,
+                            elapsedRealtime, uptime);
+                }
+            });
+        }
+    }
+
+    public void notePackageUninstalled(final String pkgName) {
+        enforceCallingPermission();
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.notePackageUninstalledLocked(pkgName, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
     @Override
-    public void noteBleScanStopped(WorkSource ws, boolean isUnoptimized) {
+    public void noteBleScanStarted(final WorkSource ws, final boolean isUnoptimized) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteBluetoothScanStoppedFromSourceLocked(ws, isUnoptimized);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteBluetoothScanStartedFromSourceLocked(ws, isUnoptimized,
+                            elapsedRealtime, uptime);
+                }
+            });
+        }
+    }
+
+    @Override
+    public void noteBleScanStopped(final WorkSource ws, final boolean isUnoptimized) {
+        enforceCallingPermission();
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteBluetoothScanStoppedFromSourceLocked(ws, isUnoptimized,
+                            uptime, elapsedRealtime);
+                }
+            });
         }
     }
 
     @Override
     public void noteResetBleScan() {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteResetBluetoothScanLocked();
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteResetBluetoothScanLocked(elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
     @Override
-    public void noteBleScanResults(WorkSource ws, int numNewResults) {
+    public void noteBleScanResults(final WorkSource ws, final int numNewResults) {
         enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteBluetoothScanResultsFromSourceLocked(ws, numNewResults);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteBluetoothScanResultsFromSourceLocked(ws, numNewResults,
+                            elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
     @Override
-    public void noteWifiControllerActivity(WifiActivityEnergyInfo info) {
+    public void noteWifiControllerActivity(final WifiActivityEnergyInfo info) {
         enforceCallingPermission();
 
         if (info == null || !info.isValid()) {
@@ -1094,24 +1696,36 @@
             return;
         }
 
-        mStats.updateWifiState(info);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                mStats.updateWifiState(info, elapsedRealtime, uptime);
+            });
+        }
     }
 
     @Override
-    public void noteBluetoothControllerActivity(BluetoothActivityEnergyInfo info) {
+    public void noteBluetoothControllerActivity(final BluetoothActivityEnergyInfo info) {
         enforceCallingPermission();
         if (info == null || !info.isValid()) {
             Slog.e(TAG, "invalid bluetooth data given: " + info);
             return;
         }
 
-        synchronized (mStats) {
-            mStats.updateBluetoothStateLocked(info);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.updateBluetoothStateLocked(info, elapsedRealtime, uptime);
+                }
+            });
         }
     }
 
     @Override
-    public void noteModemControllerActivity(ModemActivityInfo info) {
+    public void noteModemControllerActivity(final ModemActivityInfo info) {
         enforceCallingPermission();
 
         if (info == null || !info.isValid()) {
@@ -1119,7 +1733,13 @@
             return;
         }
 
-        mStats.updateMobileRadioState(info);
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                mStats.updateMobileRadioState(info, elapsedRealtime, uptime);
+            });
+        }
     }
 
     public boolean isOnBattery() {
@@ -1132,32 +1752,43 @@
             final int chargeFullUAh, final long chargeTimeToFullSeconds) {
         enforceCallingPermission();
 
-        // BatteryService calls us here and we may update external state. It would be wrong
-        // to block such a low level service like BatteryService on external stats like WiFi.
-        mWorker.scheduleRunnable(() -> {
-            synchronized (mStats) {
-                final boolean onBattery = BatteryStatsImpl.isOnBattery(plugType, status);
-                if (mStats.isOnBattery() == onBattery) {
-                    // The battery state has not changed, so we don't need to sync external
-                    // stats immediately.
-                    mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt,
-                            chargeUAh, chargeFullUAh, chargeTimeToFullSeconds);
-                    return;
-                }
-            }
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            final long currentTime = System.currentTimeMillis();
+            // We still schedule this task over the handler thread to make sure we've had
+            // all existing pending work handled before setting the battery state
+            mHandler.post(() -> {
+                // BatteryService calls us here and we may update external state. It would be wrong
+                // to block such a low level service like BatteryService on external stats like WiFi
+                mWorker.scheduleRunnable(() -> {
+                    synchronized (mStats) {
+                        final boolean onBattery = BatteryStatsImpl.isOnBattery(plugType, status);
+                        if (mStats.isOnBattery() == onBattery) {
+                            // The battery state has not changed, so we don't need to sync external
+                            // stats immediately.
+                            mStats.setBatteryStateLocked(status, health, plugType, level, temp,
+                                    volt, chargeUAh, chargeFullUAh, chargeTimeToFullSeconds,
+                                    elapsedRealtime, uptime, currentTime);
+                            return;
+                        }
+                    }
 
-            // Sync external stats first as the battery has changed states. If we don't sync
-            // before changing the state, we may not collect the relevant data later.
-            // Order here is guaranteed since we're scheduling from the same thread and we are
-            // using a single threaded executor.
-            mWorker.scheduleSync("battery-state", BatteryExternalStatsWorker.UPDATE_ALL);
-            mWorker.scheduleRunnable(() -> {
-                synchronized (mStats) {
-                    mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt,
-                            chargeUAh, chargeFullUAh, chargeTimeToFullSeconds);
-                }
+                    // Sync external stats first as the battery has changed states. If we don't sync
+                    // before changing the state, we may not collect the relevant data later.
+                    // Order here is guaranteed since we're scheduling from the same thread and we
+                    // are using a single threaded executor.
+                    mWorker.scheduleSync("battery-state", BatteryExternalStatsWorker.UPDATE_ALL);
+                    mWorker.scheduleRunnable(() -> {
+                        synchronized (mStats) {
+                            mStats.setBatteryStateLocked(status, health, plugType, level, temp,
+                                    volt, chargeUAh, chargeFullUAh, chargeTimeToFullSeconds,
+                                    elapsedRealtime, uptime, currentTime);
+                        }
+                    });
+                });
             });
-        });
+        }
     }
 
     public long getAwakeTimeBattery() {
@@ -1205,8 +1836,12 @@
             try {
                 String reason;
                 while ((reason = waitWakeup()) != null) {
+                    // Wait for the completion of pending works if there is any
+                    awaitCompletion();
+
                     synchronized (mStats) {
-                        mStats.noteWakeupReasonLocked(reason);
+                        mStats.noteWakeupReasonLocked(reason,
+                                SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
                     }
                 }
             } catch (RuntimeException e) {
@@ -1273,12 +1908,16 @@
     }
 
     private void dumpSettings(PrintWriter pw) {
+        // Wait for the completion of pending works if there is any
+        awaitCompletion();
         synchronized (mStats) {
             mStats.dumpConstantsLocked(pw);
         }
     }
 
     private void dumpCpuStats(PrintWriter pw) {
+        // Wait for the completion of pending works if there is any
+        awaitCompletion();
         synchronized (mStats) {
             mStats.dumpCpuStatsLocked(pw);
         }
@@ -1292,14 +1931,20 @@
             return -1;
         }
         if ("full-wake-history".equals(args[i]) || "full-history".equals(args[i])) {
+            // Wait for the completion of pending works if there is any
+            awaitCompletion();
             synchronized (mStats) {
                 mStats.setRecordAllHistoryLocked(enable);
             }
         } else if ("no-auto-reset".equals(args[i])) {
+            // Wait for the completion of pending works if there is any
+            awaitCompletion();
             synchronized (mStats) {
                 mStats.setNoAutoReset(enable);
             }
         } else if ("pretend-screen-off".equals(args[i])) {
+            // Wait for the completion of pending works if there is any
+            awaitCompletion();
             synchronized (mStats) {
                 mStats.setPretendScreenOff(enable);
             }
@@ -1350,6 +1995,7 @@
                         return;
                     }
                     final long events = ParseUtils.parseLong(args[i], 0);
+                    awaitCompletion();
                     synchronized (mStats) {
                         mStats.createFakeHistoryEvents(events);
                         pw.println("Battery history create events started.");
@@ -1365,6 +2011,7 @@
                 } else if ("--daily".equals(arg)) {
                     flags |= BatteryStats.DUMP_DAILY_ONLY;
                 } else if ("--reset".equals(arg)) {
+                    awaitCompletion();
                     synchronized (mStats) {
                         mStats.resetAllStatsCmdLocked();
                         pw.println("Battery stats reset.");
@@ -1372,6 +2019,7 @@
                     }
                     mWorker.scheduleSync("dump", BatteryExternalStatsWorker.UPDATE_ALL);
                 } else if ("--write".equals(arg)) {
+                    awaitCompletion();
                     syncStats("dump", BatteryExternalStatsWorker.UPDATE_ALL);
                     synchronized (mStats) {
                         mStats.writeSyncLocked();
@@ -1379,12 +2027,14 @@
                         noOutput = true;
                     }
                 } else if ("--new-daily".equals(arg)) {
+                    awaitCompletion();
                     synchronized (mStats) {
                         mStats.recordDailyStatsLocked();
                         pw.println("New daily stats written.");
                         noOutput = true;
                     }
                 } else if ("--read-daily".equals(arg)) {
+                    awaitCompletion();
                     synchronized (mStats) {
                         mStats.readDailyStatsLocked();
                         pw.println("Last daily stats read.");
@@ -1441,6 +2091,7 @@
             if (BatteryStatsHelper.checkWifiOnly(mContext)) {
                 flags |= BatteryStats.DUMP_DEVICE_WIFI_ONLY;
             }
+            awaitCompletion();
             // Fetch data from external sources and update the BatteryStatsImpl object with them.
             syncStats("dump", BatteryExternalStatsWorker.UPDATE_ALL);
         } finally {
@@ -1489,6 +2140,7 @@
                 }
             }
             if (DBG) Slog.d(TAG, "begin dumpProtoLocked from UID " + Binder.getCallingUid());
+            awaitCompletion();
             synchronized (mStats) {
                 mStats.dumpProtoLocked(mContext, fd, apps, flags, historyStart);
                 if (writeData) {
@@ -1528,6 +2180,7 @@
                 }
             }
             if (DBG) Slog.d(TAG, "begin dumpCheckinLocked from UID " + Binder.getCallingUid());
+            awaitCompletion();
             synchronized (mStats) {
                 mStats.dumpCheckinLocked(mContext, pw, apps, flags, historyStart);
                 if (writeData) {
@@ -1537,6 +2190,7 @@
             if (DBG) Slog.d(TAG, "end dumpCheckinLocked");
         } else {
             if (DBG) Slog.d(TAG, "begin dumpLocked from UID " + Binder.getCallingUid());
+            awaitCompletion();
             synchronized (mStats) {
                 mStats.dumpLocked(mContext, pw, flags, reqUid, historyStart);
                 if (writeData) {
@@ -1552,6 +2206,8 @@
      * @hide
      */
     public CellularBatteryStats getCellularBatteryStats() {
+        // Wait for the completion of pending works if there is any
+        awaitCompletion();
         synchronized (mStats) {
             return mStats.getCellularBatteryStats();
         }
@@ -1562,6 +2218,8 @@
      * @hide
      */
     public WifiBatteryStats getWifiBatteryStats() {
+        // Wait for the completion of pending works if there is any
+        awaitCompletion();
         synchronized (mStats) {
             return mStats.getWifiBatteryStats();
         }
@@ -1572,6 +2230,8 @@
      * @hide
      */
     public GpsBatteryStats getGpsBatteryStats() {
+        // Wait for the completion of pending works if there is any
+        awaitCompletion();
         synchronized (mStats) {
             return mStats.getGpsBatteryStats();
         }
@@ -1588,6 +2248,8 @@
         }
         long ident = Binder.clearCallingIdentity();
         try {
+            // Wait for the completion of pending works if there is any
+            awaitCompletion();
             if (shouldCollectExternalStats()) {
                 syncStats("get-health-stats-for-uids", BatteryExternalStatsWorker.UPDATE_ALL);
             }
@@ -1614,6 +2276,8 @@
         long ident = Binder.clearCallingIdentity();
         int i=-1;
         try {
+            // Wait for the completion of pending works if there is any
+            awaitCompletion();
             if (shouldCollectExternalStats()) {
                 syncStats("get-health-stats-for-uids", BatteryExternalStatsWorker.UPDATE_ALL);
             }
@@ -1685,4 +2349,124 @@
             Binder.restoreCallingIdentity(ident);
         }
     }
+
+    void updateForegroundTimeIfOnBattery(final String packageName, final int uid,
+            final long cpuTimeDiff) {
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                if (!isOnBattery()) {
+                    return;
+                }
+                synchronized (mStats) {
+                    final BatteryStatsImpl.Uid.Proc ps =
+                            mStats.getProcessStatsLocked(uid, packageName, elapsedRealtime, uptime);
+                    if (ps != null) {
+                        ps.addForegroundTimeLocked(cpuTimeDiff);
+                    }
+                }
+            });
+        }
+    }
+
+    void noteCurrentTimeChanged() {
+        synchronized (mLock) {
+            final long currentTime = System.currentTimeMillis();
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteCurrentTimeChangedLocked(currentTime, elapsedRealtime, uptime);
+                }
+            });
+        }
+    }
+
+    void updateBatteryStatsOnActivityUsage(final String packageName, final String className,
+            final int uid, final int userId, final boolean resumed) {
+        synchronized (mLock) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                FrameworkStatsLog.write(FrameworkStatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED,
+                        uid, packageName, className,
+                        resumed
+                        ? FrameworkStatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__FOREGROUND
+                        : FrameworkStatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__BACKGROUND);
+                synchronized (mStats) {
+                    if (resumed) {
+                        mStats.noteActivityResumedLocked(uid, elapsedRealtime, uptime);
+                    } else {
+                        mStats.noteActivityPausedLocked(uid, elapsedRealtime, uptime);
+                    }
+                }
+            });
+        }
+    }
+
+    void noteProcessDied(final int uid, final int pid) {
+        synchronized (mLock) {
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.noteProcessDiedLocked(uid, pid);
+                }
+            });
+        }
+    }
+
+    void reportExcessiveCpu(final int uid, final String processName, final long uptimeSince,
+            long cputimeUsed) {
+        synchronized (mLock) {
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    mStats.reportExcessiveCpuLocked(uid, processName, uptimeSince, cputimeUsed);
+                }
+            });
+        }
+    }
+
+    void noteServiceStartRunning(final BatteryStatsImpl.Uid.Pkg.Serv stats) {
+        synchronized (mLock) {
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    stats.startRunningLocked(uptime);
+                }
+            });
+        }
+    }
+
+    void noteServiceStopRunning(final BatteryStatsImpl.Uid.Pkg.Serv stats) {
+        synchronized (mLock) {
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    stats.stopRunningLocked(uptime);
+                }
+            });
+        }
+    }
+
+    void noteServiceStartLaunch(final BatteryStatsImpl.Uid.Pkg.Serv stats) {
+        synchronized (mLock) {
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    stats.startLaunchedLocked(uptime);
+                }
+            });
+        }
+    }
+
+    void noteServiceStopLaunch(final BatteryStatsImpl.Uid.Pkg.Serv stats) {
+        synchronized (mLock) {
+            final long uptime = SystemClock.uptimeMillis();
+            mHandler.post(() -> {
+                synchronized (mStats) {
+                    stats.stopLaunchedLocked(uptime);
+                }
+            });
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index c5047e5..9660389 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -479,6 +479,21 @@
     private static native void enableFreezerInternal(boolean enable);
 
     /**
+     * Informs binder that a process is about to be frozen. If freezer is enabled on a process via
+     * this method, this method will synchronously dispatch all pending transactions to the
+     * specified pid. This method will not add significant latencies when unfreezing.
+     * After freezing binder calls, binder will block all transaction to the frozen pid, and return
+     * an error to the sending process.
+     *
+     * @param pid the target pid for which binder transactions are to be frozen
+     * @param freeze specifies whether to flush transactions and then freeze (true) or unfreeze
+     * binder for the specificed pid.
+     *
+     * @throws RuntimeException in case a flush/freeze operation could not complete successfully.
+     */
+    private static native void freezeBinder(int pid, boolean freeze);
+
+    /**
      * Determines whether the freezer is supported by this system
      */
     public static boolean isFreezerSupported() {
@@ -727,6 +742,13 @@
         }
 
         if (!app.frozen) {
+            try {
+                freezeBinder(app.pid, false);
+            } catch (RuntimeException e) {
+                // TODO: it might be preferable to kill the target pid in this case
+                Slog.e(TAG_AM, "Unable to unfreeze binder for " + app.pid + " " + app.processName);
+            }
+
             if (DEBUG_FREEZER) {
                 Slog.d(TAG_AM, "sync unfroze " + app.pid + " " + app.processName);
             }
@@ -1039,6 +1061,14 @@
                     return;
                 }
 
+                try {
+                    freezeBinder(pid, true);
+                } catch (RuntimeException e) {
+                    // TODO: it might be preferable to kill the target pid in this case
+                    Slog.e(TAG_AM, "Unable to freeze binder for " + pid + " " + name);
+                    return;
+                }
+
                 if (pid == 0 || proc.frozen) {
                     // Already frozen or not a real process, either one being
                     // launched or one being killed
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index ab36aec..b56b09d 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -2206,6 +2206,7 @@
             updatePermissionRevokedCompat(uid, code, mode);
         }
 
+        int previousMode;
         synchronized (this) {
             final int defaultMode = AppOpsManager.opToDefaultMode(code);
 
@@ -2214,12 +2215,14 @@
                 if (mode == defaultMode) {
                     return;
                 }
+                previousMode = AppOpsManager.MODE_DEFAULT;
                 uidState = new UidState(uid);
                 uidState.opModes = new SparseIntArray();
                 uidState.opModes.put(code, mode);
                 mUidStates.put(uid, uidState);
                 scheduleWriteLocked();
             } else if (uidState.opModes == null) {
+                previousMode = AppOpsManager.MODE_DEFAULT;
                 if (mode != defaultMode) {
                     uidState.opModes = new SparseIntArray();
                     uidState.opModes.put(code, mode);
@@ -2229,6 +2232,7 @@
                 if (uidState.opModes.indexOfKey(code) >= 0 && uidState.opModes.get(code) == mode) {
                     return;
                 }
+                previousMode = uidState.opModes.get(code);
                 if (mode == defaultMode) {
                     uidState.opModes.delete(code);
                     if (uidState.opModes.size() <= 0) {
@@ -2243,7 +2247,7 @@
         }
 
         notifyOpChangedForAllPkgsInUid(code, uid, false, permissionPolicyCallback);
-        notifyOpChangedSync(code, uid, null, mode);
+        notifyOpChangedSync(code, uid, null, mode, previousMode);
     }
 
     /**
@@ -2420,11 +2424,12 @@
         }
     }
 
-    private void notifyOpChangedSync(int code, int uid, @NonNull String packageName, int mode) {
+    private void notifyOpChangedSync(int code, int uid, @NonNull String packageName, int mode,
+            int previousMode) {
         final StorageManagerInternal storageManagerInternal =
                 LocalServices.getService(StorageManagerInternal.class);
         if (storageManagerInternal != null) {
-            storageManagerInternal.onAppOpsChanged(code, uid, packageName, mode);
+            storageManagerInternal.onAppOpsChanged(code, uid, packageName, mode, previousMode);
         }
     }
 
@@ -2458,11 +2463,13 @@
             return;
         }
 
+        int previousMode = AppOpsManager.MODE_DEFAULT;
         synchronized (this) {
             UidState uidState = getUidStateLocked(uid, false);
             Op op = getOpLocked(code, uid, packageName, null, bypass, true);
             if (op != null) {
                 if (op.mode != mode) {
+                    previousMode = op.mode;
                     op.mode = mode;
                     if (uidState != null) {
                         uidState.evalForegroundOps(mOpModeWatchers);
@@ -2499,7 +2506,7 @@
                     this, repCbs, code, uid, packageName));
         }
 
-        notifyOpChangedSync(code, uid, packageName, mode);
+        notifyOpChangedSync(code, uid, packageName, mode, previousMode);
     }
 
     private void notifyOpChanged(ArraySet<ModeCallback> callbacks, int code,
@@ -2542,7 +2549,7 @@
     }
 
     private static ArrayList<ChangeRec> addChange(ArrayList<ChangeRec> reports,
-            int op, int uid, String packageName) {
+            int op, int uid, String packageName, int previousMode) {
         boolean duplicate = false;
         if (reports == null) {
             reports = new ArrayList<>();
@@ -2557,7 +2564,7 @@
             }
         }
         if (!duplicate) {
-            reports.add(new ChangeRec(op, uid, packageName));
+            reports.add(new ChangeRec(op, uid, packageName, previousMode));
         }
 
         return reports;
@@ -2565,7 +2572,7 @@
 
     private static HashMap<ModeCallback, ArrayList<ChangeRec>> addCallbacks(
             HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks,
-            int op, int uid, String packageName, ArraySet<ModeCallback> cbs) {
+            int op, int uid, String packageName, int previousMode, ArraySet<ModeCallback> cbs) {
         if (cbs == null) {
             return callbacks;
         }
@@ -2576,7 +2583,7 @@
         for (int i=0; i<N; i++) {
             ModeCallback cb = cbs.valueAt(i);
             ArrayList<ChangeRec> reports = callbacks.get(cb);
-            ArrayList<ChangeRec> changed = addChange(reports, op, uid, packageName);
+            ArrayList<ChangeRec> changed = addChange(reports, op, uid, packageName, previousMode);
             if (changed != reports) {
                 callbacks.put(cb, changed);
             }
@@ -2588,11 +2595,13 @@
         final int op;
         final int uid;
         final String pkg;
+        final int previous_mode;
 
-        ChangeRec(int _op, int _uid, String _pkg) {
+        ChangeRec(int _op, int _uid, String _pkg, int _previous_mode) {
             op = _op;
             uid = _uid;
             pkg = _pkg;
+            previous_mode = _previous_mode;
         }
     }
 
@@ -2628,18 +2637,19 @@
                     for (int j = uidOpCount - 1; j >= 0; j--) {
                         final int code = opModes.keyAt(j);
                         if (AppOpsManager.opAllowsReset(code)) {
+                            int previousMode = opModes.valueAt(j);
                             opModes.removeAt(j);
                             if (opModes.size() <= 0) {
                                 uidState.opModes = null;
                             }
                             for (String packageName : getPackagesForUid(uidState.uid)) {
                                 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
-                                        mOpModeWatchers.get(code));
+                                        previousMode, mOpModeWatchers.get(code));
                                 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
-                                        mPackageModeWatchers.get(packageName));
+                                        previousMode, mPackageModeWatchers.get(packageName));
 
                                 allChanges = addChange(allChanges, code, uidState.uid,
-                                        packageName);
+                                        packageName, previousMode);
                             }
                         }
                     }
@@ -2670,16 +2680,18 @@
                         Op curOp = pkgOps.valueAt(j);
                         if (AppOpsManager.opAllowsReset(curOp.op)
                                 && curOp.mode != AppOpsManager.opToDefaultMode(curOp.op)) {
+                            int previousMode = curOp.mode;
                             curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
                             changed = true;
                             uidChanged = true;
                             final int uid = curOp.uidState.uid;
                             callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
-                                    mOpModeWatchers.get(curOp.op));
+                                    previousMode, mOpModeWatchers.get(curOp.op));
                             callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
-                                    mPackageModeWatchers.get(packageName));
+                                    previousMode, mPackageModeWatchers.get(packageName));
 
-                            allChanges = addChange(allChanges, curOp.op, uid, packageName);
+                            allChanges = addChange(allChanges, curOp.op, uid, packageName,
+                                    previousMode);
                             curOp.removeAttributionsWithNoTime();
                             if (curOp.mAttributions.isEmpty()) {
                                 pkgOps.removeAt(j);
@@ -2720,7 +2732,7 @@
             for (int i = 0; i < numChanges; i++) {
                 ChangeRec change = allChanges.get(i);
                 notifyOpChangedSync(change.op, change.uid, change.pkg,
-                        AppOpsManager.opToDefaultMode(change.op));
+                        AppOpsManager.opToDefaultMode(change.op), change.previous_mode);
             }
         }
     }
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 92fce8a..c7de8d3 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -107,17 +107,23 @@
     }
 
     /**
-     * Internal version of the above method. Does not perform costly permission check.
+     * Internal version of the above method, without logging. Does not perform costly permission
+     * check.
+     * TODO(b/167551701): Remove this method and add 'loggability' as a changeid property.
+     */
+    public boolean isChangeEnabledInternalNoLogging(long changeId, ApplicationInfo appInfo) {
+        return mCompatConfig.isChangeEnabled(changeId, appInfo);
+    }
+
+    /**
+     * Internal version of {@link #isChangeEnabled(long, ApplicationInfo)}. Does not perform costly
+     * permission check.
      */
     public boolean isChangeEnabledInternal(long changeId, ApplicationInfo appInfo) {
-        if (mCompatConfig.isChangeEnabled(changeId, appInfo)) {
-            reportChange(changeId, appInfo.uid,
-                    ChangeReporter.STATE_ENABLED);
-            return true;
-        }
+        boolean value = isChangeEnabledInternalNoLogging(changeId, appInfo);
         reportChange(changeId, appInfo.uid,
-                ChangeReporter.STATE_DISABLED);
-        return false;
+                value ? ChangeReporter.STATE_ENABLED : ChangeReporter.STATE_DISABLED);
+        return value;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 36d69c9..f42e18a 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -17,8 +17,8 @@
 package com.android.server.display;
 
 import android.annotation.Nullable;
-import android.app.ActivityManager.StackInfo;
 import android.app.ActivityTaskManager;
+import android.app.ActivityTaskManager.RootTaskInfo;
 import android.app.IActivityTaskManager;
 import android.app.TaskStackListener;
 import android.content.Context;
@@ -846,7 +846,7 @@
             public void run() {
                 try {
                     // The foreground app is the top activity of the focused tasks stack.
-                    final StackInfo info = mActivityTaskManager.getFocusedStackInfo();
+                    final RootTaskInfo info = mActivityTaskManager.getFocusedRootTaskInfo();
                     if (info == null || info.topActivity == null) {
                         return;
                     }
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index eea1980..9e82d4f 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -20,6 +20,7 @@
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
+import android.app.ActivityTaskManager.RootTaskInfo;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -377,14 +378,14 @@
         }
 
         try {
-            final ActivityManager.StackInfo focusedStack = mInjector.getFocusedStack();
-            if (focusedStack != null && focusedStack.topActivity != null) {
-                builder.setUserId(focusedStack.userId);
-                builder.setPackageName(focusedStack.topActivity.getPackageName());
+            final RootTaskInfo focusedTask = mInjector.getFocusedStack();
+            if (focusedTask != null && focusedTask.topActivity != null) {
+                builder.setUserId(focusedTask.userId);
+                builder.setPackageName(focusedTask.topActivity.getPackageName());
             } else {
                 // Ignore the event because we can't determine user / package.
                 if (DEBUG) {
-                    Slog.d(TAG, "Ignoring event due to null focusedStack.");
+                    Slog.d(TAG, "Ignoring event due to null focusedTask.");
                 }
                 return;
             }
@@ -1104,8 +1105,8 @@
             }
         }
 
-        public ActivityManager.StackInfo getFocusedStack() throws RemoteException {
-            return ActivityTaskManager.getService().getFocusedStackInfo();
+        public RootTaskInfo getFocusedStack() throws RemoteException {
+            return ActivityTaskManager.getService().getFocusedRootTaskInfo();
         }
 
         public void scheduleIdleJob(Context context) {
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 813def4..6c14b2c 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -222,7 +222,7 @@
     private static native void nativeRegisterInputChannel(long ptr, InputChannel inputChannel);
     private static native void nativeRegisterInputMonitor(long ptr, InputChannel inputChannel,
             int displayId, boolean isGestureMonitor);
-    private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel);
+    private static native void nativeUnregisterInputChannel(long ptr, IBinder connectionToken);
     private static native void nativePilferPointers(long ptr, IBinder token);
     private static native void nativeSetInputFilterEnabled(long ptr, boolean enable);
     private static native void nativeSetInTouchMode(long ptr, boolean inTouchMode);
@@ -581,17 +581,17 @@
 
     /**
      * Unregisters an input channel.
-     * @param inputChannel The input channel to unregister.
+     * @param connectionToken The input channel to unregister.
      */
-    public void unregisterInputChannel(InputChannel inputChannel) {
-        if (inputChannel == null) {
-            throw new IllegalArgumentException("inputChannel must not be null.");
+    public void unregisterInputChannel(IBinder connectionToken) {
+        if (connectionToken == null) {
+            throw new IllegalArgumentException("connectionToken must not be null.");
         }
         synchronized (mGestureMonitorPidsLock) {
-            mGestureMonitorPidsByToken.remove(inputChannel.getToken());
+            mGestureMonitorPidsByToken.remove(connectionToken);
         }
 
-        nativeUnregisterInputChannel(mPtr, inputChannel);
+        nativeUnregisterInputChannel(mPtr, connectionToken);
     }
 
     /**
@@ -2455,7 +2455,7 @@
 
         @Override
         public void dispose() {
-            nativeUnregisterInputChannel(mPtr, mInputChannel);
+            nativeUnregisterInputChannel(mPtr, mInputChannel.getToken());
             mInputChannel.dispose();
         }
     }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 8368df9e..7401403 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1958,6 +1958,13 @@
             }
 
             @Override
+            void onConsolidatedPolicyChanged() {
+                Binder.withCleanCallingIdentity(() -> {
+                    mRankingHandler.requestSort();
+                });
+            }
+
+            @Override
             void onAutomaticRuleStatusChanged(int userId, String pkg, String id, int status) {
                 Binder.withCleanCallingIdentity(() -> {
                     Intent intent = new Intent(ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED);
@@ -8465,7 +8472,10 @@
         if (Notification.CATEGORY_CAR_EMERGENCY.equals(notification.category)
                 || Notification.CATEGORY_CAR_WARNING.equals(notification.category)
                 || Notification.CATEGORY_CAR_INFORMATION.equals(notification.category)) {
-                    checkCallerIsSystem();
+            getContext().enforceCallingPermission(
+                    android.Manifest.permission.SEND_CATEGORY_CAR_NOTIFICATIONS,
+                    String.format("Notification category %s restricted",
+                            notification.category));
         }
     }
 
diff --git a/services/core/java/com/android/server/om/OverlayActorEnforcer.java b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
index 8c03c6c..8121a43e9 100644
--- a/services/core/java/com/android/server/om/OverlayActorEnforcer.java
+++ b/services/core/java/com/android/server/om/OverlayActorEnforcer.java
@@ -26,6 +26,7 @@
 import android.text.TextUtils;
 import android.util.Pair;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.CollectionUtils;
 
@@ -66,7 +67,7 @@
 
         String actorNamespace = actorUri.getAuthority();
         Map<String, String> namespace = namedActors.get(actorNamespace);
-        if (namespace == null) {
+        if (ArrayUtils.isEmpty(namespace)) {
             return Pair.create(null, ActorState.MISSING_NAMESPACE);
         }
 
@@ -102,21 +103,32 @@
      * See {@link OverlayActorEnforcer} class comment for actor requirements.
      * @return true if the actor is allowed to act on the target overlayInfo
      */
-    private ActorState isAllowedActor(String methodName, OverlayInfo overlayInfo,
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+    public ActorState isAllowedActor(String methodName, OverlayInfo overlayInfo,
             int callingUid, int userId) {
+        // Checked first to avoid package not found errors, which are ignored for calls from shell
         switch (callingUid) {
             case Process.ROOT_UID:
             case Process.SYSTEM_UID:
                 return ActorState.ALLOWED;
         }
 
+        final String targetPackageName = overlayInfo.targetPackageName;
+        final PackageInfo targetPkgInfo = mPackageManager.getPackageInfo(targetPackageName, userId);
+        if (targetPkgInfo == null) {
+            return ActorState.TARGET_NOT_FOUND;
+        }
+
+        if ((targetPkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+            return ActorState.ALLOWED;
+        }
+
         String[] callingPackageNames = mPackageManager.getPackagesForUid(callingUid);
         if (ArrayUtils.isEmpty(callingPackageNames)) {
             return ActorState.NO_PACKAGES_FOR_UID;
         }
 
         // A target is always an allowed actor for itself
-        String targetPackageName = overlayInfo.targetPackageName;
         if (ArrayUtils.contains(callingPackageNames, targetPackageName)) {
             return ActorState.ALLOWED;
         }
@@ -149,7 +161,7 @@
             targetOverlayable = mPackageManager.getOverlayableForTarget(targetPackageName,
                     targetOverlayableName, userId);
         } catch (IOException e) {
-            return ActorState.UNABLE_TO_GET_TARGET;
+            return ActorState.UNABLE_TO_GET_TARGET_OVERLAYABLE;
         }
 
         if (targetOverlayable == null) {
@@ -189,7 +201,7 @@
         }
 
         // Currently only pre-installed apps can be actors
-        if (!appInfo.isSystemApp() && !appInfo.isUpdatedSystemApp()) {
+        if (!appInfo.isSystemApp()) {
             return ActorState.ACTOR_NOT_PREINSTALLED;
         }
 
@@ -203,22 +215,25 @@
     /**
      * For easier logging/debugging, a set of all possible failure/success states when running
      * enforcement.
+     *
+     * The ordering of this enum should be maintained in the order that cases are checked in code,
+     * as this ordering is used inside OverlayActorEnforcerTests.
      */
     public enum ActorState {
-        ALLOWED,
-        INVALID_ACTOR,
-        MISSING_NAMESPACE,
-        MISSING_PACKAGE,
-        MISSING_APP_INFO,
-        ACTOR_NOT_PREINSTALLED,
+        TARGET_NOT_FOUND,
         NO_PACKAGES_FOR_UID,
-        MISSING_ACTOR_NAME,
-        ERROR_READING_OVERLAYABLE,
         MISSING_TARGET_OVERLAYABLE_NAME,
+        MISSING_LEGACY_PERMISSION,
+        ERROR_READING_OVERLAYABLE,
+        UNABLE_TO_GET_TARGET_OVERLAYABLE,
         MISSING_OVERLAYABLE,
         INVALID_OVERLAYABLE_ACTOR_NAME,
         NO_NAMED_ACTORS,
-        UNABLE_TO_GET_TARGET,
-        MISSING_LEGACY_PERMISSION
+        MISSING_NAMESPACE,
+        MISSING_ACTOR_NAME,
+        MISSING_APP_INFO,
+        ACTOR_NOT_PREINSTALLED,
+        INVALID_ACTOR,
+        ALLOWED
     }
 }
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 07527c2..5b5ec42 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -778,7 +778,7 @@
         void registerApkInApex(AndroidPackage pkg) {
             synchronized (mLock) {
                 for (ActiveApexInfo aai : mActiveApexInfosCache) {
-                    if (pkg.getBaseCodePath().startsWith(aai.apexDirectory.getAbsolutePath())) {
+                    if (pkg.getBaseApkPath().startsWith(aai.apexDirectory.getAbsolutePath())) {
                         List<String> apks = mApksInApex.get(aai.apexModuleName);
                         if (apks == null) {
                             apks = Lists.newArrayList();
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index f168ac7..dac2e4f 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -303,7 +303,8 @@
 
         private void updateEnabledState(@NonNull AndroidPackage pkg) {
             // TODO(b/135203078): Do not use toAppInfo
-            final boolean enabled = mInjector.getCompatibility().isChangeEnabledInternal(
+            // TODO(b/167551701): Make changeId non-logging
+            final boolean enabled = mInjector.getCompatibility().isChangeEnabledInternalNoLogging(
                     PackageManager.FILTER_APPLICATION_QUERY, pkg.toAppInfoWithoutState());
             if (enabled) {
                 mDisabledPackages.remove(pkg.getPackageName());
@@ -639,24 +640,74 @@
         }
     }
 
-    private void updateEntireShouldFilterCacheAsync() {
-        mBackgroundExecutor.execute(this::updateEntireShouldFilterCache);
-    }
-
     private void updateEntireShouldFilterCache() {
         mStateProvider.runWithState((settings, users) -> {
             SparseArray<SparseBooleanArray> cache =
-                    new SparseArray<>(users.length * settings.size());
-            for (int i = settings.size() - 1; i >= 0; i--) {
-                updateShouldFilterCacheForPackage(cache,
-                        null /*skipPackage*/, settings.valueAt(i), settings, users, i);
-            }
+                    updateEntireShouldFilterCacheInner(settings, users);
             synchronized (mCacheLock) {
                 mShouldFilterCache = cache;
             }
         });
     }
 
+    private SparseArray<SparseBooleanArray> updateEntireShouldFilterCacheInner(
+            ArrayMap<String, PackageSetting> settings, UserInfo[] users) {
+        SparseArray<SparseBooleanArray> cache =
+                new SparseArray<>(users.length * settings.size());
+        for (int i = settings.size() - 1; i >= 0; i--) {
+            updateShouldFilterCacheForPackage(cache,
+                    null /*skipPackage*/, settings.valueAt(i), settings, users, i);
+        }
+        return cache;
+    }
+
+    private void updateEntireShouldFilterCacheAsync() {
+        mBackgroundExecutor.execute(() -> {
+            final ArrayMap<String, PackageSetting> settingsCopy = new ArrayMap<>();
+            final ArrayMap<String, AndroidPackage> packagesCache = new ArrayMap<>();
+            final UserInfo[][] usersRef = new UserInfo[1][];
+            mStateProvider.runWithState((settings, users) -> {
+                packagesCache.ensureCapacity(settings.size());
+                settingsCopy.putAll(settings);
+                usersRef[0] = users;
+                // store away the references to the immutable packages, since settings are retained
+                // during updates.
+                for (int i = 0, max = settings.size(); i < max; i++) {
+                    final AndroidPackage pkg = settings.valueAt(i).pkg;
+                    packagesCache.put(settings.keyAt(i), pkg);
+                }
+            });
+            SparseArray<SparseBooleanArray> cache =
+                    updateEntireShouldFilterCacheInner(settingsCopy, usersRef[0]);
+            boolean[] changed = new boolean[1];
+            // We have a cache, let's make sure the world hasn't changed out from under us.
+            mStateProvider.runWithState((settings, users) -> {
+                if (settings.size() != settingsCopy.size()) {
+                    changed[0] = true;
+                    return;
+                }
+                for (int i = 0, max = settings.size(); i < max; i++) {
+                    final AndroidPackage pkg = settings.valueAt(i).pkg;
+                    if (!Objects.equals(pkg, packagesCache.get(settings.keyAt(i)))) {
+                        changed[0] = true;
+                        return;
+                    }
+                }
+            });
+            if (changed[0]) {
+                // Something has changed, just update the cache inline with the lock held
+                updateEntireShouldFilterCache();
+                if (DEBUG_LOGGING) {
+                    Slog.i(TAG, "Rebuilding cache with lock due to package change.");
+                }
+            } else {
+                synchronized (mCacheLock) {
+                    mShouldFilterCache = cache;
+                }
+            }
+        });
+    }
+
     public void onUsersChanged() {
         synchronized (mCacheLock) {
             if (mShouldFilterCache != null) {
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index eddab76..7db2319 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -384,17 +384,17 @@
             if (!PackageDexOptimizer.canOptimizePackage(pkg)) {
                 continue;
             }
-            if (pkg.getCodePath() == null) {
+            if (pkg.getPath() == null) {
                 Slog.w(TAG, "Package " + pkg + " can be optimized but has null codePath");
                 continue;
             }
 
             // If the path is in /system, /vendor, /product or /system_ext, ignore. It will
             // have been ota-dexopted into /data/ota and moved into the dalvik-cache already.
-            if (pkg.getCodePath().startsWith("/system")
-                    || pkg.getCodePath().startsWith("/vendor")
-                    || pkg.getCodePath().startsWith("/product")
-                    || pkg.getCodePath().startsWith("/system_ext")) {
+            if (pkg.getPath().startsWith("/system")
+                    || pkg.getPath().startsWith("/vendor")
+                    || pkg.getPath().startsWith("/product")
+                    || pkg.getPath().startsWith("/system_ext")) {
                 continue;
             }
 
@@ -408,7 +408,7 @@
             for (String dexCodeInstructionSet : dexCodeInstructionSets) {
                 for (String path : paths) {
                     String oatDir = PackageDexOptimizer.getOatDir(
-                            new File(pkg.getCodePath())).getAbsolutePath();
+                            new File(pkg.getPath())).getAbsolutePath();
 
                     // TODO: Check first whether there is an artifact, to save the roundtrip time.
 
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
index 8af7e1f..da4ea16 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -136,7 +136,7 @@
         // Trying to derive the paths, thus need the raw ABI info from the parsed package, and the
         // current state in PackageSetting is irrelevant.
         return deriveNativeLibraryPaths(new Abis(pkg.getPrimaryCpuAbi(), pkg.getSecondaryCpuAbi()),
-                appLib32InstallDir, pkg.getCodePath(), pkg.getBaseCodePath(), pkg.isSystem(),
+                appLib32InstallDir, pkg.getPath(), pkg.getBaseApkPath(), pkg.isSystem(),
                 isUpdatedSystemApp);
     }
 
@@ -205,11 +205,11 @@
 
     @Override
     public Abis getBundledAppAbis(AndroidPackage pkg) {
-        final String apkName = deriveCodePathName(pkg.getCodePath());
+        final String apkName = deriveCodePathName(pkg.getPath());
 
         // If "/system/lib64/apkname" exists, assume that is the per-package
         // native library directory to use; otherwise use "/system/lib/apkname".
-        final String apkRoot = calculateBundledApkRoot(pkg.getBaseCodePath());
+        final String apkRoot = calculateBundledApkRoot(pkg.getBaseApkPath());
         final Abis abis = getBundledAppAbi(pkg, apkRoot, apkName);
         return abis;
     }
@@ -223,7 +223,7 @@
      * @param apkName the name of the installed package.
      */
     private Abis getBundledAppAbi(AndroidPackage pkg, String apkRoot, String apkName) {
-        final File codeFile = new File(pkg.getCodePath());
+        final File codeFile = new File(pkg.getPath());
 
         final boolean has64BitLibs;
         final boolean has32BitLibs;
@@ -304,15 +304,15 @@
         String pkgRawSecondaryCpuAbi = AndroidPackageUtils.getRawSecondaryCpuAbi(pkg);
         final NativeLibraryPaths initialLibraryPaths = deriveNativeLibraryPaths(
                 new Abis(pkgRawPrimaryCpuAbi, pkgRawSecondaryCpuAbi),
-                PackageManagerService.sAppLib32InstallDir, pkg.getCodePath(),
-                pkg.getBaseCodePath(), pkg.isSystem(),
+                PackageManagerService.sAppLib32InstallDir, pkg.getPath(),
+                pkg.getBaseApkPath(), pkg.isSystem(),
                 isUpdatedSystemApp);
 
         final boolean extractLibs = shouldExtractLibs(pkg, isUpdatedSystemApp);
 
         final String nativeLibraryRootStr = initialLibraryPaths.nativeLibraryRootDir;
         final boolean useIsaSpecificSubdirs = initialLibraryPaths.nativeLibraryRootRequiresIsa;
-        final boolean onIncremental = isIncrementalPath(pkg.getCodePath());
+        final boolean onIncremental = isIncrementalPath(pkg.getPath());
 
         String primaryCpuAbi = null;
         String secondaryCpuAbi = null;
@@ -453,7 +453,7 @@
         final Abis abis = new Abis(primaryCpuAbi, secondaryCpuAbi);
         return new Pair<>(abis,
                 deriveNativeLibraryPaths(abis, PackageManagerService.sAppLib32InstallDir,
-                        pkg.getCodePath(), pkg.getBaseCodePath(), pkg.isSystem(),
+                        pkg.getPath(), pkg.getBaseApkPath(), pkg.isSystem(),
                         isUpdatedSystemApp));
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 0d8ba3e..42e6d8f 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -199,7 +199,7 @@
             throw new IllegalStateException("Inconsistent information "
                 + "between PackageParser.Package and its ApplicationInfo. "
                 + "pkg.getAllCodePaths=" + paths
-                + " pkg.getBaseCodePath=" + pkg.getBaseCodePath()
+                + " pkg.getBaseCodePath=" + pkg.getBaseApkPath()
                 + " pkg.getSplitCodePaths="
                 + (splitCodePaths == null ? "null" : Arrays.toString(splitCodePaths)));
         }
@@ -772,7 +772,7 @@
         if (!AndroidPackageUtils.canHaveOatDir(pkg, isUpdatedSystemApp)) {
             return null;
         }
-        File codePath = new File(pkg.getCodePath());
+        File codePath = new File(pkg.getPath());
         if (!codePath.isDirectory()) {
             return null;
         }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index ca12532..17cd8f5 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2083,7 +2083,7 @@
         if (ps == null) {
             return 0;
         }
-        final File apkDirOrPath = ps.getCodePath();
+        final File apkDirOrPath = ps.getPath();
         if (apkDirOrPath == null) {
             return 0;
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7945d84..dffd5b3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2220,7 +2220,7 @@
             // Send installed broadcasts if the package is not a static shared lib.
             if (res.pkg.getStaticSharedLibName() == null) {
                 mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(
-                        res.pkg.getBaseCodePath());
+                        res.pkg.getBaseApkPath());
 
                 // Send added for users that see the package for the first time
                 // sendPackageAddedForNewUsers also deals with system apps
@@ -3101,7 +3101,7 @@
             final int packageSettingCount = mSettings.mPackages.size();
             for (int i = packageSettingCount - 1; i >= 0; i--) {
                 PackageSetting ps = mSettings.mPackages.valueAt(i);
-                if (!isExternal(ps) && (ps.getCodePath() == null || !ps.getCodePath().exists())
+                if (!isExternal(ps) && (ps.getPath() == null || !ps.getPath().exists())
                         && mSettings.getDisabledSystemPkgLPr(ps.name) != null) {
                     mSettings.mPackages.removeAt(i);
                     mSettings.enableSystemPackageLPw(ps.name);
@@ -3266,11 +3266,11 @@
                             logCriticalInfo(Log.WARN,
                                     "Expecting better updated system app for " + ps.name
                                     + "; removing system app.  Last known"
-                                    + " codePath=" + ps.getCodePathString()
+                                    + " codePath=" + ps.getPathString()
                                     + ", versionCode=" + ps.versionCode
                                     + "; scanned versionCode=" + scannedPkg.getLongVersionCode());
                             removePackageLI(scannedPkg, true);
-                            mExpectingBetter.put(ps.name, ps.getCodePath());
+                            mExpectingBetter.put(ps.name, ps.getPath());
                         }
 
                         continue;
@@ -3293,14 +3293,14 @@
                         // code path, but, changes the package name.
                         final PackageSetting disabledPs =
                                 mSettings.getDisabledSystemPkgLPr(ps.name);
-                        if (disabledPs.getCodePath() == null || !disabledPs.getCodePath().exists()
+                        if (disabledPs.getPath() == null || !disabledPs.getPath().exists()
                                 || disabledPs.pkg == null) {
                             possiblyDeletedUpdatedSystemApps.add(ps.name);
                         } else {
                             // We're expecting that the system app should remain disabled, but add
                             // it to expecting better to recover in case the data version cannot
                             // be scanned.
-                            mExpectingBetter.put(disabledPs.name, disabledPs.getCodePath());
+                            mExpectingBetter.put(disabledPs.name, disabledPs.getPath());
                         }
                     }
                 }
@@ -3373,7 +3373,7 @@
                         // special privileges
                         removePackageLI(pkg, true);
                         try {
-                            final File codePath = new File(pkg.getCodePath());
+                            final File codePath = new File(pkg.getPath());
                             scanPackageTracedLI(codePath, 0, scanFlags, 0, null);
                         } catch (PackageManagerException e) {
                             Slog.e(TAG, "Failed to parse updated, ex-system package: "
@@ -3854,7 +3854,7 @@
                         // If we don't, installing the system package fails during scan
                         enableSystemPackageLPw(stubPkg);
                     }
-                    installPackageFromSystemLIF(stubPkg.getCodePath(),
+                    installPackageFromSystemLIF(stubPkg.getPath(),
                             mUserManager.getUserIds() /*allUserHandles*/, null /*origUserHandles*/,
                             true /*writeSettings*/);
                 } catch (PackageManagerException pme) {
@@ -3878,7 +3878,7 @@
             clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
                     | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
             mDexManager.notifyPackageUpdated(pkg.getPackageName(),
-                    pkg.getBaseCodePath(), pkg.getSplitCodePaths());
+                    pkg.getBaseApkPath(), pkg.getSplitCodePaths());
         }
         return true;
     }
@@ -3890,10 +3890,10 @@
             Slog.i(TAG, "Uncompressing system stub; pkg: " + stubPkg.getPackageName());
         }
         // uncompress the binary to its eventual destination on /data
-        final File scanFile = decompressPackage(stubPkg.getPackageName(), stubPkg.getCodePath());
+        final File scanFile = decompressPackage(stubPkg.getPackageName(), stubPkg.getPath());
         if (scanFile == null) {
             throw new PackageManagerException(
-                    "Unable to decompress stub at " + stubPkg.getCodePath());
+                    "Unable to decompress stub at " + stubPkg.getPath());
         }
         synchronized (mLock) {
             mSettings.disableSystemPackageLPw(stubPkg.getPackageName(), true /*replaced*/);
@@ -9261,11 +9261,11 @@
         // When upgrading from pre-N MR1, verify the package time stamp using the package
         // directory and not the APK file.
         final long lastModifiedTime = mIsPreNMR1Upgrade
-                ? new File(parsedPackage.getCodePath()).lastModified()
+                ? new File(parsedPackage.getPath()).lastModified()
                 : getLastModifiedTime(parsedPackage);
         final VersionInfo settingsVersionForPackage = getSettingsVersionForPackage(parsedPackage);
         if (ps != null && !forceCollect
-                && ps.getCodePathString().equals(parsedPackage.getCodePath())
+                && ps.getPathString().equals(parsedPackage.getPath())
                 && ps.timeStamp == lastModifiedTime
                 && !isCompatSignatureUpdateNeeded(settingsVersionForPackage)
                 && !isRecoverSignatureUpdateNeeded(settingsVersionForPackage)) {
@@ -9283,8 +9283,8 @@
             Slog.w(TAG, "PackageSetting for " + ps.name
                     + " is missing signatures.  Collecting certs again to recover them.");
         } else {
-            Slog.i(TAG, parsedPackage.getCodePath() + " changed; collecting certs" +
-                    (forceCollect ? " (forced)" : ""));
+            Slog.i(TAG, parsedPackage.getPath() + " changed; collecting certs"
+                    + (forceCollect ? " (forced)" : ""));
         }
 
         try {
@@ -9368,7 +9368,7 @@
      * Returns if forced apk verification can be skipped for the whole package, including splits.
      */
     private boolean canSkipForcedPackageVerification(AndroidPackage pkg) {
-        if (!canSkipForcedApkVerification(pkg.getBaseCodePath())) {
+        if (!canSkipForcedApkVerification(pkg.getBaseApkPath())) {
             return false;
         }
         // TODO: Allow base and splits to be verified individually.
@@ -9499,7 +9499,7 @@
         }
 
         final boolean newPkgChangedPaths = pkgAlreadyExists
-                && !pkgSetting.getCodePathString().equals(parsedPackage.getCodePath());
+                && !pkgSetting.getPathString().equals(parsedPackage.getPath());
         final boolean newPkgVersionGreater =
                 pkgAlreadyExists && parsedPackage.getLongVersionCode() > pkgSetting.versionCode;
         final boolean isSystemPkgBetter = scanSystemPartition && isSystemPkgUpdated
@@ -9518,11 +9518,11 @@
                     "System package updated;"
                     + " name: " + pkgSetting.name
                     + "; " + pkgSetting.versionCode + " --> " + parsedPackage.getLongVersionCode()
-                    + "; " + pkgSetting.getCodePathString()
-                            + " --> " + parsedPackage.getCodePath());
+                    + "; " + pkgSetting.getPathString()
+                            + " --> " + parsedPackage.getPath());
 
             final InstallArgs args = createInstallArgsForExisting(
-                    pkgSetting.getCodePathString(), getAppDexInstructionSets(
+                    pkgSetting.getPathString(), getAppDexInstructionSets(
                             pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
             args.cleanUpResourcesLI();
             synchronized (mLock) {
@@ -9535,7 +9535,7 @@
             // equal to the version on the /data partition. Throw an exception and use
             // the application already installed on the /data partition.
             throw new PackageManagerException(Log.WARN, "Package " + parsedPackage.getPackageName()
-                    + " at " + parsedPackage.getCodePath() + " ignored: updated version "
+                    + " at " + parsedPackage.getPath() + " ignored: updated version "
                     + pkgSetting.versionCode + " better than this "
                     + parsedPackage.getLongVersionCode());
         }
@@ -9597,10 +9597,10 @@
                                 + " name: " + pkgSetting.name
                                 + "; " + pkgSetting.versionCode + " --> "
                                 + parsedPackage.getLongVersionCode()
-                                + "; " + pkgSetting.getCodePathString() + " --> "
-                                + parsedPackage.getCodePath());
+                                + "; " + pkgSetting.getPathString() + " --> "
+                                + parsedPackage.getPath());
                 InstallArgs args = createInstallArgsForExisting(
-                        pkgSetting.getCodePathString(), getAppDexInstructionSets(
+                        pkgSetting.getPathString(), getAppDexInstructionSets(
                                 pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
                 synchronized (mInstallLock) {
                     args.cleanUpResourcesLI();
@@ -9613,10 +9613,10 @@
                 logCriticalInfo(Log.INFO,
                         "System package disabled;"
                                 + " name: " + pkgSetting.name
-                                + "; old: " + pkgSetting.getCodePathString() + " @ "
+                                + "; old: " + pkgSetting.getPathString() + " @ "
                                 + pkgSetting.versionCode
-                                + "; new: " + parsedPackage.getCodePath() + " @ "
-                                + parsedPackage.getCodePath());
+                                + "; new: " + parsedPackage.getPath() + " @ "
+                                + parsedPackage.getPath());
             }
         }
 
@@ -9797,7 +9797,7 @@
      * Return the prebuilt profile path given a package base code path.
      */
     private static String getPrebuildProfilePath(AndroidPackage pkg) {
-        return pkg.getBaseCodePath() + ".prof";
+        return pkg.getBaseApkPath() + ".prof";
     }
 
     /**
@@ -11450,7 +11450,7 @@
                         if (changedAbiCodePath == null) {
                             changedAbiCodePath = new ArrayList<>();
                         }
-                        changedAbiCodePath.add(ps.getCodePathString());
+                        changedAbiCodePath.add(ps.getPathString());
                     }
                 }
             }
@@ -11545,7 +11545,7 @@
         }
 
         // Initialize package source and resource directories
-        final File destCodeFile = new File(parsedPackage.getCodePath());
+        final File destCodeFile = new File(parsedPackage.getPath());
 
         // We keep references to the derived CPU Abis from settings in oder to reuse
         // them in the case where we're not upgrading or booting for the first time.
@@ -11883,9 +11883,9 @@
     private static void assertCodePolicy(AndroidPackage pkg)
             throws PackageManagerException {
         final boolean shouldHaveCode = pkg.isHasCode();
-        if (shouldHaveCode && !apkHasCode(pkg.getBaseCodePath())) {
+        if (shouldHaveCode && !apkHasCode(pkg.getBaseApkPath())) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
-                    "Package " + pkg.getBaseCodePath() + " code is missing");
+                    "Package " + pkg.getBaseApkPath() + " code is missing");
         }
 
         if (!ArrayUtils.isEmpty(pkg.getSplitCodePaths())) {
@@ -11917,7 +11917,7 @@
             if (parsedPackage.isDirectBootAware()) {
                 parsedPackage.setAllComponentsDirectBootAware(true);
             }
-            if (compressedFileExists(parsedPackage.getCodePath())) {
+            if (compressedFileExists(parsedPackage.getPath())) {
                 parsedPackage.setStub(true);
             }
         } else {
@@ -12008,7 +12008,7 @@
             assertCodePolicy(pkg);
         }
 
-        if (pkg.getCodePath() == null) {
+        if (pkg.getPath() == null) {
             // Bail out. The resource and code paths haven't been set.
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                     "Code and resource paths haven't been set correctly");
@@ -12035,7 +12035,7 @@
                 if (mAndroidApplication != null) {
                     Slog.w(TAG, "*************************************************");
                     Slog.w(TAG, "Core android package being redefined.  Skipping.");
-                    Slog.w(TAG, " codePath=" + pkg.getCodePath());
+                    Slog.w(TAG, " codePath=" + pkg.getPath());
                     Slog.w(TAG, "*************************************************");
                     throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
                             "Core android package being redefined.  Skipping.");
@@ -12191,14 +12191,14 @@
                     PackageSetting known = mSettings.getPackageLPr(pkg.getPackageName());
                     if (known != null) {
                         if (DEBUG_PACKAGE_SCANNING) {
-                            Log.d(TAG, "Examining " + pkg.getCodePath()
-                                    + " and requiring known path " + known.getCodePathString());
+                            Log.d(TAG, "Examining " + pkg.getPath()
+                                    + " and requiring known path " + known.getPathString());
                         }
-                        if (!pkg.getCodePath().equals(known.getCodePathString())) {
+                        if (!pkg.getPath().equals(known.getPathString())) {
                             throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,
                                     "Application package " + pkg.getPackageName()
-                                    + " found at " + pkg.getCodePath()
-                                    + " but expected at " + known.getCodePathString()
+                                    + " found at " + pkg.getPath()
+                                    + " but expected at " + known.getPathString()
                                     + "; ignoring.");
                         }
                     } else {
@@ -14532,13 +14532,11 @@
             Log.v(TAG, "restoreAndPostInstall userId=" + userId + " package=" + res.pkg);
         }
 
-        // A restore should be performed at this point if (a) the install
-        // succeeded, (b) the operation is not an update, and (c) the new
-        // package has not opted out of backup participation.
+        // A restore should be requested at this point if (a) the install
+        // succeeded, (b) the operation is not an update.
         final boolean update = res.removedInfo != null
                 && res.removedInfo.removedPackage != null;
-        boolean allowBackup = res.pkg != null && res.pkg.isAllowBackup();
-        boolean doRestore = !update && allowBackup;
+        boolean doRestore = !update && res.pkg != null;
 
         // Set up the post-install work request bookkeeping.  This will be used
         // and cleaned up by the post-install event handling regardless of whether
@@ -15787,7 +15785,7 @@
         abstract boolean doRename(int status, ParsedPackage parsedPackage);
         abstract int doPostInstall(int status, int uid);
 
-        /** @see PackageSettingBase#getCodePath() */
+        /** @see PackageSettingBase#getPath() */
         abstract String getCodePath();
 
         // Need installer lock especially for dex file removal.
@@ -15968,7 +15966,7 @@
                 return false;
             }
             parsedPackage.setBaseCodePath(FileUtils.rewriteAfterRename(beforeCodeFile,
-                    afterCodeFile, parsedPackage.getBaseCodePath()));
+                    afterCodeFile, parsedPackage.getBaseApkPath()));
             parsedPackage.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile,
                     afterCodeFile, parsedPackage.getSplitCodePaths()));
 
@@ -16235,7 +16233,7 @@
         InstallSource installSource = installArgs.installSource;
         final String installerPackageName = installSource.installerPackageName;
 
-        if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.getCodePath());
+        if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.getPath());
         synchronized (mLock) {
 // NOTE: This changes slightly to include UPDATE_PERMISSIONS_ALL regardless of the size of pkg.permissions
             mPermissionManager.updatePermissions(pkgName, pkg);
@@ -16874,7 +16872,7 @@
                         // which means we are replacing another update that is already
                         // installed.  We need to make sure to delete the older one's .apk.
                         res.removedInfo.args = createInstallArgsForExisting(
-                                oldPackage.getCodePath(),
+                                oldPackage.getPath(),
                                 getAppDexInstructionSets(
                                         AndroidPackageUtils.getPrimaryCpuAbi(oldPackage,
                                                 deletedPkgSetting),
@@ -16917,7 +16915,7 @@
                         if (ps1.mOldCodePaths == null) {
                             ps1.mOldCodePaths = new ArraySet<>();
                         }
-                        Collections.addAll(ps1.mOldCodePaths, oldPackage.getBaseCodePath());
+                        Collections.addAll(ps1.mOldCodePaths, oldPackage.getBaseApkPath());
                         if (oldPackage.getSplitCodePaths() != null) {
                             Collections.addAll(ps1.mOldCodePaths, oldPackage.getSplitCodePaths());
                         }
@@ -17082,7 +17080,7 @@
                     // For incremental installs, we bypass the verifier prior to install. Now
                     // that we know the package is valid, send a notice to the verifier with
                     // the root hash of the base.apk.
-                    final String baseCodePath = request.installResult.pkg.getBaseCodePath();
+                    final String baseCodePath = request.installResult.pkg.getBaseApkPath();
                     final String[] splitCodePaths = request.installResult.pkg.getSplitCodePaths();
                     final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
                     final int verificationId = mPendingVerificationToken++;
@@ -17127,9 +17125,9 @@
             final AndroidPackage pkg = reconciledPkg.pkgSetting.pkg;
             final String packageName = pkg.getPackageName();
             final boolean onIncremental = mIncrementalManager != null
-                    && isIncrementalPath(pkg.getCodePath());
+                    && isIncrementalPath(pkg.getPath());
             if (onIncremental) {
-                IncrementalStorage storage = mIncrementalManager.openStorage(pkg.getCodePath());
+                IncrementalStorage storage = mIncrementalManager.openStorage(pkg.getPath());
                 if (storage == null) {
                     throw new IllegalArgumentException(
                             "Install: null storage for incremental package " + packageName);
@@ -17143,7 +17141,7 @@
             }
             if (reconciledPkg.prepareResult.replace) {
                 mDexManager.notifyPackageUpdated(pkg.getPackageName(),
-                        pkg.getBaseCodePath(), pkg.getSplitCodePaths());
+                        pkg.getBaseApkPath(), pkg.getSplitCodePaths());
             }
 
             // Prepare the application profiles for the new code paths.
@@ -17796,7 +17794,7 @@
                         final byte[] digestBytes;
                         try {
                             final MessageDigest digest = MessageDigest.getInstance("SHA-512");
-                            updateDigest(digest, new File(parsedPackage.getBaseCodePath()));
+                            updateDigest(digest, new File(parsedPackage.getBaseApkPath()));
                             if (!ArrayUtils.isEmpty(parsedPackage.getSplitCodePaths())) {
                                 for (String path : parsedPackage.getSplitCodePaths()) {
                                     updateDigest(digest, new File(path));
@@ -17976,7 +17974,7 @@
             synchronized (mLock) {
                 final PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName());
                 if (ps != null && ps.isPrivileged()) {
-                    fsverityCandidates.put(pkg.getBaseCodePath(), null);
+                    fsverityCandidates.put(pkg.getBaseApkPath(), null);
                     if (pkg.getSplitCodePaths() != null) {
                         for (String splitPath : pkg.getSplitCodePaths()) {
                             fsverityCandidates.put(splitPath, null);
@@ -17987,11 +17985,11 @@
         } else {
             // NB: These files will become only accessible if the signing key is loaded in kernel's
             // .fs-verity keyring.
-            fsverityCandidates.put(pkg.getBaseCodePath(),
-                    VerityUtils.getFsveritySignatureFilePath(pkg.getBaseCodePath()));
+            fsverityCandidates.put(pkg.getBaseApkPath(),
+                    VerityUtils.getFsveritySignatureFilePath(pkg.getBaseApkPath()));
 
             final String dmPath = DexMetadataHelper.buildDexMetadataPathForApk(
-                    pkg.getBaseCodePath());
+                    pkg.getBaseApkPath());
             if (new File(dmPath).exists()) {
                 fsverityCandidates.put(dmPath, VerityUtils.getFsveritySignatureFilePath(dmPath));
             }
@@ -19102,7 +19100,7 @@
         // Install the system package
         if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
         try {
-            installPackageFromSystemLIF(disabledPs.getCodePathString(), allUserHandles,
+            installPackageFromSystemLIF(disabledPs.getPathString(), allUserHandles,
                     outInfo == null ? null : outInfo.origUsers, writeSettings);
         } catch (PackageManagerException e) {
             Slog.w(TAG, "Failed to restore system package:" + deletedPkg.getPackageName() + ": "
@@ -19227,7 +19225,7 @@
         // Delete application code and resources only for parent packages
         if (deleteCodeAndResources && (outInfo != null)) {
             outInfo.args = createInstallArgsForExisting(
-                    ps.getCodePathString(), getAppDexInstructionSets(
+                    ps.getPathString(), getAppDexInstructionSets(
                             ps.primaryCpuAbiString, ps.secondaryCpuAbiString));
             if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);
         }
@@ -19769,7 +19767,7 @@
 
         final String[] packageNames = { packageName };
         final long[] ceDataInodes = { ps.getCeDataInode(userId) };
-        final String[] codePaths = { ps.getCodePathString() };
+        final String[] codePaths = { ps.getPathString() };
 
         try {
             mInstaller.getAppSize(ps.volumeUuid, packageNames, userId, 0,
@@ -21632,6 +21630,8 @@
                         .getUriFor(Secure.INSTANT_APPS_ENABLED), false, co, UserHandle.USER_ALL);
         co.onChange(true);
 
+        mAppsFilter.onSystemReady();
+
         // Disable any carrier apps. We do this very early in boot to prevent the apps from being
         // disabled after already being started.
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(
@@ -21780,9 +21780,6 @@
         mInstallerService.restoreAndApplyStagedSessionIfNeeded();
 
         mExistingPackages = null;
-
-        // We'll do this last as it builds its cache while holding mLock via callback.
-        mAppsFilter.onSystemReady();
     }
 
     public void waitForAppDataPrepared() {
@@ -22696,11 +22693,11 @@
             synchronized (mInstallLock) {
                 final AndroidPackage pkg;
                 try {
-                    pkg = scanPackageTracedLI(ps.getCodePath(), parseFlags, SCAN_INITIAL, 0, null);
+                    pkg = scanPackageTracedLI(ps.getPath(), parseFlags, SCAN_INITIAL, 0, null);
                     loaded.add(pkg);
 
                 } catch (PackageManagerException e) {
-                    Slog.w(TAG, "Failed to scan " + ps.getCodePath() + ": " + e.getMessage());
+                    Slog.w(TAG, "Failed to scan " + ps.getPath() + ": " + e.getMessage());
                 }
 
                 if (!Build.FINGERPRINT.equals(ver.fingerprint)) {
@@ -22787,7 +22784,7 @@
                                 false, null)) {
                             unloaded.add(pkg);
                         } else {
-                            Slog.w(TAG, "Failed to unload " + ps.getCodePath());
+                            Slog.w(TAG, "Failed to unload " + ps.getPath());
                         }
                     }
 
@@ -22841,7 +22838,7 @@
             final int packageCount = mSettings.mPackages.size();
             for (int i = 0; i < packageCount; i++) {
                 final PackageSetting ps = mSettings.mPackages.valueAt(i);
-                codePaths.add(ps.getCodePath().getAbsolutePath());
+                codePaths.add(ps.getPath().getAbsolutePath());
             }
             return codePaths;
         }
@@ -23417,7 +23414,7 @@
 
             currentVolumeUuid = ps.volumeUuid;
 
-            final File probe = new File(pkg.getCodePath());
+            final File probe = new File(pkg.getPath());
             final File probeOat = new File(probe, "oat");
             if (!probe.isDirectory() || !probeOat.isDirectory()) {
                 throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
@@ -23439,7 +23436,7 @@
             }
 
             isCurrentLocationExternal = pkg.isExternalStorage();
-            codeFile = new File(pkg.getCodePath());
+            codeFile = new File(pkg.getPath());
             installSource = ps.installSource;
             packageAbiOverride = ps.cpuAbiOverrideString;
             appId = UserHandle.getAppId(pkg.getUid());
@@ -24870,7 +24867,7 @@
                             mApexManager.getApksInApex(apexPackages.get(i).packageName);
                     for (int j = 0, apksInApex = apkNames.size(); j < apksInApex; j++) {
                         final AndroidPackage pkg = getPackage(apkNames.get(j));
-                        cacher.cleanCachedResult(new File(pkg.getCodePath()));
+                        cacher.cleanCachedResult(new File(pkg.getPath()));
                     }
                 }
             }
@@ -24946,7 +24943,7 @@
                             Slog.e(TAG, "failed to find package " + packageName);
                             return false;
                         }
-                        overlayPaths.add(pkg.getBaseCodePath());
+                        overlayPaths.add(pkg.getBaseApkPath());
                     }
                 }
 
@@ -25662,7 +25659,7 @@
                 pkgSetting.getPkgState().isUpdatedSystemApp())) {
             return null;
         }
-        File codePath = new File(pkg.getCodePath());
+        File codePath = new File(pkg.getPath());
         if (codePath.isDirectory()) {
             return PackageDexOptimizer.getOatDir(codePath).getAbsolutePath();
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 5553cd0..e5dad85 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -326,11 +326,11 @@
     }
 
     public static long getLastModifiedTime(AndroidPackage pkg) {
-        final File srcFile = new File(pkg.getCodePath());
+        final File srcFile = new File(pkg.getPath());
         if (!srcFile.isDirectory()) {
             return srcFile.lastModified();
         }
-        final File baseFile = new File(pkg.getBaseCodePath());
+        final File baseFile = new File(pkg.getBaseApkPath());
         long maxModifiedTime = baseFile.lastModified();
         if (pkg.getSplitCodePaths() != null) {
             for (int i = pkg.getSplitCodePaths().length - 1; i >=0; --i) {
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 009c5d7..4476e8a 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -44,8 +44,33 @@
 public class PackageSetting extends PackageSettingBase {
     int appId;
 
+    /**
+     * This can be null whenever a physical APK on device is missing. This can be the result of
+     * removing an external storage device where the APK resides.
+     *
+     * This will result in the system reading the {@link PackageSetting} from disk, but without
+     * being able to parse the base APK's AndroidManifest.xml to read all of its metadata. The data
+     * that is written and read in {@link Settings} includes a minimal set of metadata needed to
+     * perform other checks in the system.
+     *
+     * This is important in order to enforce uniqueness within the system, as the package, even if
+     * on a removed storage device, is still considered installed. Another package of the same
+     * application ID or declaring the same permissions or similar cannot be installed.
+     *
+     * Re-attaching the storage device to make the APK available should allow the user to use the
+     * app once the device reboots or otherwise re-scans it.
+     *
+     * It is expected that all code that uses a {@link PackageSetting} understands this inner field
+     * may be null. Note that this relationship only works one way. It should not be possible to
+     * have an entry inside {@link PackageManagerService#mPackages} without a corresponding
+     * {@link PackageSetting} inside {@link Settings#mPackages}.
+     *
+     * @deprecated Use {@link #getPkg()}. The setter is favored to avoid unintended mutation.
+     */
     @Nullable
+    @Deprecated
     public AndroidPackage pkg;
+
     /**
      * WARNING. The object reference is important. We perform integer equality and NOT
      * object equality to check whether shared user settings are the same.
@@ -104,6 +129,12 @@
         doCopy(orig);
     }
 
+    /** @see #pkg **/
+    @Nullable
+    public AndroidPackage getPkg() {
+        return pkg;
+    }
+
     public int getSharedUserId() {
         if (sharedUser != null) {
             return sharedUser.userId;
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 6010344..a7bbf8d 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -40,6 +40,7 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 
 import java.io.File;
 import java.util.Arrays;
@@ -59,13 +60,9 @@
     public final String name;
     final String realName;
 
-    /**
-     * Path where this package was found on disk. For monolithic packages
-     * this is path to single base APK file; for cluster packages this is
-     * path to the cluster directory.
-     */
-    private File mCodePath;
-    private String mCodePathString;
+    /** @see AndroidPackage#getPath() */
+    private File mPath;
+    private String mPathString;
 
     String[] usesStaticLibraries;
     long[] usesStaticLibrariesVersions;
@@ -136,7 +133,7 @@
 
     boolean forceQueryableOverride;
 
-    PackageSettingBase(String name, String realName, @NonNull File codePath,
+    PackageSettingBase(String name, String realName, @NonNull File path,
             String legacyNativeLibraryPathString, String primaryCpuAbiString,
             String secondaryCpuAbiString, String cpuAbiOverrideString,
             long pVersionCode, int pkgFlags, int pkgPrivateFlags,
@@ -146,7 +143,7 @@
         this.realName = realName;
         this.usesStaticLibraries = usesStaticLibraries;
         this.usesStaticLibrariesVersions = usesStaticLibrariesVersions;
-        setCodePath(codePath);
+        setPath(path);
         this.legacyNativeLibraryPathString = legacyNativeLibraryPathString;
         this.primaryCpuAbiString = primaryCpuAbiString;
         this.secondaryCpuAbiString = secondaryCpuAbiString;
@@ -230,7 +227,7 @@
     }
 
     private void doCopy(PackageSettingBase orig) {
-        setCodePath(orig.getCodePath());
+        setPath(orig.getPath());
         cpuAbiOverrideString = orig.cpuAbiOverrideString;
         firstInstallTime = orig.firstInstallTime;
         installPermissionsFixed = orig.installPermissionsFixed;
@@ -697,18 +694,23 @@
         return userState.harmfulAppWarning;
     }
 
-    PackageSettingBase setCodePath(@NonNull File codePath) {
-        this.mCodePath = codePath;
-        this.mCodePathString = codePath.toString();
+    /**
+     * @see #mPath
+     */
+    PackageSettingBase setPath(@NonNull File path) {
+        this.mPath = path;
+        this.mPathString = path.toString();
         return this;
     }
 
-    File getCodePath() {
-        return mCodePath;
+    /** @see #mPath */
+    File getPath() {
+        return mPath;
     }
 
-    String getCodePathString() {
-        return mCodePathString;
+    /** @see #mPath */
+    String getPathString() {
+        return mPathString;
     }
 
     /**
@@ -733,7 +735,7 @@
 
     protected PackageSettingBase updateFrom(PackageSettingBase other) {
         super.copyFrom(other);
-        setCodePath(other.getCodePath());
+        setPath(other.getPath());
         this.usesStaticLibraries = other.usesStaticLibraries;
         this.usesStaticLibrariesVersions = other.usesStaticLibrariesVersions;
         this.legacyNativeLibraryPathString = other.legacyNativeLibraryPathString;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 5a8dd97..74bc49d 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -306,8 +306,8 @@
     private final ArrayMap<String, KernelPackageState> mKernelMapping = new ArrayMap<>();
 
     // List of replaced system applications
-    private final ArrayMap<String, PackageSetting> mDisabledSysPackages =
-        new ArrayMap<String, PackageSetting>();
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+    final ArrayMap<String, PackageSetting> mDisabledSysPackages = new ArrayMap<>();
 
     /** List of packages that are blocked for uninstall for specific users */
     private final SparseArray<ArraySet<String>> mBlockUninstallPackages = new SparseArray<>();
@@ -538,7 +538,7 @@
             return null;
         }
         p.getPkgState().setUpdatedSystemApp(false);
-        PackageSetting ret = addPackageLPw(name, p.realName, p.getCodePath(),
+        PackageSetting ret = addPackageLPw(name, p.realName, p.getPath(),
                 p.legacyNativeLibraryPathString, p.primaryCpuAbiString,
                 p.secondaryCpuAbiString, p.cpuAbiOverrideString,
                 p.appId, p.versionCode, p.pkgFlags, p.pkgPrivateFlags,
@@ -645,7 +645,7 @@
             if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package "
                     + pkgName + " is adopting original package " + originalPkg.name);
             pkgSetting = new PackageSetting(originalPkg, pkgName /*realPkgName*/);
-            pkgSetting.setCodePath(codePath);
+            pkgSetting.setPath(codePath);
             pkgSetting.legacyNativeLibraryPathString = legacyNativeLibraryPath;
             pkgSetting.pkgFlags = pkgFlags;
             pkgSetting.pkgPrivateFlags = pkgPrivateFlags;
@@ -770,12 +770,12 @@
                     "Updating application package " + pkgName + " failed");
         }
 
-        if (!pkgSetting.getCodePath().equals(codePath)) {
+        if (!pkgSetting.getPath().equals(codePath)) {
             final boolean isSystem = pkgSetting.isSystem();
             Slog.i(PackageManagerService.TAG,
                     "Update" + (isSystem ? " system" : "")
                     + " package " + pkgName
-                    + " code path from " + pkgSetting.getCodePathString()
+                    + " code path from " + pkgSetting.getPathString()
                     + " to " + codePath.toString()
                     + "; Retain data and using new");
             if (!isSystem) {
@@ -797,7 +797,7 @@
                 // internal to external storage or vice versa.
                 pkgSetting.legacyNativeLibraryPathString = legacyNativeLibraryPath;
             }
-            pkgSetting.setCodePath(codePath);
+            pkgSetting.setPath(codePath);
         }
         // If what we are scanning is a system (and possibly privileged) package,
         // then make it so, regardless of whether it was previously installed only
@@ -2174,32 +2174,24 @@
 
     void readUsesStaticLibLPw(XmlPullParser parser, PackageSetting outPs)
             throws IOException, XmlPullParserException {
-        int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-            String libName = parser.getAttributeValue(null, ATTR_NAME);
-            String libVersionStr = parser.getAttributeValue(null, ATTR_VERSION);
+        String libName = parser.getAttributeValue(null, ATTR_NAME);
+        String libVersionStr = parser.getAttributeValue(null, ATTR_VERSION);
 
-            long libVersion = -1;
-            try {
-                libVersion = Long.parseLong(libVersionStr);
-            } catch (NumberFormatException e) {
-                // ignore
-            }
-
-            if (libName != null && libVersion >= 0) {
-                outPs.usesStaticLibraries = ArrayUtils.appendElement(String.class,
-                        outPs.usesStaticLibraries, libName);
-                outPs.usesStaticLibrariesVersions = ArrayUtils.appendLong(
-                        outPs.usesStaticLibrariesVersions, libVersion);
-            }
-
-            XmlUtils.skipCurrentTag(parser);
+        long libVersion = -1;
+        try {
+            libVersion = Long.parseLong(libVersionStr);
+        } catch (NumberFormatException e) {
+            // ignore
         }
+
+        if (libName != null && libVersion >= 0) {
+            outPs.usesStaticLibraries = ArrayUtils.appendElement(String.class,
+                    outPs.usesStaticLibraries, libName);
+            outPs.usesStaticLibrariesVersions = ArrayUtils.appendLong(
+                    outPs.usesStaticLibrariesVersions, libVersion);
+        }
+
+        XmlUtils.skipCurrentTag(parser);
     }
 
     void writeUsesStaticLibLPw(XmlSerializer serializer, String[] usesStaticLibraries,
@@ -2710,7 +2702,7 @@
         if (pkg.realName != null) {
             serializer.attribute(null, "realName", pkg.realName);
         }
-        serializer.attribute(null, "codePath", pkg.getCodePathString());
+        serializer.attribute(null, "codePath", pkg.getPathString());
         serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp));
         serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime));
         serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime));
@@ -2752,7 +2744,7 @@
         if (pkg.realName != null) {
             serializer.attribute(null, "realName", pkg.realName);
         }
-        serializer.attribute(null, "codePath", pkg.getCodePathString());
+        serializer.attribute(null, "codePath", pkg.getPathString());
 
         if (pkg.legacyNativeLibraryPathString != null) {
             serializer.attribute(null, "nativeLibraryPath", pkg.legacyNativeLibraryPathString);
@@ -3875,6 +3867,8 @@
                     readDomainVerificationLPw(parser, packageSetting);
                 } else if (tagName.equals(TAG_MIME_GROUP)) {
                     packageSetting.mimeGroups = readMimeGroupLPw(parser, packageSetting.mimeGroups);
+                } else if (tagName.equals(TAG_USES_STATIC_LIB)) {
+                    readUsesStaticLibLPw(parser, packageSetting);
                 } else {
                     PackageManagerService.reportSettingsProblem(Log.WARN,
                             "Unknown element under <package>: " + parser.getName());
@@ -4561,9 +4555,9 @@
             pw.print(prefix); pw.print("  sharedUser="); pw.println(ps.sharedUser);
         }
         pw.print(prefix); pw.print("  pkg="); pw.println(pkg);
-        pw.print(prefix); pw.print("  codePath="); pw.println(ps.getCodePathString());
+        pw.print(prefix); pw.print("  codePath="); pw.println(ps.getPathString());
         if (permissionNames == null) {
-            pw.print(prefix); pw.print("  resourcePath="); pw.println(ps.getCodePathString());
+            pw.print(prefix); pw.print("  resourcePath="); pw.println(ps.getPathString());
             pw.print(prefix); pw.print("  legacyNativeLibraryDir=");
             pw.println(ps.legacyNativeLibraryPathString);
             pw.print(prefix); pw.print("  extractNativeLibs=");
@@ -4581,6 +4575,7 @@
         pw.println();
         if (pkg != null) {
             pw.print(prefix); pw.print("  versionName="); pw.println(pkg.getVersionName());
+            pw.print(prefix); pw.print("  usesNonSdkApi="); pw.println(pkg.isUsesNonSdkApi());
             pw.print(prefix); pw.print("  splits="); dumpSplitNames(pw, pkg); pw.println();
             final int apkSigningVersion = pkg.getSigningDetails().signatureSchemeVersion;
             pw.print(prefix); pw.print("  apkSigningVersion="); pw.println(apkSigningVersion);
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 8000c63..587cb825 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -486,7 +486,7 @@
     public boolean compileLayouts(AndroidPackage pkg) {
         try {
             final String packageName = pkg.getPackageName();
-            final String apkPath = pkg.getBaseCodePath();
+            final String apkPath = pkg.getBaseApkPath();
             // TODO(b/143971007): Use a cross-user directory
             File dataDir = PackageInfoWithoutStateUtils.getDataDir(pkg, UserHandle.myUserId());
             final String outDexFile = dataDir.getAbsolutePath() + "/code_cache/compiled_view.dex";
@@ -524,7 +524,7 @@
     private ArrayMap<String, String> getPackageProfileNames(AndroidPackage pkg) {
         ArrayMap<String, String> result = new ArrayMap<>();
         if (pkg.isHasCode()) {
-            result.put(pkg.getBaseCodePath(), ArtManager.getProfileName(null));
+            result.put(pkg.getBaseApkPath(), ArtManager.getProfileName(null));
         }
 
         String[] splitCodePaths = pkg.getSplitCodePaths();
diff --git a/services/core/java/com/android/server/pm/dex/DexoptUtils.java b/services/core/java/com/android/server/pm/dex/DexoptUtils.java
index 6807388..fa01836 100644
--- a/services/core/java/com/android/server/pm/dex/DexoptUtils.java
+++ b/services/core/java/com/android/server/pm/dex/DexoptUtils.java
@@ -18,12 +18,12 @@
 
 import android.content.pm.ApplicationInfo;
 import android.content.pm.SharedLibraryInfo;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
 import android.util.Slog;
 import android.util.SparseArray;
 
 import com.android.internal.os.ClassLoaderFactory;
 import com.android.internal.util.ArrayUtils;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 
 import java.io.File;
 import java.util.List;
@@ -90,7 +90,7 @@
 
         // The splits have an implicit dependency on the base apk.
         // This means that we have to add the base apk file in addition to the shared libraries.
-        String baseApkName = new File(pkg.getBaseCodePath()).getName();
+        String baseApkName = new File(pkg.getBaseApkPath()).getName();
         String baseClassPath = baseApkName;
 
         // The result is stored in classLoaderContexts.
@@ -401,7 +401,7 @@
      * Assumes that the application declares a non-null array of splits.
      */
     private static String[] getSplitRelativeCodePaths(AndroidPackage pkg) {
-        String baseCodePath = new File(pkg.getBaseCodePath()).getParent();
+        String baseCodePath = new File(pkg.getBaseApkPath()).getParent();
         String[] splitCodePaths = pkg.getSplitCodePaths();
         String[] splitRelativeCodePaths = new String[ArrayUtils.size(splitCodePaths)];
         for (int i = 0; i < splitRelativeCodePaths.length; i++) {
diff --git a/services/core/java/com/android/server/pm/dex/ViewCompiler.java b/services/core/java/com/android/server/pm/dex/ViewCompiler.java
index 5506a52..a567266 100644
--- a/services/core/java/com/android/server/pm/dex/ViewCompiler.java
+++ b/services/core/java/com/android/server/pm/dex/ViewCompiler.java
@@ -40,7 +40,7 @@
     public boolean compileLayouts(AndroidPackage pkg) {
         try {
             final String packageName = pkg.getPackageName();
-            final String apkPath = pkg.getBaseCodePath();
+            final String apkPath = pkg.getBaseApkPath();
             // TODO(b/143971007): Use a cross-user directory
             File dataDir = PackageInfoWithoutStateUtils.getDataDir(pkg, UserHandle.myUserId());
             final String outDexFile = dataDir.getAbsolutePath() + "/code_cache/compiled_view.dex";
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
index 39784cf..a13680a 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
@@ -23,7 +23,6 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageParser;
 import android.content.pm.PermissionGroupInfo;
-import android.content.pm.SharedLibraryInfo;
 import android.content.pm.parsing.ParsingPackageRead;
 import android.content.pm.parsing.component.ParsedAttribution;
 import android.content.pm.parsing.component.ParsedIntentInfo;
@@ -65,18 +64,16 @@
 
     /** Path of base APK */
     @NonNull
-    String getBaseCodePath();
+    String getBaseApkPath();
 
     /** Revision code of base APK */
     int getBaseRevisionCode();
 
     /**
-     * Path where this package was found on disk. For monolithic packages
-     * this is path to single base APK file; for cluster packages this is
-     * path to the cluster directory.
+     * The path to the folder containing the base APK and any installed splits.
      */
     @NonNull
-    String getCodePath();
+    String getPath();
 
     /**
      * Permissions requested but not in the manifest. These may have been split or migrated from
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
index a6f02e7..0a56e13 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
@@ -58,7 +58,7 @@
         PackageImpl pkg = (PackageImpl) aPkg;
         ArrayList<String> paths = new ArrayList<>();
         if (pkg.isHasCode()) {
-            paths.add(pkg.getBaseCodePath());
+            paths.add(pkg.getBaseApkPath());
         }
         String[] splitCodePaths = pkg.getSplitCodePaths();
         if (!ArrayUtils.isEmpty(splitCodePaths)) {
@@ -77,7 +77,7 @@
     public static List<String> getAllCodePaths(AndroidPackage aPkg) {
         PackageImpl pkg = (PackageImpl) aPkg;
         ArrayList<String> paths = new ArrayList<>();
-        paths.add(pkg.getBaseCodePath());
+        paths.add(pkg.getBaseApkPath());
 
         String[] splitCodePaths = pkg.getSplitCodePaths();
         if (!ArrayUtils.isEmpty(splitCodePaths)) {
@@ -147,7 +147,7 @@
         if (pkg.isSystem() && !isUpdatedSystemApp) {
             return false;
         }
-        if (IncrementalManager.isIncrementalPath(pkg.getCodePath())) {
+        if (IncrementalManager.isIncrementalPath(pkg.getPath())) {
             return false;
         }
         return true;
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
index 33fb8be..0e3e110 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
@@ -136,9 +136,9 @@
     private int uid = -1;
 
     @VisibleForTesting
-    public PackageImpl(@NonNull String packageName, @NonNull String baseCodePath,
-            @NonNull String codePath, @Nullable TypedArray manifestArray, boolean isCoreApp) {
-        super(packageName, baseCodePath, codePath, manifestArray);
+    public PackageImpl(@NonNull String packageName, @NonNull String baseApkPath,
+            @NonNull String path, @Nullable TypedArray manifestArray, boolean isCoreApp) {
+        super(packageName, baseApkPath, path, manifestArray);
         this.manifestPackageName = this.packageName;
         this.coreApp = isCoreApp;
     }
@@ -247,7 +247,7 @@
 
     @Override
     public PackageImpl setCodePath(@NonNull String value) {
-        this.codePath = value;
+        this.mPath = value;
         return this;
     }
 
@@ -322,7 +322,7 @@
 
     @Override
     public PackageImpl setBaseCodePath(@NonNull String baseCodePath) {
-        this.baseCodePath = TextUtils.safeIntern(baseCodePath);
+        this.mBaseApkPath = TextUtils.safeIntern(baseCodePath);
         return this;
     }
 
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 ffdcc22..1cfc5b1 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -3526,7 +3526,7 @@
                                 deniedPermissions == null || !deniedPermissions.contains(perm);
                         if (permissionViolation) {
                             Slog.w(TAG, "Privileged permission " + perm + " for package "
-                                    + pkg.getPackageName() + " (" + pkg.getCodePath()
+                                    + pkg.getPackageName() + " (" + pkg.getPath()
                                     + ") not in privapp-permissions whitelist");
 
                             if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) {
@@ -3534,7 +3534,7 @@
                                     mPrivappPermissionsViolations = new ArraySet<>();
                                 }
                                 mPrivappPermissionsViolations.add(
-                                        pkg.getPackageName() + " (" + pkg.getCodePath() + "): "
+                                        pkg.getPackageName() + " (" + pkg.getPath() + "): "
                                                 + perm);
                             }
                         } else {
diff --git a/services/core/java/com/android/server/search/Searchables.java b/services/core/java/com/android/server/search/Searchables.java
index 8af76a1..c769a50 100644
--- a/services/core/java/com/android/server/search/Searchables.java
+++ b/services/core/java/com/android/server/search/Searchables.java
@@ -20,6 +20,7 @@
 import android.app.SearchManager;
 import android.app.SearchableInfo;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -397,8 +398,9 @@
     }
 
     private String getGlobalSearchProviderSetting() {
-        return Settings.Secure.getString(mContext.getContentResolver(),
-                Settings.Secure.SEARCH_GLOBAL_SEARCH_ACTIVITY);
+        final ContentResolver cr = mContext.getContentResolver();
+        return Settings.Secure.getStringForUser(cr,
+                Settings.Secure.SEARCH_GLOBAL_SEARCH_ACTIVITY, cr.getUserId());
     }
 
     /**
diff --git a/services/core/java/com/android/server/telecom/InternalServiceRepository.java b/services/core/java/com/android/server/telecom/InternalServiceRepository.java
new file mode 100644
index 0000000..76ea5c7
--- /dev/null
+++ b/services/core/java/com/android/server/telecom/InternalServiceRepository.java
@@ -0,0 +1,63 @@
+/*
+ * 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.telecom;
+
+import android.content.Context;
+import android.os.Binder;
+import android.os.Process;
+
+import com.android.internal.telecom.IDeviceIdleControllerAdapter;
+import com.android.internal.telecom.IInternalServiceRetriever;
+import com.android.server.DeviceIdleInternal;
+
+/**
+ * The Telecom APK can not access services stored in LocalService directly and since it is in the
+ * SYSTEM process, it also can not use the *Manager interfaces
+ * (see {@link Context#enforceCallingPermission(String, String)}). Instead, we must wrap these local
+ * services in binder interfaces to allow Telecom access.
+ */
+public class InternalServiceRepository extends IInternalServiceRetriever.Stub {
+
+    private final IDeviceIdleControllerAdapter.Stub mDeviceIdleControllerAdapter =
+            new IDeviceIdleControllerAdapter.Stub() {
+        @Override
+        public void exemptAppTemporarilyForEvent(String packageName, long duration, int userHandle,
+                String reason) {
+            mDeviceIdleController.addPowerSaveTempWhitelistApp(Process.myUid(), packageName,
+                    duration, userHandle, true /*sync*/, reason);
+        }
+    };
+
+    private final DeviceIdleInternal mDeviceIdleController;
+
+    public InternalServiceRepository(DeviceIdleInternal deviceIdleController) {
+        mDeviceIdleController = deviceIdleController;
+    }
+
+    @Override
+    public IDeviceIdleControllerAdapter getDeviceIdleController() {
+        ensureSystemProcess();
+        return mDeviceIdleControllerAdapter;
+    }
+
+    private void ensureSystemProcess() {
+        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+            // Correctness check - this should never happen.
+            throw new SecurityException("SYSTEM ONLY API.");
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/telecom/TelecomLoaderService.java b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
index a853529..52ad893 100644
--- a/services/core/java/com/android/server/telecom/TelecomLoaderService.java
+++ b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
@@ -35,7 +35,10 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.telecom.ITelecomLoader;
+import com.android.internal.telecom.ITelecomService;
 import com.android.internal.telephony.SmsApplication;
+import com.android.server.DeviceIdleInternal;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.pm.UserManagerService;
@@ -53,16 +56,13 @@
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
             // Normally, we would listen for death here, but since telecom runs in the same process
-            // as this loader (process="system") thats redundant here.
+            // as this loader (process="system") that's redundant here.
             try {
-                service.linkToDeath(new IBinder.DeathRecipient() {
-                    @Override
-                    public void binderDied() {
-                        connectToTelecom();
-                    }
-                }, 0);
+                ITelecomLoader telecomLoader = ITelecomLoader.Stub.asInterface(service);
+                ITelecomService telecomService = telecomLoader.createTelecomService(mServiceRepo);
+
                 SmsApplication.getDefaultMmsApplication(mContext, false);
-                ServiceManager.addService(Context.TELECOM_SERVICE, service);
+                ServiceManager.addService(Context.TELECOM_SERVICE, telecomService.asBinder());
 
                 synchronized (mLock) {
                     final PermissionManagerServiceInternal permissionManager =
@@ -114,6 +114,8 @@
     @GuardedBy("mLock")
     private TelecomServiceConnection mServiceConnection;
 
+    private InternalServiceRepository mServiceRepo;
+
     public TelecomLoaderService(Context context) {
         super(context);
         mContext = context;
@@ -129,6 +131,8 @@
         if (phase == PHASE_ACTIVITY_MANAGER_READY) {
             registerDefaultAppNotifier();
             registerCarrierConfigChangedReceiver();
+            // core services will have already been loaded.
+            setupServiceRepository();
             connectToTelecom();
         }
     }
@@ -154,6 +158,11 @@
         }
     }
 
+    private void setupServiceRepository() {
+        DeviceIdleInternal deviceIdleInternal = getLocalService(DeviceIdleInternal.class);
+        mServiceRepo = new InternalServiceRepository(deviceIdleInternal);
+    }
+
 
     private void registerDefaultAppProviders() {
         final PermissionManagerServiceInternal permissionManager =
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 6df46ed..ad28124 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4628,18 +4628,26 @@
         mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(this);
     }
 
-    /** @return {@code true} if this activity should be made visible. */
-    boolean shouldBeVisible(boolean behindFullscreenActivity, boolean ignoringKeyguard) {
+    private void updateVisibleIgnoringKeyguard(boolean behindFullscreenActivity) {
         // Check whether activity should be visible without Keyguard influence
         visibleIgnoringKeyguard = (!behindFullscreenActivity || mLaunchTaskBehind)
                 && okToShowLocked();
+    }
+
+    /** @return {@code true} if this activity should be made visible. */
+    private boolean shouldBeVisible(boolean behindFullscreenActivity, boolean ignoringKeyguard) {
+        updateVisibleIgnoringKeyguard(behindFullscreenActivity);
 
         if (ignoringKeyguard) {
             return visibleIgnoringKeyguard;
         }
 
+        return shouldBeVisibleUnchecked();
+    }
+
+    boolean shouldBeVisibleUnchecked() {
         final Task stack = getRootTask();
-        if (stack == null) {
+        if (stack == null || !visibleIgnoringKeyguard) {
             return false;
         }
 
@@ -4652,26 +4660,30 @@
             return false;
         }
 
-        // Check if the activity is on a sleeping display, and if it can turn it ON.
-        if (mDisplayContent.isSleeping()) {
-            final boolean canTurnScreenOn = !mSetToSleep || canTurnScreenOn()
-                    || canShowWhenLocked() || containsDismissKeyguardWindow();
-            if (!canTurnScreenOn) {
-                return false;
-            }
+        // Check if the activity is on a sleeping display
+        // TODO b/163993448 mSetToSleep is required when restarting an existing activity, try to
+        // remove it if possible.
+        if (mSetToSleep && mDisplayContent.isSleeping()) {
+            return false;
         }
 
+        return mStackSupervisor.getKeyguardController().checkKeyguardVisibility(this);
+    }
+
+    void updateVisibility(boolean behindFullscreenActivity) {
+        updateVisibleIgnoringKeyguard(behindFullscreenActivity);
+        final Task task = getRootTask();
+        if (task == null || !visibleIgnoringKeyguard) {
+            return;
+        }
         // Now check whether it's really visible depending on Keyguard state, and update
         // {@link ActivityStack} internal states.
         // Inform the method if this activity is the top activity of this stack, but exclude the
         // case where this is the top activity in a pinned stack.
-        final boolean isTop = this == stack.getTopNonFinishingActivity();
-        final boolean isTopNotPinnedStack = stack.isAttached()
-                && stack.getDisplayArea().isTopNotFinishNotPinnedStack(stack);
-        final boolean visibleIgnoringDisplayStatus = stack.checkKeyguardVisibility(this,
-                visibleIgnoringKeyguard, isTop && isTopNotPinnedStack);
-
-        return visibleIgnoringDisplayStatus;
+        final boolean isTop = this == task.getTopNonFinishingActivity();
+        final boolean isTopNotPinnedStack = task.isAttached()
+                && task.getDisplayArea().isTopNotFinishNotPinnedStack(task);
+        task.updateKeyguardVisibility(this, isTop && isTopNotPinnedStack);
     }
 
     boolean shouldBeVisible() {
@@ -6643,8 +6655,7 @@
         final Configuration resolvedConfig = getResolvedOverrideConfiguration();
         final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
         final int requestedOrientation = getRequestedConfigurationOrientation();
-        final boolean orientationRequested = requestedOrientation != ORIENTATION_UNDEFINED
-                && !mDisplayContent.ignoreRotationForApps();
+        final boolean orientationRequested = requestedOrientation != ORIENTATION_UNDEFINED;
         final int orientation = orientationRequested
                 ? requestedOrientation
                 : newParentConfiguration.orientation;
@@ -7538,10 +7549,8 @@
             return false;
         }
         final Task stack = getRootTask();
-        return stack != null
-                && !stack.inMultiWindowMode()
-                && stack.checkKeyguardVisibility(this, true /* shouldBeVisible */,
-                        stack.topRunningActivity() == this /* isTop */);
+        return stack != null && !stack.inMultiWindowMode()
+                && mStackSupervisor.getKeyguardController().checkKeyguardVisibility(this);
     }
 
     void setTurnScreenOn(boolean turnScreenOn) {
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 9df192b7..5196416 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -759,8 +759,7 @@
                         false /* markFrozenIfConfigChanged */, true /* deferResume */);
             }
 
-            if (r.getRootTask().checkKeyguardVisibility(r, true /* shouldBeVisible */,
-                    true /* isTop */) && r.allowMoveToFront()) {
+            if (mKeyguardController.checkKeyguardVisibility(r) && r.allowMoveToFront()) {
                 // We only set the visibility to true if the activity is not being launched in
                 // background, and is allowed to be visible based on keyguard state. This avoids
                 // setting this into motion in window manager that is later cancelled due to later
@@ -2298,11 +2297,15 @@
     }
 
     /** Ends a batch of visibility updates. */
-    void endActivityVisibilityUpdate() {
-        mVisibilityTransactionDepth--;
-        if (mVisibilityTransactionDepth == 0) {
+    void endActivityVisibilityUpdate(ActivityRecord starting, int configChanges,
+            boolean preserveWindows, boolean notifyClients) {
+        if (mVisibilityTransactionDepth == 1) {
             getKeyguardController().visibilitiesUpdated();
+            // commit visibility to activities
+            mRootWindowContainer.commitActivitiesVisible(starting, configChanges, preserveWindows,
+                    notifyClients);
         }
+        mVisibilityTransactionDepth--;
     }
 
     /** Returns {@code true} if the caller is on the path to update visibility. */
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 080a438..2657eb2 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -137,6 +137,7 @@
 import android.app.ActivityManagerInternal;
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
+import android.app.ActivityTaskManager.RootTaskInfo;
 import android.app.ActivityThread;
 import android.app.AlertDialog;
 import android.app.AppGlobals;
@@ -2158,14 +2159,14 @@
     }
 
     @Override
-    public ActivityManager.StackInfo getFocusedStackInfo() throws RemoteException {
-        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
+    public RootTaskInfo getFocusedRootTaskInfo() throws RemoteException {
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getFocusedRootTaskInfo()");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
                 Task focusedStack = getTopDisplayFocusedStack();
                 if (focusedStack != null) {
-                    return mRootWindowContainer.getStackInfo(focusedStack.mTaskId);
+                    return mRootWindowContainer.getRootTaskInfo(focusedStack.mTaskId);
                 }
                 return null;
             }
@@ -2893,14 +2894,13 @@
         }
     }
 
-    // TODO(148895075): deprecate and replace with task equivalents
     @Override
-    public List<ActivityManager.StackInfo> getAllStackInfos() {
-        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getAllStackInfos()");
+    public List<RootTaskInfo> getAllRootTaskInfos() {
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getAllRootTaskInfos()");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
-                return mRootWindowContainer.getAllStackInfos(INVALID_DISPLAY);
+                return mRootWindowContainer.getAllRootTaskInfos(INVALID_DISPLAY);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -2908,26 +2908,12 @@
     }
 
     @Override
-    public ActivityManager.StackInfo getStackInfo(int windowingMode, int activityType) {
-        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
+    public RootTaskInfo getRootTaskInfo(int windowingMode, int activityType) {
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getRootTaskInfo()");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
-                return mRootWindowContainer.getStackInfo(windowingMode, activityType);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    // TODO(148895075): deprecate and replace with task equivalents
-    @Override
-    public List<ActivityManager.StackInfo> getAllStackInfosOnDisplay(int displayId) {
-        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getAllStackInfos()");
-        long ident = Binder.clearCallingIdentity();
-        try {
-            synchronized (mGlobalLock) {
-                return mRootWindowContainer.getAllStackInfos(displayId);
+                return mRootWindowContainer.getRootTaskInfo(windowingMode, activityType);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -2935,13 +2921,27 @@
     }
 
     @Override
-    public ActivityManager.StackInfo getStackInfoOnDisplay(int windowingMode, int activityType,
+    public List<RootTaskInfo> getAllRootTaskInfosOnDisplay(int displayId) {
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
+                "getAllRootTaskInfosOnDisplay()");
+        long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                return mRootWindowContainer.getAllRootTaskInfos(displayId);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
+    public RootTaskInfo getRootTaskInfoOnDisplay(int windowingMode, int activityType,
             int displayId) {
-        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getRootTaskInfoOnDisplay()");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
-                return mRootWindowContainer.getStackInfo(windowingMode, activityType, displayId);
+                return mRootWindowContainer.getRootTaskInfo(windowingMode, activityType, displayId);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 77e5736..4db121b 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -28,7 +28,6 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
@@ -36,20 +35,21 @@
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.util.DisplayMetrics.DENSITY_DEFAULT;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
 import static android.view.Display.FLAG_PRIVATE;
 import static android.view.Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.Display.REMOVE_MODE_DESTROY_CONTENT;
 import static android.view.InsetsState.ITYPE_IME;
 import static android.view.InsetsState.ITYPE_LEFT_GESTURES;
+import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.ITYPE_RIGHT_GESTURES;
 import static android.view.Surface.ROTATION_0;
 import static android.view.Surface.ROTATION_180;
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
 import static android.view.View.GONE;
-import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
-import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
@@ -367,13 +367,6 @@
     final float mCloseToSquareMaxAspectRatio;
 
     /**
-     * If this is true, we would not rotate the display for apps. The rotation would be either the
-     * sensor rotation or the user rotation, controlled by
-     * {@link WindowManagerPolicy.UserRotationMode}.
-     */
-    private boolean mIgnoreRotationForApps;
-
-    /**
      * Keep track of wallpaper visibility to notify changes.
      */
     private boolean mLastWallpaperVisible = false;
@@ -1757,26 +1750,6 @@
 
         mDisplayFrames.onDisplayInfoUpdated(mDisplayInfo,
                 calculateDisplayCutoutForRotation(mDisplayInfo.rotation));
-
-        // Not much of use to rotate the display for apps since it's close to square.
-        mIgnoreRotationForApps = isNonDecorDisplayCloseToSquare(Surface.ROTATION_0, width, height);
-    }
-
-    /** @return {@code true} if the orientation requested from application will be ignored. */
-    boolean ignoreRotationForApps() {
-        return mIgnoreRotationForApps;
-    }
-
-    private boolean isNonDecorDisplayCloseToSquare(int rotation, int width, int height) {
-        final DisplayCutout displayCutout =
-                calculateDisplayCutoutForRotation(rotation).getDisplayCutout();
-        final int uiMode = mWmService.mPolicy.getUiMode();
-        final int w = mDisplayPolicy.getNonDecorDisplayWidth(
-                width, height, rotation, uiMode, displayCutout);
-        final int h = mDisplayPolicy.getNonDecorDisplayHeight(
-                width, height, rotation, uiMode, displayCutout);
-        final float aspectRatio = Math.max(w, h) / (float) Math.min(w, h);
-        return aspectRatio <= mCloseToSquareMaxAspectRatio;
     }
 
     /**
@@ -2342,10 +2315,6 @@
     int getOrientation() {
         mLastOrientationSource = null;
 
-        if (mIgnoreRotationForApps) {
-            return SCREEN_ORIENTATION_USER;
-        }
-
         if (mWmService.mDisplayFrozen) {
             if (mWmService.mPolicy.isKeyguardLocked()) {
                 // Use the last orientation the while the display is frozen with the keyguard
@@ -4759,7 +4728,7 @@
             }
 
             // Apply restriction if necessary.
-            if (needsGestureExclusionRestrictions(w, mLastDispatchedSystemUiVisibility)) {
+            if (needsGestureExclusionRestrictions(w, false /* ignoreRequest */)) {
 
                 // Processes the region along the left edge.
                 remainingLeftRight[0] = addToGlobalAndConsumeLimit(local, outExclusion, leftEdge,
@@ -4776,7 +4745,7 @@
                 outExclusion.op(middle, Op.UNION);
                 middle.recycle();
             } else {
-                boolean loggable = needsGestureExclusionRestrictions(w, 0 /* lastSysUiVis */);
+                boolean loggable = needsGestureExclusionRestrictions(w, true /* ignoreRequest */);
                 if (loggable) {
                     addToGlobalAndConsumeLimit(local, outExclusion, leftEdge,
                             Integer.MAX_VALUE, w, EXCLUSION_LEFT);
@@ -4798,17 +4767,21 @@
     }
 
     /**
-     * @return Whether gesture exclusion area should be restricted from the window depending on the
-     *         current SystemUI visibility flags.
+     * Returns whether gesture exclusion area should be restricted from the window depending on the
+     * window/activity types and the requested navigation bar visibility and the behavior.
+     *
+     * @param win The target window.
+     * @param ignoreRequest If this is {@code true}, only the window/activity types are considered.
+     * @return {@code true} if the gesture exclusion restrictions are needed.
      */
-    private static boolean needsGestureExclusionRestrictions(WindowState win, int sysUiVisibility) {
+    private static boolean needsGestureExclusionRestrictions(WindowState win,
+            boolean ignoreRequest) {
         final int type = win.mAttrs.type;
-        final int stickyHideNavFlags =
-                SYSTEM_UI_FLAG_HIDE_NAVIGATION | SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
         final boolean stickyHideNav =
-                (sysUiVisibility & stickyHideNavFlags) == stickyHideNavFlags;
-        return !stickyHideNav && type != TYPE_INPUT_METHOD && type != TYPE_NOTIFICATION_SHADE
-                && win.getActivityType() != ACTIVITY_TYPE_HOME;
+                !win.getRequestedInsetsState().getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR)
+                        && win.mAttrs.insetsFlags.behavior == BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
+        return (!stickyHideNav || ignoreRequest) && type != TYPE_INPUT_METHOD
+                && type != TYPE_NOTIFICATION_SHADE && win.getActivityType() != ACTIVITY_TYPE_HOME;
     }
 
     /**
@@ -4824,7 +4797,7 @@
                 && type != TYPE_APPLICATION_STARTING
                 && type != TYPE_NAVIGATION_BAR
                 && (attrs.flags & FLAG_NOT_TOUCHABLE) == 0
-                && needsGestureExclusionRestrictions(win, 0 /* sysUiVisibility */)
+                && needsGestureExclusionRestrictions(win, true /* ignoreRequest */)
                 && win.getDisplayContent().mDisplayPolicy.hasSideGestures();
     }
 
@@ -5299,6 +5272,14 @@
         mSingleTaskInstance = true;
     }
 
+    /**
+     * Check if the display has {@link Display#FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD} applied.
+     */
+    boolean canShowWithInsecureKeyguard() {
+        final int flags = mDisplay.getFlags();
+        return (flags & FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0;
+    }
+
     /** Returns true if the display can only contain one task */
     boolean isSingleTaskInstance() {
         return mSingleTaskInstance;
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index c9f463b..6e32d0e 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -308,7 +308,7 @@
         }
 
         void tearDown() {
-            mService.mInputManager.unregisterInputChannel(mServerChannel);
+            mService.mInputManager.unregisterInputChannel(mServerChannel.getToken());
             mInputEventReceiver.dispose();
             mInputEventReceiver = null;
             mClientChannel.dispose();
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index 5a24847..8d20bb8 100644
--- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java
+++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
@@ -192,7 +192,7 @@
 
         void onRemoved() {
             if (mInputChannel != null) {
-                mWmService.mInputManager.unregisterInputChannel(mInputChannel);
+                mWmService.mInputManager.unregisterInputChannel(mInputChannel.getToken());
                 mInputChannel.dispose();
                 mInputChannel = null;
             }
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index e2c0749..251c014 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -22,12 +22,9 @@
 import android.annotation.Nullable;
 import android.util.Slog;
 
-import com.android.internal.util.function.pooled.PooledConsumer;
-import com.android.internal.util.function.pooled.PooledLambda;
-
 /** Helper class to ensure activities are in the right visible state for a container. */
 class EnsureActivitiesVisibleHelper {
-    private final Task mContiner;
+    private final Task mTask;
     private ActivityRecord mTop;
     private ActivityRecord mStarting;
     private boolean mAboveTop;
@@ -38,11 +35,11 @@
     private boolean mNotifyClients;
 
     EnsureActivitiesVisibleHelper(Task container) {
-        mContiner = container;
+        mTask = container;
     }
 
     /**
-     * Update all attributes except {@link mContiner} to use in subsequent calculations.
+     * Update all attributes except {@link mTask} to use in subsequent calculations.
      *
      * @param starting The activity that is being started
      * @param configChanges Parts of the configuration that changed for this activity for evaluating
@@ -54,11 +51,11 @@
     void reset(ActivityRecord starting, int configChanges, boolean preserveWindows,
             boolean notifyClients) {
         mStarting = starting;
-        mTop = mContiner.topRunningActivity();
+        mTop = mTask.topRunningActivity();
         // If the top activity is not fullscreen, then we need to make sure any activities under it
         // are now visible.
         mAboveTop = mTop != null;
-        mContainerShouldBeVisible = mContiner.shouldBeVisible(mStarting);
+        mContainerShouldBeVisible = mTask.shouldBeVisible(mStarting);
         mBehindFullscreenActivity = !mContainerShouldBeVisible;
         mConfigChanges = configChanges;
         mPreserveWindows = preserveWindows;
@@ -66,7 +63,26 @@
     }
 
     /**
-     * Ensure visibility with an option to also update the configuration of visible activities.
+     * Update visibility to activities.
+     * @see Task#ensureActivitiesVisible(ActivityRecord, int, boolean)
+     * @see RootWindowContainer#ensureActivitiesVisible(ActivityRecord, int, boolean)
+     * @param starting The top most activity in the task.
+     *                 The activity is either starting or resuming.
+     *                 Caller should ensure starting activity is visible.
+     *
+     */
+    void processUpdate(@Nullable ActivityRecord starting) {
+        reset(starting, 0 /* configChanges */, false /* preserveWindows */,
+                false /* notifyClients */);
+        if (DEBUG_VISIBILITY) {
+            Slog.v(TAG_VISIBILITY, "ensureActivitiesVisible processUpdate behind " + mTop);
+        }
+
+        mTask.forAllActivities(this::updateActivityVisibility);
+    }
+
+    /**
+     * Commit visibility with an option to also update the configuration of visible activities.
      * @see Task#ensureActivitiesVisible(ActivityRecord, int, boolean)
      * @see RootWindowContainer#ensureActivitiesVisible(ActivityRecord, int, boolean)
      * @param starting The top most activity in the task.
@@ -79,54 +95,84 @@
      * @param notifyClients Flag indicating whether the configuration and visibility changes shoulc
      *                      be sent to the clients.
      */
-    void process(@Nullable ActivityRecord starting, int configChanges, boolean preserveWindows,
-            boolean notifyClients) {
+    void processCommit(ActivityRecord starting, int configChanges,
+            boolean preserveWindows, boolean notifyClients) {
         reset(starting, configChanges, preserveWindows, notifyClients);
 
-        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "ensureActivitiesVisible behind " + mTop
-                + " configChanges=0x" + Integer.toHexString(configChanges));
+        if (DEBUG_VISIBILITY) {
+            Slog.v(TAG_VISIBILITY, "ensureActivitiesVisible processCommit behind " + mTop);
+        }
         if (mTop != null) {
-            mContiner.checkTranslucentActivityWaiting(mTop);
+            mTask.checkTranslucentActivityWaiting(mTop);
         }
 
         // We should not resume activities that being launched behind because these
         // activities are actually behind other fullscreen activities, but still required
         // to be visible (such as performing Recents animation).
         final boolean resumeTopActivity = mTop != null && !mTop.mLaunchTaskBehind
-                && mContiner.isTopActivityFocusable()
-                && (starting == null || !starting.isDescendantOf(mContiner));
+                && mTask.isTopActivityFocusable()
+                && (starting == null || !starting.isDescendantOf(mTask));
 
-        final PooledConsumer f = PooledLambda.obtainConsumer(
-                EnsureActivitiesVisibleHelper::setActivityVisibilityState, this,
-                PooledLambda.__(ActivityRecord.class), starting, resumeTopActivity);
-        mContiner.forAllActivities(f);
-        f.recycle();
+        mTask.forAllActivities(a -> {
+            commitActivityVisibility(a, starting, resumeTopActivity);
+        });
     }
 
-    private void setActivityVisibilityState(ActivityRecord r, ActivityRecord starting,
-            final boolean resumeTopActivity) {
-        final boolean isTop = r == mTop;
+    private boolean isAboveTop(boolean isTop) {
         if (mAboveTop && !isTop) {
-            return;
+            return true;
         }
         mAboveTop = false;
+        return false;
+    }
 
-        final boolean reallyVisible = r.shouldBeVisible(
-                mBehindFullscreenActivity, false /* ignoringKeyguard */);
+    private void updateActivityVisibility(ActivityRecord r) {
+        final boolean isTop = r == mTop;
+        if (isAboveTop(isTop)) {
+            return;
+        }
+
+        r.updateVisibility(mBehindFullscreenActivity);
 
         // Check whether activity should be visible without Keyguard influence
         if (r.visibleIgnoringKeyguard) {
             if (r.occludesParent()) {
                 // At this point, nothing else needs to be shown in this task.
-                if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Fullscreen: at " + r
-                        + " stackVisible=" + mContainerShouldBeVisible
-                        + " behindFullscreen=" + mBehindFullscreenActivity);
+                if (DEBUG_VISIBILITY) {
+                    Slog.v(TAG_VISIBILITY, "Fullscreen: at " + r
+                            + " stackVisible=" + mContainerShouldBeVisible
+                            + " behindFullscreen=" + mBehindFullscreenActivity);
+                }
                 mBehindFullscreenActivity = true;
             } else {
                 mBehindFullscreenActivity = false;
             }
         }
 
+        if (!mBehindFullscreenActivity && mTask.isActivityTypeHome() && r.isRootOfTask()) {
+            if (DEBUG_VISIBILITY) {
+                Slog.v(TAG_VISIBILITY, "Home task: at " + mTask
+                        + " stackShouldBeVisible=" + mContainerShouldBeVisible
+                        + " behindFullscreenActivity=" + mBehindFullscreenActivity);
+            }
+            // No other task in the home stack should be visible behind the home activity.
+            // Home activities is usually a translucent activity with the wallpaper behind
+            // them. However, when they don't have the wallpaper behind them, we want to
+            // show activities in the next application stack behind them vs. another
+            // task in the home stack like recents.
+            mBehindFullscreenActivity = true;
+        }
+    }
+
+    private void commitActivityVisibility(ActivityRecord r, ActivityRecord starting,
+            final boolean resumeTopActivity) {
+        final boolean isTop = r == mTop;
+        if (isAboveTop(isTop)) {
+            return;
+        }
+
+        final boolean reallyVisible = r.shouldBeVisibleUnchecked();
+
         if (reallyVisible) {
             if (r.finishing) {
                 return;
@@ -170,20 +216,6 @@
                     + " mLaunchTaskBehind=" + r.mLaunchTaskBehind);
             r.makeInvisible();
         }
-
-        final int windowingMode = mContiner.getWindowingMode();
-        if (!mBehindFullscreenActivity && mContiner.isActivityTypeHome()
-                && r.isRootOfTask()) {
-            if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Home task: at " + mContiner
-                    + " stackShouldBeVisible=" + mContainerShouldBeVisible
-                    + " behindFullscreenActivity=" + mBehindFullscreenActivity);
-            // No other task in the home stack should be visible behind the home activity.
-            // Home activities is usually a translucent activity with the wallpaper behind
-            // them. However, when they don't have the wallpaper behind them, we want to
-            // show activities in the next application stack behind them vs. another
-            // task in the home stack like recents.
-            mBehindFullscreenActivity = true;
-        }
     }
 
     private void makeVisibleAndRestartIfNeeded(ActivityRecord starting, int configChanges,
@@ -207,7 +239,7 @@
             r.setVisibility(true);
         }
         if (r != starting) {
-            mContiner.mStackSupervisor.startSpecificActivity(r, andResume, true /* checkConfig */);
+            mTask.mStackSupervisor.startSpecificActivity(r, andResume, true /* checkConfig */);
         }
     }
 }
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index a79d3bb..1d1a266 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -156,7 +156,7 @@
     }
 
     void disposeChannelsLw(SurfaceControl.Transaction t) {
-        mService.mInputManager.unregisterInputChannel(mServerChannel);
+        mService.mInputManager.unregisterInputChannel(mServerChannel.getToken());
         mClientChannel.dispose();
         mServerChannel.dispose();
         t.remove(mInputSurface);
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index ab1074e..5520ad3 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -286,6 +286,7 @@
         }
         if (changed) {
             notifyInsetsChanged();
+            mDisplayContent.updateSystemGestureExclusion();
             mDisplayContent.getDisplayPolicy().updateSystemUiVisibilityLw();
         }
     }
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 69e8c57..bad28ba 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -278,6 +278,27 @@
     }
 
     /**
+     * Checks whether {@param r} should be visible depending on Keyguard state.
+     *
+     * @return true if {@param r} is visible taken Keyguard state into account, false otherwise
+     */
+    boolean checkKeyguardVisibility(ActivityRecord r) {
+        if (r.mDisplayContent.canShowWithInsecureKeyguard() && canDismissKeyguard()) {
+            return true;
+        }
+
+        if (isKeyguardOrAodShowing(r.mDisplayContent.getDisplayId())) {
+            // If keyguard is showing, nothing is visible, except if we are able to dismiss Keyguard
+            // right away and AOD isn't visible.
+            return canShowActivityWhileKeyguardShowing(r, r.containsDismissKeyguardWindow());
+        } else if (isKeyguardLocked()) {
+            return canShowWhileOccluded(r.containsDismissKeyguardWindow(), r.canShowWhenLocked());
+        } else {
+            return true;
+        }
+    }
+
+    /**
      * Makes sure to update lockscreen occluded/dismiss state if needed after completing all
      * visibility updates ({@link ActivityStackSupervisor#endActivityVisibilityUpdate}).
      */
@@ -442,6 +463,7 @@
         private final int mDisplayId;
         private boolean mOccluded;
         private ActivityRecord mDismissingKeyguardActivity;
+        private ActivityRecord mTopTurnScreenOnActivity;
         private boolean mRequestDismissKeyguard;
         private final ActivityTaskManagerService mService;
         private final ActivityTaskManagerInternal.SleepTokenAcquirer mSleepTokenAcquirer;
@@ -455,30 +477,38 @@
 
         void onRemoved() {
             mDismissingKeyguardActivity = null;
+            mTopTurnScreenOnActivity = null;
             mSleepTokenAcquirer.release(mDisplayId);
         }
 
         void visibilitiesUpdated(KeyguardController controller, DisplayContent display) {
             final boolean lastOccluded = mOccluded;
             final ActivityRecord lastDismissActivity = mDismissingKeyguardActivity;
+            final ActivityRecord lastTurnScreenOnActivity = mTopTurnScreenOnActivity;
             mRequestDismissKeyguard = false;
             mOccluded = false;
             mDismissingKeyguardActivity = null;
+            mTopTurnScreenOnActivity = null;
 
+            // only top + focusable + visible task can control occluding.
             final Task stack = getStackForControllingOccluding(display);
             if (stack != null) {
                 final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity();
+                final ActivityRecord topTurnScreenOn = stack.getTopTurnScreenOnActivity();
                 mOccluded = stack.topActivityOccludesKeyguard() || (topDismissing != null
                         && stack.topRunningActivity() == topDismissing
                         && controller.canShowWhileOccluded(
                                 true /* dismissKeyguard */,
                                 false /* showWhenLocked */));
-                if (stack.getTopDismissingKeyguardActivity() != null) {
-                    mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
+                if (topDismissing != null) {
+                    mDismissingKeyguardActivity = topDismissing;
+                }
+                if (topTurnScreenOn != null) {
+                    mTopTurnScreenOnActivity = topTurnScreenOn;
                 }
                 // FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD only apply for secondary display.
-                if (mDisplayId != DEFAULT_DISPLAY) {
-                    mOccluded |= stack.canShowWithInsecureKeyguard()
+                if (mDisplayId != DEFAULT_DISPLAY && stack.mDisplayContent != null) {
+                    mOccluded |= stack.mDisplayContent.canShowWithInsecureKeyguard()
                             && controller.canDismissKeyguard();
                 }
             }
@@ -488,14 +518,20 @@
                         .getDisplayPolicy().isShowingDreamLw();
             }
 
-            if (lastOccluded != mOccluded) {
-                controller.handleOccludedChanged(mDisplayId);
-            }
-            if (lastDismissActivity != mDismissingKeyguardActivity && !mOccluded
+            mRequestDismissKeyguard = lastDismissActivity != mDismissingKeyguardActivity
+                    && !mOccluded
                     && mDismissingKeyguardActivity != null
                     && controller.mWindowManager.isKeyguardSecure(
-                            controller.mService.getCurrentUserId())) {
-                mRequestDismissKeyguard = true;
+                    controller.mService.getCurrentUserId());
+
+            if (mTopTurnScreenOnActivity != null
+                    && mTopTurnScreenOnActivity != lastTurnScreenOnActivity
+                    && !mService.mWindowManager.mPowerManager.isInteractive()) {
+                controller.mStackSupervisor.wakeUp("handleTurnScreenOn");
+            }
+
+            if (lastOccluded != mOccluded) {
+                controller.handleOccludedChanged(mDisplayId);
             }
         }
 
@@ -525,6 +561,8 @@
             sb.append("  Occluded=").append(mOccluded)
                     .append(" DismissingKeyguardActivity=")
                     .append(mDismissingKeyguardActivity)
+                    .append(" TurnScreenOnActivity=")
+                    .append(mTopTurnScreenOnActivity)
                     .append(" at display=")
                     .append(mDisplayId);
             pw.println(sb.toString());
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index dccd3a6..4fe678d 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -239,7 +239,7 @@
         }
 
         void dispose() {
-            mWmService.mInputManager.unregisterInputChannel(mServerChannel);
+            mWmService.mInputManager.unregisterInputChannel(mServerChannel.getToken());
             mInputEventReceiver.dispose();
             mServerChannel.dispose();
             mClientChannel.dispose();
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 80ccf3c..d149db6 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -99,6 +99,7 @@
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
+import android.app.ActivityTaskManager.RootTaskInfo;
 import android.app.AppGlobals;
 import android.app.WindowConfiguration;
 import android.content.ComponentName;
@@ -1982,10 +1983,22 @@
                         notifyClients);
             }
         } finally {
-            mStackSupervisor.endActivityVisibilityUpdate();
+            mStackSupervisor.endActivityVisibilityUpdate(starting, configChanges, preserveWindows,
+                    notifyClients);
         }
     }
 
+    void commitActivitiesVisible(ActivityRecord starting, int configChanges,
+            boolean preserveWindows, boolean notifyClients) {
+        forAllTaskDisplayAreas(taskDisplayArea -> {
+            for (int stackNdx = taskDisplayArea.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
+                final Task task = taskDisplayArea.getStackAt(stackNdx);
+                task.commitActivitiesVisible(starting, configChanges, preserveWindows,
+                        notifyClients);
+            }
+        });
+    }
+
     boolean switchUser(int userId, UserState uss) {
         final Task topFocusedStack = getTopDisplayFocusedStack();
         final int focusStackId = topFocusedStack != null
@@ -2438,77 +2451,73 @@
         return display.getStack(windowingMode, activityType);
     }
 
-    private ActivityManager.StackInfo getStackInfo(Task stack) {
-        final TaskDisplayArea taskDisplayArea = stack.getDisplayArea();
-        ActivityManager.StackInfo info = new ActivityManager.StackInfo();
-        stack.getBounds(info.bounds);
-        info.displayId = taskDisplayArea != null ? taskDisplayArea.getDisplayId() : INVALID_DISPLAY;
-        info.stackId = stack.mTaskId;
-        info.stackToken = stack.mRemoteToken.toWindowContainerToken();
-        info.userId = stack.mCurrentUser;
-        info.visible = stack.shouldBeVisible(null);
-        // A stack might be not attached to a display.
-        // TODO: Can be removed since no one is using it.
-        info.position = taskDisplayArea != null ? taskDisplayArea.getIndexOf(stack) : 0;
-        info.configuration.setTo(stack.getConfiguration());
+    private RootTaskInfo getRootTaskInfo(Task task) {
+        final TaskDisplayArea taskDisplayArea = task.getDisplayArea();
+        RootTaskInfo info = new RootTaskInfo();
+        task.fillTaskInfo(info);
 
-        final int numTasks = stack.getDescendantTaskCount();
-        info.taskIds = new int[numTasks];
-        info.taskNames = new String[numTasks];
-        info.taskBounds = new Rect[numTasks];
-        info.taskUserIds = new int[numTasks];
+        // A task might be not attached to a display.
+        info.position = taskDisplayArea != null ? taskDisplayArea.getIndexOf(task) : 0;
+        info.visible = task.shouldBeVisible(null);
+        task.getBounds(info.bounds);
+
+        final int numTasks = task.getDescendantTaskCount();
+        info.childTaskIds = new int[numTasks];
+        info.childTaskNames = new String[numTasks];
+        info.childTaskBounds = new Rect[numTasks];
+        info.childTaskUserIds = new int[numTasks];
         final int[] currentIndex = {0};
 
         final PooledConsumer c = PooledLambda.obtainConsumer(
-                RootWindowContainer::processTaskForStackInfo, PooledLambda.__(Task.class), info,
+                RootWindowContainer::processTaskForTaskInfo, PooledLambda.__(Task.class), info,
                 currentIndex);
-        stack.forAllLeafTasks(c, false /* traverseTopToBottom */);
+        task.forAllLeafTasks(c, false /* traverseTopToBottom */);
         c.recycle();
 
-        final ActivityRecord top = stack.topRunningActivity();
+        final ActivityRecord top = task.topRunningActivity();
         info.topActivity = top != null ? top.intent.getComponent() : null;
         return info;
     }
 
-    private static void processTaskForStackInfo(
-            Task task, ActivityManager.StackInfo info, int[] currentIndex) {
+    private static void processTaskForTaskInfo(
+            Task task, RootTaskInfo info, int[] currentIndex) {
         int i = currentIndex[0];
-        info.taskIds[i] = task.mTaskId;
-        info.taskNames[i] = task.origActivity != null ? task.origActivity.flattenToString()
+        info.childTaskIds[i] = task.mTaskId;
+        info.childTaskNames[i] = task.origActivity != null ? task.origActivity.flattenToString()
                 : task.realActivity != null ? task.realActivity.flattenToString()
                         : task.getTopNonFinishingActivity() != null
                                 ? task.getTopNonFinishingActivity().packageName : "unknown";
-        info.taskBounds[i] = task.mAtmService.getTaskBounds(task.mTaskId);
-        info.taskUserIds[i] = task.mUserId;
+        info.childTaskBounds[i] = task.mAtmService.getTaskBounds(task.mTaskId);
+        info.childTaskUserIds[i] = task.mUserId;
         currentIndex[0] = ++i;
     }
 
-    ActivityManager.StackInfo getStackInfo(int stackId) {
-        Task stack = getStack(stackId);
-        if (stack != null) {
-            return getStackInfo(stack);
+    RootTaskInfo getRootTaskInfo(int taskId) {
+        Task task = getStack(taskId);
+        if (task != null) {
+            return getRootTaskInfo(task);
         }
         return null;
     }
 
-    ActivityManager.StackInfo getStackInfo(int windowingMode, int activityType) {
+    RootTaskInfo getRootTaskInfo(int windowingMode, int activityType) {
         final Task stack = getStack(windowingMode, activityType);
-        return (stack != null) ? getStackInfo(stack) : null;
+        return (stack != null) ? getRootTaskInfo(stack) : null;
     }
 
-    ActivityManager.StackInfo getStackInfo(int windowingMode, int activityType, int displayId) {
+    RootTaskInfo getRootTaskInfo(int windowingMode, int activityType, int displayId) {
         final Task stack = getStack(windowingMode, activityType, displayId);
-        return (stack != null) ? getStackInfo(stack) : null;
+        return (stack != null) ? getRootTaskInfo(stack) : null;
     }
 
-    /** If displayId == INVALID_DISPLAY, this will get stack infos on all displays */
-    ArrayList<ActivityManager.StackInfo> getAllStackInfos(int displayId) {
-        ArrayList<ActivityManager.StackInfo> list = new ArrayList<>();
+    /** If displayId == INVALID_DISPLAY, this will get root task infos on all displays */
+    ArrayList<RootTaskInfo> getAllRootTaskInfos(int displayId) {
+        ArrayList<RootTaskInfo> list = new ArrayList<>();
         if (displayId == INVALID_DISPLAY) {
             forAllTaskDisplayAreas(taskDisplayArea -> {
                 for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
                     final Task stack = taskDisplayArea.getStackAt(sNdx);
-                    list.add(getStackInfo(stack));
+                    list.add(getRootTaskInfo(stack));
                 }
             });
             return list;
@@ -2520,7 +2529,7 @@
         display.forAllTaskDisplayAreas(taskDisplayArea -> {
             for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
                 final Task stack = taskDisplayArea.getStackAt(sNdx);
-                list.add(getStackInfo(stack));
+                list.add(getRootTaskInfo(stack));
             }
         });
         return list;
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 3b32a9d76..3d6d7b7 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -56,6 +56,7 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 import android.view.WindowManager;
+import android.window.ClientWindowFrames;
 
 import com.android.internal.os.logging.MetricsLoggerWrapper;
 import com.android.internal.protolog.common.ProtoLog;
@@ -201,9 +202,7 @@
     @Override
     public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
             int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,
-            Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,
-            Rect outStableInsets, Rect outBackdropFrame,
-            DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration,
+            ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
             SurfaceControl outSurfaceControl, InsetsState outInsetsState,
             InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
             SurfaceControl outBLASTSurfaceControl) {
@@ -212,10 +211,8 @@
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
         int res = mService.relayoutWindow(this, window, seq, attrs,
                 requestedWidth, requestedHeight, viewFlags, flags, frameNumber,
-                outFrame, outContentInsets, outVisibleInsets,
-                outStableInsets, outBackdropFrame, cutout,
-                mergedConfiguration, outSurfaceControl, outInsetsState, outActiveControls,
-                outSurfaceSize, outBLASTSurfaceControl);
+                outFrames, mergedConfiguration, outSurfaceControl, outInsetsState,
+                outActiveControls, outSurfaceSize, outBLASTSurfaceControl);
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
                 + Binder.getCallingPid());
@@ -240,11 +237,6 @@
     }
 
     @Override
-    public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
-        mService.getWindowDisplayFrame(this, window, outDisplayFrame);
-    }
-
-    @Override
     public void finishDrawing(IWindow window,
             @Nullable SurfaceControl.Transaction postDrawTransaction) {
         if (DEBUG) Slog.v(TAG_WM, "IWindow finishDrawing called for " + window);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index b32e91f..c4ca4cd 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -61,7 +61,6 @@
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
 import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.SurfaceControl.METADATA_TASK_ID;
 import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
@@ -197,7 +196,6 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
-import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationTarget;
@@ -600,6 +598,7 @@
 
     private boolean mTopActivityOccludesKeyguard;
     private ActivityRecord mTopDismissingKeyguardActivity;
+    private ActivityRecord mTopTurnScreenOnActivity;
 
     private static final int TRANSLUCENT_TIMEOUT_MSG = FIRST_ACTIVITY_STACK_MSG + 1;
 
@@ -4019,7 +4018,7 @@
      */
     void fillTaskInfo(TaskInfo info, boolean stripExtras) {
         getNumRunningActivities(mReuseActivitiesReport);
-        info.userId = mUserId;
+        info.userId = isLeafTask() ? mUserId : mCurrentUser;
         info.stackId = getRootTaskId();
         info.taskId = mTaskId;
         info.displayId = getDisplayId();
@@ -5664,21 +5663,29 @@
             boolean preserveWindows, boolean notifyClients) {
         mTopActivityOccludesKeyguard = false;
         mTopDismissingKeyguardActivity = null;
+        mTopTurnScreenOnActivity = null;
         mStackSupervisor.beginActivityVisibilityUpdate();
         try {
-            mEnsureActivitiesVisibleHelper.process(
-                    starting, configChanges, preserveWindows, notifyClients);
+            mEnsureActivitiesVisibleHelper.processUpdate(starting);
 
             if (mTranslucentActivityWaiting != null &&
                     mUndrawnActivitiesBelowTopTranslucent.isEmpty()) {
-                // Nothing is getting drawn or everything was already visible, don't wait for timeout.
+                // Nothing is getting drawn or everything was already visible, don't wait for
+                // timeout.
                 notifyActivityDrawnLocked(null);
             }
         } finally {
-            mStackSupervisor.endActivityVisibilityUpdate();
+            mStackSupervisor.endActivityVisibilityUpdate(starting, configChanges, preserveWindows,
+                    notifyClients);
         }
     }
 
+    void commitActivitiesVisible(ActivityRecord starting, int configChanges,
+            boolean preserveWindows, boolean notifyClients) {
+        mEnsureActivitiesVisibleHelper.processCommit(starting, configChanges, preserveWindows,
+                notifyClients);
+    }
+
     /**
      * @return true if the top visible activity wants to occlude the Keyguard, false otherwise
      */
@@ -5712,64 +5719,34 @@
     }
 
     /**
-     * Checks whether {@param r} should be visible depending on Keyguard state and updates
-     * {@link #mTopActivityOccludesKeyguard} and {@link #mTopDismissingKeyguardActivity} if
-     * necessary.
-     *
-     * @return true if {@param r} is visible taken Keyguard state into account, false otherwise
+     * @return the top most visible activity that wants to turn screen on
      */
-    boolean checkKeyguardVisibility(ActivityRecord r, boolean shouldBeVisible, boolean isTop) {
-        int displayId = getDisplayId();
-        if (displayId == INVALID_DISPLAY) displayId = DEFAULT_DISPLAY;
-
-        final boolean keyguardOrAodShowing = mStackSupervisor.getKeyguardController()
-                .isKeyguardOrAodShowing(displayId);
-        final boolean keyguardLocked = mStackSupervisor.getKeyguardController().isKeyguardLocked();
-        final boolean showWhenLocked = r.canShowWhenLocked();
-        final boolean dismissKeyguard = r.containsDismissKeyguardWindow();
-        if (shouldBeVisible) {
-            if (dismissKeyguard && mTopDismissingKeyguardActivity == null) {
-                mTopDismissingKeyguardActivity = r;
-            }
-
-            // Only the top activity may control occluded, as we can't occlude the Keyguard if the
-            // top app doesn't want to occlude it.
-            if (isTop) {
-                mTopActivityOccludesKeyguard |= showWhenLocked;
-            }
-
-            final boolean canShowWithKeyguard = canShowWithInsecureKeyguard()
-                    && mStackSupervisor.getKeyguardController().canDismissKeyguard();
-            if (canShowWithKeyguard) {
-                return true;
-            }
-        }
-        if (keyguardOrAodShowing) {
-            // If keyguard is showing, nothing is visible, except if we are able to dismiss Keyguard
-            // right away and AOD isn't visible.
-            return shouldBeVisible && mStackSupervisor.getKeyguardController()
-                    .canShowActivityWhileKeyguardShowing(r, dismissKeyguard);
-        } else if (keyguardLocked) {
-            return shouldBeVisible && mStackSupervisor.getKeyguardController().canShowWhileOccluded(
-                    dismissKeyguard, showWhenLocked);
-        } else {
-            return shouldBeVisible;
-        }
+    ActivityRecord getTopTurnScreenOnActivity() {
+        return mTopTurnScreenOnActivity;
     }
 
     /**
-     * Check if the display to which this stack is attached has
-     * {@link Display#FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD} applied.
+     * Updates {@link #mTopActivityOccludesKeyguard}, {@link #mTopTurnScreenOnActivity} and
+     * {@link #mTopDismissingKeyguardActivity} if this task could be visible.
+     *
      */
-    boolean canShowWithInsecureKeyguard() {
-        final DisplayContent displayContent = mDisplayContent;
-        if (displayContent == null) {
-            throw new IllegalStateException("Stack is not attached to any display, stackId="
-                    + getRootTaskId());
+    void updateKeyguardVisibility(ActivityRecord r, boolean isTop) {
+        final boolean showWhenLocked = r.canShowWhenLocked();
+        final boolean dismissKeyguard = r.containsDismissKeyguardWindow();
+        final boolean turnScreenOn = r.canTurnScreenOn();
+        if (dismissKeyguard && mTopDismissingKeyguardActivity == null) {
+            mTopDismissingKeyguardActivity = r;
         }
 
-        final int flags = displayContent.mDisplay.getFlags();
-        return (flags & FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0;
+        if (turnScreenOn && mTopTurnScreenOnActivity == null) {
+            mTopTurnScreenOnActivity = r;
+        }
+
+        // Only the top activity may control occluded, as we can't occlude the Keyguard if the
+        // top app doesn't want to occlude it.
+        if (isTop) {
+            mTopActivityOccludesKeyguard |= showWhenLocked;
+        }
     }
 
     void checkTranslucentActivityWaiting(ActivityRecord top) {
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 6550167..2b32e40 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -1779,7 +1779,8 @@
                         notifyClients);
             }
         } finally {
-            mAtmService.mStackSupervisor.endActivityVisibilityUpdate();
+            mAtmService.mStackSupervisor.endActivityVisibilityUpdate(starting, configChanges,
+                    preserveWindows, notifyClients);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index f32781a..abe6329 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -299,7 +299,7 @@
         }
 
         mService.mTaskPositioningController.hideInputSurface(mDisplayContent.getDisplayId());
-        mService.mInputManager.unregisterInputChannel(mServerChannel);
+        mService.mInputManager.unregisterInputChannel(mServerChannel.getToken());
 
         mInputEventReceiver.dispose();
         mInputEventReceiver = null;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index e9ada6b..100f1bf 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -67,7 +67,6 @@
 import android.os.SystemClock;
 import android.util.MergedConfiguration;
 import android.util.Slog;
-import android.view.DisplayCutout;
 import android.view.IWindowSession;
 import android.view.InsetsSourceControl;
 import android.view.InsetsState;
@@ -79,6 +78,7 @@
 import android.view.ViewRootImpl;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
+import android.window.ClientWindowFrames;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
@@ -159,12 +159,8 @@
         final IWindowSession session = WindowManagerGlobal.getWindowSession();
         window.setSession(session);
         final SurfaceControl surfaceControl = new SurfaceControl();
-        final Rect tmpRect = new Rect();
-        final DisplayCutout.ParcelableWrapper tmpCutout = new DisplayCutout.ParcelableWrapper();
-        final Rect tmpFrame = new Rect();
+        final ClientWindowFrames tmpFrames = new ClientWindowFrames();
         final Rect taskBounds;
-        final Rect tmpContentInsets = new Rect();
-        final Rect tmpStableInsets = new Rect();
         final InsetsState mTmpInsetsState = new InsetsState();
         final InsetsSourceControl[] mTempControls = new InsetsSourceControl[0];
         final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
@@ -254,8 +250,9 @@
         }
         try {
             final int res = session.addToDisplay(window, window.mSeq, layoutParams,
-                    View.GONE, activity.getDisplayContent().getDisplayId(), tmpFrame, tmpRect,
-                    tmpRect, tmpCutout, null, mTmpInsetsState, mTempControls);
+                    View.GONE, activity.getDisplayContent().getDisplayId(), tmpFrames.frame,
+                    tmpFrames.contentInsets, tmpFrames.stableInsets, tmpFrames.displayCutout,
+                    null /* outInputChannel */, mTmpInsetsState, mTempControls);
             if (res < 0) {
                 Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
                 return null;
@@ -270,15 +267,14 @@
         window.setOuter(snapshotSurface);
         try {
             session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, -1,
-                    tmpFrame, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect,
-                    tmpCutout, tmpMergedConfiguration, surfaceControl, mTmpInsetsState,
+                    tmpFrames, tmpMergedConfiguration, surfaceControl, mTmpInsetsState,
                     mTempControls, sTmpSurfaceSize, sTmpSurfaceControl);
         } catch (RemoteException e) {
             // Local call.
         }
 
-        final Rect systemBarInsets = getSystemBarInsets(tmpFrame, insetsState);
-        snapshotSurface.setFrames(tmpFrame, systemBarInsets);
+        final Rect systemBarInsets = getSystemBarInsets(tmpFrames.frame, insetsState);
+        snapshotSurface.setFrames(tmpFrames.frame, systemBarInsets);
         snapshotSurface.drawSnapshot();
         return snapshotSurface;
     }
@@ -528,11 +524,9 @@
         }
 
         @Override
-        public void resized(Rect frame, Rect contentInsets, Rect visibleInsets,
-                Rect stableInsets, boolean reportDraw,
-                MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
-                boolean alwaysConsumeSystemBars, int displayId,
-                DisplayCutout.ParcelableWrapper displayCutout) {
+        public void resized(ClientWindowFrames frames, boolean reportDraw,
+                MergedConfiguration mergedConfiguration, boolean forceLayout,
+                boolean alwaysConsumeSystemBars, int displayId) {
             if (mergedConfiguration != null && mOuter != null
                     && mOuter.mOrientationOnCreation
                             != mergedConfiguration.getMergedConfiguration().orientation) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 3fd8aaf..8eb6432 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -258,6 +258,7 @@
 import android.view.WindowManager.TransitionType;
 import android.view.WindowManagerGlobal;
 import android.view.WindowManagerPolicyConstants.PointerEventListener;
+import android.window.ClientWindowFrames;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
@@ -2065,21 +2066,6 @@
         }
     }
 
-    public void getWindowDisplayFrame(Session session, IWindow client,
-            Rect outDisplayFrame) {
-        synchronized (mGlobalLock) {
-            WindowState win = windowForClientLocked(session, client, false);
-            if (win == null) {
-                outDisplayFrame.setEmpty();
-                return;
-            }
-            outDisplayFrame.set(win.getDisplayFrame());
-            if (win.inSizeCompatMode()) {
-                outDisplayFrame.scale(win.mInvGlobalScale);
-            }
-        }
-    }
-
     public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) {
         synchronized (mGlobalLock) {
             if (mAccessibilityController != null) {
@@ -2115,9 +2101,7 @@
 
     public int relayoutWindow(Session session, IWindow client, int seq, LayoutParams attrs,
             int requestedWidth, int requestedHeight, int viewVisibility, int flags,
-            long frameNumber, Rect outFrame, Rect outContentInsets,
-            Rect outVisibleInsets, Rect outStableInsets, Rect outBackdropFrame,
-            DisplayCutout.ParcelableWrapper outCutout, MergedConfiguration mergedConfiguration,
+            long frameNumber, ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
             SurfaceControl outSurfaceControl, InsetsState outInsetsState,
             InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
             SurfaceControl outBLASTSurfaceControl) {
@@ -2415,18 +2399,14 @@
             // The last inset values represent the last client state
             win.updateLastInsetValues();
 
-            win.getCompatFrame(outFrame);
-            win.getInsetsForRelayout(outContentInsets, outVisibleInsets,
-                    outStableInsets);
-            outCutout.set(win.getWmDisplayCutout().getDisplayCutout());
-            outBackdropFrame.set(win.getBackdropFrame(win.getFrame()));
+            win.fillClientWindowFrames(outFrames);
             outInsetsState.set(win.getInsetsState(), win.isClientLocal());
             if (DEBUG) {
                 Slog.v(TAG_WM, "Relayout given client " + client.asBinder()
                         + ", requestedWidth=" + requestedWidth
                         + ", requestedHeight=" + requestedHeight
                         + ", viewVisibility=" + viewVisibility
-                        + "\nRelayout returning frame=" + outFrame
+                        + "\nRelayout returning frame=" + outFrames.frame
                         + ", surface=" + outSurfaceControl);
             }
 
@@ -2436,8 +2416,7 @@
             result |= mInTouchMode ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0;
 
             if (DEBUG_LAYOUT) {
-                Slog.v(TAG_WM,
-                        "Relayout complete " + win + ": outFrame=" + outFrame.toShortString());
+                Slog.v(TAG_WM, "Relayout complete " + win + ": outFrames=" + outFrames);
             }
             win.mInRelayout = false;
 
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 84a9c75..cf73def 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -209,7 +209,6 @@
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 import android.view.Display;
-import android.view.DisplayCutout;
 import android.view.DisplayInfo;
 import android.view.Gravity;
 import android.view.IApplicationToken;
@@ -233,6 +232,7 @@
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
+import android.window.ClientWindowFrames;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.policy.KeyInterceptionInfo;
@@ -388,15 +388,6 @@
     private final Configuration mTempConfiguration = new Configuration();
 
     /**
-     * The last content insets returned to the client in relayout. We use
-     * these in the bounds animation to ensure we only observe inset changes
-     * at the same time that a client resizes it's surface so that we may use
-     * the geometryAppliesWithResize synchronization mechanism to keep
-     * the contents in place.
-     */
-    final Rect mLastRelayoutContentInsets = new Rect();
-
-    /**
      * Set to true if we are waiting for this window to receive its
      * given internal insets before laying out other windows based on it.
      */
@@ -437,6 +428,8 @@
 
     private final WindowFrames mWindowFrames = new WindowFrames();
 
+    private final ClientWindowFrames mClientWindowFrames = new ClientWindowFrames();
+
     /** The frames used to compute a temporal layout appearance. */
     private WindowFrames mSimulatedWindowFrames;
 
@@ -1299,7 +1292,10 @@
         return mWindowFrames.mRelFrame;
     }
 
-    /** Retrieves the frame of the display that this window was last laid out in. */
+    /**
+     * Gets the frame that excludes the area of side insets according to the layout parameter from
+     * {@link WindowManager.LayoutParams#setFitInsetsSides}.
+     */
     Rect getDisplayFrame() {
         return mWindowFrames.mDisplayFrame;
     }
@@ -2504,7 +2500,7 @@
 
         // unregister server channel first otherwise it complains about broken channel
         if (mInputChannel != null) {
-            mWmService.mInputManager.unregisterInputChannel(mInputChannel);
+            mWmService.mInputManager.unregisterInputChannel(mInputChannel.getToken());
 
             mInputChannel.dispose();
             mInputChannel = null;
@@ -3585,6 +3581,39 @@
         return wpc != null && wpc.registeredForDisplayConfigChanges();
     }
 
+    void fillClientWindowFrames(ClientWindowFrames outFrames) {
+        outFrames.frame.set(mWindowFrames.mCompatFrame);
+        outFrames.displayFrame.set(mWindowFrames.mDisplayFrame);
+        if (mInvGlobalScale != 1.0f && inSizeCompatMode()) {
+            outFrames.displayFrame.scale(mInvGlobalScale);
+        }
+
+        final Rect backdropFrame = outFrames.backdropFrame;
+        // When the task is docked, we send fullscreen sized backdropFrame as soon as resizing
+        // start even if we haven't received the relayout window, so that the client requests
+        // the relayout sooner. When dragging stops, backdropFrame needs to stay fullscreen
+        // until the window to small size, otherwise the multithread renderer will shift last
+        // one or more frame to wrong offset. So here we send fullscreen backdrop if either
+        // isDragResizing() or isDragResizeChanged() is true.
+        final boolean resizing = isDragResizing() || isDragResizeChanged();
+        if (!resizing || getWindowConfiguration().useWindowFrameForBackdrop()) {
+            // Surface position is now inherited from parent, and BackdropFrameRenderer uses
+            // backdrop frame to position content. Thus we just keep the size of backdrop frame,
+            // and remove the offset to avoid double offset from display origin.
+            backdropFrame.set(outFrames.frame);
+            backdropFrame.offsetTo(0, 0);
+        } else {
+            final DisplayInfo displayInfo = getDisplayInfo();
+            backdropFrame.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
+        }
+        outFrames.displayCutout.set(mWindowFrames.mDisplayCutout.getDisplayCutout());
+
+        // TODO(b/149813814): Remove legacy insets.
+        outFrames.contentInsets.set(mWindowFrames.mLastContentInsets);
+        outFrames.visibleInsets.set(mWindowFrames.mLastVisibleInsets);
+        outFrames.stableInsets.set(mWindowFrames.mLastStableInsets);
+    }
+
     void reportResized() {
         // If the activity is scheduled to relaunch, skip sending the resized to ViewRootImpl now
         // since it will be destroyed anyway. This also prevents the client from receiving
@@ -3616,23 +3645,18 @@
         mWinAnimator.mSurfaceResized = false;
         mWindowFrames.resetInsetsChanged();
 
-        final Rect frame = mWindowFrames.mCompatFrame;
-        final Rect contentInsets = mWindowFrames.mLastContentInsets;
-        final Rect visibleInsets = mWindowFrames.mLastVisibleInsets;
-        final Rect stableInsets = mWindowFrames.mLastStableInsets;
         final MergedConfiguration mergedConfiguration = mLastReportedConfiguration;
         final boolean reportDraw = mWinAnimator.mDrawState == DRAW_PENDING || useBLASTSync() || !mRedrawForSyncReported;
         final boolean forceRelayout = reportOrientation || isDragResizeChanged() || !mRedrawForSyncReported;
         final int displayId = getDisplayId();
-        final DisplayCutout displayCutout = getWmDisplayCutout().getDisplayCutout();
+        fillClientWindowFrames(mClientWindowFrames);
 
         mRedrawForSyncReported = true;
 
         try {
-            mClient.resized(frame, contentInsets, visibleInsets, stableInsets, reportDraw,
-                    mergedConfiguration, getBackdropFrame(frame), forceRelayout,
+            mClient.resized(mClientWindowFrames, reportDraw, mergedConfiguration, forceRelayout,
                     getDisplayContent().getDisplayPolicy().areSystemBarsForcedShownLw(this),
-                    displayId, new DisplayCutout.ParcelableWrapper(displayCutout));
+                    displayId);
 
             if (mWmService.mAccessibilityController != null) {
                 mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked(displayId);
@@ -3738,27 +3762,6 @@
         return (mAttrs.insetsFlags.behavior & BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE) != 0;
     }
 
-    Rect getBackdropFrame(Rect frame) {
-        // When the task is docked, we send fullscreen sized backDropFrame as soon as resizing
-        // start even if we haven't received the relayout window, so that the client requests
-        // the relayout sooner. When dragging stops, backDropFrame needs to stay fullscreen
-        // until the window to small size, otherwise the multithread renderer will shift last
-        // one or more frame to wrong offset. So here we send fullscreen backdrop if either
-        // isDragResizing() or isDragResizeChanged() is true.
-        boolean resizing = isDragResizing() || isDragResizeChanged();
-        if (getWindowConfiguration().useWindowFrameForBackdrop() || !resizing) {
-            // Surface position is now inherited from parent, and BackdropFrameRenderer uses
-            // backdrop frame to position content. Thus we just keep the size of backdrop frame, and
-            // remove the offset to avoid double offset from display origin.
-            mTmpRect.set(frame);
-            mTmpRect.offsetTo(0, 0);
-            return mTmpRect;
-        }
-        final DisplayInfo displayInfo = getDisplayInfo();
-        mTmpRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
-        return mTmpRect;
-    }
-
     private int getRootTaskId() {
         final Task stack = getRootTask();
         if (stack == null) {
@@ -5670,18 +5673,6 @@
         }
     }
 
-    /**
-     * Copy the inset values over so they can be sent back to the client when a relayout occurs.
-     */
-    void getInsetsForRelayout(Rect outContentInsets, Rect outVisibleInsets,
-            Rect outStableInsets) {
-        outContentInsets.set(mWindowFrames.mContentInsets);
-        outVisibleInsets.set(mWindowFrames.mVisibleInsets);
-        outStableInsets.set(mWindowFrames.mStableInsets);
-
-        mLastRelayoutContentInsets.set(mWindowFrames.mContentInsets);
-    }
-
     void getContentInsets(Rect outContentInsets) {
         outContentInsets.set(mWindowFrames.mContentInsets);
     }
diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
index 7e9e11d..95d4ba7 100644
--- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
+++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
@@ -29,6 +29,7 @@
 
 #include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
+#include <binder/IPCThreadState.h>
 #include <jni.h>
 #include <processgroup/processgroup.h>
 
@@ -90,11 +91,20 @@
     }
 }
 
+static void com_android_server_am_CachedAppOptimizer_freezeBinder(
+        JNIEnv *env, jobject clazz, jint pid, jboolean freeze) {
+
+    if (IPCThreadState::freeze(pid, freeze, 100 /* timeout [ms] */) != 0) {
+        jniThrowException(env, "java/lang/RuntimeException", "Unable to freeze/unfreeze binder");
+    }
+}
+
 static const JNINativeMethod sMethods[] = {
     /* name, signature, funcPtr */
     {"compactSystem", "()V", (void*)com_android_server_am_CachedAppOptimizer_compactSystem},
     {"enableFreezerInternal", "(Z)V",
         (void*)com_android_server_am_CachedAppOptimizer_enableFreezerInternal},
+    {"freezeBinder", "(IZ)V", (void*)com_android_server_am_CachedAppOptimizer_freezeBinder}
 };
 
 int register_android_server_am_CachedAppOptimizer(JNIEnv* env)
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 5dd6cd7..46136ca 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -209,7 +209,7 @@
     status_t registerInputChannel(JNIEnv* env, const std::shared_ptr<InputChannel>& inputChannel);
     status_t registerInputMonitor(JNIEnv* env, const std::shared_ptr<InputChannel>& inputChannel,
                                   int32_t displayId, bool isGestureMonitor);
-    status_t unregisterInputChannel(JNIEnv* env, const InputChannel& inputChannel);
+    status_t unregisterInputChannel(JNIEnv* env, const sp<IBinder>& connectionToken);
     status_t pilferPointers(const sp<IBinder>& token);
 
     void displayRemoved(JNIEnv* env, int32_t displayId);
@@ -447,9 +447,9 @@
 }
 
 status_t NativeInputManager::unregisterInputChannel(JNIEnv* /* env */,
-                                                    const InputChannel& inputChannel) {
+                                                    const sp<IBinder>& connectionToken) {
     ATRACE_CALL();
-    return mInputManager->getDispatcher()->unregisterInputChannel(inputChannel);
+    return mInputManager->getDispatcher()->unregisterInputChannel(connectionToken);
 }
 
 status_t NativeInputManager::pilferPointers(const sp<IBinder>& token) {
@@ -1364,7 +1364,7 @@
 
     ALOGW("Input channel object '%s' was disposed without first being unregistered with "
             "the input manager!", inputChannel->getName().c_str());
-    im->unregisterInputChannel(env, *inputChannel);
+    im->unregisterInputChannel(env, inputChannel->getConnectionToken());
 }
 
 static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
@@ -1417,20 +1417,12 @@
     }
 }
 
-static void nativeUnregisterInputChannel(JNIEnv* env, jclass /* clazz */,
-        jlong ptr, jobject inputChannelObj) {
+static void nativeUnregisterInputChannel(JNIEnv* env, jclass /* clazz */, jlong ptr,
+                                         jobject tokenObj) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+    sp<IBinder> token = ibinderForJavaObject(env, tokenObj);
 
-    std::shared_ptr<InputChannel> inputChannel =
-            android_view_InputChannel_getInputChannel(env, inputChannelObj);
-    if (inputChannel == nullptr) {
-        throwInputChannelNotInitialized(env);
-        return;
-    }
-
-    android_view_InputChannel_setDisposeCallback(env, inputChannelObj, nullptr, nullptr);
-
-    status_t status = im->unregisterInputChannel(env, *inputChannel);
+    status_t status = im->unregisterInputChannel(env, token);
     if (status && status != BAD_VALUE) { // ignore already unregistered channel
         std::string message;
         message += StringPrintf("Failed to unregister input channel.  status=%d", status);
@@ -1792,7 +1784,7 @@
          (void*)nativeRegisterInputChannel},
         {"nativeRegisterInputMonitor", "(JLandroid/view/InputChannel;IZ)V",
          (void*)nativeRegisterInputMonitor},
-        {"nativeUnregisterInputChannel", "(JLandroid/view/InputChannel;)V",
+        {"nativeUnregisterInputChannel", "(JLandroid/os/IBinder;)V",
          (void*)nativeUnregisterInputChannel},
         {"nativePilferPointers", "(JLandroid/os/IBinder;)V", (void*)nativePilferPointers},
         {"nativeSetInputFilterEnabled", "(JZ)V", (void*)nativeSetInputFilterEnabled},
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b6f0f9f..33b1213 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2159,6 +2159,11 @@
         return getDeviceOwnerOfCallerLocked(caller);
     }
 
+    @NonNull ActiveAdmin getParentOfAdminIfRequired(ActiveAdmin admin, boolean parent) {
+        Objects.requireNonNull(admin);
+        return parent ? admin.getParentActiveAdmin() : admin;
+    }
+
     /**
      * Finds an active admin for the caller then checks {@code permission} if admin check failed.
      *
@@ -4527,6 +4532,8 @@
         }
         Objects.requireNonNull(who, "ComponentName is null");
         Preconditions.checkArgument(timeoutMs >= 0, "Timeout must not be a negative number.");
+        final CallerIdentity caller = getCallerIdentity(who);
+        Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
         // timeoutMs with value 0 means that the admin doesn't participate
         // timeoutMs is clamped to the interval in case the internal constants change in the future
         final long minimumStrongAuthTimeout = getMinimumStrongAuthTimeoutMs();
@@ -4537,11 +4544,11 @@
             timeoutMs = DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS;
         }
 
-        final int userHandle = mInjector.userHandleGetCallingUserId();
+        final int userHandle = caller.getUserId();
         boolean changed = false;
         synchronized (getLockObject()) {
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, parent);
+            ActiveAdmin ap = getParentOfAdminIfRequired(getProfileOwnerOrDeviceOwnerLocked(caller),
+                    parent);
             if (ap.strongAuthUnlockTimeout != timeoutMs) {
                 ap.strongAuthUnlockTimeout = timeoutMs;
                 saveSettingsLocked(userHandle);
@@ -5646,8 +5653,9 @@
             List<String> lockdownWhitelist)
             throws SecurityException {
         enforceProfileOrDeviceOwner(who);
+        final CallerIdentity caller = getCallerIdentity(who);
 
-        final int userId = mInjector.userHandleGetCallingUserId();
+        final int userId = caller.getUserId();
         mInjector.binderWithCleanCallingIdentity(() -> {
             if (vpnPackage != null && !isPackageInstalledForUser(vpnPackage, userId)) {
                 Slog.w(LOG_TAG, "Non-existent VPN package specified: " + vpnPackage);
@@ -5678,8 +5686,7 @@
                     .write();
         });
         synchronized (getLockObject()) {
-            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
             if (!TextUtils.equals(vpnPackage, admin.mAlwaysOnVpnPackage)
                     || lockdown != admin.mAlwaysOnVpnLockdown) {
                 admin.mAlwaysOnVpnPackage = vpnPackage;
@@ -9675,10 +9682,11 @@
             return null;
         }
         Objects.requireNonNull(who, "ComponentName is null");
+        final CallerIdentity caller = getCallerIdentity(who);
 
         synchronized (getLockObject()) {
-            final ActiveAdmin activeAdmin = getActiveAdminForCallerLocked(who,
-                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, parent);
+            final ActiveAdmin activeAdmin = getParentOfAdminIfRequired(
+                    getProfileOwnerOrDeviceOwnerLocked(caller), parent);
             if (parent) {
                 enforceProfileOwnerOfOrganizationOwnedDevice(activeAdmin);
             }
@@ -9929,6 +9937,7 @@
             return;
         }
         Objects.requireNonNull(who, "ComponentName is null");
+        final CallerIdentity caller = getCallerIdentity(who);
         synchronized (getLockObject()) {
             /*
              * When called on the parent DPM instance (parent == true), affects active admin
@@ -9936,9 +9945,14 @@
              * * The ActiveAdmin must be of an org-owned profile owner.
              * * The parent ActiveAdmin instance should be used for managing the restriction.
              */
-            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
-                    parent ? DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER
-                            : DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, parent);
+            final ActiveAdmin ap;
+            if (parent) {
+                ap = getParentOfAdminIfRequired(getOrganizationOwnedProfileOwnerLocked(caller),
+                        parent);
+            } else {
+                ap = getParentOfAdminIfRequired(getProfileOwnerOrDeviceOwnerLocked(caller), parent);
+            }
+
             if (disabled) {
                 ap.accountTypesWithManagementDisabled.add(accountType);
             } else {
diff --git a/services/tests/PackageManagerServiceTests/host/Android.bp b/services/tests/PackageManagerServiceTests/host/Android.bp
index 4f636ef..a941331 100644
--- a/services/tests/PackageManagerServiceTests/host/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/Android.bp
@@ -21,12 +21,15 @@
         "truth-prebuilt",
     ],
     static_libs: [
+        "cts-host-utils",
         "frameworks-base-hostutils",
         "PackageManagerServiceHostTestsIntentVerifyUtils",
     ],
     test_suites: ["general-tests"],
     java_resources: [
+        ":PackageManagerTestAppDeclaresStaticLibrary",
         ":PackageManagerTestAppStub",
+        ":PackageManagerTestAppUsesStaticLibrary",
         ":PackageManagerTestAppVersion1",
         ":PackageManagerTestAppVersion2",
         ":PackageManagerTestAppVersion3",
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt
index 24c714c..9399030 100644
--- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt
@@ -18,6 +18,7 @@
 
 import com.android.internal.util.test.SystemPreparer
 import com.android.tradefed.device.ITestDevice
+import com.google.common.truth.Truth
 import org.junit.rules.TemporaryFolder
 import java.io.File
 import java.io.FileOutputStream
@@ -48,6 +49,44 @@
 internal fun ITestDevice.uninstallPackages(vararg pkgNames: String) =
         pkgNames.forEach { uninstallPackage(it) }
 
+/**
+ * Retry [block] a total of [maxAttempts] times, waiting [millisBetweenAttempts] milliseconds
+ * between each iteration, until a non-null result is returned, providing that result back to the
+ * caller.
+ *
+ * If an [AssertionError] is thrown by the [block] and a non-null result is never returned, that
+ * error will be re-thrown. This allows the use of [Truth.assertThat] to indicate success while
+ * providing a meaningful error message in case of failure.
+ */
+internal fun <T> retryUntilNonNull(
+    maxAttempts: Int = 10,
+    millisBetweenAttempts: Long = 1000,
+    block: () -> T?
+): T {
+    var attempt = 0
+    var failure: AssertionError? = null
+    while (attempt++ < maxAttempts) {
+        val result = try {
+            block()
+        } catch (e: AssertionError) {
+            failure = e
+            null
+        }
+
+        if (result != null) {
+            return result
+        } else {
+            Thread.sleep(millisBetweenAttempts)
+        }
+    }
+
+    throw failure ?: AssertionError("Never succeeded")
+}
+
+internal fun retryUntilSuccess(block: () -> Boolean) {
+    retryUntilNonNull { block().takeIf { it } }
+}
+
 internal object HostUtils {
 
     fun getDataDir(device: ITestDevice, pkgName: String) =
@@ -78,6 +117,25 @@
      * dumpsys package and therefore device.getAppPackageInfo doesn't work immediately after reboot,
      * so the following methods parse the package dump directly to see if the path matches.
      */
+
+    /**
+     * Reads the pm dump for a package name starting from the Packages: metadata section until
+     * the following section.
+     */
+    fun packageSection(
+        device: ITestDevice,
+        pkgName: String,
+        sectionName: String = "Packages"
+    ) = device.executeShellCommand("pm dump $pkgName")
+            .lineSequence()
+            .dropWhile { !it.startsWith(sectionName) } // Wait until the header
+            .drop(1) // Drop the header itself
+            .takeWhile {
+                // Until next top level header, a non-empty line that doesn't start with whitespace
+                it.isEmpty() || it.first().isWhitespace()
+            }
+            .map(String::trim)
+
     fun getCodePaths(device: ITestDevice, pkgName: String) =
             device.executeShellCommand("pm dump $pkgName")
                     .lineSequence()
@@ -87,14 +145,7 @@
                     .toList()
 
     private fun userIdLineSequence(device: ITestDevice, pkgName: String) =
-            device.executeShellCommand("pm dump $pkgName")
-                    .lineSequence()
-                    .dropWhile { !it.startsWith("Packages:") }
-                    .takeWhile {
-                        !it.startsWith("Hidden system packages:") &&
-                                !it.startsWith("Queries:")
-                    }
-                    .map(String::trim)
+            packageSection(device, pkgName)
                     .filter { it.startsWith("User ") }
 
     fun getUserIdToPkgEnabledState(device: ITestDevice, pkgName: String) =
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SdCardEjectionTests.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SdCardEjectionTests.kt
new file mode 100644
index 0000000..9f9e6a3
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SdCardEjectionTests.kt
@@ -0,0 +1,255 @@
+/*
+ * 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.test
+
+import android.cts.host.utils.DeviceJUnit4ClassRunnerWithParameters
+import android.cts.host.utils.DeviceJUnit4Parameterized
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import java.io.File
+import java.util.regex.Pattern
+
+/**
+ * Verifies PackageManagerService behavior when an app is moved to an adoptable storage device.
+ *
+ * Also has the effect of verifying system behavior when the PackageSetting for a package has no
+ * corresponding AndroidPackage which can be parsed from the APK on disk. This is done by removing
+ * the storage device and causing a reboot, at which point PMS will read PackageSettings from disk
+ * and fail to find the package path.
+ */
+@RunWith(DeviceJUnit4Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(
+        DeviceJUnit4ClassRunnerWithParameters.RunnerFactory::class)
+class SdCardEjectionTests : BaseHostJUnit4Test() {
+
+    companion object {
+        private const val VERSION_DECLARES = "PackageManagerTestAppDeclaresStaticLibrary.apk"
+        private const val VERSION_DECLARES_PKG_NAME =
+                "com.android.server.pm.test.test_app_declares_static_library"
+        private const val VERSION_USES = "PackageManagerTestAppUsesStaticLibrary.apk"
+        private const val VERSION_USES_PKG_NAME =
+                "com.android.server.pm.test.test_app_uses_static_library"
+
+        // TODO(chiuwinson): Use the HostUtils constants when merged
+        private const val TEST_PKG_NAME = "com.android.server.pm.test.test_app"
+        private const val VERSION_ONE = "PackageManagerTestAppVersion1.apk"
+
+        @Parameterized.Parameters(name = "reboot={0}")
+        @JvmStatic
+        fun parameters() = arrayOf(false, true)
+
+        data class Volume(
+            val diskId: String,
+            val fsUuid: String
+        )
+    }
+
+    @Rule
+    @JvmField
+    val tempFolder = TemporaryFolder()
+
+    @Parameterized.Parameter(0)
+    @JvmField
+    var reboot: Boolean = false
+
+    @Before
+    @After
+    fun removePackagesAndDeleteVirtualDisk() {
+        device.uninstallPackages(VERSION_ONE, VERSION_USES_PKG_NAME, VERSION_DECLARES_PKG_NAME)
+        removeVirtualDisk()
+        device.reboot()
+    }
+
+    @Test
+    fun launchActivity() {
+        val hostApkFile = HostUtils.copyResourceToHostFile(VERSION_ONE, tempFolder.newFile())
+        assertThat(device.installPackage(hostApkFile, true)).isNull()
+
+        val errorRegex = Pattern.compile("error", Pattern.CASE_INSENSITIVE)
+        fun assertStartResponse(launched: Boolean) {
+            val response = device.executeShellCommand("am start -n $TEST_PKG_NAME/.TestActivity")
+            if (launched) {
+                assertThat(response).doesNotContainMatch(errorRegex)
+            } else {
+                assertThat(response).containsMatch(errorRegex)
+            }
+        }
+
+        assertStartResponse(launched = true)
+
+        val volume = initializeVirtualDisk()
+
+        movePackage(TEST_PKG_NAME, volume)
+        assertStartResponse(launched = true)
+
+        unmount(volume, TEST_PKG_NAME)
+        assertStartResponse(launched = false)
+
+        remount(volume, hostApkFile, TEST_PKG_NAME)
+        assertStartResponse(launched = true)
+    }
+
+    @Test
+    fun uninstallStaticLibraryInUse() {
+        assertThat(device.installJavaResourceApk(tempFolder, VERSION_DECLARES)).isNull()
+
+        val usesApkFile = HostUtils.copyResourceToHostFile(VERSION_USES, tempFolder.newFile())
+        assertThat(device.installPackage(usesApkFile, true)).isNull()
+
+        fun assertUninstallFails() = assertThat(device.uninstallPackage(VERSION_DECLARES_PKG_NAME))
+                .isEqualTo("DELETE_FAILED_USED_SHARED_LIBRARY")
+
+        assertUninstallFails()
+
+        val volume = initializeVirtualDisk()
+
+        movePackage(VERSION_USES_PKG_NAME, volume)
+        assertUninstallFails()
+
+        unmount(volume, VERSION_USES_PKG_NAME)
+        assertUninstallFails()
+
+        remount(volume, usesApkFile, VERSION_USES_PKG_NAME)
+        assertUninstallFails()
+
+        // Check that install in the correct order (uses first) passes
+        assertThat(device.uninstallPackage(VERSION_USES_PKG_NAME)).isNull()
+        assertThat(device.uninstallPackage(VERSION_DECLARES_PKG_NAME)).isNull()
+    }
+
+    private fun initializeVirtualDisk(): Volume {
+        // Rather than making any assumption about what disks/volumes exist on the device,
+        // save the existing disks/volumes to compare and see when a new one pops up, assuming
+        // it was created as the result of the calls in this test.
+        val existingDisks = device.executeShellCommand("sm list-disks adoptable").lines()
+        val existingVolumes = device.executeShellCommand("sm list-volumes private").lines()
+        device.executeShellCommand("sm set-virtual-disk true")
+
+        val diskId = retryUntilNonNull {
+            device.executeShellCommand("sm list-disks adoptable")
+                    .lines()
+                    .filterNot(existingDisks::contains)
+                    .filterNot(String::isEmpty)
+                    .firstOrNull()
+        }
+
+        device.executeShellCommand("sm partition $diskId private")
+
+        return retrieveNewVolume(existingVolumes)
+    }
+
+    private fun retrieveNewVolume(existingVolumes: List<String>): Volume {
+        val newVolume = retryUntilNonNull {
+            device.executeShellCommand("sm list-volumes private")
+                    .lines()
+                    .toMutableList()
+                    .apply { removeAll(existingVolumes) }
+                    .firstOrNull()
+                    ?.takeIf { it.isNotEmpty() }
+        }
+
+        val sections = newVolume.split(" ")
+        return Volume(diskId = sections.first(), fsUuid = sections.last()).also {
+            assertThat(it.diskId).isNotEmpty()
+            assertThat(it.fsUuid).isNotEmpty()
+        }
+    }
+
+    private fun removeVirtualDisk() {
+        device.executeShellCommand("sm set-virtual-disk false")
+        retryUntilSuccess {
+            !device.executeShellCommand("sm list-volumes").contains("ejecting")
+        }
+    }
+
+    private fun movePackage(pkgName: String, volume: Volume) {
+        // TODO(b/167241596): oat dir must exist for a move install
+        val codePath = HostUtils.getCodePaths(device, pkgName).first()
+        device.executeShellCommand("mkdir $codePath/oat")
+        assertThat(device.executeShellCommand(
+                "pm move-package $pkgName ${volume.fsUuid}").trim())
+                .isEqualTo("Success")
+    }
+
+    private fun unmount(volume: Volume, pkgName: String) {
+        assertThat(device.executeShellCommand("sm unmount ${volume.diskId}")).isEmpty()
+        if (reboot) {
+            // The system automatically mounts the virtual disk on startup, which would mean the
+            // app files are available to the system. To prevent this, disable the disk entirely.
+            // TODO: There must be a better way to prevent it from auto-mounting.
+            removeVirtualDisk()
+            device.reboot()
+        } else {
+            // Because PackageManager unmount scan is asynchronous, need to retry until the package
+            // has been unloaded. This only has to be done in the non-reboot case. Reboot will
+            // clear the data structure by its nature.
+            retryUntilSuccess {
+                // The compiler section will print the state of the physical APK
+                HostUtils.packageSection(device, pkgName, sectionName = "Compiler stats")
+                        .any { it.contains("Unable to find package: $pkgName") }
+            }
+        }
+    }
+
+    private fun remount(volume: Volume, hostApkFile: File, pkgName: String) {
+        if (reboot) {
+            // Because the disk was destroyed when unmounting, it now has to be rebuilt manually.
+            // This enables a new virtual disk, unmounts it, mutates its UUID to match the previous
+            // partition's, remounts it, and pushes the base.apk back onto the device. This
+            // simulates the same disk being re-inserted. This is very hacky.
+            val newVolume = initializeVirtualDisk()
+            val mountPoint = device.executeShellCommand("mount")
+                    .lineSequence()
+                    .first { it.contains(newVolume.fsUuid) }
+                    .takeWhile { !it.isWhitespace() }
+
+            device.executeShellCommand("sm unmount ${newVolume.diskId}")
+
+            // Save without renamed UUID to compare and see when the renamed pops up
+            val existingVolumes = device.executeShellCommand("sm list-volumes private").lines()
+
+            device.executeShellCommand("make_f2fs -U ${volume.fsUuid} $mountPoint")
+            device.executeShellCommand("sm mount ${newVolume.diskId}")
+
+            val reparsedVolume = retrieveNewVolume(existingVolumes)
+            assertThat(reparsedVolume.fsUuid).isEqualTo(volume.fsUuid)
+
+            val codePath = HostUtils.getCodePaths(device, pkgName).first()
+            device.pushFile(hostApkFile, "$codePath/base.apk")
+
+            // Unmount so following remount will re-kick package scan
+            device.executeShellCommand("sm unmount ${newVolume.diskId}")
+        }
+
+        device.executeShellCommand("sm mount ${volume.diskId}")
+
+        // Because PackageManager remount scan is asynchronous, need to retry until the package
+        // has been loaded and added to the internal structures. Otherwise resolution will fail.
+        retryUntilSuccess {
+            // The compiler section will print the state of the physical APK
+            HostUtils.packageSection(device, pkgName, sectionName = "Compiler stats")
+                    .none { it.contains("Unable to find package: $pkgName") }
+        }
+    }
+}
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/Generic/Android.bp
similarity index 100%
rename from services/tests/PackageManagerServiceTests/host/test-apps/Android.bp
rename to services/tests/PackageManagerServiceTests/host/test-apps/Generic/Android.bp
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestOriginalOverride.xml b/services/tests/PackageManagerServiceTests/host/test-apps/Generic/AndroidManifestOriginalOverride.xml
similarity index 100%
rename from services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestOriginalOverride.xml
rename to services/tests/PackageManagerServiceTests/host/test-apps/Generic/AndroidManifestOriginalOverride.xml
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion1.xml b/services/tests/PackageManagerServiceTests/host/test-apps/Generic/AndroidManifestVersion1.xml
similarity index 84%
rename from services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion1.xml
rename to services/tests/PackageManagerServiceTests/host/test-apps/Generic/AndroidManifestVersion1.xml
index efc7372..05b6248 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion1.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/Generic/AndroidManifestVersion1.xml
@@ -25,4 +25,9 @@
         android:protectionLevel="normal"
         />
 
+    <application>
+        <activity android:name="com.android.server.pm.test.test_app.TestActivity"
+            android:label="PackageManagerTestApp" />
+    </application>
+
 </manifest>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion2.xml b/services/tests/PackageManagerServiceTests/host/test-apps/Generic/AndroidManifestVersion2.xml
similarity index 97%
rename from services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion2.xml
rename to services/tests/PackageManagerServiceTests/host/test-apps/Generic/AndroidManifestVersion2.xml
index 620054c..d6eb3e0 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion2.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/Generic/AndroidManifestVersion2.xml
@@ -25,4 +25,6 @@
         android:protectionLevel="normal"
         />
 
+    <application/>
+
 </manifest>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml b/services/tests/PackageManagerServiceTests/host/test-apps/Generic/AndroidManifestVersion3.xml
similarity index 97%
rename from services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml
rename to services/tests/PackageManagerServiceTests/host/test-apps/Generic/AndroidManifestVersion3.xml
index 1997771..90317cb 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/Generic/AndroidManifestVersion3.xml
@@ -25,4 +25,6 @@
         android:protectionLevel="normal"
         />
 
+    <application/>
+
 </manifest>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion4.xml b/services/tests/PackageManagerServiceTests/host/test-apps/Generic/AndroidManifestVersion4.xml
similarity index 97%
rename from services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion4.xml
rename to services/tests/PackageManagerServiceTests/host/test-apps/Generic/AndroidManifestVersion4.xml
index d6ade03..795c3c1 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion4.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/Generic/AndroidManifestVersion4.xml
@@ -25,4 +25,6 @@
         android:protectionLevel="normal"
         />
 
+    <application/>
+
 </manifest>
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/ContainerView.java b/services/tests/PackageManagerServiceTests/host/test-apps/Generic/src/com/android/server/pm/test/test_app/TestActivity.kt
similarity index 61%
copy from packages/SystemUI/src/com/android/keyguard/dagger/ContainerView.java
copy to services/tests/PackageManagerServiceTests/host/test-apps/Generic/src/com/android/server/pm/test/test_app/TestActivity.kt
index e65f19d..0c9b8d4 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/ContainerView.java
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/Generic/src/com/android/server/pm/test/test_app/TestActivity.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,17 +14,8 @@
  * limitations under the License.
  */
 
-package com.android.keyguard.dagger;
+package com.android.server.pm.test.test_app
 
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import android.app.Activity
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
-import javax.inject.Qualifier;
-
-@Qualifier
-@Documented
-@Retention(RUNTIME)
-public @interface ContainerView {
-}
+class TestActivity : Activity()
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/Android.bp
new file mode 100644
index 0000000..58f17f2
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/Android.bp
@@ -0,0 +1,24 @@
+// 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_helper_app {
+    name: "PackageManagerTestAppDeclaresStaticLibrary",
+    manifest: "AndroidManifestDeclaresStaticLibrary.xml",
+    certificate: ":FrameworksCoreTests_keyset_A_cert",
+}
+
+android_test_helper_app {
+    name: "PackageManagerTestAppUsesStaticLibrary",
+    manifest: "AndroidManifestUsesStaticLibrary.xml",
+}
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml b/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/AndroidManifestDeclaresStaticLibrary.xml
similarity index 64%
copy from services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml
copy to services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/AndroidManifestDeclaresStaticLibrary.xml
index 1997771..8a6c01a 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/AndroidManifestDeclaresStaticLibrary.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?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");
@@ -14,15 +13,12 @@
   ~ 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.server.pm.test.test_app"
-    android:versionCode="3"
-    >
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.server.pm.test.test_app_declares_static_library">
 
-    <permission
-        android:name="com.android.server.pm.test.test_app.TEST_PERMISSION"
-        android:protectionLevel="normal"
-        />
+    <application>
+        <static-library android:name="com.android.server.pm.test.static_library"
+            android:version="1" />
+    </application>
 
 </manifest>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/AndroidManifestUsesStaticLibrary.xml b/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/AndroidManifestUsesStaticLibrary.xml
new file mode 100644
index 0000000..82d9ac4
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/AndroidManifestUsesStaticLibrary.xml
@@ -0,0 +1,34 @@
+<?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.server.pm.test.test_app_uses_static_library">
+
+    <application>
+        <activity android:name="com.android.server.pm.test.static_library.TestActivity"
+            android:label="TestActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <uses-static-library android:name="com.android.server.pm.test.static_library"
+            android:certDigest="1F:BE:5F:FB:B0:AD:DC:0C:CD:BF:22:B9:8A:2F:5A:58:A5:C8:29:80:E1:30:2F:65:0E:6B:CA:ED:03:82:BF:CF"
+            android:version="1" />
+    </application>
+
+</manifest>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/src/com/android/server/pm/test/static_library/TestActivity.kt b/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/src/com/android/server/pm/test/static_library/TestActivity.kt
new file mode 100644
index 0000000..fa85258
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/src/com/android/server/pm/test/static_library/TestActivity.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.test.static_library
+
+import android.app.Activity
+import android.graphics.Color
+import android.os.Bundle
+import android.view.ViewGroup
+import android.widget.FrameLayout
+
+class TestActivity : Activity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(FrameLayout(this).apply {
+            setBackgroundColor(Color.BLUE)
+        }, ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT
+        ))
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
index 1d04c83..e02a46af 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
@@ -24,7 +24,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import android.app.ActivityManager;
+import android.app.ActivityTaskManager.RootTaskInfo;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -984,8 +984,8 @@
         }
 
         @Override
-        public ActivityManager.StackInfo getFocusedStack() throws RemoteException {
-            ActivityManager.StackInfo focusedStack = new ActivityManager.StackInfo();
+        public RootTaskInfo getFocusedStack() throws RemoteException {
+            RootTaskInfo focusedStack = new RootTaskInfo();
             focusedStack.userId = 0;
             focusedStack.topActivity = new ComponentName("a.package", "a.class");
             return focusedStack;
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt b/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
index 0839273..154d42c 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt
@@ -21,172 +21,387 @@
 import android.content.pm.ApplicationInfo
 import android.content.pm.PackageInfo
 import android.os.Process
-import org.junit.Rule
+import com.android.server.om.OverlayActorEnforcer.ActorState
+import com.android.server.testutils.mockThrowOnUnmocked
+import com.android.server.testutils.whenever
+import com.google.common.truth.Truth.assertThat
+import org.junit.BeforeClass
 import org.junit.Test
-import org.junit.rules.ExpectedException
-import java.lang.UnsupportedOperationException
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.mockito.Mockito.spy
+import java.io.IOException
 
+@RunWith(Parameterized::class)
 class OverlayActorEnforcerTests {
+
     companion object {
-        private const val NAMESPACE = "testnamespace"
-        private const val ACTOR_NAME = "testactor"
-        private const val ACTOR_PKG_NAME = "com.test.actor.one"
+        private const val TARGET_PKG = "com.test.target"
+        private const val OVERLAY_PKG = "com.test.overlay"
+
+        private const val VALID_NAMESPACE = "testNamespaceValid"
+        private const val INVALID_NAMESPACE = "testNamespaceInvalid"
+        private const val VALID_ACTOR_NAME = "testActorOne"
+        private const val INVALID_ACTOR_NAME = "testActorTwo"
+        private const val VALID_ACTOR_PKG = "com.test.actor.valid"
+        private const val INVALID_ACTOR_PKG = "com.test.actor.invalid"
         private const val OVERLAYABLE_NAME = "TestOverlayable"
-        private const val UID = 3536
+        private const val NULL_UID = 3536
+        private const val EMPTY_UID = NULL_UID + 1
+        private const val INVALID_ACTOR_UID = NULL_UID + 2
+        private const val VALID_ACTOR_UID = NULL_UID + 3
+        private const val TARGET_UID = NULL_UID + 4
         private const val USER_ID = 55
-    }
 
-    @get:Rule
-    val expectedException = ExpectedException.none()!!
+        @JvmStatic
+        @Parameterized.Parameters(name = "{0}")
+        fun parameters() = CASES.mapIndexed { caseIndex, testCase ->
+            fun param(pair: Pair<String, TestState.() -> Unit>, type: Params.Type): Params {
+                val expectedState = testCase.state.takeUnless { type == Params.Type.ALLOWED }
+                        ?: ActorState.ALLOWED
+                val (caseName, case) = pair
+                val testName = makeTestName(testCase, caseName, type)
+                return Params(caseIndex, expectedState, testName, type, case)
+            }
 
-    @Test
-    fun isRoot() {
-        verify(callingUid = Process.ROOT_UID)
-    }
+            testCase.failures.map { param(it, Params.Type.FAILURE) } +
+                    testCase.allowed.map { param(it, Params.Type.ALLOWED) }
+        }.flatten()
 
-    @Test(expected = SecurityException::class)
-    fun isShell() {
-        verify(callingUid = Process.SHELL_UID)
-    }
-
-    @Test
-    fun isSystem() {
-        verify(callingUid = Process.SYSTEM_UID)
-    }
-
-    @Test(expected = SecurityException::class)
-    fun noOverlayable_noTarget() {
-        verify(targetOverlayableName = null)
-    }
-
-    @Test
-    fun noOverlayable_noTarget_withPermission() {
-        verify(targetOverlayableName = null, hasPermission = true)
-    }
-
-    @Test(expected = SecurityException::class)
-    fun noOverlayable_withTarget() {
-        verify(targetOverlayableName = OVERLAYABLE_NAME)
-    }
-
-    @Test(expected = SecurityException::class)
-    fun withOverlayable_noTarget() {
-        verify(
-                targetOverlayableName = null,
-                overlayableInfo = OverlayableInfo(OVERLAYABLE_NAME, null)
-        )
-    }
-
-    @Test(expected = SecurityException::class)
-    fun withOverlayable_noActor() {
-        verify(
-                overlayableInfo = OverlayableInfo(OVERLAYABLE_NAME, null)
-        )
-    }
-
-    @Test
-    fun withOverlayable_noActor_withPermission() {
-        verify(
-                hasPermission = true,
-                overlayableInfo = OverlayableInfo(OVERLAYABLE_NAME, null)
-        )
-    }
-
-    @Test(expected = SecurityException::class)
-    fun withOverlayable_withActor_notActor() {
-        verify(
-                isActor = false,
-                overlayableInfo = OverlayableInfo(OVERLAYABLE_NAME,
-                        "overlay://$NAMESPACE/$ACTOR_NAME")
-        )
-    }
-
-    @Test(expected = SecurityException::class)
-    fun withOverlayable_withActor_isActor_notPreInstalled() {
-        verify(
-                isActor = true,
-                isPreInstalled = false,
-                overlayableInfo = OverlayableInfo(OVERLAYABLE_NAME,
-                        "overlay://$NAMESPACE/$ACTOR_NAME")
-        )
-    }
-
-    @Test
-    fun withOverlayable_withActor_isActor_isPreInstalled() {
-        verify(
-                isActor = true,
-                isPreInstalled = true,
-                overlayableInfo = OverlayableInfo(OVERLAYABLE_NAME,
-                        "overlay://$NAMESPACE/$ACTOR_NAME")
-        )
-    }
-
-    @Test(expected = SecurityException::class)
-    fun withOverlayable_invalidActor() {
-        verify(
-                isActor = true,
-                isPreInstalled = true,
-                overlayableInfo = OverlayableInfo(OVERLAYABLE_NAME, "notValidActor")
-        )
-    }
-
-    private fun verify(
-        isActor: Boolean = false,
-        isPreInstalled: Boolean = false,
-        hasPermission: Boolean = false,
-        overlayableInfo: OverlayableInfo? = null,
-        callingUid: Int = UID,
-        targetOverlayableName: String? = OVERLAYABLE_NAME
-    ) {
-        val callback = MockCallback(
-                isActor = isActor,
-                isPreInstalled = isPreInstalled,
-                hasPermission = hasPermission,
-                overlayableInfo = overlayableInfo
-        )
-
-        val overlayInfo = overlayInfo(targetOverlayableName)
-        OverlayActorEnforcer(callback)
-                .enforceActor(overlayInfo, "test", callingUid, USER_ID)
-    }
-
-    private fun overlayInfo(targetOverlayableName: String?) = OverlayInfo("com.test.overlay",
-            "com.test.target", targetOverlayableName, null, "/path", OverlayInfo.STATE_UNKNOWN, 0,
-            0, false)
-
-    private class MockCallback(
-        private val isActor: Boolean = false,
-        private val isPreInstalled: Boolean = false,
-        private val hasPermission: Boolean = false,
-        private val overlayableInfo: OverlayableInfo? = null,
-        private vararg val packageNames: String = arrayOf("com.test.actor.one")
-    ) : PackageManagerHelper {
-
-        override fun getNamedActors() = if (isActor) {
-            mapOf(NAMESPACE to mapOf(ACTOR_NAME to ACTOR_PKG_NAME))
-        } else {
-            emptyMap()
+        @BeforeClass
+        @JvmStatic
+        fun checkAllCasesHandled() {
+            // Assert that all states have been tested at least once.
+            assertThat(CASES.map { it.state }.distinct()).containsAllIn(ActorState.values())
         }
 
+        @BeforeClass
+        @JvmStatic
+        fun checkAllCasesUniquelyNamed() {
+            val duplicateCaseNames = CASES.mapIndexed { caseIndex, testCase ->
+                testCase.failures.map {
+                    makeTestName(testCase, it.first, Params.Type.FAILURE)
+                } + testCase.allowed.map {
+                    makeTestName(testCase, it.first, Params.Type.ALLOWED)
+                }
+            }
+                    .flatten()
+                    .groupingBy { it }
+                    .eachCount()
+                    .filterValues { it > 1 }
+                    .keys
+
+            assertThat(duplicateCaseNames).isEmpty()
+        }
+
+        /*
+            The pattern in this block is a result of the incredible number of branches in
+            enforcement logic. It serves to verify failures with the assumption that all errors
+            are checked in order. The idea is to emulate the if-else branches from code, but using
+            actual test data instead of if statements.
+
+            Each state is verified by providing a failure or exclusive set of failures which cause
+            a failure state to be returned. Each state also provides a success case which will
+            "skip" the state. This allows subsequent failure cases to cascade from the first case
+            by calling all the skip branches for preceding states and then choosing only 1 of
+            the failures to test.
+
+            Given the failure states A, B, and C: testA calls A.failure + assert, testB calls
+            A.skip + B.failure + assert, testC calls A.skip + B.skip + C.failure + assert, etc.
+
+            Calling `allowed` is a special case for when there is a combination of parameters that
+            skips the remaining checks and immediately allows the actor through. For these cases,
+            the first failure branch will be run, assert that it's not allowed, and the
+            allowed branch will run, asserting that it now results in ALLOWED, skipping all
+            remaining functions.
+
+            This is an ordered list of TestCase objects, with the possibility to repeat failure
+            states if any can occur multiple times in the logic tree.
+
+            Each failure must be handled at least once.
+         */
+        private val CASES = listOf(
+                ActorState.TARGET_NOT_FOUND withCases {
+                    failure("nullPkgInfo") { targetPkgInfo = null }
+                    allowed("debuggable") {
+                        targetPkgInfo = pkgInfo(TARGET_PKG).apply {
+                            applicationInfo.flags = ApplicationInfo.FLAG_DEBUGGABLE
+                        }
+                    }
+                    skip { targetPkgInfo = pkgInfo(TARGET_PKG) }
+                },
+                ActorState.NO_PACKAGES_FOR_UID withCases {
+                    failure("empty") { callingUid = EMPTY_UID }
+                    failure("null") { callingUid = NULL_UID }
+                    failure("shell") { callingUid = Process.SHELL_UID }
+                    allowed("targetUid") { callingUid = TARGET_UID }
+                    allowed("rootUid") { callingUid = Process.ROOT_UID }
+                    allowed("systemUid") { callingUid = Process.SYSTEM_UID }
+                    skip { callingUid = INVALID_ACTOR_UID }
+                },
+                ActorState.MISSING_TARGET_OVERLAYABLE_NAME withCases {
+                    failure("nullTargetOverlayableName") {
+                        overlayInfoParams.targetOverlayableName = null
+                        targetOverlayableInfo = OverlayableInfo(OVERLAYABLE_NAME,
+                                "overlay://$VALID_NAMESPACE/$VALID_ACTOR_NAME")
+                    }
+                    skip { overlayInfoParams.targetOverlayableName = OVERLAYABLE_NAME }
+                },
+                ActorState.MISSING_LEGACY_PERMISSION withCases {
+                    failure("noPermission") {
+                        overlayInfoParams.targetOverlayableName = null
+                        targetOverlayableInfo = null
+                        hasPermission = false
+                    }
+                    allowed("hasPermission") { hasPermission = true }
+                    skip { overlayInfoParams.targetOverlayableName = OVERLAYABLE_NAME }
+                },
+                ActorState.ERROR_READING_OVERLAYABLE withCases {
+                    failure("doesTargetDefineOverlayableIOException") {
+                        overlayInfoParams.targetOverlayableName = null
+                        whenever(doesTargetDefineOverlayable(TARGET_PKG, USER_ID))
+                                .thenThrow(IOException::class.java)
+                    }
+                    skip { overlayInfoParams.targetOverlayableName = OVERLAYABLE_NAME }
+                },
+                ActorState.UNABLE_TO_GET_TARGET_OVERLAYABLE withCases {
+                    failure("getOverlayableForTargetIOException") {
+                        whenever(getOverlayableForTarget(TARGET_PKG, OVERLAYABLE_NAME,
+                                USER_ID)).thenThrow(IOException::class.java)
+                    }
+                },
+                ActorState.MISSING_OVERLAYABLE withCases {
+                    failure("nullTargetOverlayableInfo") { targetOverlayableInfo = null }
+                    skip {
+                        targetOverlayableInfo = OverlayableInfo(OVERLAYABLE_NAME,
+                                "overlay://$VALID_NAMESPACE/$VALID_ACTOR_NAME")
+                    }
+                },
+                ActorState.MISSING_LEGACY_PERMISSION withCases {
+                    failure("noPermissionNullActor") {
+                        targetOverlayableInfo = OverlayableInfo(OVERLAYABLE_NAME, null)
+                        hasPermission = false
+                    }
+                    failure("noPermissionEmptyActor") {
+                        targetOverlayableInfo = OverlayableInfo(OVERLAYABLE_NAME, "")
+                        hasPermission = false
+                    }
+                    allowed("hasPermissionNullActor") {
+                        hasPermission = true
+                    }
+                    skip {
+                        targetOverlayableInfo = OverlayableInfo(OVERLAYABLE_NAME,
+                                "overlay://$VALID_NAMESPACE/$VALID_ACTOR_NAME")
+                    }
+                },
+                ActorState.INVALID_OVERLAYABLE_ACTOR_NAME withCases {
+                    fun TestState.mockActor(actorUri: String) {
+                        targetOverlayableInfo = OverlayableInfo(OVERLAYABLE_NAME, actorUri)
+                    }
+                    failure("wrongScheme") {
+                        mockActor("notoverlay://$VALID_NAMESPACE/$VALID_ACTOR_NAME")
+                    }
+                    failure("extraPath") {
+                        mockActor("overlay://$VALID_NAMESPACE/$VALID_ACTOR_NAME/extraPath")
+                    }
+                    failure("missingPath") { mockActor("overlay://$VALID_NAMESPACE") }
+                    failure("missingAuthority") { mockActor("overlay://") }
+                    skip { mockActor("overlay://$VALID_NAMESPACE/$VALID_ACTOR_NAME") }
+                },
+                ActorState.NO_NAMED_ACTORS withCases {
+                    failure("empty") { namedActorsMap = emptyMap() }
+                    skip {
+                        namedActorsMap = mapOf(INVALID_NAMESPACE to
+                                mapOf(INVALID_ACTOR_NAME to VALID_ACTOR_PKG))
+                    }
+                },
+                ActorState.MISSING_NAMESPACE withCases {
+                    failure("invalidNamespace") {
+                        namedActorsMap = mapOf(INVALID_NAMESPACE to
+                                mapOf(INVALID_ACTOR_NAME to VALID_ACTOR_PKG))
+                    }
+                    skip {
+                        namedActorsMap = mapOf(VALID_NAMESPACE to
+                                mapOf(INVALID_ACTOR_NAME to VALID_ACTOR_PKG))
+                    }
+                },
+                ActorState.MISSING_ACTOR_NAME withCases {
+                    failure("invalidActorName") {
+                        namedActorsMap = mapOf(VALID_NAMESPACE to
+                                mapOf(INVALID_ACTOR_NAME to VALID_ACTOR_PKG))
+                    }
+                    skip {
+                        namedActorsMap = mapOf(VALID_NAMESPACE to
+                                mapOf(VALID_ACTOR_NAME to VALID_ACTOR_PKG))
+                    }
+                },
+                ActorState.MISSING_APP_INFO withCases {
+                    failure("nullActorPkgInfo") { actorPkgInfo = null }
+                    failure("nullActorAppInfo") {
+                        actorPkgInfo = PackageInfo().apply { applicationInfo = null }
+                    }
+                    skip { actorPkgInfo = pkgInfo(VALID_ACTOR_PKG) }
+                },
+                ActorState.ACTOR_NOT_PREINSTALLED withCases {
+                    failure("notSystem") {
+                        actorPkgInfo = pkgInfo(VALID_ACTOR_PKG).apply {
+                            applicationInfo.flags = 0
+                        }
+                    }
+                    skip {
+                        actorPkgInfo = pkgInfo(VALID_ACTOR_PKG).apply {
+                            applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM
+                        }
+                    }
+                },
+                ActorState.INVALID_ACTOR withCases {
+                    failure("invalidUid") { callingUid = INVALID_ACTOR_UID }
+                    skip { callingUid = VALID_ACTOR_UID }
+                },
+                ActorState.ALLOWED withCases {
+                    // No point making an exception for this case in all of the test code, so
+                    // just pretend this is a failure that results in a success result code.
+                    failure("allowed") { /* Do nothing */ }
+                }
+        )
+
+        data class OverlayInfoParams(
+            var targetPackageName: String = TARGET_PKG,
+            var targetOverlayableName: String? = null
+        ) {
+            fun toOverlayInfo() = OverlayInfo(
+                    OVERLAY_PKG,
+                    targetPackageName,
+                    targetOverlayableName,
+                    null,
+                    "/path",
+                    OverlayInfo.STATE_UNKNOWN, 0,
+                    0, false)
+        }
+
+        private infix fun ActorState.withCases(block: TestCase.() -> Unit) =
+                TestCase(this).apply(block)
+
+        private fun pkgInfo(pkgName: String): PackageInfo = mockThrowOnUnmocked {
+            this.packageName = pkgName
+            this.applicationInfo = ApplicationInfo().apply {
+                this.packageName = pkgName
+            }
+        }
+
+        private fun makeTestName(testCase: TestCase, caseName: String, type: Params.Type): String {
+            val resultSuffix = if (type == Params.Type.ALLOWED) "allowed" else "failed"
+            return "${testCase.state}_${resultSuffix}_$caseName"
+        }
+    }
+
+    @Parameterized.Parameter(0)
+    lateinit var params: Params
+
+    @Test
+    fun verify() {
+        // Apply all the skip states before the failure to be verified
+        val testState = CASES.take(params.index)
+                .fold(TestState.create()) { testState, case ->
+                    testState.apply(case.skip)
+                }
+
+        // If testing an allowed branch, first apply a failure to ensure it fails
+        if (params.type == Params.Type.ALLOWED) {
+            CASES[params.index].failures.firstOrNull()?.second?.run(testState::apply)
+            assertThat(testState.toResult()).isNotEqualTo(ActorState.ALLOWED)
+        }
+
+        // Apply the test case in the params to the collected state
+        testState.apply(params.function)
+
+        // Assert the result matches the expected state
+        assertThat(testState.toResult()).isEqualTo(params.expectedState)
+    }
+
+    private fun TestState.toResult() = OverlayActorEnforcer(this)
+            .isAllowedActor("test", overlayInfoParams.toOverlayInfo(), callingUid, USER_ID)
+
+    data class Params(
+        var index: Int,
+        var expectedState: ActorState,
+        val testName: String,
+        val type: Type,
+        val function: TestState.() -> Unit
+    ) {
+        override fun toString() = testName
+
+        enum class Type {
+            FAILURE,
+            ALLOWED
+        }
+    }
+
+    data class TestCase(
+        val state: ActorState,
+        val failures: MutableList<Pair<String, TestState.() -> Unit>> = mutableListOf(),
+        var allowed: MutableList<Pair<String, TestState.() -> Unit>> = mutableListOf(),
+        var skip: (TestState.() -> Unit) = {}
+    ) {
+        fun failure(caseName: String, block: TestState.() -> Unit) {
+            failures.add(caseName to block)
+        }
+
+        fun allowed(caseName: String, block: TestState.() -> Unit) {
+            allowed.add(caseName to block)
+        }
+
+        fun skip(block: TestState.() -> Unit) {
+            this.skip = block
+        }
+    }
+
+    open class TestState private constructor(
+        var callingUid: Int = NULL_UID,
+        val overlayInfoParams: OverlayInfoParams = OverlayInfoParams(),
+        var namedActorsMap: Map<String, Map<String, String>> = emptyMap(),
+        var hasPermission: Boolean = false,
+        var targetOverlayableInfo: OverlayableInfo? = null,
+        var targetPkgInfo: PackageInfo? = null,
+        var actorPkgInfo: PackageInfo? = null,
+        vararg val packageNames: String = arrayOf("com.test.actor.one")
+    ) : PackageManagerHelper {
+
+        companion object {
+            // Enforce that new instances are spied
+            fun create() = spy(TestState())!!
+        }
+
+        override fun getNamedActors() = namedActorsMap
+
+        @Throws(IOException::class)
         override fun getOverlayableForTarget(
             packageName: String,
             targetOverlayableName: String,
             userId: Int
-        ) = overlayableInfo
+        ) = targetOverlayableInfo?.takeIf {
+            // Protect against this method being called with the wrong package name
+            targetPkgInfo == null || targetPkgInfo?.packageName == packageName
+        }
 
         override fun getPackagesForUid(uid: Int) = when (uid) {
-            UID -> packageNames
+            EMPTY_UID -> emptyArray()
+            INVALID_ACTOR_UID -> arrayOf(INVALID_ACTOR_PKG)
+            VALID_ACTOR_UID -> arrayOf(VALID_ACTOR_PKG)
+            TARGET_UID -> arrayOf(TARGET_PKG)
+            NULL_UID -> null
             else -> null
         }
 
-        override fun getPackageInfo(packageName: String, userId: Int) = PackageInfo().apply {
-            applicationInfo = ApplicationInfo().apply {
-                flags = if (isPreInstalled) ApplicationInfo.FLAG_SYSTEM else 0
-            }
-        }
+        override fun getPackageInfo(packageName: String, userId: Int) =
+                listOfNotNull(targetPkgInfo, actorPkgInfo).find { it.packageName == packageName }
 
+        @Throws(IOException::class) // Mockito requires this checked exception to be declared
         override fun doesTargetDefineOverlayable(targetPackageName: String?, userId: Int): Boolean {
-            return overlayableInfo != null
+            return targetOverlayableInfo?.takeIf {
+                // Protect against this method being called with the wrong package name
+                targetPkgInfo == null || targetPkgInfo?.packageName == targetPackageName
+            } != null
         }
 
         override fun enforcePermission(permission: String?, message: String?) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 0bf06bb..dac0542 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -45,6 +45,7 @@
 import android.content.pm.UserInfo;
 import android.os.BaseBundle;
 import android.os.PersistableBundle;
+import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManagerInternal;
 import android.util.ArrayMap;
@@ -59,8 +60,12 @@
 
 import com.android.permission.persistence.RuntimePermissionsPersistence;
 import com.android.server.LocalServices;
+import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
 import com.android.server.pm.permission.PermissionSettings;
 
+import com.google.common.truth.Truth;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -380,6 +385,74 @@
     }
 
     @Test
+    public void testWriteReadUsesStaticLibraries() {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        final Object lock = new Object();
+        final Settings settingsUnderTest = new Settings(context.getFilesDir(), mPermissionSettings,
+                mRuntimePermissionsPersistence, lock);
+        final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
+        ps1.appId = Process.FIRST_APPLICATION_UID;
+        ps1.pkg = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME_1).hideAsParsed())
+                .setUid(ps1.appId)
+                .setSystem(true)
+                .hideAsFinal();
+        final PackageSetting ps2 = createPackageSetting(PACKAGE_NAME_2);
+        ps2.appId = Process.FIRST_APPLICATION_UID + 1;
+        ps2.pkg = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME_2).hideAsParsed())
+                .setUid(ps2.appId)
+                .hideAsFinal();
+
+        ps1.usesStaticLibraries = new String[] { "com.example.shared.one" };
+        ps1.usesStaticLibrariesVersions = new long[] { 12 };
+        ps1.setFlags(ps1.pkgFlags | ApplicationInfo.FLAG_SYSTEM);
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_1, ps1);
+        assertThat(settingsUnderTest.disableSystemPackageLPw(PACKAGE_NAME_1, false), is(true));
+
+        ps2.usesStaticLibraries = new String[] { "com.example.shared.two" };
+        ps2.usesStaticLibrariesVersions = new long[] { 34 };
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2);
+
+        settingsUnderTest.writeLPr();
+
+        settingsUnderTest.mPackages.clear();
+        settingsUnderTest.mDisabledSysPackages.clear();
+
+        assertThat(settingsUnderTest.readLPw(createFakeUsers()), is(true));
+
+        PackageSetting readPs1 = settingsUnderTest.getPackageLPr(PACKAGE_NAME_1);
+        PackageSetting readPs2 = settingsUnderTest.getPackageLPr(PACKAGE_NAME_2);
+
+        Truth.assertThat(readPs1).isNotNull();
+        Truth.assertThat(readPs1.usesStaticLibraries).isNotNull();
+        Truth.assertThat(readPs1.usesStaticLibrariesVersions).isNotNull();
+        Truth.assertThat(readPs2).isNotNull();
+        Truth.assertThat(readPs2.usesStaticLibraries).isNotNull();
+        Truth.assertThat(readPs2.usesStaticLibrariesVersions).isNotNull();
+
+        List<Long> ps1VersionsAsList = new ArrayList<>();
+        for (long version : ps1.usesStaticLibrariesVersions) {
+            ps1VersionsAsList.add(version);
+        }
+
+        List<Long> ps2VersionsAsList = new ArrayList<>();
+        for (long version : ps2.usesStaticLibrariesVersions) {
+            ps2VersionsAsList.add(version);
+        }
+
+        Truth.assertThat(readPs1.usesStaticLibraries).asList()
+                .containsExactlyElementsIn(ps1.usesStaticLibraries).inOrder();
+
+        Truth.assertThat(readPs1.usesStaticLibrariesVersions).asList()
+                .containsExactlyElementsIn(ps1VersionsAsList).inOrder();
+
+        Truth.assertThat(readPs2.usesStaticLibraries).asList()
+                .containsExactlyElementsIn(ps2.usesStaticLibraries).inOrder();
+
+        Truth.assertThat(readPs2.usesStaticLibrariesVersions).asList()
+                .containsExactlyElementsIn(ps2VersionsAsList).inOrder();
+    }
+
+    @Test
     public void testPackageRestrictionsDistractionFlagsDefault() {
         final PackageSetting defaultSetting = createPackageSetting(PACKAGE_NAME_1);
         assertThat(defaultSetting.getDistractionFlags(0), is(PackageManager.RESTRICTION_NONE));
@@ -617,7 +690,7 @@
                 null /*usesStaticLibraries*/,
                 null /*usesStaticLibrariesVersions*/,
                 null /*mimeGroups*/);
-        assertThat(testPkgSetting01.getCodePath(), is(UPDATED_CODE_PATH));
+        assertThat(testPkgSetting01.getPath(), is(UPDATED_CODE_PATH));
         assertThat(testPkgSetting01.name, is(PACKAGE_NAME));
         assertThat(testPkgSetting01.pkgFlags, is(ApplicationInfo.FLAG_SYSTEM));
         assertThat(testPkgSetting01.pkgPrivateFlags, is(ApplicationInfo.PRIVATE_FLAG_PRIVILEGED));
@@ -656,7 +729,7 @@
                 null /*usesStaticLibrariesVersions*/,
                 null /*mimeGroups*/);
         assertThat(testPkgSetting01.appId, is(0));
-        assertThat(testPkgSetting01.getCodePath(), is(INITIAL_CODE_PATH));
+        assertThat(testPkgSetting01.getPath(), is(INITIAL_CODE_PATH));
         assertThat(testPkgSetting01.name, is(PACKAGE_NAME));
         assertThat(testPkgSetting01.pkgFlags, is(0));
         assertThat(testPkgSetting01.pkgPrivateFlags, is(0));
@@ -700,7 +773,7 @@
                 null /*usesStaticLibrariesVersions*/,
                 null /*mimeGroups*/);
         assertThat(testPkgSetting01.appId, is(10064));
-        assertThat(testPkgSetting01.getCodePath(), is(INITIAL_CODE_PATH));
+        assertThat(testPkgSetting01.getPath(), is(INITIAL_CODE_PATH));
         assertThat(testPkgSetting01.name, is(PACKAGE_NAME));
         assertThat(testPkgSetting01.pkgFlags, is(0));
         assertThat(testPkgSetting01.pkgPrivateFlags, is(0));
@@ -741,7 +814,7 @@
                 null /*usesStaticLibrariesVersions*/,
                 null /*mimeGroups*/);
         assertThat(testPkgSetting01.appId, is(10064));
-        assertThat(testPkgSetting01.getCodePath(), is(UPDATED_CODE_PATH));
+        assertThat(testPkgSetting01.getPath(), is(UPDATED_CODE_PATH));
         assertThat(testPkgSetting01.name, is(PACKAGE_NAME));
         assertThat(testPkgSetting01.pkgFlags, is(0));
         assertThat(testPkgSetting01.pkgPrivateFlags, is(0));
@@ -792,10 +865,10 @@
     private void verifySettingCopy(PackageSetting origPkgSetting, PackageSetting testPkgSetting) {
         assertThat(origPkgSetting, is(not(testPkgSetting)));
         assertThat(origPkgSetting.appId, is(testPkgSetting.appId));
-        assertSame(origPkgSetting.getCodePath(), testPkgSetting.getCodePath());
-        assertThat(origPkgSetting.getCodePath(), is(testPkgSetting.getCodePath()));
-        assertSame(origPkgSetting.getCodePathString(), testPkgSetting.getCodePathString());
-        assertThat(origPkgSetting.getCodePathString(), is(testPkgSetting.getCodePathString()));
+        assertSame(origPkgSetting.getPath(), testPkgSetting.getPath());
+        assertThat(origPkgSetting.getPath(), is(testPkgSetting.getPath()));
+        assertSame(origPkgSetting.getPathString(), testPkgSetting.getPathString());
+        assertThat(origPkgSetting.getPathString(), is(testPkgSetting.getPathString()));
         assertSame(origPkgSetting.cpuAbiOverrideString, testPkgSetting.cpuAbiOverrideString);
         assertThat(origPkgSetting.cpuAbiOverrideString, is(testPkgSetting.cpuAbiOverrideString));
         assertThat(origPkgSetting.firstInstallTime, is(testPkgSetting.firstInstallTime));
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index 2651cfa..1d384e9 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -312,7 +312,7 @@
 
     private static PackageSetting mockPkgSetting(AndroidPackage pkg) {
         return new PackageSetting(pkg.getPackageName(), pkg.getRealPackage(),
-                new File(pkg.getCodePath()), null, pkg.getPrimaryCpuAbi(), pkg.getSecondaryCpuAbi(),
+                new File(pkg.getPath()), null, pkg.getPrimaryCpuAbi(), pkg.getSecondaryCpuAbi(),
                 null, pkg.getVersionCode(),
                 PackageInfoUtils.appInfoFlags(pkg, null),
                 PackageInfoUtils.appInfoPrivateFlags(pkg, null),
@@ -335,8 +335,8 @@
         assertEquals(a.getPackageName(), b.getPackageName());
         assertArrayEquals(a.getSplitNames(), b.getSplitNames());
         assertEquals(a.getVolumeUuid(), b.getVolumeUuid());
-        assertEquals(a.getCodePath(), b.getCodePath());
-        assertEquals(a.getBaseCodePath(), b.getBaseCodePath());
+        assertEquals(a.getPath(), b.getPath());
+        assertEquals(a.getBaseApkPath(), b.getBaseApkPath());
         assertArrayEquals(a.getSplitCodePaths(), b.getSplitCodePaths());
         assertArrayEquals(a.getSplitRevisionCodes(), b.getSplitRevisionCodes());
         assertArrayEquals(a.getSplitFlags(), b.getSplitFlags());
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 56dddb0..4d8cc4647 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -533,7 +533,7 @@
                 arrayContaining("some.static.library", "some.other.static.library"));
         assertThat(pkgSetting.usesStaticLibrariesVersions, is(new long[]{234L, 456L}));
         assertThat(pkgSetting.pkg, is(scanResult.request.parsedPackage));
-        assertThat(pkgSetting.getCodePath(), is(new File(createCodePath(packageName))));
+        assertThat(pkgSetting.getPath(), is(new File(createCodePath(packageName))));
         assertThat(pkgSetting.versionCode, is(PackageInfo.composeLongVersionCode(1, 2345)));
     }
 
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 caa8ae5..3ce7a7d 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
@@ -29,12 +29,10 @@
 import android.content.pm.PackageParser.PackageParserException;
 import android.content.pm.dex.DexMetadataHelper;
 import android.content.pm.parsing.ApkLiteParseUtils;
-import android.content.pm.parsing.result.ParseInput;
 import android.content.pm.parsing.result.ParseResult;
 import android.content.pm.parsing.result.ParseTypeImpl;
 import android.os.FileUtils;
 
-import androidx.annotation.NonNull;
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -106,9 +104,9 @@
 
         Map<String, String> packageDexMetadata = AndroidPackageUtils.getPackageDexMetadata(pkg);
         assertEquals(1, packageDexMetadata.size());
-        String baseDexMetadata = packageDexMetadata.get(pkg.getBaseCodePath());
+        String baseDexMetadata = packageDexMetadata.get(pkg.getBaseApkPath());
         assertNotNull(baseDexMetadata);
-        assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.getBaseCodePath()));
+        assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.getBaseApkPath()));
     }
 
     @Test
@@ -122,9 +120,9 @@
 
         Map<String, String> packageDexMetadata = AndroidPackageUtils.getPackageDexMetadata(pkg);
         assertEquals(2, packageDexMetadata.size());
-        String baseDexMetadata = packageDexMetadata.get(pkg.getBaseCodePath());
+        String baseDexMetadata = packageDexMetadata.get(pkg.getBaseApkPath());
         assertNotNull(baseDexMetadata);
-        assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.getBaseCodePath()));
+        assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.getBaseApkPath()));
 
         String splitDexMetadata = packageDexMetadata.get(pkg.getSplitCodePaths()[0]);
         assertNotNull(splitDexMetadata);
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 30db3db..59cbd1c 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
@@ -62,7 +62,7 @@
 
 fun whenever(mock: Unit) = Mockito.`when`(mock).thenAnswer { }
 
-inline fun <reified T> spyThrowOnUnmocked(value: T?, block: T.() -> Unit): T {
+inline fun <reified T> spyThrowOnUnmocked(value: T?, block: T.() -> Unit = {}): T {
     val swappingAnswer = object : Answer<Any?> {
         var delegate: Answer<*> = Answers.RETURNS_DEFAULTS
 
@@ -79,4 +79,5 @@
             }
 }
 
-inline fun <reified T> mockThrowOnUnmocked(block: T.() -> Unit) = spyThrowOnUnmocked<T>(null, block)
+inline fun <reified T> mockThrowOnUnmocked(block: T.() -> Unit = {}) =
+        spyThrowOnUnmocked<T>(null, block)
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 8644719..9e7226e7 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -1086,12 +1086,18 @@
     }
 
     /**
-     * Confirm the system user on automotive devices can use car categories
+     * Confirm an application with the SEND_CATEGORY_CAR_NOTIFICATIONS permission on automotive
+     * devices can use car categories.
      */
     @Test
-    public void testEnqueuedRestrictedNotifications_asSystem() throws Exception {
+    public void testEnqueuedRestrictedNotifications_hasPermission() throws Exception {
         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0))
                 .thenReturn(true);
+        // SEND_CATEGORY_CAR_NOTIFICATIONS is a system-level permission that this test cannot
+        // obtain. Mocking out enforce permission call to ensure notifications can be created when
+        // permitted.
+        doNothing().when(mContext).enforceCallingPermission(
+                eq("android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS"), anyString());
         List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY,
                 Notification.CATEGORY_CAR_WARNING,
                 Notification.CATEGORY_CAR_INFORMATION);
@@ -1114,7 +1120,6 @@
      */
     @Test
     public void testEnqueuedRestrictedNotifications_notAutomotive() throws Exception {
-        mService.isSystemUid = false;
         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0))
                 .thenReturn(false);
         List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY,
@@ -1134,12 +1139,11 @@
     }
 
     /**
-     * Confirm if a non-system user tries to use the car categories on a automotive device that
-     * they will get a security exception
+     * Confirm if an application tries to use the car categories on a automotive device without the
+     * SEND_CATEGORY_CAR_NOTIFICATIONS permission that a security exception will be thrown.
      */
     @Test
-    public void testEnqueuedRestrictedNotifications_badUser() throws Exception {
-        mService.isSystemUid = false;
+    public void testEnqueuedRestrictedNotifications_noPermission() throws Exception {
         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0))
                 .thenReturn(true);
         List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 09375db..89a0c7c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -73,7 +73,6 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.same;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.never;
 
@@ -1671,8 +1670,6 @@
     @Test
     public void testCanTurnScreenOn() {
         mStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
-        doReturn(true).when(mStack).checkKeyguardVisibility(
-                same(mActivity), eq(true) /* shouldBeVisible */, anyBoolean());
         doReturn(true).when(mActivity).getTurnScreenOnFlag();
 
         assertTrue(mActivity.canTurnScreenOn());
@@ -1681,8 +1678,6 @@
     @Test
     public void testFreeformWindowCantTurnScreenOn() {
         mStack.setWindowingMode(WINDOWING_MODE_FREEFORM);
-        doReturn(true).when(mStack).checkKeyguardVisibility(
-                same(mActivity), eq(true) /* shouldBeVisible */, anyBoolean());
         doReturn(true).when(mActivity).getTurnScreenOnFlag();
 
         assertFalse(mActivity.canTurnScreenOn());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 4951658..a60f93a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -1410,7 +1410,7 @@
                 new ActivityBuilder(mAtm).setTask(mTask).build();
         new ActivityBuilder(mAtm).setTask(mTask).build();
         doReturn(false).when(nonTopVisibleActivity).attachedToProcess();
-        doReturn(true).when(nonTopVisibleActivity).shouldBeVisible(anyBoolean(), anyBoolean());
+        doReturn(true).when(nonTopVisibleActivity).shouldBeVisibleUnchecked();
         doNothing().when(mSupervisor).startSpecificActivity(any(), anyBoolean(),
                 anyBoolean());
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 7f90426..89a34cf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -24,7 +24,6 @@
 import static android.content.pm.ActivityInfo.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.pm.ActivityInfo.SCREEN_ORIENTATION_USER;
 import static android.os.Build.VERSION_CODES.P;
 import static android.os.Build.VERSION_CODES.Q;
 import static android.view.Display.DEFAULT_DISPLAY;
@@ -762,13 +761,14 @@
                 window.mAttrs.screenOrientation, dc.getOrientation());
 
         // ----------------------------
-        // Test close-to-square display
+        // Test close-to-square display - should be handled in the same way
         // ----------------------------
         dc.mBaseDisplayHeight = dc.mBaseDisplayWidth;
         dc.configureDisplayPolicy();
 
-        assertEquals("Screen orientation must be SCREEN_ORIENTATION_USER.",
-                SCREEN_ORIENTATION_USER, dc.getOrientation());
+        assertEquals(
+                "Screen orientation must be defined by the window even on close-to-square display.",
+                window.mAttrs.screenOrientation, dc.getOrientation());
     }
 
     @Test
@@ -823,7 +823,14 @@
         final DisplayContent newDisplay = createNewDisplay();
 
         final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin");
+        final Task stack = mDisplayContent.getTopStack();
+        final ActivityRecord activity = stack.topRunningActivity();
+        doReturn(true).when(activity).shouldBeVisibleUnchecked();
+
         final WindowState appWin1 = createWindow(null, TYPE_APPLICATION, newDisplay, "appWin1");
+        final Task stack1 = newDisplay.getTopStack();
+        final ActivityRecord activity1 = stack1.topRunningActivity();
+        doReturn(true).when(activity1).shouldBeVisibleUnchecked();
         appWin.setHasSurface(true);
         appWin1.setHasSurface(true);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 253fbae..58d994c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -44,6 +44,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -291,7 +292,8 @@
             mRecentTasks.add(mTasks.get(1));
             invocation.callRealMethod();
             return null;
-        }).when(mSupervisor).endActivityVisibilityUpdate();
+        }).when(mSupervisor).endActivityVisibilityUpdate(any(), anyInt(), anyBoolean(),
+                anyBoolean());
 
         mTaskContainer.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
                 false /* preserveWindows */, false /* notifyClients */);
@@ -1170,12 +1172,12 @@
                 () -> mAtm.setTaskWindowingModeSplitScreenPrimary(0, true));
         assertSecurityException(expectCallable,
                 () -> mAtm.moveTopActivityToPinnedStack(INVALID_STACK_ID, new Rect()));
-        assertSecurityException(expectCallable, () -> mAtm.getAllStackInfos());
+        assertSecurityException(expectCallable, () -> mAtm.getAllRootTaskInfos());
         assertSecurityException(expectCallable,
-                () -> mAtm.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED));
+                () -> mAtm.getRootTaskInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED));
         assertSecurityException(expectCallable, () -> {
             try {
-                mAtm.getFocusedStackInfo();
+                mAtm.getFocusedRootTaskInfo();
             } catch (RemoteException e) {
                 // Ignore
             }
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 29081d3..edcf0d4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -138,8 +138,6 @@
     public void testFixedAspectRatioBoundsWithDecorInSquareDisplay() {
         final int notchHeight = 100;
         setUpApp(new TestDisplayContent.Builder(mAtm, 600, 800).setNotch(notchHeight).build());
-        // Rotation is ignored so because the display size is close to square (700/600<1.333).
-        assertTrue(mActivity.mDisplayContent.ignoreRotationForApps());
 
         final Rect displayBounds = mActivity.mDisplayContent.getWindowConfiguration().getBounds();
         final float aspectRatio = 1.2f;
@@ -163,23 +161,14 @@
         mActivity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
         assertFitted();
 
-        // After the orientation of activity is changed, even display is not rotated, the aspect
-        // ratio should be the same (bounds=[0, 0 - 600, 600], appBounds=[0, 100 - 600, 600]).
+        // After the orientation of activity is changed, the display is rotated, the aspect
+        // ratio should be the same (bounds=[100, 0 - 800, 583], appBounds=[100, 0 - 800, 583]).
         assertEquals(appBounds.width(), appBounds.height() * aspectRatio, 0.5f /* delta */);
-        // The notch is still on top.
-        assertEquals(mActivity.getBounds().height(), appBounds.height() + notchHeight);
+        // The notch is no longer on top.
+        assertEquals(appBounds, mActivity.getBounds());
 
         mActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
         assertFitted();
-
-        // Close-to-square display can rotate without being restricted by the requested orientation.
-        // The notch becomes on the left side. The activity is horizontal centered in 100 ~ 800.
-        // So the bounds and appBounds will be [200, 0 - 700, 600] (500x600) that is still fitted.
-        // Left = 100 + (800 - 100 - 500) / 2 = 200.
-        rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
-        assertFitted();
-        assertEquals(appBounds.left,
-                notchHeight + (displayBounds.width() - notchHeight - appBounds.width()) / 2);
     }
 
     @Test
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 eb7d9c2..6a29c5b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -534,11 +534,14 @@
             doNothing().when(this).scheduleIdleTimeout(any());
             // unit test version does not handle launch wake lock
             doNothing().when(this).acquireLaunchWakelock();
-            doReturn(mock(KeyguardController.class)).when(this).getKeyguardController();
 
             mLaunchingActivityWakeLock = mock(PowerManager.WakeLock.class);
 
             initialize();
+
+            final KeyguardController controller = getKeyguardController();
+            spyOn(controller);
+            doReturn(true).when(controller).checkKeyguardVisibility(any());
         }
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
index e39b4bc..d37f3f4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
@@ -17,17 +17,16 @@
 package com.android.server.wm;
 
 import android.graphics.Point;
-import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.util.MergedConfiguration;
-import android.view.DisplayCutout;
 import android.view.DragEvent;
 import android.view.IScrollCaptureController;
 import android.view.IWindow;
 import android.view.InsetsSourceControl;
 import android.view.InsetsState;
+import android.window.ClientWindowFrames;
 
 import com.android.internal.os.IResultReceiver;
 
@@ -38,10 +37,9 @@
     }
 
     @Override
-    public void resized(Rect frame, Rect contentInsets, Rect visibleInsets,
-            Rect stableInsets, boolean reportDraw, MergedConfiguration mergedConfig,
-            Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
-            DisplayCutout.ParcelableWrapper displayCutout) throws RemoteException {
+    public void resized(ClientWindowFrames frames, boolean reportDraw,
+            MergedConfiguration mergedConfig, boolean forceLayout, boolean alwaysConsumeSystemBars,
+            int displayId) throws RemoteException {
     }
 
     @Override
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 38909f6..5d8a2a1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -52,7 +52,7 @@
 
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningTaskInfo;
-import android.app.ActivityManager.StackInfo;
+import android.app.ActivityTaskManager.RootTaskInfo;
 import android.app.PictureInPictureParams;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
@@ -301,9 +301,9 @@
         removeGlobalMinSizeRestriction();
         final Task stack = new TaskBuilder(mSupervisor)
                 .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
-        StackInfo info =
-                mWm.mAtmService.getStackInfo(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
-        assertEquals(stack.mRemoteToken.toWindowContainerToken(), info.stackToken);
+        RootTaskInfo info =
+                mWm.mAtmService.getRootTaskInfo(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
+        assertEquals(stack.mRemoteToken.toWindowContainerToken(), info.token);
         testTransaction(stack);
     }
 
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 3106ca2..c18043f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -581,12 +581,10 @@
         mWm.mResizingWindows.remove(win);
         spyOn(win.mClient);
         try {
-            doThrow(new RemoteException("test")).when(win.mClient).resized(any() /* frame */,
-                    any() /* contentInsets */, any() /* visibleInsets */, any() /* stableInsets */,
+            doThrow(new RemoteException("test")).when(win.mClient).resized(any() /* frames */,
                     anyBoolean() /* reportDraw */, any() /* mergedConfig */,
-                    any() /* backDropFrame */, anyBoolean() /* forceLayout */,
-                    anyBoolean() /* alwaysConsumeSystemBars */, anyInt() /* displayId */,
-                    any() /* displayCutout */);
+                    anyBoolean() /* forceLayout */, anyBoolean() /* alwaysConsumeSystemBars */,
+                    anyInt() /* displayId */);
         } catch (RemoteException ignored) {
         }
         win.reportResized();
diff --git a/telecomm/java/com/android/internal/telecom/IDeviceIdleControllerAdapter.aidl b/telecomm/java/com/android/internal/telecom/IDeviceIdleControllerAdapter.aidl
new file mode 100644
index 0000000..50bbf4c
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecom/IDeviceIdleControllerAdapter.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.telecom;
+
+/*
+ * Adapter interface for using DeviceIdleController, since the PowerWhitelistManager is not
+ * directly accessible in the SYSTEM process.
+ */
+interface IDeviceIdleControllerAdapter {
+    void exemptAppTemporarilyForEvent(String packageName, long duration, int userHandle,
+            String reason);
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/ContainerView.java b/telecomm/java/com/android/internal/telecom/IInternalServiceRetriever.aidl
similarity index 60%
copy from packages/SystemUI/src/com/android/keyguard/dagger/ContainerView.java
copy to telecomm/java/com/android/internal/telecom/IInternalServiceRetriever.aidl
index e65f19d..b560106 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/ContainerView.java
+++ b/telecomm/java/com/android/internal/telecom/IInternalServiceRetriever.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,17 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.keyguard.dagger;
+package com.android.internal.telecom;
 
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import com.android.internal.telecom.IDeviceIdleControllerAdapter;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
-import javax.inject.Qualifier;
-
-@Qualifier
-@Documented
-@Retention(RUNTIME)
-public @interface ContainerView {
+/*
+ * Interface used to retrieve services that are only accessible via LocalService in the SYSTEM
+ * process.
+ */
+interface IInternalServiceRetriever {
+    IDeviceIdleControllerAdapter getDeviceIdleController();
 }
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomLoader.aidl b/telecomm/java/com/android/internal/telecom/ITelecomLoader.aidl
new file mode 100644
index 0000000..eda0f5b
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecom/ITelecomLoader.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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.telecom;
+
+import com.android.internal.telecom.ITelecomService;
+import com.android.internal.telecom.IInternalServiceRetriever;
+
+/*
+ * Internal interface for getting an instance of the ITelecomService for external publication.
+ * Allows the TelecomLoaderService to pass additional dependencies required for creation.
+ */
+interface ITelecomLoader {
+    ITelecomService createTelecomService(IInternalServiceRetriever retriever);
+}
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 943d783..a53ea16 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -28,7 +28,6 @@
         "flickertestapplib",
         "flickerlib",
         "truth-prebuilt",
-        "app-helpers-core",
         "launcher-helper-lib",
         "launcher-aosp-tapl"
     ],
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.kt
deleted file mode 100644
index 7147577..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.kt
+++ /dev/null
@@ -1,31 +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.server.wm.flicker.helpers
-
-import android.app.Instrumentation
-import android.support.test.launcherhelper.ILauncherStrategy
-import com.android.server.wm.flicker.StandardAppHelper
-
-abstract class FlickerAppHelper(
-    instr: Instrumentation,
-    launcherName: String,
-    launcherStrategy: ILauncherStrategy
-) : StandardAppHelper(instr, sFlickerPackage, launcherName, launcherStrategy) {
-    companion object {
-        var sFlickerPackage = "com.android.server.wm.flicker.testapp"
-    }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
index c1b7657..f4de36e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
@@ -30,7 +30,7 @@
     launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
             .getInstance(instr)
             .launcherStrategy
-) : FlickerAppHelper(instr, launcherName, launcherStrategy) {
+) : StandardAppHelper(instr, launcherName, launcherStrategy) {
     open fun openIME(device: UiDevice) {
         val editText = device.wait(
                 Until.findObject(By.res(getPackage(), "plain_text_input")),
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
index d10bb1e..0572a78 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
@@ -28,7 +28,7 @@
     launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
             .getInstance(instr)
             .launcherStrategy
-) : FlickerAppHelper(instr, "PipApp", launcherStrategy) {
+) : StandardAppHelper(instr, "PipApp", launcherStrategy) {
     fun clickEnterPipButton(device: UiDevice) {
         val enterPipButton = device.findObject(By.res(getPackage(), "enter_pip"))
         Assert.assertNotNull("Pip button not found, this usually happens when the device " +
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTestBase.kt
index 7d70812..98e05d5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTestBase.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTestBase.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.launch
 
 import com.android.server.wm.flicker.NonRotationTestBase
-import com.android.server.wm.flicker.StandardAppHelper
+import com.android.server.wm.flicker.helpers.StandardAppHelper
 import com.android.server.wm.flicker.dsl.LayersAssertion
 import com.android.server.wm.flicker.dsl.WmAssertion
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index afadb58..acd141a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -18,7 +18,7 @@
 
 import android.view.Surface
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.StandardAppHelper
+import com.android.server.wm.flicker.helpers.StandardAppHelper
 import com.android.server.wm.flicker.dsl.flicker
 import com.android.server.wm.flicker.focusChanges
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
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 0ca1508..99218c2 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
@@ -20,7 +20,7 @@
 import android.view.Surface
 import com.android.server.wm.flicker.NonRotationTestBase.Companion.SCREENSHOT_LAYER
 import com.android.server.wm.flicker.RotationTestBase
-import com.android.server.wm.flicker.StandardAppHelper
+import com.android.server.wm.flicker.helpers.StandardAppHelper
 import com.android.server.wm.flicker.dsl.flicker
 import com.android.server.wm.flicker.focusDoesNotChange
 import com.android.server.wm.flicker.helpers.WindowUtils
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
index c5e48d9..3b5e669 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
@@ -19,7 +19,7 @@
 import android.view.Surface
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.NonRotationTestBase
-import com.android.server.wm.flicker.StandardAppHelper
+import com.android.server.wm.flicker.helpers.StandardAppHelper
 import com.android.server.wm.flicker.dsl.flicker
 import com.android.server.wm.flicker.focusChanges
 import com.android.server.wm.flicker.helpers.exitSplitScreen
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
index 91211ca..abf41a1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
@@ -24,7 +24,7 @@
 import androidx.test.filters.RequiresDevice
 import androidx.test.uiautomator.By
 import com.android.server.wm.flicker.FlickerTestBase
-import com.android.server.wm.flicker.StandardAppHelper
+import com.android.server.wm.flicker.helpers.StandardAppHelper
 import com.android.server.wm.flicker.dsl.flicker
 import com.android.server.wm.flicker.focusDoesNotChange
 import com.android.server.wm.flicker.helpers.ImeAppHelper
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
index 5c7dcd9..87c8633 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
@@ -19,7 +19,7 @@
 import android.view.Surface
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.NonRotationTestBase
-import com.android.server.wm.flicker.StandardAppHelper
+import com.android.server.wm.flicker.helpers.StandardAppHelper
 import com.android.server.wm.flicker.dsl.flicker
 import com.android.server.wm.flicker.focusDoesNotChange
 import com.android.server.wm.flicker.helpers.exitSplitScreen
diff --git a/wifi/api/current.txt b/wifi/api/current.txt
index d0742c7..3f5c673 100644
--- a/wifi/api/current.txt
+++ b/wifi/api/current.txt
@@ -144,6 +144,7 @@
 
   @Deprecated public static class WifiConfiguration.GroupCipher {
     field @Deprecated public static final int CCMP = 3; // 0x3
+    field @Deprecated public static final int GCMP_128 = 7; // 0x7
     field @Deprecated public static final int GCMP_256 = 5; // 0x5
     field @Deprecated public static final int SMS4 = 6; // 0x6
     field @Deprecated public static final int TKIP = 2; // 0x2
@@ -173,6 +174,7 @@
 
   @Deprecated public static class WifiConfiguration.PairwiseCipher {
     field @Deprecated public static final int CCMP = 2; // 0x2
+    field @Deprecated public static final int GCMP_128 = 5; // 0x5
     field @Deprecated public static final int GCMP_256 = 3; // 0x3
     field @Deprecated public static final int NONE = 0; // 0x0
     field @Deprecated public static final int SMS4 = 4; // 0x4
diff --git a/wifi/api/system-current.txt b/wifi/api/system-current.txt
index eff64a3..c3e573c 100644
--- a/wifi/api/system-current.txt
+++ b/wifi/api/system-current.txt
@@ -449,6 +449,7 @@
     method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.WifiConfiguration getWifiApConfiguration();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public int getWifiApState();
     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 public boolean isConnectedMacRandomizationSupported();
     method @Deprecated public boolean isDeviceToDeviceRttSupported();
@@ -651,6 +652,7 @@
     field public static final int WIFI_BAND_5_GHZ = 2; // 0x2
     field public static final int WIFI_BAND_5_GHZ_DFS_ONLY = 4; // 0x4
     field public static final int WIFI_BAND_5_GHZ_WITH_DFS = 6; // 0x6
+    field public static final int WIFI_BAND_60_GHZ = 16; // 0x10
     field public static final int WIFI_BAND_6_GHZ = 8; // 0x8
     field public static final int WIFI_BAND_BOTH = 3; // 0x3
     field public static final int WIFI_BAND_BOTH_WITH_DFS = 7; // 0x7
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index e493789..b3ed8ac 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -118,6 +118,8 @@
 
     boolean is6GHzBandSupported();
 
+    boolean is60GHzBandSupported();
+
     boolean isWifiStandardSupported(int standard);
 
     DhcpInfo getDhcpInfo();
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 656444e..02b7a42 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -301,9 +301,16 @@
          */
         public static final int SMS4 = 4;
 
+        /**
+         * AES in Galois/Counter Mode with a 128-bit integrity key
+         */
+        public static final int GCMP_128 = 5;
+
+
         public static final String varName = "pairwise";
 
-        public static final String[] strings = { "NONE", "TKIP", "CCMP", "GCMP_256", "SMS4" };
+        public static final String[] strings = { "NONE", "TKIP", "CCMP", "GCMP_256", "SMS4",
+                "GCMP_128" };
     }
 
     /**
@@ -345,13 +352,17 @@
          * SMS4 cipher for WAPI
          */
         public static final int SMS4 = 6;
+        /**
+         * AES in Galois/Counter Mode with a 128-bit integrity key
+         */
+        public static final int GCMP_128 = 7;
 
         public static final String varName = "group";
 
         public static final String[] strings =
                 { /* deprecated */ "WEP40", /* deprecated */ "WEP104",
                         "TKIP", "CCMP", "GTK_NOT_USED", "GCMP_256",
-                        "SMS4" };
+                        "SMS4", "GCMP_128" };
     }
 
     /**
@@ -498,8 +509,10 @@
                 allowedProtocols.set(WifiConfiguration.Protocol.RSN);
                 allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
                 allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+                allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_128);
                 allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
                 allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
+                allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_128);
                 allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
                 requirePmf = true;
                 break;
@@ -508,7 +521,9 @@
                 allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
                 allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
                 allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192);
+                allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_128);
                 allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
+                allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_128);
                 allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
                 allowedGroupManagementCiphers.set(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256);
                 // Note: allowedSuiteBCiphers bitset will be set by the service once the
@@ -519,8 +534,10 @@
                 allowedProtocols.set(WifiConfiguration.Protocol.RSN);
                 allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);
                 allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+                allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_128);
                 allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
                 allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
+                allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_128);
                 allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
                 requirePmf = true;
                 break;
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index b28b902..c76f4a6 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -2407,6 +2407,8 @@
     public static final long WIFI_FEATURE_OCE              = 0x1000000000L; // OCE Support
     /** @hide */
     public static final long WIFI_FEATURE_WAPI             = 0x2000000000L; // WAPI
+    /** @hide */
+    public static final long WIFI_FEATURE_INFRA_60G        = 0x4000000000L; // 60 GHz Band Support
 
     /** @hide */
     public static final long WIFI_FEATURE_FILS_SHA256     = 0x4000000000L; // FILS-SHA256
@@ -2569,6 +2571,21 @@
     }
 
     /**
+     * Check if the chipset supports the 60GHz frequency band.
+     *
+     * @return {@code true} if supported, {@code false} otherwise.
+     * @hide
+     */
+    @SystemApi
+    public boolean is60GHzBandSupported() {
+        try {
+            return mService.is60GHzBandSupported();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Check if the chipset supports 6GHz band.
      * @return {@code true} if supported, {@code false} otherwise.
      */
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index aa69963..145c39d 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -176,7 +176,7 @@
             mWapiEnterpriseConfig = null;
             mIsNetworkUntrusted = false;
             mPriorityGroup = 0;
-            mIsEnhancedMacRandomizationEnabled = true;
+            mIsEnhancedMacRandomizationEnabled = false;
         }
 
         /**
@@ -409,11 +409,12 @@
          * Suggested networks will never use the device (factory) MAC address to associate to the
          * network - instead they use a locally generated random MAC address. This method controls
          * the strategy for generating the random MAC address:
-         * <li> Persisted MAC randomization (false): generates the MAC address from a secret seed
-         * and information from the Wi-Fi configuration (SSID or Passpoint profile). That means that
-         * the same generated MAC address will be used for each subsequent association. </li>
-         * <li> Enhanced MAC randomization (true - the default): periodically generates a new MAC
-         * address new connections. Under this option, the randomized MAC address should change
+         * <li> Persisted MAC randomization (false - the default): generates the MAC address from a
+         * secret seed and information from the Wi-Fi configuration (SSID or Passpoint profile).
+         * This means that the same generated MAC address will be used for each subsequent
+         * association. </li>
+         * <li> Enhanced MAC randomization (true): periodically generates a new MAC
+         * address for new connections. Under this option, the randomized MAC address should change
          * if the suggestion is removed and then added back. </li>
          *
          * @param enabled {@code true} to periodically change the randomized MAC address.
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 94771ac..a68d7e2 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -68,7 +68,9 @@
     /** @hide */
     public static final int WIFI_BAND_INDEX_6_GHZ = 3;
     /** @hide */
-    public static final int WIFI_BAND_COUNT = 4;
+    public static final int WIFI_BAND_INDEX_60_GHZ = 4;
+    /** @hide */
+    public static final int WIFI_BAND_COUNT = 5;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -76,7 +78,8 @@
             WIFI_BAND_INDEX_24_GHZ,
             WIFI_BAND_INDEX_5_GHZ,
             WIFI_BAND_INDEX_5_GHZ_DFS_ONLY,
-            WIFI_BAND_INDEX_6_GHZ})
+            WIFI_BAND_INDEX_6_GHZ,
+            WIFI_BAND_INDEX_60_GHZ})
     public @interface WifiBandIndex {}
 
     /** no band specified; use channel list instead */
@@ -89,6 +92,8 @@
     public static final int WIFI_BAND_5_GHZ_DFS_ONLY  = 1 << WIFI_BAND_INDEX_5_GHZ_DFS_ONLY;
     /** 6 GHz band */
     public static final int WIFI_BAND_6_GHZ = 1 << WIFI_BAND_INDEX_6_GHZ;
+    /** 60 GHz band */
+    public static final int WIFI_BAND_60_GHZ = 1 << WIFI_BAND_INDEX_60_GHZ;
 
     /**
      * Combination of bands
@@ -113,6 +118,12 @@
     /** 2.4 GHz band and 5 GHz band; with DFS channels and 6 GHz */
     public static final int WIFI_BAND_24_5_WITH_DFS_6_GHZ =
             WIFI_BAND_BOTH_WITH_DFS | WIFI_BAND_6_GHZ;
+    /** @hide */
+    public static final int WIFI_BAND_24_5_6_60_GHZ =
+            WIFI_BAND_24_5_6_GHZ | WIFI_BAND_60_GHZ;
+    /** @hide */
+    public static final int WIFI_BAND_24_5_WITH_DFS_6_60_GHZ =
+            WIFI_BAND_24_5_6_60_GHZ | WIFI_BAND_5_GHZ_DFS_ONLY;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -127,7 +138,10 @@
             WIFI_BAND_BOTH_WITH_DFS,
             WIFI_BAND_6_GHZ,
             WIFI_BAND_24_5_6_GHZ,
-            WIFI_BAND_24_5_WITH_DFS_6_GHZ})
+            WIFI_BAND_24_5_WITH_DFS_6_GHZ,
+            WIFI_BAND_60_GHZ,
+            WIFI_BAND_24_5_6_60_GHZ,
+            WIFI_BAND_24_5_WITH_DFS_6_60_GHZ})
     public @interface WifiBand {}
 
     /**
@@ -179,7 +193,10 @@
      * @hide
      */
     public static boolean isFullBandScan(@WifiBand int bandScanned, boolean excludeDfs) {
-        return (bandScanned | WIFI_BAND_6_GHZ | (excludeDfs ? WIFI_BAND_5_GHZ_DFS_ONLY : 0))
+        // 5GHz DFS channel is part of 5GHz, mark 5GHz scanned as well.
+        if ((bandScanned & WIFI_BAND_5_GHZ_DFS_ONLY) != 0) bandScanned |= WIFI_BAND_5_GHZ;
+        return (bandScanned | WIFI_BAND_6_GHZ | WIFI_BAND_60_GHZ
+                | (excludeDfs ? WIFI_BAND_5_GHZ_DFS_ONLY : 0))
                 == WIFI_BAND_ALL;
     }
 
@@ -571,6 +588,19 @@
             }
         }
 
+        /** {@hide} */
+        public void addResults(@NonNull ScanData s) {
+            mBandScanned |= s.mBandScanned;
+            mFlags |= s.mFlags;
+            addResults(s.getResults());
+        }
+
+        /** {@hide} */
+        public boolean isFullBandScanResults() {
+            return (mBandScanned & WifiScanner.WIFI_BAND_24_GHZ) != 0
+                && (mBandScanned & WifiScanner.WIFI_BAND_5_GHZ) != 0;
+        }
+
         /** Implement the Parcelable interface {@hide} */
         public int describeContents() {
             return 0;
diff --git a/wifi/java/android/net/wifi/nl80211/NativeScanResult.java b/wifi/java/android/net/wifi/nl80211/NativeScanResult.java
index a8e9999..35cf45f 100644
--- a/wifi/java/android/net/wifi/nl80211/NativeScanResult.java
+++ b/wifi/java/android/net/wifi/nl80211/NativeScanResult.java
@@ -225,6 +225,15 @@
      * BSS capability bit (see IEEE Std 802.11: 9.4.1.4): Immediate Block Ack.
      */
     public static final int BSS_CAPABILITY_IMMEDIATE_BLOCK_ACK = 0x1 << 15;
+    /**
+     * BSS capability bit (see IEEE Std 802.11: 9.4.1.4): DMG ESS.
+     * In DMG bits 0 and 1 are parsed together, where ESS=0x3 and IBSS=0x1
+     */
+    public static final int BSS_CAPABILITY_DMG_ESS = 0x3;
+    /**
+     * BSS capability bit (see IEEE Std 802.11: 9.4.1.4): DMG IBSS.
+     */
+    public static final int BSS_CAPABILITY_DMG_IBSS = 0x1;
 
     /**
      *  Returns the capabilities of the AP repseresented by this scan result as advertised in the
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index abb9ce6..631e5e2 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -682,15 +682,15 @@
     }
 
     /**
-     * Verify that the macRandomizationSetting defaults to RANDOMIZATION_ENHANCED and could be set
-     * to RANDOMIZATION_PERSISTENT.
+     * Verify that the macRandomizationSetting defaults to RANDOMIZATION_PERSISTENT and could be set
+     * to RANDOMIZATION_ENHANCED.
      */
     @Test
     public void testWifiNetworkSuggestionBuilderSetMacRandomization() {
         WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
                 .setSsid(TEST_SSID)
                 .build();
-        assertEquals(WifiConfiguration.RANDOMIZATION_ENHANCED,
+        assertEquals(WifiConfiguration.RANDOMIZATION_PERSISTENT,
                 suggestion.wifiConfiguration.macRandomizationSetting);
 
         suggestion = new WifiNetworkSuggestion.Builder()