Merge changes from topics "CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED", "CATEGORY_EVENT_DEACTIVATED_BY_USER" into tm-dev

* changes:
  Test VpnManager event for CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED
  Test VpnManager event for CATEGORY_EVENT_DEACTIVATED_BY_USER
diff --git a/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java b/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java
index 75c2ad1..68c1c57 100644
--- a/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java
+++ b/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java
@@ -352,15 +352,6 @@
         assertFalse(mTestMap.isEmpty());
         mTestMap.clear();
         assertTrue(mTestMap.isEmpty());
-
-        // Clearing an already-closed map throws.
-        mTestMap.close();
-        try {
-            mTestMap.clear();
-            fail("clearing already-closed map should throw");
-        } catch (IllegalStateException expected) {
-            // ParcelFileDescriptor.getFd throws IllegalStateException: Already closed.
-        }
     }
 
     @Test
diff --git a/service-t/src/com/android/server/net/NetworkStatsObservers.java b/service-t/src/com/android/server/net/NetworkStatsObservers.java
index df4e7f5..1cd670a 100644
--- a/service-t/src/com/android/server/net/NetworkStatsObservers.java
+++ b/service-t/src/com/android/server/net/NetworkStatsObservers.java
@@ -198,7 +198,7 @@
 
         if (LOG) Log.d(TAG, "Unregistering " + requestInfo);
         mDataUsageRequests.remove(request.requestId);
-        mDataUsageRequestsPerUid.decrementCountOrThrow(callingUid);
+        mDataUsageRequestsPerUid.decrementCountOrThrow(requestInfo.mCallingUid);
         requestInfo.unlinkDeathRecipient();
         requestInfo.callCallback(NetworkStatsManager.CALLBACK_RELEASED);
     }
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java
index 63e6501..dc09bc2 100644
--- a/service-t/src/com/android/server/net/NetworkStatsService.java
+++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -253,7 +253,8 @@
             "netstats_import_legacy_target_attempts";
     static final int DEFAULT_NETSTATS_IMPORT_LEGACY_TARGET_ATTEMPTS = 1;
     static final String NETSTATS_IMPORT_ATTEMPTS_COUNTER_NAME = "import.attempts";
-    static final String NETSTATS_IMPORT_SUCCESS_COUNTER_NAME = "import.successes";
+    static final String NETSTATS_IMPORT_SUCCESSES_COUNTER_NAME = "import.successes";
+    static final String NETSTATS_IMPORT_FALLBACKS_COUNTER_NAME = "import.fallbacks";
 
     private final Context mContext;
     private final NetworkStatsFactory mStatsFactory;
@@ -273,10 +274,11 @@
     private final AlertObserver mAlertObserver = new AlertObserver();
 
     // Persistent counters that backed by AtomicFile which stored in the data directory as a file,
-    // to track attempts/successes count across reboot. Note that these counter values will be
-    // rollback as the module rollbacks.
+    // to track attempts/successes/fallbacks count across reboot. Note that these counter values
+    // will be rollback as the module rollbacks.
     private PersistentInt mImportLegacyAttemptsCounter = null;
     private PersistentInt mImportLegacySuccessesCounter = null;
+    private PersistentInt mImportLegacyFallbacksCounter = null;
 
     @VisibleForTesting
     public static final String ACTION_NETWORK_STATS_POLL =
@@ -619,21 +621,14 @@
         }
 
         /**
-         * Create the persistent counter that counts total import legacy stats attempts.
+         * Create a persistent counter for given directory and name.
          */
