Merge "isEthernet() - ARPHRD_PPP does not require ethernet headers"
diff --git a/service/Android.bp b/service/Android.bp
index 3ff7a7c..02717f7 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -68,7 +68,6 @@
"dnsresolver_aidl_interface-V9-java",
"modules-utils-build",
"modules-utils-shell-command-handler",
- "modules-utils-statemachine",
"net-utils-device-common",
"net-utils-device-common-netlink",
"net-utils-framework-common",
diff --git a/service/jarjar-rules.txt b/service/jarjar-rules.txt
index 4ba6837..e5d1a88 100644
--- a/service/jarjar-rules.txt
+++ b/service/jarjar-rules.txt
@@ -8,10 +8,7 @@
# the one in com.android.internal.util
rule android.util.IndentingPrintWriter* com.android.connectivity.@0
rule com.android.internal.util.IndentingPrintWriter* com.android.connectivity.@0
-rule com.android.internal.util.IState* com.android.connectivity.@0
rule com.android.internal.util.MessageUtils* com.android.connectivity.@0
-rule com.android.internal.util.State* com.android.connectivity.@0
-rule com.android.internal.util.StateMachine* com.android.connectivity.@0
rule com.android.internal.util.WakeupMessage* com.android.connectivity.@0
rule com.android.internal.messages.** com.android.connectivity.@0
diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp
index 1872327..81c30b1 100644
--- a/tests/cts/net/Android.bp
+++ b/tests/cts/net/Android.bp
@@ -69,7 +69,7 @@
// devices.
android_test {
name: "CtsNetTestCases",
- defaults: ["CtsNetTestCasesDefaults"],
+ defaults: ["CtsNetTestCasesDefaults", "NetworkStackNextEnableDefaults"],
// TODO: CTS should not depend on the entirety of the networkstack code.
static_libs: [
"NetworkStackApiCurrentLib",
diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
index 9f98e3f..a378aa7 100644
--- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
+++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
@@ -40,7 +40,6 @@
import android.net.cts.util.CtsNetUtils
import android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL
import android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL
-import android.net.wifi.WifiManager
import android.os.Build
import android.platform.test.annotations.AppModeFull
import android.provider.DeviceConfig
@@ -77,7 +76,7 @@
private const val LOCALHOST_HOSTNAME = "localhost"
// Re-connecting to the AP, obtaining an IP address, revalidating can take a long time
-private const val WIFI_CONNECT_TIMEOUT_MS = 120_000L
+private const val WIFI_CONNECT_TIMEOUT_MS = 40_000L
private const val TEST_TIMEOUT_MS = 10_000L
private const val TAG = "CaptivePortalTest"
@@ -94,7 +93,6 @@
@RunWith(AndroidJUnit4::class)
class CaptivePortalTest {
private val context: android.content.Context by lazy { getInstrumentation().context }
- private val wm by lazy { context.getSystemService(WifiManager::class.java) }
private val cm by lazy { context.getSystemService(ConnectivityManager::class.java) }
private val pm by lazy { context.packageManager }
private val utils by lazy { CtsNetUtils(context) }
diff --git a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
index e17200e..05e40f9 100644
--- a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
+++ b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
@@ -306,14 +306,18 @@
}
try {
+ if (wasWifiConnected) {
+ // Make sure the callback is registered before turning off WiFi.
+ callback.waitForAvailable();
+ }
SystemUtil.runShellCommand("svc wifi disable");
if (wasWifiConnected) {
// Ensure we get both an onLost callback and a CONNECTIVITY_ACTION.
assertNotNull("Did not receive onLost callback after disabling wifi",
callback.waitForLost());
- }
- if (wasWifiConnected && expectLegacyBroadcast) {
- assertTrue("Wifi failed to reach DISCONNECTED state.", receiver.waitForState());
+ if (expectLegacyBroadcast) {
+ assertTrue("Wifi failed to reach DISCONNECTED state.", receiver.waitForState());
+ }
}
} catch (InterruptedException ex) {
fail("disconnectFromWifi was interrupted");
@@ -599,12 +603,14 @@
@Override
public void onAvailable(Network network) {
+ Log.i(TAG, "CtsNetUtils TestNetworkCallback onAvailable " + network);
currentNetwork = network;
mAvailableCv.open();
}
@Override
public void onLost(Network network) {
+ Log.i(TAG, "CtsNetUtils TestNetworkCallback onLost " + network);
lastLostNetwork = network;
if (network.equals(currentNetwork)) {
mAvailableCv.close();
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp
index 448869d..bd30b77 100644
--- a/tests/unit/Android.bp
+++ b/tests/unit/Android.bp
@@ -93,6 +93,17 @@
]
}
+// Subset of services-core used to by ConnectivityService tests to test VPN realistically.
+// This is stripped by jarjar (see rules below) from other unrelated classes, so tests do not
+// include most classes from services-core, which are unrelated and cause wrong code coverage
+// calculations.
+java_library {
+ name: "services.core-vpn",
+ static_libs: ["services.core"],
+ jarjar_rules: "vpn-jarjar-rules.txt",
+ visibility: ["//visibility:private"],
+}
+
android_library {
name: "FrameworksNetTestsLib",
min_sdk_version: "30",
@@ -116,11 +127,11 @@
"framework-protos",
"mockito-target-minus-junit4",
"net-tests-utils",
+ "net-utils-services-common",
"platform-compat-test-rules",
"platform-test-annotations",
"service-connectivity-pre-jarjar",
- "services.core",
- "services.net",
+ "services.core-vpn",
],
libs: [
"android.net.ipsec.ike.stubs.module_lib",
@@ -144,6 +155,8 @@
srcs: [":non-connectivity-module-test"],
test_suites: ["device-tests"],
static_libs: [
+ "services.core",
+ "services.net",
"FrameworksNetTestsLib",
],
libs: [
diff --git a/tests/unit/java/android/net/nsd/NsdManagerTest.java b/tests/unit/java/android/net/nsd/NsdManagerTest.java
index de77d23..30b8fcd 100644
--- a/tests/unit/java/android/net/nsd/NsdManagerTest.java
+++ b/tests/unit/java/android/net/nsd/NsdManagerTest.java
@@ -20,38 +20,32 @@
import static libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.compat.testing.PlatformCompatChangeRule;
import android.content.Context;
import android.os.Build;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
import androidx.test.filters.SmallTest;
-import com.android.internal.util.AsyncChannel;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
-import com.android.testutils.HandlerUtils;
+import com.android.testutils.ExceptionUtils;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -67,9 +61,10 @@
@Mock Context mContext;
@Mock INsdManager mService;
- MockServiceHandler mServiceHandler;
+ @Mock INsdServiceConnector mServiceConn;
NsdManager mManager;
+ INsdManagerCallback mCallback;
long mTimeoutMs = 200; // non-final so that tests can adjust the value.
@@ -77,91 +72,85 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mServiceHandler = spy(MockServiceHandler.create(mContext));
- doReturn(new Messenger(mServiceHandler)).when(mService).getMessenger();
- }
-
- @After
- public void tearDown() throws Exception {
- HandlerUtils.waitForIdle(mServiceHandler, mTimeoutMs);
- mServiceHandler.chan.disconnect();
- mServiceHandler.stop();
- if (mManager != null) {
- mManager.disconnect();
- }
+ doReturn(mServiceConn).when(mService).connect(any());
+ mManager = new NsdManager(mContext, mService);
+ final ArgumentCaptor<INsdManagerCallback> cbCaptor = ArgumentCaptor.forClass(
+ INsdManagerCallback.class);
+ verify(mService).connect(cbCaptor.capture());
+ mCallback = cbCaptor.getValue();
}
@Test
@EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
- public void testResolveServiceS() {
- mManager = makeNsdManagerS();
+ public void testResolveServiceS() throws Exception {
+ verify(mServiceConn, never()).startDaemon();
doTestResolveService();
}
@Test
@DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
- public void testResolveServicePreS() {
- mManager = makeNsdManagerPreS();
+ public void testResolveServicePreS() throws Exception {
+ verify(mServiceConn).startDaemon();
doTestResolveService();
}
@Test
@EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
- public void testDiscoverServiceS() {
- mManager = makeNsdManagerS();
+ public void testDiscoverServiceS() throws Exception {
+ verify(mServiceConn, never()).startDaemon();
doTestDiscoverService();
}
@Test
@DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
- public void testDiscoverServicePreS() {
- mManager = makeNsdManagerPreS();
+ public void testDiscoverServicePreS() throws Exception {
+ verify(mServiceConn).startDaemon();
doTestDiscoverService();
}
@Test
@EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
- public void testParallelResolveServiceS() {
- mManager = makeNsdManagerS();
+ public void testParallelResolveServiceS() throws Exception {
+ verify(mServiceConn, never()).startDaemon();
doTestParallelResolveService();
}
@Test
@DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
- public void testParallelResolveServicePreS() {
- mManager = makeNsdManagerPreS();
+ public void testParallelResolveServicePreS() throws Exception {
+ verify(mServiceConn).startDaemon();
doTestParallelResolveService();
}
@Test
@EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
- public void testInvalidCallsS() {
- mManager = makeNsdManagerS();
+ public void testInvalidCallsS() throws Exception {
+ verify(mServiceConn, never()).startDaemon();
doTestInvalidCalls();
}
@Test
@DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
- public void testInvalidCallsPreS() {
- mManager = makeNsdManagerPreS();
+ public void testInvalidCallsPreS() throws Exception {
+ verify(mServiceConn).startDaemon();
doTestInvalidCalls();
}
@Test
@EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
- public void testRegisterServiceS() {
- mManager = makeNsdManagerS();
+ public void testRegisterServiceS() throws Exception {
+ verify(mServiceConn, never()).startDaemon();
doTestRegisterService();
}
@Test
@DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
- public void testRegisterServicePreS() {
- mManager = makeNsdManagerPreS();
+ public void testRegisterServicePreS() throws Exception {
+ verify(mServiceConn).startDaemon();
doTestRegisterService();
}
- public void doTestResolveService() {
+ private void doTestResolveService() throws Exception {
NsdManager manager = mManager;
NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
@@ -169,18 +158,19 @@
NsdManager.ResolveListener listener = mock(NsdManager.ResolveListener.class);
manager.resolveService(request, listener);
- int key1 = verifyRequest(NsdManager.RESOLVE_SERVICE);
+ int key1 = getRequestKey(req -> verify(mServiceConn).resolveService(req.capture(), any()));
int err = 33;
- sendResponse(NsdManager.RESOLVE_SERVICE_FAILED, err, key1, null);
+ mCallback.onResolveServiceFailed(key1, err);
verify(listener, timeout(mTimeoutMs).times(1)).onResolveFailed(request, err);
manager.resolveService(request, listener);
- int key2 = verifyRequest(NsdManager.RESOLVE_SERVICE);
- sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key2, reply);
+ int key2 = getRequestKey(req ->
+ verify(mServiceConn, times(2)).resolveService(req.capture(), any()));
+ mCallback.onResolveServiceSucceeded(key2, reply);
verify(listener, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
}
- public void doTestParallelResolveService() {
+ private void doTestParallelResolveService() throws Exception {
NsdManager manager = mManager;
NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
@@ -190,19 +180,20 @@
NsdManager.ResolveListener listener2 = mock(NsdManager.ResolveListener.class);
manager.resolveService(request, listener1);
- int key1 = verifyRequest(NsdManager.RESOLVE_SERVICE);
+ int key1 = getRequestKey(req -> verify(mServiceConn).resolveService(req.capture(), any()));
manager.resolveService(request, listener2);
- int key2 = verifyRequest(NsdManager.RESOLVE_SERVICE);
+ int key2 = getRequestKey(req ->
+ verify(mServiceConn, times(2)).resolveService(req.capture(), any()));
- sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key2, reply);
- sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key1, reply);
+ mCallback.onResolveServiceSucceeded(key2, reply);
+ mCallback.onResolveServiceSucceeded(key1, reply);
verify(listener1, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
verify(listener2, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
}
- public void doTestRegisterService() {
+ private void doTestRegisterService() throws Exception {
NsdManager manager = mManager;
NsdServiceInfo request1 = new NsdServiceInfo("a_name", "a_type");
@@ -214,40 +205,43 @@
// Register two services
manager.registerService(request1, PROTOCOL, listener1);
- int key1 = verifyRequest(NsdManager.REGISTER_SERVICE);
+ int key1 = getRequestKey(req -> verify(mServiceConn).registerService(req.capture(), any()));
manager.registerService(request2, PROTOCOL, listener2);
- int key2 = verifyRequest(NsdManager.REGISTER_SERVICE);
+ int key2 = getRequestKey(req ->
+ verify(mServiceConn, times(2)).registerService(req.capture(), any()));
// First reques fails, second request succeeds
- sendResponse(NsdManager.REGISTER_SERVICE_SUCCEEDED, 0, key2, request2);
+ mCallback.onRegisterServiceSucceeded(key2, request2);
verify(listener2, timeout(mTimeoutMs).times(1)).onServiceRegistered(request2);
int err = 1;
- sendResponse(NsdManager.REGISTER_SERVICE_FAILED, err, key1, request1);
+ mCallback.onRegisterServiceFailed(key1, err);
verify(listener1, timeout(mTimeoutMs).times(1)).onRegistrationFailed(request1, err);
// Client retries first request, it succeeds
manager.registerService(request1, PROTOCOL, listener1);
- int key3 = verifyRequest(NsdManager.REGISTER_SERVICE);
+ int key3 = getRequestKey(req ->
+ verify(mServiceConn, times(3)).registerService(req.capture(), any()));
- sendResponse(NsdManager.REGISTER_SERVICE_SUCCEEDED, 0, key3, request1);
+ mCallback.onRegisterServiceSucceeded(key3, request1);
verify(listener1, timeout(mTimeoutMs).times(1)).onServiceRegistered(request1);
// First request is unregistered, it succeeds
manager.unregisterService(listener1);
- int key3again = verifyRequest(NsdManager.UNREGISTER_SERVICE);
+ int key3again = getRequestKey(req -> verify(mServiceConn).unregisterService(req.capture()));
assertEquals(key3, key3again);
- sendResponse(NsdManager.UNREGISTER_SERVICE_SUCCEEDED, 0, key3again, null);
+ mCallback.onUnregisterServiceSucceeded(key3again);
verify(listener1, timeout(mTimeoutMs).times(1)).onServiceUnregistered(request1);
// Second request is unregistered, it fails
manager.unregisterService(listener2);
- int key2again = verifyRequest(NsdManager.UNREGISTER_SERVICE);
+ int key2again = getRequestKey(req ->
+ verify(mServiceConn, times(2)).unregisterService(req.capture()));
assertEquals(key2, key2again);
- sendResponse(NsdManager.UNREGISTER_SERVICE_FAILED, err, key2again, null);
+ mCallback.onUnregisterServiceFailed(key2again, err);
verify(listener2, timeout(mTimeoutMs).times(1)).onUnregistrationFailed(request2, err);
// TODO: do not unregister listener until service is unregistered
@@ -260,7 +254,7 @@
//verify(listener2, timeout(mTimeoutMs).times(1)).onServiceUnregistered(request2);
}
- public void doTestDiscoverService() {
+ private void doTestDiscoverService() throws Exception {
NsdManager manager = mManager;
NsdServiceInfo reply1 = new NsdServiceInfo("a_name", "a_type");
@@ -271,69 +265,73 @@
// Client registers for discovery, request fails
manager.discoverServices("a_type", PROTOCOL, listener);
- int key1 = verifyRequest(NsdManager.DISCOVER_SERVICES);
+ int key1 = getRequestKey(req ->
+ verify(mServiceConn).discoverServices(req.capture(), any()));
int err = 1;
- sendResponse(NsdManager.DISCOVER_SERVICES_FAILED, err, key1, null);
+ mCallback.onDiscoverServicesFailed(key1, err);
verify(listener, timeout(mTimeoutMs).times(1)).onStartDiscoveryFailed("a_type", err);
// Client retries, request succeeds
manager.discoverServices("a_type", PROTOCOL, listener);
- int key2 = verifyRequest(NsdManager.DISCOVER_SERVICES);
+ int key2 = getRequestKey(req ->
+ verify(mServiceConn, times(2)).discoverServices(req.capture(), any()));
- sendResponse(NsdManager.DISCOVER_SERVICES_STARTED, 0, key2, reply1);
+ mCallback.onDiscoverServicesStarted(key2, reply1);
verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStarted("a_type");
// mdns notifies about services
- sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply1);
+ mCallback.onServiceFound(key2, reply1);
verify(listener, timeout(mTimeoutMs).times(1)).onServiceFound(reply1);
- sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply2);
+ mCallback.onServiceFound(key2, reply2);
verify(listener, timeout(mTimeoutMs).times(1)).onServiceFound(reply2);
- sendResponse(NsdManager.SERVICE_LOST, 0, key2, reply2);
+ mCallback.onServiceLost(key2, reply2);
verify(listener, timeout(mTimeoutMs).times(1)).onServiceLost(reply2);
// Client unregisters its listener
manager.stopServiceDiscovery(listener);
- int key2again = verifyRequest(NsdManager.STOP_DISCOVERY);
+ int key2again = getRequestKey(req -> verify(mServiceConn).stopDiscovery(req.capture()));
assertEquals(key2, key2again);
// TODO: unregister listener immediately and stop notifying it about services
// Notifications are still passed to the client's listener
- sendResponse(NsdManager.SERVICE_LOST, 0, key2, reply1);
+ mCallback.onServiceLost(key2, reply1);
verify(listener, timeout(mTimeoutMs).times(1)).onServiceLost(reply1);
// Client is notified of complete unregistration
- sendResponse(NsdManager.STOP_DISCOVERY_SUCCEEDED, 0, key2again, "a_type");
+ mCallback.onStopDiscoverySucceeded(key2again);
verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStopped("a_type");
// Notifications are not passed to the client anymore
- sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply3);
+ mCallback.onServiceFound(key2, reply3);
verify(listener, timeout(mTimeoutMs).times(0)).onServiceLost(reply3);
// Client registers for service discovery
reset(listener);
manager.discoverServices("a_type", PROTOCOL, listener);
- int key3 = verifyRequest(NsdManager.DISCOVER_SERVICES);
+ int key3 = getRequestKey(req ->
+ verify(mServiceConn, times(3)).discoverServices(req.capture(), any()));
- sendResponse(NsdManager.DISCOVER_SERVICES_STARTED, 0, key3, reply1);
+ mCallback.onDiscoverServicesStarted(key3, reply1);
verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStarted("a_type");
// Client unregisters immediately, it fails
manager.stopServiceDiscovery(listener);
- int key3again = verifyRequest(NsdManager.STOP_DISCOVERY);
+ int key3again = getRequestKey(req ->
+ verify(mServiceConn, times(2)).stopDiscovery(req.capture()));
assertEquals(key3, key3again);
err = 2;
- sendResponse(NsdManager.STOP_DISCOVERY_FAILED, err, key3again, "a_type");
+ mCallback.onStopDiscoveryFailed(key3again, err);
verify(listener, timeout(mTimeoutMs).times(1)).onStopDiscoveryFailed("a_type", err);
// New notifications are not passed to the client anymore
- sendResponse(NsdManager.SERVICE_FOUND, 0, key3, reply1);
+ mCallback.onServiceFound(key3, reply1);
verify(listener, timeout(mTimeoutMs).times(0)).onServiceFound(reply1);
}
@@ -398,77 +396,10 @@
}
}
- NsdManager makeNsdManagerS() {
- // Expect we'll get 2 AsyncChannel related msgs.
- return makeManager(2);
- }
-
- NsdManager makeNsdManagerPreS() {
- // Expect we'll get 3 msgs. 2 AsyncChannel related msgs + 1 additional daemon startup msg.
- return makeManager(3);
- }
-
- NsdManager makeManager(int expectedMsgCount) {
- NsdManager manager = new NsdManager(mContext, mService);
- // Acknowledge first two messages connecting the AsyncChannel.
- verify(mServiceHandler, timeout(mTimeoutMs).times(expectedMsgCount)).handleMessage(any());
-
- reset(mServiceHandler);
- assertNotNull(mServiceHandler.chan);
- return manager;
- }
-
- int verifyRequest(int expectedMessageType) {
- HandlerUtils.waitForIdle(mServiceHandler, mTimeoutMs);
- verify(mServiceHandler, timeout(mTimeoutMs)).handleMessage(any());
- reset(mServiceHandler);
- Message received = mServiceHandler.getLastMessage();
- assertEquals(NsdManager.nameOf(expectedMessageType), NsdManager.nameOf(received.what));
- return received.arg2;
- }
-
- void sendResponse(int replyType, int arg, int key, Object obj) {
- mServiceHandler.chan.sendMessage(replyType, arg, key, obj);
- }
-
- // Implements the server side of AsyncChannel connection protocol
- public static class MockServiceHandler extends Handler {
- public final Context context;
- public AsyncChannel chan;
- public Message lastMessage;
-
- MockServiceHandler(Looper l, Context c) {
- super(l);
- context = c;
- }
-
- synchronized Message getLastMessage() {
- return lastMessage;
- }
-
- synchronized void setLastMessage(Message msg) {
- lastMessage = obtainMessage();
- lastMessage.copyFrom(msg);
- }
-
- @Override
- public void handleMessage(Message msg) {
- setLastMessage(msg);
- if (msg.what == AsyncChannel.CMD_CHANNEL_FULL_CONNECTION) {
- chan = new AsyncChannel();
- chan.connect(context, this, msg.replyTo);
- chan.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
- }
- }
-
- void stop() {
- getLooper().quitSafely();
- }
-
- static MockServiceHandler create(Context context) {
- HandlerThread t = new HandlerThread("mock-service-handler");
- t.start();
- return new MockServiceHandler(t.getLooper(), context);
- }
+ int getRequestKey(ExceptionUtils.ThrowingConsumer<ArgumentCaptor<Integer>> verifier)
+ throws Exception {
+ final ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class);
+ verifier.accept(captor);
+ return captor.getValue();
}
}
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index e0dd886..e76762e 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -249,6 +249,8 @@
import android.net.NetworkStateSnapshot;
import android.net.NetworkTestResultParcelable;
import android.net.OemNetworkPreferences;
+import android.net.PacProxyManager;
+import android.net.Proxy;
import android.net.ProxyInfo;
import android.net.QosCallbackException;
import android.net.QosFilter;
@@ -478,6 +480,7 @@
private Context mContext;
private NetworkPolicyCallback mPolicyCallback;
private WrappedMultinetworkPolicyTracker mPolicyTracker;
+ private ProxyTracker mProxyTracker;
private HandlerThread mAlarmManagerThread;
private TestNetIdManager mNetIdManager;
private QosCallbackMockHelper mQosCallbackMockHelper;
@@ -511,7 +514,7 @@
@Mock VpnProfileStore mVpnProfileStore;
@Mock SystemConfigManager mSystemConfigManager;
@Mock Resources mResources;
- @Mock ProxyTracker mProxyTracker;
+ @Mock PacProxyManager mPacProxyManager;
// BatteryStatsManager is final and cannot be mocked with regular mockito, so just mock the
// underlying binder calls.
@@ -613,6 +616,7 @@
if (Context.SYSTEM_CONFIG_SERVICE.equals(name)) return mSystemConfigManager;
if (Context.NETWORK_STATS_SERVICE.equals(name)) return mStatsManager;
if (Context.BATTERY_STATS_SERVICE.equals(name)) return mBatteryStatsManager;
+ if (Context.PAC_PROXY_SERVICE.equals(name)) return mPacProxyManager;
return super.getSystemService(name);
}
@@ -1703,6 +1707,8 @@
mCsHandlerThread = new HandlerThread("TestConnectivityService");
mVMSHandlerThread = new HandlerThread("TestVpnManagerService");
+ mProxyTracker = new ProxyTracker(mServiceContext, mock(Handler.class),
+ 16 /* EVENT_PROXY_HAS_CHANGED */);
initMockedResources();
final Context mockResContext = mock(Context.class);
@@ -2135,6 +2141,39 @@
return expected;
}
+ private ExpectedBroadcast expectProxyChangeAction(ProxyInfo proxy) {
+ return registerPacProxyBroadcastThat(intent -> {
+ final ProxyInfo actualProxy = (ProxyInfo) intent.getExtra(Proxy.EXTRA_PROXY_INFO,
+ ProxyInfo.buildPacProxy(Uri.EMPTY));
+ return proxy.equals(actualProxy);
+ });
+ }
+
+ private ExpectedBroadcast registerPacProxyBroadcast() {
+ return registerPacProxyBroadcastThat(intent -> true);
+ }
+
+ private ExpectedBroadcast registerPacProxyBroadcastThat(
+ @NonNull final Predicate<Intent> filter) {
+ final IntentFilter intentFilter = new IntentFilter(Proxy.PROXY_CHANGE_ACTION);
+ // AtomicReference allows receiver to access expected even though it is constructed later.
+ final AtomicReference<ExpectedBroadcast> expectedRef = new AtomicReference<>();
+ final BroadcastReceiver receiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ final ProxyInfo proxy = (ProxyInfo) intent.getExtra(
+ Proxy.EXTRA_PROXY_INFO, ProxyInfo.buildPacProxy(Uri.EMPTY));
+ Log.d(TAG, "Receive PROXY_CHANGE_ACTION, proxy = " + proxy);
+ if (filter.test(intent)) {
+ expectedRef.get().complete(intent);
+ }
+ }
+ };
+ final ExpectedBroadcast expected = new ExpectedBroadcast(receiver);
+ expectedRef.set(expected);
+ mServiceContext.registerReceiver(receiver, intentFilter);
+ return expected;
+ }
+
private boolean extraInfoInBroadcastHasExpectedNullness(NetworkInfo ni) {
final DetailedState state = ni.getDetailedState();
if (state == DetailedState.CONNECTED && ni.getExtraInfo() == null) return false;
@@ -9945,7 +9984,7 @@
final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
final Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
- doReturn(testProxyInfo).when(mService.mProxyTracker).getGlobalProxy();
+ mProxyTracker.setGlobalProxy(testProxyInfo);
assertEquals(testProxyInfo, mService.getProxyForNetwork(wifiNetwork));
}
@@ -11353,6 +11392,7 @@
assertNull(mService.getProxyForNetwork(null));
assertNull(mCm.getDefaultProxy());
+ final ExpectedBroadcast b1 = registerPacProxyBroadcast();
final LinkProperties lp = new LinkProperties();
lp.setInterfaceName("tun0");
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
@@ -11362,9 +11402,10 @@
mMockVpn.establish(lp, VPN_UID, vpnRanges);
assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
// VPN is connected but proxy is not set, so there is no need to send proxy broadcast.
- verify(mProxyTracker, never()).sendProxyBroadcast();
+ b1.expectNoBroadcast(500);
// Update to new range which is old range minus APP1, i.e. only APP2
+ final ExpectedBroadcast b2 = registerPacProxyBroadcast();
final Set<UidRange> newRanges = new HashSet<>(asList(
new UidRange(vpnRange.start, APP1_UID - 1),
new UidRange(APP1_UID + 1, vpnRange.stop)));
@@ -11375,37 +11416,37 @@
assertVpnUidRangesUpdated(false, vpnRanges, VPN_UID);
// Uid has changed but proxy is not set, so there is no need to send proxy broadcast.
- verify(mProxyTracker, never()).sendProxyBroadcast();
+ b2.expectNoBroadcast(500);
final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
+ final ExpectedBroadcast b3 = registerPacProxyBroadcast();
lp.setHttpProxy(testProxyInfo);
mMockVpn.sendLinkProperties(lp);
waitForIdle();
// Proxy is set, so send a proxy broadcast.
- verify(mProxyTracker, times(1)).sendProxyBroadcast();
- reset(mProxyTracker);
+ b3.expectBroadcast();
+ final ExpectedBroadcast b4 = registerPacProxyBroadcast();
mMockVpn.setUids(vpnRanges);
waitForIdle();
// Uid has changed and proxy is already set, so send a proxy broadcast.
- verify(mProxyTracker, times(1)).sendProxyBroadcast();
- reset(mProxyTracker);
+ b4.expectBroadcast();
+ final ExpectedBroadcast b5 = registerPacProxyBroadcast();
// Proxy is removed, send a proxy broadcast.
lp.setHttpProxy(null);
mMockVpn.sendLinkProperties(lp);
waitForIdle();
- verify(mProxyTracker, times(1)).sendProxyBroadcast();
- reset(mProxyTracker);
+ b5.expectBroadcast();
// Proxy is added in WiFi(default network), setDefaultProxy will be called.
final LinkProperties wifiLp = mCm.getLinkProperties(mWiFiNetworkAgent.getNetwork());
assertNotNull(wifiLp);
+ final ExpectedBroadcast b6 = expectProxyChangeAction(testProxyInfo);
wifiLp.setHttpProxy(testProxyInfo);
mWiFiNetworkAgent.sendLinkProperties(wifiLp);
waitForIdle();
- verify(mProxyTracker, times(1)).setDefaultProxy(eq(testProxyInfo));
- reset(mProxyTracker);
+ b6.expectBroadcast();
}
@Test
@@ -11424,18 +11465,21 @@
lp.setHttpProxy(testProxyInfo);
final UidRange vpnRange = PRIMARY_UIDRANGE;
final Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
+ final ExpectedBroadcast b1 = registerPacProxyBroadcast();
mMockVpn.setOwnerAndAdminUid(VPN_UID);
mMockVpn.registerAgent(false, vpnRanges, lp);
// In any case, the proxy broadcast won't be sent before VPN goes into CONNECTED state.
// Otherwise, the app that calls ConnectivityManager#getDefaultProxy() when it receives the
// proxy broadcast will get null.
- verify(mProxyTracker, never()).sendProxyBroadcast();
+ b1.expectNoBroadcast(500);
+
+ final ExpectedBroadcast b2 = registerPacProxyBroadcast();
mMockVpn.connect(true /* validated */, true /* hasInternet */, false /* isStrictMode */);
waitForIdle();
assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
// Vpn is connected with proxy, so the proxy broadcast will be sent to inform the apps to
// update their proxy data.
- verify(mProxyTracker, times(1)).sendProxyBroadcast();
+ b2.expectBroadcast();
}
@Test
@@ -11464,10 +11508,10 @@
final LinkProperties cellularLp = new LinkProperties();
cellularLp.setInterfaceName(MOBILE_IFNAME);
final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
+ final ExpectedBroadcast b = registerPacProxyBroadcast();
cellularLp.setHttpProxy(testProxyInfo);
mCellNetworkAgent.sendLinkProperties(cellularLp);
- waitForIdle();
- verify(mProxyTracker, times(1)).sendProxyBroadcast();
+ b.expectBroadcast();
}
@Test
diff --git a/tests/unit/java/com/android/server/NsdServiceTest.java b/tests/unit/java/com/android/server/NsdServiceTest.java
index 4d2970a..4172553 100644
--- a/tests/unit/java/com/android/server/NsdServiceTest.java
+++ b/tests/unit/java/com/android/server/NsdServiceTest.java
@@ -20,6 +20,7 @@
import static libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -33,14 +34,19 @@
import android.compat.testing.PlatformCompatChangeRule;
import android.content.ContentResolver;
import android.content.Context;
+import android.net.nsd.INsdManagerCallback;
+import android.net.nsd.INsdServiceConnector;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
+import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import androidx.annotation.NonNull;
import androidx.test.filters.SmallTest;
import com.android.server.NsdService.DaemonConnection;
@@ -56,11 +62,15 @@
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
+import org.mockito.AdditionalAnswers;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
+import java.util.LinkedList;
+import java.util.Queue;
+
// TODOs:
// - test client can send requests and receive replies
// - test NSD_ON ENABLE/DISABLED listening
@@ -73,6 +83,11 @@
private static final long CLEANUP_DELAY_MS = 500;
private static final long TIMEOUT_MS = 500;
+ // Records INsdManagerCallback created when NsdService#connect is called.
+ // Only accessed on the test thread, since NsdService#connect is called by the NsdManager
+ // constructor called on the test thread.
+ private final Queue<INsdManagerCallback> mCreatedCallbacks = new LinkedList<>();
+
@Rule
public TestRule compatChangeRule = new PlatformCompatChangeRule();
@Mock Context mContext;
@@ -83,6 +98,16 @@
HandlerThread mThread;
TestHandler mHandler;
+ private static class LinkToDeathRecorder extends Binder {
+ IBinder.DeathRecipient mDr;
+
+ @Override
+ public void linkToDeath(@NonNull DeathRecipient recipient, int flags) {
+ super.linkToDeath(recipient, flags);
+ mDr = recipient;
+ }
+ }
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -103,26 +128,30 @@
@Test
@DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
- public void testPreSClients() {
+ public void testPreSClients() throws Exception {
when(mSettings.isEnabled()).thenReturn(true);
NsdService service = makeService();
// Pre S client connected, the daemon should be started.
- NsdManager client1 = connectClient(service);
+ connectClient(service);
waitForIdle();
+ final INsdManagerCallback cb1 = getCallback();
+ final IBinder.DeathRecipient deathRecipient1 = verifyLinkToDeath(cb1);
verify(mDaemon, times(1)).maybeStart();
verifyDaemonCommands("start-service");
- NsdManager client2 = connectClient(service);
+ connectClient(service);
waitForIdle();
+ final INsdManagerCallback cb2 = getCallback();
+ final IBinder.DeathRecipient deathRecipient2 = verifyLinkToDeath(cb2);
verify(mDaemon, times(1)).maybeStart();
- client1.disconnect();
+ deathRecipient1.binderDied();
// Still 1 client remains, daemon shouldn't be stopped.
waitForIdle();
verify(mDaemon, never()).maybeStop();
- client2.disconnect();
+ deathRecipient2.binderDied();
// All clients are disconnected, the daemon should be stopped.
verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
verifyDaemonCommands("stop-service");
@@ -130,43 +159,51 @@
@Test
@EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
- public void testNoDaemonStartedWhenClientsConnect() {
+ public void testNoDaemonStartedWhenClientsConnect() throws Exception {
when(mSettings.isEnabled()).thenReturn(true);
-
- NsdService service = makeService();
+ final NsdService service = makeService();
// Creating an NsdManager will not cause any cmds executed, which means
// no daemon is started.
- NsdManager client1 = connectClient(service);
+ connectClient(service);
waitForIdle();
verify(mDaemon, never()).execute(any());
+ final INsdManagerCallback cb1 = getCallback();
+ final IBinder.DeathRecipient deathRecipient1 = verifyLinkToDeath(cb1);
// Creating another NsdManager will not cause any cmds executed.
- NsdManager client2 = connectClient(service);
+ connectClient(service);
waitForIdle();
verify(mDaemon, never()).execute(any());
+ final INsdManagerCallback cb2 = getCallback();
+ final IBinder.DeathRecipient deathRecipient2 = verifyLinkToDeath(cb2);
// If there is no active request, try to clean up the daemon
// every time the client disconnects.
- client1.disconnect();
+ deathRecipient1.binderDied();
verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
reset(mDaemon);
- client2.disconnect();
+ deathRecipient2.binderDied();
verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
+ }
- client1.disconnect();
- client2.disconnect();
+ private IBinder.DeathRecipient verifyLinkToDeath(INsdManagerCallback cb)
+ throws Exception {
+ final IBinder.DeathRecipient dr = ((LinkToDeathRecorder) cb.asBinder()).mDr;
+ assertNotNull(dr);
+ return dr;
}
@Test
@EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
- public void testClientRequestsAreGCedAtDisconnection() {
+ public void testClientRequestsAreGCedAtDisconnection() throws Exception {
when(mSettings.isEnabled()).thenReturn(true);
-
NsdService service = makeService();
- NsdManager client = connectClient(service);
+ NsdManager client = connectClient(service);
waitForIdle();
+ final INsdManagerCallback cb1 = getCallback();
+ final IBinder.DeathRecipient deathRecipient = verifyLinkToDeath(cb1);
verify(mDaemon, never()).maybeStart();
verify(mDaemon, never()).execute(any());
@@ -195,18 +232,16 @@
verifyDaemonCommand("resolve 4 a_name a_type local.");
// Client disconnects, stop the daemon after CLEANUP_DELAY_MS.
- client.disconnect();
+ deathRecipient.binderDied();
verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
// checks that request are cleaned
verifyDaemonCommands("stop-register 2", "stop-discover 3",
"stop-resolve 4", "stop-service");
-
- client.disconnect();
}
@Test
@EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
- public void testCleanupDelayNoRequestActive() {
+ public void testCleanupDelayNoRequestActive() throws Exception {
when(mSettings.isEnabled()).thenReturn(true);
NsdService service = makeService();
@@ -218,6 +253,8 @@
client.registerService(request, PROTOCOL, listener1);
waitForIdle();
verify(mDaemon, times(1)).maybeStart();
+ final INsdManagerCallback cb1 = getCallback();
+ final IBinder.DeathRecipient deathRecipient = verifyLinkToDeath(cb1);
verifyDaemonCommands("start-service", "register 2 a_name a_type 2201");
client.unregisterService(listener1);
@@ -226,7 +263,7 @@
verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
verifyDaemonCommand("stop-service");
reset(mDaemon);
- client.disconnect();
+ deathRecipient.binderDied();
// Client disconnects, after CLEANUP_DELAY_MS, maybeStop the daemon.
verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
}
@@ -240,12 +277,29 @@
mDaemonCallback = callback;
return mDaemon;
};
- NsdService service = new NsdService(mContext, mSettings,
- mHandler, supplier, CLEANUP_DELAY_MS);
+ final NsdService service = new NsdService(mContext, mSettings,
+ mHandler, supplier, CLEANUP_DELAY_MS) {
+ @Override
+ public INsdServiceConnector connect(INsdManagerCallback baseCb) {
+ // Wrap the callback in a transparent mock, to mock asBinder returning a
+ // LinkToDeathRecorder. This will allow recording the binder death recipient
+ // registered on the callback. Use a transparent mock and not a spy as the actual
+ // implementation class is not public and cannot be spied on by Mockito.
+ final INsdManagerCallback cb = mock(INsdManagerCallback.class,
+ AdditionalAnswers.delegatesTo(baseCb));
+ doReturn(new LinkToDeathRecorder()).when(cb).asBinder();
+ mCreatedCallbacks.add(cb);
+ return super.connect(cb);
+ }
+ };
verify(mDaemon, never()).execute(any(String.class));
return service;
}
+ private INsdManagerCallback getCallback() {
+ return mCreatedCallbacks.remove();
+ }
+
NsdManager connectClient(NsdService service) {
return new NsdManager(mContext, service);
}
diff --git a/tests/unit/vpn-jarjar-rules.txt b/tests/unit/vpn-jarjar-rules.txt
new file mode 100644
index 0000000..16661b9
--- /dev/null
+++ b/tests/unit/vpn-jarjar-rules.txt
@@ -0,0 +1,4 @@
+# Only keep classes imported by ConnectivityServiceTest
+keep com.android.server.VpnManagerService
+keep com.android.server.connectivity.Vpn
+keep com.android.server.connectivity.VpnProfileStore
\ No newline at end of file