From 1ff0c98745ed446cdca3af8fae636ffc365e9ec0 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 3 Jun 2025 18:18:55 +0800 Subject: [PATCH] Fix SatisfiedTime initialization mSatisfiedTime now initializes with the current time upon NRI creation, or copied when the copy constructor is called. Test: atest ConnectivityCoverageTests --test-filter 'NetworkRequestInfo*' --update-device Flag: EXEMPT controlled by kill switch Bug: 419123367 Change-Id: If707b96bf6ce5c6cb0287d5c2d6056591dd6769f --- .../android/server/ConnectivityService.java | 12 +- .../CSNetworkRequestInfoTest.kt | 105 ++++++++++++++++++ .../server/connectivityservice/base/CSTest.kt | 8 ++ 3 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 tests/unit/java/com/android/server/connectivityservice/CSNetworkRequestInfoTest.kt diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index f00233e422..2646be0e48 100644 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -1549,6 +1549,11 @@ public class ConnectivityService extends IConnectivityManager.Stub return SdkLevel.isAtLeastB(); } + /** Get SystemClock.elapsedRealtime() */ + public long getElapsedRealtime() { + return SystemClock.elapsedRealtime(); + } + /** * Get system properties to use in ConnectivityService. */ @@ -8121,7 +8126,7 @@ public class ConnectivityService extends IConnectivityManager.Stub @Nullable final NetworkRequest activeRequest) { mSatisfier = satisfier; mActiveRequest = activeRequest; - mSatisfiedTime = SystemClock.elapsedRealtime(); + mSatisfiedTime = mDeps.getElapsedRealtime(); } // The network currently satisfying this NRI. Only one request in an NRI can have a @@ -8132,10 +8137,10 @@ public class ConnectivityService extends IConnectivityManager.Stub return mSatisfier; } - private long mSatisfiedTime = 0; + private long mSatisfiedTime = mDeps.getElapsedRealtime(); /** - * Get timestamp (SystemClock.elapsedRealtime()) when the satisfier is set for this NRI. + * Get timestamp (SystemClock.elapsedRealtime()) when is set or removed. * Resets when the satisfier changes. */ public long getSatisfiedTime() { @@ -8318,6 +8323,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } setSatisfier(satisfier, activeRequest); } + mSatisfiedTime = nri.mSatisfiedTime; mMatchedNetIdWhenFrozen = nri.mMatchedNetIdWhenFrozen; mQueuedCallbacks = nri.mQueuedCallbacks; mMessenger = nri.mMessenger; diff --git a/tests/unit/java/com/android/server/connectivityservice/CSNetworkRequestInfoTest.kt b/tests/unit/java/com/android/server/connectivityservice/CSNetworkRequestInfoTest.kt new file mode 100644 index 0000000000..d8b5138f2c --- /dev/null +++ b/tests/unit/java/com/android/server/connectivityservice/CSNetworkRequestInfoTest.kt @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server + +import android.net.ConnectivityManager +import android.net.NetworkCapabilities +import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET +import android.net.NetworkRequest +import android.os.Build +import com.android.server.connectivity.NetworkAgentInfo +import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.DevSdkIgnoreRunner +import java.util.Collections +import kotlin.test.assertEquals +import org.junit.Test +import org.junit.runner.RunWith + +private const val TEST_UID = 1234 + +@RunWith(DevSdkIgnoreRunner::class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) +class CSNetworkRequestInfoTest : CSTest() { + /** + * Helper function to create a NetworkRequestInfo for internal system usage. + * This simplifies NRI creation within the test. + */ + private fun createNri(request: NetworkRequest): ConnectivityService.NetworkRequestInfo { + // This uses the internal constructor to create an NRI as the system would. + return service.NetworkRequestInfo( + TEST_UID, + Collections.singletonList(request), + 0 // preferenceOrder + ) + } + + @Test + fun testGetSatisfiedTime() { + // Setup: Create a basic NetworkRequestInfo and mock a network. + val t0 = 50L + deps.elapsedRealtime = t0 + val capabilities = NetworkCapabilities.Builder() + .addCapability(NET_CAPABILITY_INTERNET) + .build() + val request = NetworkRequest( + capabilities, + ConnectivityManager.TYPE_NONE, + 1 /* requestId */, + NetworkRequest.Type.REQUEST + ) + val nri = createNri(request) + val nai = mock() + + // Initially, satisfiedTime should be the created time, which is the "null" start + // to satisfying the request. + assertEquals(t0, nri.satisfiedTime) + + // When a network satisfies the request at t=100, verify the satisfiedTime updates. + val t1 = 100L + deps.elapsedRealtime = t1 + nri.setSatisfier(nai, request) + assertEquals(t1, nri.satisfiedTime) + + // When the request becomes unsatisfied at t=250, verify the satisfiedTime updates. + val t2 = 250L + deps.elapsedRealtime = t2 + nri.setSatisfier(null, null) + assertEquals(t2, nri.satisfiedTime) + } + + @Test + fun testCopyConstructorPreservesSatisfiedTime() { + val capabilities = NetworkCapabilities.Builder() + .addCapability(NET_CAPABILITY_INTERNET) + .build() + val request = NetworkRequest( + capabilities, + ConnectivityManager.TYPE_NONE, + 1 /* requestId */, + NetworkRequest.Type.REQUEST + ) + val t1 = 100L + deps.elapsedRealtime = t1 + val originalNri = createNri(request) + + // Change time, and verify it is not used by copy constructor. + val t2 = 12345L + deps.elapsedRealtime = t2 + val newNri = service.NetworkRequestInfo(originalNri, Collections.singletonList(request)) + assertEquals(t1, newNri.satisfiedTime) + } +} diff --git a/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt b/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt index 1d05e4ad20..1a97e3a9c0 100644 --- a/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt +++ b/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt @@ -447,6 +447,14 @@ open class CSTest { override fun getCallingUid() = if (callingUid == CALLING_UID_UNMOCKED) super.getCallingUid() else callingUid + private var mockedElapsedTime = 0L + + override fun getElapsedRealtime() = mockedElapsedTime + + fun setElapsedRealtime(time: Long) { + visibleOnHandlerThread(csHandler) { mockedElapsedTime = time } + } + override fun destroyLiveTcpSocketsByOwnerUids(ownerUids: Set) { // Call mocked destroyLiveTcpSocketsByOwnerUids so that test can verify this method call destroySocketsWrapper.destroyLiveTcpSocketsByOwnerUids(ownerUids)