-        public PersistentInt createImportLegacyAttemptsCounter(@NonNull Path path)
+        public PersistentInt createPersistentCounter(@NonNull Path dir, @NonNull String name)
                 throws IOException {
             // TODO: Modify PersistentInt to call setStartTime every time a write is made.
             //  Create and pass a real logger here.
-            return new PersistentInt(path.toString(), null /* logger */);
-        }
-
-        /**
-         * Create the persistent counter that counts total import legacy stats successes.
-         */
-        public PersistentInt createImportLegacySuccessesCounter(@NonNull Path path)
-                throws IOException {
-            return new PersistentInt(path.toString(), null /* logger */);
+            final String path = dir.resolve(name).toString();
+            return new PersistentInt(path, null /* logger */);
         }
 
         /**
@@ -911,10 +906,12 @@
             return;
         }
         try {
-            mImportLegacyAttemptsCounter = mDeps.createImportLegacyAttemptsCounter(
-                    mStatsDir.toPath().resolve(NETSTATS_IMPORT_ATTEMPTS_COUNTER_NAME));
-            mImportLegacySuccessesCounter = mDeps.createImportLegacySuccessesCounter(
-                    mStatsDir.toPath().resolve(NETSTATS_IMPORT_SUCCESS_COUNTER_NAME));
+            mImportLegacyAttemptsCounter = mDeps.createPersistentCounter(mStatsDir.toPath(),
+                    NETSTATS_IMPORT_ATTEMPTS_COUNTER_NAME);
+            mImportLegacySuccessesCounter = mDeps.createPersistentCounter(mStatsDir.toPath(),
+                    NETSTATS_IMPORT_SUCCESSES_COUNTER_NAME);
+            mImportLegacyFallbacksCounter = mDeps.createPersistentCounter(mStatsDir.toPath(),
+                    NETSTATS_IMPORT_FALLBACKS_COUNTER_NAME);
         } catch (IOException e) {
             Log.wtf(TAG, "Failed to create persistent counters, skip.", e);
             return;
@@ -922,15 +919,24 @@
 
         final int targetAttempts = mDeps.getImportLegacyTargetAttempts();
         final int attempts;
+        final int fallbacks;
         try {
             attempts = mImportLegacyAttemptsCounter.get();
+            fallbacks = mImportLegacyFallbacksCounter.get();
         } catch (IOException e) {
-            Log.wtf(TAG, "Failed to read attempts counter, skip.", e);
+            Log.wtf(TAG, "Failed to read counters, skip.", e);
             return;
         }
-        if (attempts >= targetAttempts) return;
+        // If fallbacks is not zero, proceed with reading only to give signals from dogfooders.
+        // TODO(b/233752318): Remove fallbacks counter check before T formal release.
+        if (attempts >= targetAttempts && fallbacks == 0) return;
 
-        Log.i(TAG, "Starting import : attempts " + attempts + "/" + targetAttempts);
+        final boolean dryRunImportOnly = (attempts >= targetAttempts);
+        if (dryRunImportOnly) {
+            Log.i(TAG, "Starting import : only perform read");
+        } else {
+            Log.i(TAG, "Starting import : attempts " + attempts + "/" + targetAttempts);
+        }
 
         final MigrationInfo[] migrations = new MigrationInfo[]{
                 new MigrationInfo(mDevRecorder), new MigrationInfo(mXtRecorder),
@@ -987,6 +993,10 @@
                 }
             }
 
+            // For cases where the fallbacks is not zero but target attempts counts reached,
+            // only perform reads above and return here.
+            if (dryRunImportOnly) return;
+
             // Find the latest end time.
             for (final MigrationInfo migration : migrations) {
                 final long migrationEnd = migration.collection.getEndMillis();
@@ -1009,11 +1019,7 @@
                 migration.recorder.importCollectionLocked(migration.collection);
             }
 
-            if (endedWithFallback) {
-                Log.wtf(TAG, "Imported platform collections with legacy fallback");
-            } else {
-                Log.i(TAG, "Successfully imported platform collections");
-            }
+            // Success normally or uses fallback method.
         } catch (Throwable e) {
             // The code above calls OEM code that may behave differently across devices.
             // It can throw any exception including RuntimeExceptions and
@@ -1053,10 +1059,17 @@
         // Success ! No need to import again next time.
         try {
             mImportLegacyAttemptsCounter.set(targetAttempts);
-            // The successes counter is only for debugging. Hence, the synchronization
-            // between these two counters are not very critical.
-            final int successCount = mImportLegacySuccessesCounter.get();
-            mImportLegacySuccessesCounter.set(successCount + 1);
+            if (endedWithFallback) {
+                Log.wtf(TAG, "Imported platform collections with legacy fallback");
+                final int fallbacksCount = mImportLegacyFallbacksCounter.get();
+                mImportLegacyFallbacksCounter.set(fallbacksCount + 1);
+            } else {
+                Log.i(TAG, "Successfully imported platform collections");
+                // The successes counter is only for debugging. Hence, the synchronization
+                // between successes counter and attempts counter are not very critical.
+                final int successCount = mImportLegacySuccessesCounter.get();
+                mImportLegacySuccessesCounter.set(successCount + 1);
+            }
         } catch (IOException e) {
             Log.wtf(TAG, "Succeed but failed to update counters.", e);
         }
@@ -2478,6 +2491,9 @@
                     pw.print("platform legacy stats import successes count",
                             mImportLegacySuccessesCounter.get());
                     pw.println();
+                    pw.print("platform legacy stats import fallbacks count",
+                            mImportLegacyFallbacksCounter.get());
+                    pw.println();
                 } catch (IOException e) {
                     pw.println("(failed to dump platform legacy stats import counters)");
                 }
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
index e4a9ebe..108a86e 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
@@ -219,7 +219,10 @@
             Log.d(TAG, "Expecting count " + expectedCount + " but actual is " + count + " after "
                     + attempts + " attempts; sleeping "
                     + SLEEP_TIME_SEC + " seconds before trying again");
-            SystemClock.sleep(SLEEP_TIME_SEC * SECOND_IN_MS);
+            // No sleep after the last turn
+            if (attempts <= maxAttempts) {
+                SystemClock.sleep(SLEEP_TIME_SEC * SECOND_IN_MS);
+            }
         } while (attempts <= maxAttempts);
         assertEquals("Number of expected broadcasts for " + receiverName + " not reached after "
                 + maxAttempts * SLEEP_TIME_SEC + " seconds", expectedCount, count);
@@ -330,7 +333,10 @@
             }
             Log.d(TAG, "App not on background state (" + state + ") on attempt #" + i
                     + "; sleeping 1s before trying again");
-            SystemClock.sleep(SECOND_IN_MS);
+            // No sleep after the last turn
+            if (i < maxTries) {
+                SystemClock.sleep(SECOND_IN_MS);
+            }
         }
         fail("App2 (" + mUid + ") is not on background state after "
                 + maxTries + " attempts: " + state);
@@ -349,7 +355,10 @@
             Log.d(TAG, "App not on foreground state on attempt #" + i
                     + "; sleeping 1s before trying again");
             turnScreenOn();
-            SystemClock.sleep(SECOND_IN_MS);
+            // No sleep after the last turn
+            if (i < maxTries) {
+                SystemClock.sleep(SECOND_IN_MS);
+            }
         }
         fail("App2 (" + mUid + ") is not on foreground state after "
                 + maxTries + " attempts: " + state);
@@ -367,7 +376,10 @@
             }
             Log.d(TAG, "App not on foreground service state on attempt #" + i
                     + "; sleeping 1s before trying again");
-            SystemClock.sleep(SECOND_IN_MS);
+            // No sleep after the last turn
+            if (i < maxTries) {
+                SystemClock.sleep(SECOND_IN_MS);
+            }
         }
         fail("App2 (" + mUid + ") is not on foreground service state after "
                 + maxTries + " attempts: " + state);
@@ -508,7 +520,10 @@
             Log.v(TAG, "Command '" + command + "' returned '" + result + " instead of '"
                     + checker.getExpected() + "' on attempt #" + i
                     + "; sleeping " + napTimeSeconds + "s before trying again");
-            SystemClock.sleep(napTimeSeconds * SECOND_IN_MS);
+            // No sleep after the last turn
+            if (i < maxTries) {
+                SystemClock.sleep(napTimeSeconds * SECOND_IN_MS);
+            }
         }
         fail("Command '" + command + "' did not return '" + checker.getExpected() + "' after "
                 + maxTries
@@ -580,7 +595,10 @@
             }
             Log.v(TAG, list + " check for uid " + uid + " doesn't match yet (expected "
                     + expected + ", got " + actual + "); sleeping 1s before polling again");
-            SystemClock.sleep(SECOND_IN_MS);
+            // No sleep after the last turn
+            if (i < maxTries) {
+                SystemClock.sleep(SECOND_IN_MS);
+            }
         }
         fail(list + " check for uid " + uid + " failed: expected " + expected + ", got " + actual
                 + ". Full list: " + uids);
@@ -740,7 +758,8 @@
 
     protected void assertAppIdle(boolean enabled) throws Exception {
         try {
-            assertDelayedShellCommand("am get-inactive " + TEST_APP2_PKG, 15, 2, "Idle=" + enabled);
+            assertDelayedShellCommand("am get-inactive " + TEST_APP2_PKG,
+                    30 /* maxTries */, 1 /* napTimeSeconds */, "Idle=" + enabled);
         } catch (Throwable e) {
             throw e;
         }
