Add callbacks for service offload

Components that can provide offload like IpClient (packet
filter offloading) can use the API to register a callback to be notified
when offload is necessary.

Bug: 269240366
Test: atest CtsNetTestCases
Change-Id: I8080702f5b530001b88e79e504f4722ac01bc576
This commit is contained in:
Yuyang Huang
2023-02-14 22:59:37 +09:00
parent 50f07be9c2
commit 33fa4d268c
15 changed files with 939 additions and 30 deletions

View File

@@ -20,6 +20,8 @@ import android.net.InetAddresses.parseNumericAddress
import android.net.LinkAddress
import android.net.Network
import android.net.nsd.NsdServiceInfo
import android.net.nsd.OffloadEngine
import android.net.nsd.OffloadServiceInfo
import android.os.Build
import android.os.Handler
import android.os.HandlerThread
@@ -60,6 +62,8 @@ private val TEST_SOCKETKEY_1 = SocketKey(1001 /* interfaceIndex */)
private val TEST_SOCKETKEY_2 = SocketKey(1002 /* interfaceIndex */)
private val TEST_HOSTNAME = arrayOf("Android_test", "local")
private const val TEST_SUBTYPE = "_subtype"
private val TEST_INTERFACE1 = "test_iface1"
private val TEST_INTERFACE2 = "test_iface2"
private val SERVICE_1 = NsdServiceInfo("TestServiceName", "_advertisertest._tcp").apply {
port = 12345
@@ -94,6 +98,24 @@ private val LONG_ALL_NETWORKS_SERVICE =
network = null
}
private val OFFLOAD_SERVICEINFO = OffloadServiceInfo(
OffloadServiceInfo.Key("TestServiceName", "_advertisertest._tcp"),
listOf(TEST_SUBTYPE),
"Android_test.local",
null, /* rawOffloadPacket */
0, /* priority */
OffloadEngine.OFFLOAD_TYPE_REPLY.toLong()
)
private val OFFLOAD_SERVICEINFO_NO_SUBTYPE = OffloadServiceInfo(
OffloadServiceInfo.Key("TestServiceName", "_advertisertest._tcp"),
listOf(),
"Android_test.local",
null, /* rawOffloadPacket */
0, /* priority */
OffloadEngine.OFFLOAD_TYPE_REPLY.toLong()
)
@RunWith(DevSdkIgnoreRunner::class)
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
class MdnsAdvertiserTest {
@@ -123,6 +145,8 @@ class MdnsAdvertiserTest {
doReturn(true).`when`(mockInterfaceAdvertiser2).isProbing(anyInt())
doReturn(createEmptyNetworkInterface()).`when`(mockSocket1).getInterface()
doReturn(createEmptyNetworkInterface()).`when`(mockSocket2).getInterface()
doReturn(TEST_INTERFACE1).`when`(mockInterfaceAdvertiser1).socketInterfaceName
doReturn(TEST_INTERFACE2).`when`(mockInterfaceAdvertiser2).socketInterfaceName
}
@After
@@ -160,12 +184,15 @@ class MdnsAdvertiserTest {
)
doReturn(false).`when`(mockInterfaceAdvertiser1).isProbing(SERVICE_ID_1)
postSync { intAdvCbCaptor.value.onRegisterServiceSucceeded(
postSync { intAdvCbCaptor.value.onServiceProbingSucceeded(
mockInterfaceAdvertiser1, SERVICE_ID_1) }
verify(cb).onRegisterServiceSucceeded(eq(SERVICE_ID_1), argThat { it.matches(SERVICE_1) })
verify(cb).onOffloadStartOrUpdate(eq(TEST_INTERFACE1), eq(OFFLOAD_SERVICEINFO_NO_SUBTYPE))
postSync { socketCb.onInterfaceDestroyed(TEST_SOCKETKEY_1, mockSocket1) }
verify(mockInterfaceAdvertiser1).destroyNow()
postSync { intAdvCbCaptor.value.onDestroyed(mockSocket1) }
verify(cb).onOffloadStop(eq(TEST_INTERFACE1), eq(OFFLOAD_SERVICEINFO_NO_SUBTYPE))
}
@Test
@@ -195,14 +222,16 @@ class MdnsAdvertiserTest {
anyInt(), eq(ALL_NETWORKS_SERVICE), eq(TEST_SUBTYPE))
doReturn(false).`when`(mockInterfaceAdvertiser1).isProbing(SERVICE_ID_1)
postSync { intAdvCbCaptor1.value.onRegisterServiceSucceeded(
postSync { intAdvCbCaptor1.value.onServiceProbingSucceeded(
mockInterfaceAdvertiser1, SERVICE_ID_1) }
verify(cb).onOffloadStartOrUpdate(eq(TEST_INTERFACE1), eq(OFFLOAD_SERVICEINFO))
// Need both advertisers to finish probing and call onRegisterServiceSucceeded
verify(cb, never()).onRegisterServiceSucceeded(anyInt(), any())
doReturn(false).`when`(mockInterfaceAdvertiser2).isProbing(SERVICE_ID_1)
postSync { intAdvCbCaptor2.value.onRegisterServiceSucceeded(
postSync { intAdvCbCaptor2.value.onServiceProbingSucceeded(
mockInterfaceAdvertiser2, SERVICE_ID_1) }
verify(cb).onOffloadStartOrUpdate(eq(TEST_INTERFACE2), eq(OFFLOAD_SERVICEINFO))
verify(cb).onRegisterServiceSucceeded(eq(SERVICE_ID_1),
argThat { it.matches(ALL_NETWORKS_SERVICE) })
@@ -210,6 +239,8 @@ class MdnsAdvertiserTest {
postSync { advertiser.removeService(SERVICE_ID_1) }
verify(mockInterfaceAdvertiser1).removeService(SERVICE_ID_1)
verify(mockInterfaceAdvertiser2).removeService(SERVICE_ID_1)
verify(cb).onOffloadStop(eq(TEST_INTERFACE1), eq(OFFLOAD_SERVICEINFO))
verify(cb).onOffloadStop(eq(TEST_INTERFACE2), eq(OFFLOAD_SERVICEINFO))
// Interface advertisers call onDestroyed after sending exit announcements
postSync { intAdvCbCaptor1.value.onDestroyed(mockSocket1) }
@@ -285,12 +316,12 @@ class MdnsAdvertiserTest {
argThat { it.matches(expectedCaseInsensitiveRenamed) }, eq(null))
doReturn(false).`when`(mockInterfaceAdvertiser1).isProbing(SERVICE_ID_1)
postSync { intAdvCbCaptor.value.onRegisterServiceSucceeded(
postSync { intAdvCbCaptor.value.onServiceProbingSucceeded(
mockInterfaceAdvertiser1, SERVICE_ID_1) }
verify(cb).onRegisterServiceSucceeded(eq(SERVICE_ID_1), argThat { it.matches(SERVICE_1) })
doReturn(false).`when`(mockInterfaceAdvertiser1).isProbing(SERVICE_ID_2)
postSync { intAdvCbCaptor.value.onRegisterServiceSucceeded(
postSync { intAdvCbCaptor.value.onServiceProbingSucceeded(
mockInterfaceAdvertiser1, SERVICE_ID_2) }
verify(cb).onRegisterServiceSucceeded(eq(SERVICE_ID_2),
argThat { it.matches(expectedRenamed) })

View File

@@ -150,7 +150,7 @@ class MdnsInterfaceAdvertiserTest {
0L /* initialDelayMs */)
thread.waitForIdle(TIMEOUT_MS)
verify(cb).onRegisterServiceSucceeded(advertiser, TEST_SERVICE_ID_1)
verify(cb).onServiceProbingSucceeded(advertiser, TEST_SERVICE_ID_1)
// Remove the service: expect exit announcements
val testExitInfo = mock(ExitAnnouncementInfo::class.java)
@@ -256,7 +256,7 @@ class MdnsInterfaceAdvertiserTest {
val mockProbingInfo = mock(ProbingInfo::class.java)
doReturn(mockProbingInfo).`when`(repository).setServiceProbing(TEST_SERVICE_ID_1)
advertiser.restartProbingForConflict(TEST_SERVICE_ID_1)
advertiser.maybeRestartProbingForConflict(TEST_SERVICE_ID_1)
verify(prober).restartForConflict(mockProbingInfo)
}