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
This commit is contained in:
Junyu Lai 2025-06-03 18:18:55 +08:00
commit 1ff0c98745
3 changed files with 122 additions and 3 deletions

View file

@ -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;

View file

@ -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<NetworkAgentInfo>()
// 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)
}
}

View file

@ -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<Int>) {
// Call mocked destroyLiveTcpSocketsByOwnerUids so that test can verify this method call
destroySocketsWrapper.destroyLiveTcpSocketsByOwnerUids(ownerUids)