@@ -767,7 +786,10 @@
                 return;
             }
             Log.v(TAG, "app2 receiver is not ready yet; sleeping 1s before polling again");
-            SystemClock.sleep(SECOND_IN_MS);
+            // No sleep after the last turn
+            if (i < maxTries) {
+                SystemClock.sleep(SECOND_IN_MS);
+            }
         }
         fail("app2 receiver is not ready in " + mUid);
     }
@@ -832,8 +854,6 @@
             return;
         } else if (type == TYPE_COMPONENT_ACTIVTIY) {
             turnScreenOn();
-            // Wait for screen-on state to propagate through the system.
-            SystemClock.sleep(2000);
             final CountDownLatch latch = new CountDownLatch(1);
             final Intent launchIntent = getIntentForComponent(type);
             final Bundle extras = new Bundle();
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
index bffa7b0..aa58ff9 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
@@ -27,6 +27,7 @@
 import android.os.Bundle;
 import android.os.RemoteCallback;
 import android.util.Log;
+import android.view.WindowManager;
 
 import androidx.annotation.GuardedBy;
 
@@ -42,6 +43,8 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         Log.d(TAG, "MyActivity.onCreate()");
+
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
     }
 
     @Override
diff --git a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
index 088d202..33a0a83 100644
--- a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
+++ b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
@@ -52,9 +52,7 @@
 import androidx.test.runner.AndroidJUnit4
 import com.android.net.module.util.ArrayTrackRecord
 import com.android.net.module.util.TrackRecord
