Merge "Renamed thread_enabled flag to thread_enabled_platform" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index d1afb86..858620b 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -12,52 +12,36 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-aconfig_srcjars = [
-    // !!! KEEP THIS LIST ALPHABETICAL !!!
-    ":aconfig_mediacodec_flags_java_lib{.generated_srcjars}",
-    ":android.content.pm.flags-aconfig-java{.generated_srcjars}",
-    ":android.content.res.flags-aconfig-java{.generated_srcjars}",
-    ":android.crashrecovery.flags-aconfig-java{.generated_srcjars}",
-    ":android.hardware.biometrics.flags-aconfig-java{.generated_srcjars}",
-    ":android.media.codec-aconfig-java{.generated_srcjars}",
-    ":android.media.playback.flags-aconfig-java{.generated_srcjars}",
-    ":android.net.platform.flags-aconfig-java{.generated_srcjars}",
-    ":android.net.vcn.flags-aconfig-java{.generated_srcjars}",
-    ":android.nfc.flags-aconfig-java{.generated_srcjars}",
-    ":android.os.flags-aconfig-java{.generated_srcjars}",
-    ":android.security.flags-aconfig-java{.generated_srcjars}",
-    ":com.android.hardware.camera2-aconfig-java{.generated_srcjars}",
-    ":com.android.hardware.input-aconfig-java{.generated_srcjars}",
-    ":com.android.net.thread.flags-aconfig-java{.generated_srcjars}",
-    ":com.android.text.flags-aconfig-java{.generated_srcjars}",
-    ":com.android.window.flags.window-aconfig-java{.generated_srcjars}",
-    // !!! KEEP THIS LIST ALPHABETICAL !!!
-]
-
-stubs_defaults {
+aconfig_declarations_group {
     name: "framework-minus-apex-aconfig-declarations",
-    aconfig_declarations: [
-        "android.content.pm.flags-aconfig",
-        "android.content.res.flags-aconfig",
-        "android.crashrecovery.flags-aconfig",
-        "android.hardware.biometrics.flags-aconfig",
-        "android.media.playback.flags-aconfig",
-        "android.net.platform.flags-aconfig",
-        "android.net.vcn.flags-aconfig",
-        "android.nfc.flags-aconfig",
-        "android.os.flags-aconfig",
-        "android.security.flags-aconfig",
-        "com.android.hardware.camera2-aconfig",
-        "com.android.hardware.input.input-aconfig",
-        "com.android.net.thread.flags-aconfig",
-        "com.android.window.flags.window-aconfig",
-        "com.android.text.flags-aconfig",
+    java_aconfig_libraries: [
+        // !!! KEEP THIS LIST ALPHABETICAL !!!
+        "aconfig_mediacodec_flags_java_lib",
+        "android.content.pm.flags-aconfig-java",
+        "android.content.res.flags-aconfig-java",
+        "android.crashrecovery.flags-aconfig-java",
+        "android.hardware.biometrics.flags-aconfig-java",
+        "android.media.codec-aconfig-java",
+        "android.media.playback.flags-aconfig-java",
+        "android.net.platform.flags-aconfig-java",
+        "android.net.vcn.flags-aconfig-java",
+        "android.nfc.flags-aconfig-java",
+        "android.os.flags-aconfig-java",
+        "android.security.flags-aconfig-java",
+        "com.android.hardware.camera2-aconfig-java",
+        "com.android.hardware.input-aconfig-java",
+        "com.android.net.thread.flags-aconfig-java",
+        "com.android.text.flags-aconfig-java",
+        "com.android.window.flags.window-aconfig-java",
+        // !!! KEEP THIS LIST ALPHABETICAL !!!
     ],
 }
 
 filegroup {
     name: "framework-minus-apex-aconfig-srcjars",
-    srcs: aconfig_srcjars,
+    srcs: [
+        ":framework-minus-apex-aconfig-declarations{.srcjars}",
+    ],
 }
 
 // Aconfig declarations and libraries for the core framework
@@ -66,7 +50,9 @@
 
     // Add java_aconfig_libraries to here to add them to the core framework
     // Add aconfig-annotations-lib as a dependency for the optimization
-    srcs: aconfig_srcjars,
+    srcs: [
+        ":framework-minus-apex-aconfig-declarations{.srcjars}",
+    ],
     libs: ["aconfig-annotations-lib"],
 }
 
diff --git a/Android.bp b/Android.bp
index 6f4593b..65ec015 100644
--- a/Android.bp
+++ b/Android.bp
@@ -479,6 +479,8 @@
     lint: {
         baseline_filename: "lint-baseline.xml",
     },
+    // For jarjar repackaging
+    jarjar_prefix: "com.android.internal.hidden_from_bootclasspath",
 }
 
 java_library {
diff --git a/api/Android.bp b/api/Android.bp
index ea59d0b..14320c9 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -310,7 +310,7 @@
 // classpath (or sources) somehow.
 stubs_defaults {
     name: "android-non-updatable-stubs-defaults",
-    defaults: ["framework-minus-apex-aconfig-declarations"],
+    aconfig_declarations: ["framework-minus-apex-aconfig-declarations"],
     srcs: [":android-non-updatable-stub-sources"],
     sdk_version: "none",
     system_modules: "none",
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
index 388a65d..00068bd 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
@@ -1709,7 +1709,7 @@
      * <p>
      * Two images are strongly equal if and only if the data, formats, sizes,
      * and timestamps are same. For {@link ImageFormat#PRIVATE PRIVATE} format
-     * images, the image data is not not accessible thus the data comparison is
+     * images, the image data is not accessible thus the data comparison is
      * effectively skipped as the number of planes is zero.
      * </p>
      * <p>
@@ -2049,7 +2049,7 @@
                     }
                 } else {
                     // Case 2.
-                    collector.expectEquals("Exif orientaiton should match requested orientation",
+                    collector.expectEquals("Exif orientation should match requested orientation",
                             requestedOrientation, getExifOrientationInDegree(exifOrientation,
                             collector));
                 }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/StaticMetadata.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/StaticMetadata.java
index ed70ab9..5dcd1cb 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/StaticMetadata.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/StaticMetadata.java
@@ -1127,8 +1127,8 @@
      * Get aeAvailableModes and do the validation check.
      *
      * <p>Depending on the check level this class has, for WAR or COLLECT levels,
-     * If the aeMode list is invalid, return an empty mode array. The the caller doesn't
-     * have to abort the execution even the aeMode list is invalid.</p>
+     * If the aeMode list is invalid, return an empty mode array. The caller doesn't
+     * have to abort the execution even if the aeMode list is invalid.</p>
      * @return AE available modes
      */
     public int[] getAeAvailableModesChecked() {
diff --git a/packages/CrashRecovery/services/java/com/android/server/RescueParty.java b/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
index 6766afc..b5951e8 100644
--- a/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
+++ b/packages/CrashRecovery/services/java/com/android/server/RescueParty.java
@@ -40,7 +40,6 @@
 import android.sysprop.CrashRecoveryProperties;
 import android.text.TextUtils;
 import android.util.ArraySet;
-import android.util.ExceptionUtils;
 import android.util.Log;
 import android.util.Slog;
 
@@ -136,7 +135,7 @@
         }
 
         // We're disabled on all engineering devices
-        if (Build.IS_ENG) {
+        if (Build.TYPE.equals("eng")) {
             Slog.v(TAG, "Disabled because of eng build");
             return true;
         }
@@ -144,7 +143,7 @@
         // We're disabled on userdebug devices connected over USB, since that's
         // a decent signal that someone is actively trying to debug the device,
         // or that it's in a lab environment.
-        if (Build.IS_USERDEBUG && isUsbActive()) {
+        if (Build.TYPE.equals("userdebug") && isUsbActive()) {
             Slog.v(TAG, "Disabled because of active USB connection");
             return true;
         }
@@ -478,9 +477,18 @@
         }
     }
 
+    private static String getCompleteMessage(Throwable t) {
+        final StringBuilder builder = new StringBuilder();
+        builder.append(t.getMessage());
+        while ((t = t.getCause()) != null) {
+            builder.append(": ").append(t.getMessage());
+        }
+        return builder.toString();
+    }
+
     private static void logRescueException(int level, @Nullable String failedPackageName,
             Throwable t) {
-        final String msg = ExceptionUtils.getCompleteMessage(t);
+        final String msg = getCompleteMessage(t);
         EventLogTags.writeRescueFailure(level, msg);
         String failureMsg = "Failed rescue level " + levelToString(level);
         if (!TextUtils.isEmpty(failedPackageName)) {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index b47458b..c11356b 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -26,6 +26,8 @@
 import static android.Manifest.permission.OBSERVE_NETWORK_POLICY;
 import static android.Manifest.permission.READ_PHONE_STATE;
 import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK;
 import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
 import static android.app.ActivityManager.isProcStateConsideredInteraction;
 import static android.app.ActivityManager.printCapabilitiesSummary;
@@ -85,8 +87,10 @@
 import static android.net.NetworkPolicyManager.ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
 import static android.net.NetworkPolicyManager.ALLOWED_REASON_SYSTEM;
 import static android.net.NetworkPolicyManager.ALLOWED_REASON_TOP;
+import static android.net.NetworkPolicyManager.BACKGROUND_THRESHOLD_STATE;
 import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
+import static android.net.NetworkPolicyManager.FOREGROUND_THRESHOLD_STATE;
 import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
 import static android.net.NetworkPolicyManager.POLICY_NONE;
 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
@@ -97,6 +101,7 @@
 import static android.net.NetworkPolicyManager.RULE_REJECT_RESTRICTED_MODE;
 import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
 import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED;
+import static android.net.NetworkPolicyManager.TOP_THRESHOLD_STATE;
 import static android.net.NetworkPolicyManager.allowedReasonsToString;
 import static android.net.NetworkPolicyManager.blockedReasonsToString;
 import static android.net.NetworkPolicyManager.isProcStateAllowedNetworkWhileBackground;
@@ -334,6 +339,8 @@
     static final String TAG = NetworkPolicyLogger.TAG;
     private static final boolean LOGD = NetworkPolicyLogger.LOGD;
     private static final boolean LOGV = NetworkPolicyLogger.LOGV;
+    // TODO: b/304347838 - Remove once the feature is in staging.
+    private static final boolean ALWAYS_RESTRICT_BACKGROUND_NETWORK = false;
 
     /**
      * No opportunistic quota could be calculated from user data plan or data settings.
@@ -468,7 +475,8 @@
      */
     private static final int MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS = 24;
 
-    private static final int UID_MSG_STATE_CHANGED = 100;
+    @VisibleForTesting
+    static final int UID_MSG_STATE_CHANGED = 100;
     private static final int UID_MSG_GONE = 101;
 
     private static final String PROP_SUB_PLAN_OWNER = "persist.sys.sub_plan_owner";
@@ -1054,7 +1062,8 @@
                     }
 
                     // The flag is boot-stable.
-                    mBackgroundNetworkRestricted = Flags.networkBlockedForTopSleepingAndAbove();
+                    mBackgroundNetworkRestricted = ALWAYS_RESTRICT_BACKGROUND_NETWORK
+                            && Flags.networkBlockedForTopSleepingAndAbove();
                     if (mBackgroundNetworkRestricted) {
                         // Firewall rules and UidBlockedState will get updated in
                         // updateRulesForGlobalChangeAL below.
@@ -1074,8 +1083,6 @@
 
                 final int cutpoint = mBackgroundNetworkRestricted ? PROCESS_STATE_UNKNOWN
                         : NetworkPolicyManager.FOREGROUND_THRESHOLD_STATE;
-                // TODO (b/319728914): Filter out the unnecessary changes when using no cutpoint.
-
                 mActivityManagerInternal.registerNetworkPolicyUidObserver(mUidObserver, changes,
                         cutpoint, "android");
                 mNetworkManager.registerObserver(mAlertObserver);
@@ -1184,6 +1191,51 @@
     }
 
     final private IUidObserver mUidObserver = new UidObserver() {
+
+        /**
+         * Returns whether the uid state change information is relevant for the service. If the
+         * state information does not lead to any change in the network rules, it can safely be
+         * ignored.
+         */
+        @GuardedBy("mUidStateCallbackInfos")
+        private boolean isUidStateChangeRelevant(UidStateCallbackInfo previousInfo,
+                int newProcState, long newProcStateSeq, int newCapability) {
+            if (previousInfo.procStateSeq == -1) {
+                // No previous record. Always process the first state change callback.
+                return true;
+            }
+            if (newProcStateSeq <= previousInfo.procStateSeq) {
+                // Stale callback. Ignore.
+                return false;
+            }
+            final int previousProcState = previousInfo.procState;
+            if (mBackgroundNetworkRestricted && (previousProcState >= BACKGROUND_THRESHOLD_STATE)
+                    != (newProcState >= BACKGROUND_THRESHOLD_STATE)) {
+                // Proc-state change crossed BACKGROUND_THRESHOLD_STATE: Network rules for the
+                // BACKGROUND chain may change.
+                return true;
+            }
+            if ((previousProcState <= TOP_THRESHOLD_STATE)
+                    != (newProcState <= TOP_THRESHOLD_STATE)) {
+                // Proc-state change crossed TOP_THRESHOLD_STATE: Network rules for the
+                // LOW_POWER_STANDBY chain may change.
+                return true;
+            }
+            if ((previousProcState <= FOREGROUND_THRESHOLD_STATE)
+                    != (newProcState <= FOREGROUND_THRESHOLD_STATE)) {
+                // Proc-state change crossed FOREGROUND_THRESHOLD_STATE: Network rules for many
+                // different chains may change.
+                return true;
+            }
+            final int networkCapabilities = PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
+                    | PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK;
+            if ((previousInfo.capability & networkCapabilities)
+                    != (newCapability & networkCapabilities)) {
+                return true;
+            }
+            return false;
+        }
+
         @Override public void onUidStateChanged(int uid, int procState, long procStateSeq,
                 @ProcessCapability int capability) {
             synchronized (mUidStateCallbackInfos) {
@@ -1192,13 +1244,13 @@
                     callbackInfo = new UidStateCallbackInfo();
                     mUidStateCallbackInfos.put(uid, callbackInfo);
                 }
-                if (callbackInfo.procStateSeq == -1 || procStateSeq > callbackInfo.procStateSeq) {
+                if (isUidStateChangeRelevant(callbackInfo, procState, procStateSeq, capability)) {
                     callbackInfo.update(uid, procState, procStateSeq, capability);
-                }
-                if (!callbackInfo.isPending) {
-                    mUidEventHandler.obtainMessage(UID_MSG_STATE_CHANGED, callbackInfo)
-                            .sendToTarget();
-                    callbackInfo.isPending = true;
+                    if (!callbackInfo.isPending) {
+                        mUidEventHandler.obtainMessage(UID_MSG_STATE_CHANGED, callbackInfo)
+                                .sendToTarget();
+                        callbackInfo.isPending = true;
+                    }
                 }
             }
         }
diff --git a/services/core/java/com/android/server/pm/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java
index c81d6d7..1440a1e 100644
--- a/services/core/java/com/android/server/pm/permission/Permission.java
+++ b/services/core/java/com/android/server/pm/permission/Permission.java
@@ -146,6 +146,10 @@
         return mPermissionInfo.packageName;
     }
 
+    public boolean isReconciled() {
+        return mReconciled;
+    }
+
     public int getType() {
         return mType;
     }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 574f121..b92ae23 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -4137,6 +4137,10 @@
                     // being uninstalled,
                     continue;
                 }
+                // Don't remove config permissions and lose their GIDs.
+                if (bp.getType() == Permission.TYPE_CONFIG && !bp.isReconciled()) {
+                    continue;
+                }
                 // The target package is the source of the current permission
                 // Set to changed for either install or uninstall
                 changed = true;
diff --git a/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java
index 5f4852f..a25d67a 100644
--- a/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java
+++ b/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java
@@ -252,7 +252,7 @@
             }
 
             getInboundTransformInternal()
-                    .getIpSecTransformState(
+                    .requestIpSecTransformState(
                             new HandlerExecutor(mHandler), new IpSecTransformStateReceiver());
 
             // Schedule for next poll
@@ -302,7 +302,8 @@
                 "packetLossRate: "
                         + packetLossRate
                         + "% in the past "
-                        + (state.getTimestamp() - mLastIpSecTransformState.getTimestamp())
+                        + (state.getTimestampMillis()
+                                - mLastIpSecTransformState.getTimestampMillis())
                         + "ms";
 
         mLastIpSecTransformState = state;
diff --git a/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java b/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java
index a79f188..1704aa1 100644
--- a/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java
+++ b/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java
@@ -138,10 +138,10 @@
         }
 
         /** Poll an IpSecTransformState */
-        public void getIpSecTransformState(
+        public void requestIpSecTransformState(
                 @NonNull Executor executor,
                 @NonNull OutcomeReceiver<IpSecTransformState, RuntimeException> callback) {
-            ipSecTransform.getIpSecTransformState(executor, callback);
+            ipSecTransform.requestIpSecTransformState(executor, callback);
         }
 
         /** Close this instance and release the underlying resources */
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 4451cae..3492935 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
 import static android.Manifest.permission.NETWORK_STACK;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK;
@@ -58,9 +59,11 @@
 import static android.net.NetworkPolicyManager.ALLOWED_REASON_TOP;
 import static android.net.NetworkPolicyManager.BACKGROUND_THRESHOLD_STATE;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
+import static android.net.NetworkPolicyManager.FOREGROUND_THRESHOLD_STATE;
 import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
 import static android.net.NetworkPolicyManager.POLICY_NONE;
 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
+import static android.net.NetworkPolicyManager.TOP_THRESHOLD_STATE;
 import static android.net.NetworkPolicyManager.allowedReasonsToString;
 import static android.net.NetworkPolicyManager.blockedReasonsToString;
 import static android.net.NetworkPolicyManager.uidPoliciesToString;
@@ -88,6 +91,7 @@
 import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOOZED;
 import static com.android.server.net.NetworkPolicyManagerService.TYPE_RAPID;
 import static com.android.server.net.NetworkPolicyManagerService.TYPE_WARNING;
+import static com.android.server.net.NetworkPolicyManagerService.UID_MSG_STATE_CHANGED;
 import static com.android.server.net.NetworkPolicyManagerService.UidBlockedState.getEffectiveBlockedReasons;
 import static com.android.server.net.NetworkPolicyManagerService.normalizeTemplate;
 
@@ -196,13 +200,12 @@
 import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.usage.AppStandbyInternal;
 
-import com.google.common.util.concurrent.AbstractFuture;
-
 import libcore.io.Streams;
 
 import org.junit.After;
 import org.junit.Assume;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.MethodRule;
@@ -241,10 +244,8 @@
 import java.util.Set;
 import java.util.TimeZone;
 import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
@@ -2217,6 +2218,7 @@
         assertFalse(mService.isUidNetworkingBlocked(UID_B, false));
     }
 
+    @Ignore("Temporarily disabled until the feature is enabled")
     @Test
     @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
     public void testBackgroundChainOnTempAllowlistChange() throws Exception {
@@ -2246,6 +2248,126 @@
         assertTrue(mService.isUidNetworkingBlocked(UID_A, false));
     }
 
+    @Ignore("Temporarily disabled until the feature is enabled")
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
+    public void testUidObserverFiltersProcStateChanges() throws Exception {
+        int testProcStateSeq = 0;
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // First callback for uid.
+            callOnUidStatechanged(UID_A, BACKGROUND_THRESHOLD_STATE + 1, testProcStateSeq++,
+                    PROCESS_CAPABILITY_NONE);
+            assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // Doesn't cross the background threshold.
+            callOnUidStatechanged(UID_A, BACKGROUND_THRESHOLD_STATE, testProcStateSeq++,
+                    PROCESS_CAPABILITY_NONE);
+            assertFalse(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // Crosses the background threshold.
+            callOnUidStatechanged(UID_A, BACKGROUND_THRESHOLD_STATE - 1, testProcStateSeq++,
+                    PROCESS_CAPABILITY_NONE);
+            assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // Doesn't cross the foreground threshold.
+            callOnUidStatechanged(UID_A, FOREGROUND_THRESHOLD_STATE + 1, testProcStateSeq++,
+                    PROCESS_CAPABILITY_NONE);
+            assertFalse(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // Crosses the foreground threshold.
+            callOnUidStatechanged(UID_A, FOREGROUND_THRESHOLD_STATE, testProcStateSeq++,
+                    PROCESS_CAPABILITY_NONE);
+            assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // Doesn't cross the top threshold.
+            callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE + 1, testProcStateSeq++,
+                    PROCESS_CAPABILITY_NONE);
+            assertFalse(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // Crosses the top threshold.
+            callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE, testProcStateSeq++,
+                    PROCESS_CAPABILITY_NONE);
+            assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // Doesn't cross any other threshold.
+            callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE - 1, testProcStateSeq++,
+                    PROCESS_CAPABILITY_NONE);
+            assertFalse(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+    }
+
+    @Ignore("Temporarily disabled until the feature is enabled")
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
+    public void testUidObserverFiltersStaleChanges() throws Exception {
+        final int testProcStateSeq = 51;
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // First callback for uid.
+            callOnUidStatechanged(UID_B, BACKGROUND_THRESHOLD_STATE + 100, testProcStateSeq,
+                    PROCESS_CAPABILITY_NONE);
+            assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // Stale callback because the procStateSeq is smaller.
+            callOnUidStatechanged(UID_B, BACKGROUND_THRESHOLD_STATE - 100, testProcStateSeq - 10,
+                    PROCESS_CAPABILITY_NONE);
+            assertFalse(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+    }
+
+    @Ignore("Temporarily disabled until the feature is enabled")
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
+    public void testUidObserverFiltersCapabilityChanges() throws Exception {
+        int testProcStateSeq = 0;
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // First callback for uid.
+            callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE, testProcStateSeq++,
+                    PROCESS_CAPABILITY_NONE);
+            assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // The same process-state with one network capability added.
+            callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE, testProcStateSeq++,
+                    PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK);
+            assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // The same process-state with another network capability added.
+            callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE, testProcStateSeq++,
+                    PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
+                            | PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK);
+            assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // The same process-state with all capabilities, but no change in network capabilities.
+            callOnUidStatechanged(UID_A, TOP_THRESHOLD_STATE, testProcStateSeq++,
+                    PROCESS_CAPABILITY_ALL);
+            assertFalse(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+    }
+
     @Test
     public void testLowPowerStandbyAllowlist() throws Exception {
         // Chain background is also enabled but these procstates are important enough to be exempt.
@@ -2559,17 +2681,6 @@
         verify(mStatsManager).setDefaultGlobalAlert(anyLong());
     }
 
-    private static class TestAbstractFuture<T> extends AbstractFuture<T> {
-        @Override
-        public T get() throws InterruptedException, ExecutionException {
-            try {
-                return get(5, TimeUnit.SECONDS);
-            } catch (TimeoutException e) {
-                throw new RuntimeException(e);
-            }
-        }
-    }
-
     private static void assertTimeEquals(long expected, long actual) {
         if (expected != actual) {
             fail("expected " + formatTime(expected) + " but was actually " + formatTime(actual));
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java
index 9daba6a..1d7be2f 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java
@@ -144,7 +144,7 @@
         mTestLooper.dispatchAll();
 
         verify(mIpSecTransform)
-                .getIpSecTransformState(any(), mTransformStateReceiverCaptor.capture());
+                .requestIpSecTransformState(any(), mTransformStateReceiverCaptor.capture());
         return mTransformStateReceiverCaptor.getValue();
     }
 
@@ -210,7 +210,7 @@
         assertNull(mIpSecPacketLossDetector.getLastTransformState());
         mTestLooper.moveTimeForward(POLL_IPSEC_STATE_INTERVAL_MS);
         mTestLooper.dispatchAll();
-        verify(newTransform).getIpSecTransformState(any(), any());
+        verify(newTransform).requestIpSecTransformState(any(), any());
     }
 
     @Test