-import com.android.networkstack.apishim.ConstantsShim
 import com.android.networkstack.apishim.NsdShimImpl
-import com.android.testutils.SC_V2
 import com.android.testutils.TestableNetworkAgent
 import com.android.testutils.TestableNetworkCallback
 import com.android.testutils.runAsShell
@@ -249,9 +247,11 @@
     fun setUp() {
         handlerThread.start()
 
-        runAsShell(MANAGE_TEST_NETWORKS) {
-            testNetwork1 = createTestNetwork()
-            testNetwork2 = createTestNetwork()
+        if (TestUtils.shouldTestTApis()) {
+            runAsShell(MANAGE_TEST_NETWORKS) {
+                testNetwork1 = createTestNetwork()
+                testNetwork2 = createTestNetwork()
+            }
         }
     }
 
@@ -290,9 +290,11 @@
 
     @After
     fun tearDown() {
-        runAsShell(MANAGE_TEST_NETWORKS) {
-            testNetwork1.close(cm)
-            testNetwork2.close(cm)
+        if (TestUtils.shouldTestTApis()) {
+            runAsShell(MANAGE_TEST_NETWORKS) {
+                testNetwork1.close(cm)
+                testNetwork2.close(cm)
+            }
         }
         handlerThread.quitSafely()
     }
@@ -419,7 +421,7 @@
     @Test
     fun testNsdManager_DiscoverOnNetwork() {
         // This test requires shims supporting T+ APIs (discovering on specific network)
-        assumeTrue(ConstantsShim.VERSION > SC_V2)
+        assumeTrue(TestUtils.shouldTestTApis())
 
         val si = NsdServiceInfo()
         si.serviceType = SERVICE_TYPE
@@ -453,7 +455,7 @@
     @Test
     fun testNsdManager_DiscoverWithNetworkRequest() {
         // This test requires shims supporting T+ APIs (discovering on network request)
-        assumeTrue(ConstantsShim.VERSION > SC_V2)
+        assumeTrue(TestUtils.shouldTestTApis())
 
         val si = NsdServiceInfo()
         si.serviceType = SERVICE_TYPE
@@ -518,7 +520,7 @@
     @Test
     fun testNsdManager_ResolveOnNetwork() {
         // This test requires shims supporting T+ APIs (NsdServiceInfo.network)
-        assumeTrue(ConstantsShim.VERSION > SC_V2)
+        assumeTrue(TestUtils.shouldTestTApis())
 
         val si = NsdServiceInfo()
         si.serviceType = SERVICE_TYPE
@@ -562,7 +564,7 @@
     @Test
     fun testNsdManager_RegisterOnNetwork() {
         // This test requires shims supporting T+ APIs (NsdServiceInfo.network)
-        assumeTrue(ConstantsShim.VERSION > SC_V2)
+        assumeTrue(TestUtils.shouldTestTApis())
 
         val si = NsdServiceInfo()
         si.serviceType = SERVICE_TYPE
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsObserversTest.java b/tests/unit/java/com/android/server/net/NetworkStatsObserversTest.java
index e8c9637..5747e10 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsObserversTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsObserversTest.java
@@ -274,8 +274,12 @@
 
         mStatsObservers.unregister(request, UID_BLUE);
         waitForObserverToIdle();
-
         Mockito.verifyZeroInteractions(mUsageCallbackBinder);
+
+        // Verify that system uid can unregister for other uids.
+        mStatsObservers.unregister(request, Process.SYSTEM_UID);
+        waitForObserverToIdle();
+        mUsageCallback.expectOnCallbackReleased(request);
     }
 
     private NetworkIdentitySet makeTestIdentSet() {
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index f1820b3..d37ae23 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -67,6 +67,9 @@
 
 import static com.android.net.module.util.NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT;
 import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
+import static com.android.server.net.NetworkStatsService.NETSTATS_IMPORT_ATTEMPTS_COUNTER_NAME;
+import static com.android.server.net.NetworkStatsService.NETSTATS_IMPORT_FALLBACKS_COUNTER_NAME;
+import static com.android.server.net.NetworkStatsService.NETSTATS_IMPORT_SUCCESSES_COUNTER_NAME;
 import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
 
 import static org.junit.Assert.assertEquals;
@@ -141,6 +144,7 @@
 import com.android.testutils.TestableNetworkStatsProviderBinder;
 
 import java.io.File;
+import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.time.Clock;
@@ -239,6 +243,7 @@
     private int mImportLegacyTargetAttempts = 0;
     private @Mock PersistentInt mImportLegacyAttemptsCounter;
     private @Mock PersistentInt mImportLegacySuccessesCounter;
+    private @Mock PersistentInt mImportLegacyFallbacksCounter;
 
     private class MockContext extends BroadcastInterceptingContext {
         private final Context mBaseContext;
@@ -379,15 +384,18 @@
             }
 
             @Override
-            public PersistentInt createImportLegacyAttemptsCounter(
-                    @androidx.annotation.NonNull Path path) {
-                return mImportLegacyAttemptsCounter;
-            }
-
-            @Override
-            public PersistentInt createImportLegacySuccessesCounter(
-                    @androidx.annotation.NonNull Path path) {
-                return mImportLegacySuccessesCounter;
+            public PersistentInt createPersistentCounter(@androidx.annotation.NonNull Path dir,
+                    @androidx.annotation.NonNull String name) throws IOException {
+                switch (name) {
+                    case NETSTATS_IMPORT_ATTEMPTS_COUNTER_NAME:
+                        return mImportLegacyAttemptsCounter;
+                    case NETSTATS_IMPORT_SUCCESSES_COUNTER_NAME:
+                        return mImportLegacySuccessesCounter;
+                    case NETSTATS_IMPORT_FALLBACKS_COUNTER_NAME:
+                        return mImportLegacyFallbacksCounter;
+                    default:
+                        throw new IllegalArgumentException("Unknown counter name: " + name);
+                }
             }
 
             @Override
@@ -1861,7 +1869,7 @@
     }
 
     private NetworkStatsCollection getLegacyCollection(String prefix, boolean includeTags) {
-        final NetworkStatsRecorder recorder = makeTestRecorder(mLegacyStatsDir, PREFIX_DEV,
+        final NetworkStatsRecorder recorder = makeTestRecorder(mLegacyStatsDir, prefix,
                 mSettings.getDevConfig(), includeTags);
         return recorder.getOrLoadCompleteLocked();
     }