Snap for 9453251 from 6640702afc95ae0ad30d473311c42888b9216678 to mainline-resolv-release Change-Id: I55dd1f8fa806c249e6fa4aa13c0083d841bdf27c
diff --git a/Android.bp b/Android.bp index 116d6a6..49c011e 100644 --- a/Android.bp +++ b/Android.bp
@@ -45,10 +45,6 @@ default_applicable_licenses: ["Android-Apache-2.0"], } -// In some branches, this may be module_current instead of module_33 if the SDK prebuilts are not -// yet dropped there, meaning module_33 cannot be used yet. -module_33_version = "module_33" - // TODO: remove this default and replace with ConnectivityNextEnableDefaults. This will need to be // done separately in each branch due to merge conflicts. // Defaults to enable/disable java targets that depend on @@ -86,7 +82,7 @@ java_defaults { name: "NetworkStackReleaseApiLevel", defaults:["NetworkStackReleaseTargetSdk"], - sdk_version: module_33_version, + sdk_version: "module_33", libs: [ "framework-connectivity", "framework-connectivity-t", @@ -179,7 +175,7 @@ java_library { name: "NetworkStackApi33Shims", - defaults: ["NetworkStackShimsDefaults", "ConnectivityNextEnableDefaults"], + defaults: ["NetworkStackShimsDefaults"], srcs: [ "apishim/33/**/*.java", ], @@ -193,7 +189,7 @@ "framework-connectivity-t.stubs.module_lib", "framework-tethering", ], - sdk_version: module_33_version, + sdk_version: "module_33", visibility: ["//visibility:private"], } @@ -298,7 +294,6 @@ "net-utils-device-common-ip", "net-utils-device-common-netlink", ], - plugins: ["java_api_finder"], } // The versions of the android library containing network stack code compiled for each SDK variant.
diff --git a/apishim/33/com/android/networkstack/apishim/api33/TelephonyManagerShimImpl.java b/apishim/33/com/android/networkstack/apishim/api33/TelephonyManagerShimImpl.java index 473db91..fceb19a 100644 --- a/apishim/33/com/android/networkstack/apishim/api33/TelephonyManagerShimImpl.java +++ b/apishim/33/com/android/networkstack/apishim/api33/TelephonyManagerShimImpl.java
@@ -23,6 +23,7 @@ import android.telephony.TelephonyManager; import android.telephony.TelephonyManager.CarrierPrivilegesCallback; +import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import com.android.networkstack.apishim.common.TelephonyManagerShim; @@ -72,6 +73,12 @@ int[] pkgUids = toIntArray(privilegedUids); listener.onCarrierPrivilegesChanged(pkgNames, pkgUids); } + + @Override + public void onCarrierServiceChanged(@Nullable final String carrierServicePackageName, + final int carrierServiceUid) { + listener.onCarrierServiceChanged(carrierServicePackageName, carrierServiceUid); + } }; mTm.registerCarrierPrivilegesCallback(logicalSlotIndex, executor, carrierPrivilegesCallback); @@ -86,6 +93,7 @@ mListenerMap.remove(listener); } + // TODO : remove this method when all changes are in /** See android.telephony.TelephonyManager#getCarrierServicePackageNameForLogicalSlot */ public String getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex) { return mTm.getCarrierServicePackageNameForLogicalSlot(logicalSlotIndex);
diff --git a/apishim/common/com/android/networkstack/apishim/common/TelephonyManagerShim.java b/apishim/common/com/android/networkstack/apishim/common/TelephonyManagerShim.java index 492624a..6fec190 100644 --- a/apishim/common/com/android/networkstack/apishim/common/TelephonyManagerShim.java +++ b/apishim/common/com/android/networkstack/apishim/common/TelephonyManagerShim.java
@@ -16,6 +16,8 @@ package com.android.networkstack.apishim.common; +import androidx.annotation.Nullable; + import java.util.List; import java.util.concurrent.Executor; @@ -30,12 +32,17 @@ */ public interface TelephonyManagerShim { /** See android.telephony.TelephonyManager.CarrierPrivilegesListener */ - public interface CarrierPrivilegesListenerShim { + interface CarrierPrivilegesListenerShim { /** See android.telephony.TelephonyManager - * .CarrierPrivilegesListener#onCarrierPrivilegesChanged */ - void onCarrierPrivilegesChanged( + * .CarrierPrivilegesCallback#onCarrierPrivilegesChanged */ + default void onCarrierPrivilegesChanged( List<String> privilegedPackageNames, - int[] privilegedUids); + int[] privilegedUids) {} + // TODO : remove the default implementation of this method once all changes are in + /** See CarrierPrivilegesCallback#onCarrierServiceChanged */ + default void onCarrierServiceChanged( + @Nullable String carrierServicePackageName, + int carrierServiceUid) {} } /** See android.telephony.TelephonyManager#addCarrierPrivilegesListener */ @@ -54,6 +61,7 @@ throw new UnsupportedApiLevelException("Only supported starting from API 33"); } + // TODO : remove this method when all changes are in /** See android.telephony.TelephonyManager#getCarrierServicePackageNameForLogicalSlot */ default String getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex) throws UnsupportedApiLevelException {
diff --git a/jni/network_stack_utils_jni.cpp b/jni/network_stack_utils_jni.cpp index 5ff0288..20eb051 100644 --- a/jni/network_stack_utils_jni.cpp +++ b/jni/network_stack_utils_jni.cpp
@@ -99,7 +99,9 @@ } } -static void network_stack_utils_attachDhcpFilter(JNIEnv *env, jclass clazz, jobject javaFd) { +static void network_stack_utils_attachDhcpFilter(JNIEnv *env, jclass clazz, jobject javaFd, jboolean dropMF) { + static const __u32 frag_mask = static_cast<__u32>((dropMF ? IP_MF : 0) | IP_OFFMASK); + static sock_filter filter_code[] = { // Check the protocol is UDP. BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv4Protocol), @@ -107,7 +109,7 @@ // Check this is not a fragment. BPF_STMT(BPF_LD | BPF_H | BPF_ABS, kIPv4FlagsOffset), - BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K, IP_MF | IP_OFFMASK, 4, 0), + BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K, frag_mask, 4, 0), // Get the IP header length. BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, kEtherHeaderLen), @@ -251,7 +253,7 @@ static const JNINativeMethod gNetworkStackUtilsMethods[] = { /* name, signature, funcPtr */ { "addArpEntry", "([B[BLjava/lang/String;Ljava/io/FileDescriptor;)V", (void*) network_stack_utils_addArpEntry }, - { "attachDhcpFilter", "(Ljava/io/FileDescriptor;)V", (void*) network_stack_utils_attachDhcpFilter }, + { "attachDhcpFilter", "(Ljava/io/FileDescriptor;Z)V", (void*) network_stack_utils_attachDhcpFilter }, { "attachRaFilter", "(Ljava/io/FileDescriptor;I)V", (void*) network_stack_utils_attachRaFilter }, { "attachControlPacketFilter", "(Ljava/io/FileDescriptor;I)V", (void*) network_stack_utils_attachControlPacketFilter }, };
diff --git a/src/android/net/dhcp/DhcpClient.java b/src/android/net/dhcp/DhcpClient.java index a540cef..e494451 100644 --- a/src/android/net/dhcp/DhcpClient.java +++ b/src/android/net/dhcp/DhcpClient.java
@@ -51,6 +51,7 @@ import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY; import static com.android.net.module.util.NetworkStackConstants.IPV4_CONFLICT_ANNOUNCE_NUM; import static com.android.net.module.util.NetworkStackConstants.IPV4_CONFLICT_PROBE_NUM; +import static com.android.networkstack.util.NetworkStackUtils.DHCP_DISABLE_DROP_MF; import static com.android.networkstack.util.NetworkStackUtils.DHCP_INIT_REBOOT_VERSION; import static com.android.networkstack.util.NetworkStackUtils.DHCP_IPV6_ONLY_PREFERRED_VERSION; import static com.android.networkstack.util.NetworkStackUtils.DHCP_IP_CONFLICT_DETECT_VERSION; @@ -692,9 +693,11 @@ @Override protected FileDescriptor createFd() { + boolean dropMF = !DeviceConfigUtils.getDeviceConfigPropertyBoolean( + NAMESPACE_CONNECTIVITY, DHCP_DISABLE_DROP_MF, false); try { mPacketSock = Os.socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, 0 /* protocol */); - NetworkStackUtils.attachDhcpFilter(mPacketSock); + NetworkStackUtils.attachDhcpFilter(mPacketSock, dropMF); final SocketAddress addr = makePacketSocketAddress(ETH_P_IP, mIface.index); Os.bind(mPacketSock, addr); } catch (SocketException | ErrnoException e) {
diff --git a/src/android/net/ip/IpClientLinkObserver.java b/src/android/net/ip/IpClientLinkObserver.java index 4135f68..654d390 100644 --- a/src/android/net/ip/IpClientLinkObserver.java +++ b/src/android/net/ip/IpClientLinkObserver.java
@@ -45,6 +45,7 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.HexDump; import com.android.net.module.util.InterfaceParams; import com.android.net.module.util.SharedLog; import com.android.net.module.util.ip.NetlinkMonitor; @@ -205,7 +206,8 @@ private void maybeLog(String operation, String iface, LinkAddress address) { if (DBG) { Log.d(mTag, operation + ": " + address + " on " + iface - + " flags " + address.getFlags() + " scope " + address.getScope()); + + " flags " + "0x" + HexDump.toHexString(address.getFlags()) + + " scope " + address.getScope()); } }
diff --git a/src/com/android/networkstack/netlink/TcpSocketTracker.java b/src/com/android/networkstack/netlink/TcpSocketTracker.java index 33d3e61..acf716b 100644 --- a/src/com/android/networkstack/netlink/TcpSocketTracker.java +++ b/src/com/android/networkstack/netlink/TcpSocketTracker.java
@@ -39,7 +39,10 @@ import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_DUMP; import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.net.INetd; import android.net.MarkMaskParcel; import android.net.Network; @@ -47,6 +50,7 @@ import android.os.AsyncTask; import android.os.Build; import android.os.IBinder; +import android.os.PowerManager; import android.os.RemoteException; import android.os.SystemClock; import android.provider.DeviceConfig; @@ -60,6 +64,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.net.module.util.DeviceConfigUtils; import com.android.net.module.util.netlink.NetlinkConstants; @@ -128,6 +133,10 @@ private final int mNetworkMask; private int mMinPacketsThreshold = DEFAULT_DATA_STALL_MIN_PACKETS_THRESHOLD; private int mTcpPacketsFailRateThreshold = DEFAULT_TCP_PACKETS_FAIL_PERCENTAGE; + + private final Object mDozeModeLock = new Object(); + @GuardedBy("mDozeModeLock") + private boolean mInDozeMode = false; @VisibleForTesting protected final DeviceConfig.OnPropertiesChangedListener mConfigListener = new DeviceConfig.OnPropertiesChangedListener() { @@ -144,6 +153,19 @@ } }; + final BroadcastReceiver mDeviceIdleReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent == null) return; + + if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction())) { + final PowerManager powerManager = context.getSystemService(PowerManager.class); + final boolean deviceIdle = powerManager.isDeviceIdleMode(); + setDozeMode(deviceIdle); + } + } + }; + public TcpSocketTracker(@NonNull final Dependencies dps, @NonNull final Network network) { mDependencies = dps; mNetwork = network; @@ -172,6 +194,7 @@ TCP_MONITOR_STATE_FILTER)); } mDependencies.addDeviceConfigChangedListener(mConfigListener); + mDependencies.addDeviceIdleReceiver(mDeviceIdleReceiver); } @Nullable @@ -191,10 +214,17 @@ * Request to send a SockDiag Netlink request. Receive and parse the returned message. This * function is not thread-safe and should only be called from only one thread. * - * @Return if this polling request executes successfully or not. + * @Return if this polling request is sent to kernel and executes successfully or not. */ public boolean pollSocketsInfo() { if (!mDependencies.isTcpInfoParsingSupported()) return false; + // Traffic will be restricted in doze mode. TCP info may not reflect the correct network + // behavior. + // TODO: Traffic may be restricted by other reason. Get the restriction info from bpf in T+. + synchronized (mDozeModeLock) { + if (mInDozeMode) return false; + } + FileDescriptor fd = null; try { @@ -358,6 +388,14 @@ */ public boolean isDataStallSuspected() { if (!mDependencies.isTcpInfoParsingSupported()) return false; + + // Skip checking data stall since the traffic will be restricted and it will not be real + // network stall. + // TODO: Traffic may be restricted by other reason. Get the restriction info from bpf in T+. + synchronized (mDozeModeLock) { + if (mInDozeMode) return false; + } + return (getLatestPacketFailPercentage() >= getTcpPacketsFailRateThreshold()); } @@ -467,7 +505,12 @@ /** Stops monitoring and releases resources. */ public void quit() { + // Do not need to unregister receiver and listener since registration is skipped + // in the constructor. + if (!mDependencies.isTcpInfoParsingSupported()) return; + mDependencies.removeDeviceConfigChangedListener(mConfigListener); + mDependencies.removeBroadcastReceiver(mDeviceIdleReceiver); } /** @@ -564,6 +607,14 @@ } } + private void setDozeMode(boolean isEnabled) { + synchronized (mDozeModeLock) { + if (mInDozeMode == isEnabled) return; + mInDozeMode = isEnabled; + log("Doze mode enabled=" + mInDozeMode); + } + } + /** * Dependencies class for testing. */ @@ -658,5 +709,16 @@ @NonNull final DeviceConfig.OnPropertiesChangedListener listener) { DeviceConfig.removeOnPropertiesChangedListener(listener); } + + /** Add receiver for detecting doze mode change to control TCP detection. */ + public void addDeviceIdleReceiver(@NonNull final BroadcastReceiver receiver) { + mContext.registerReceiver(receiver, + new IntentFilter(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)); + } + + /** Remove broadcast receiver. */ + public void removeBroadcastReceiver(@NonNull final BroadcastReceiver receiver) { + mContext.unregisterReceiver(receiver); + } } }
diff --git a/src/com/android/networkstack/util/NetworkStackUtils.java b/src/com/android/networkstack/util/NetworkStackUtils.java index 670a320..67a67c2 100755 --- a/src/com/android/networkstack/util/NetworkStackUtils.java +++ b/src/com/android/networkstack/util/NetworkStackUtils.java
@@ -166,6 +166,11 @@ public static final String DHCP_RAPID_COMMIT_ENABLED = "dhcp_rapid_commit_enabled"; /** + * Disable dropping DHCP packets with IPv4 MF flag set. + */ + public static final String DHCP_DISABLE_DROP_MF = "dhcp_disable_drop_mf"; + + /** * Minimum module version at which to enable the DHCP INIT-REBOOT state. */ public static final String DHCP_INIT_REBOOT_VERSION = "dhcp_init_reboot_version"; @@ -194,14 +199,6 @@ "dhcp_slow_retransmission_version"; /** - * Minimum module version at which to enable dismissal CaptivePortalLogin app in validated - * network feature. CaptivePortalLogin app will also use validation facilities in - * {@link NetworkMonitor} to perform portal validation if feature is enabled. - */ - public static final String DISMISS_PORTAL_IN_VALIDATED_NETWORK = - "dismiss_portal_in_validated_network"; - - /** * Experiment flag to enable considering DNS probes returning private IP addresses as failed * when attempting to detect captive portals. * @@ -321,7 +318,8 @@ /** * Attaches a socket filter that accepts DHCP packets to the given socket. */ - public static native void attachDhcpFilter(FileDescriptor fd) throws ErrnoException; + public static native void attachDhcpFilter(FileDescriptor fd, boolean dropMF) + throws ErrnoException; /** * Attaches a socket filter that accepts ICMPv6 router advertisements to the given socket.
diff --git a/src/com/android/server/connectivity/NetworkMonitor.java b/src/com/android/server/connectivity/NetworkMonitor.java index d34437f..8e0130e 100755 --- a/src/com/android/server/connectivity/NetworkMonitor.java +++ b/src/com/android/server/connectivity/NetworkMonitor.java
@@ -86,7 +86,6 @@ import static com.android.networkstack.util.NetworkStackUtils.DEFAULT_CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS; import static com.android.networkstack.util.NetworkStackUtils.DEFAULT_CAPTIVE_PORTAL_HTTPS_URLS; import static com.android.networkstack.util.NetworkStackUtils.DEFAULT_CAPTIVE_PORTAL_HTTP_URLS; -import static com.android.networkstack.util.NetworkStackUtils.DISMISS_PORTAL_IN_VALIDATED_NETWORK; import static com.android.networkstack.util.NetworkStackUtils.DNS_PROBE_PRIVATE_IP_NO_INTERNET_VERSION; import android.app.PendingIntent; @@ -1325,10 +1324,7 @@ private boolean useRedirectUrlForPortal() { // It must match the conditions in CaptivePortalLogin in which the redirect URL is not // used to validate that the portal is gone. - final boolean aboveQ = - ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.Q); - return aboveQ && mDependencies.isFeatureEnabled(mContext, NAMESPACE_CONNECTIVITY, - DISMISS_PORTAL_IN_VALIDATED_NETWORK, aboveQ /* defaultEnabled */); + return ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.Q); } @Override
diff --git a/tests/integration/Android.bp b/tests/integration/Android.bp index 5926fec..7f8a9d3 100644 --- a/tests/integration/Android.bp +++ b/tests/integration/Android.bp
@@ -121,7 +121,7 @@ "root/**/*.kt", ], static_libs: [ - "NetworkStackApiCurrentLib", + "NetworkStackApiStableLib", ], platform_apis: true, test_suites: ["general-tests", "mts-networking"],
diff --git a/tests/integration/common/android/net/ip/IpClientIntegrationTestCommon.java b/tests/integration/common/android/net/ip/IpClientIntegrationTestCommon.java index 2aeecfa..50f25e6 100644 --- a/tests/integration/common/android/net/ip/IpClientIntegrationTestCommon.java +++ b/tests/integration/common/android/net/ip/IpClientIntegrationTestCommon.java
@@ -265,6 +265,7 @@ private static final int IFA_F_STABLE_PRIVACY = 0x800; protected static final long TEST_TIMEOUT_MS = 2_000L; + private static final long TEST_WAIT_ENOBUFS_TIMEOUT_MS = 30_000L; @Rule public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(); @@ -611,8 +612,15 @@ mIsNetlinkEventParseEnabled /* default value */); setUpTapInterface(); - mCb = mock(IIpClientCallbacks.class); + // It turns out that Router Solicitation will also be sent out even after the tap interface + // is brought up, however, we want to wait for RS which is sent due to IPv6 stack is enabled + // in the test code. The early RS might bring kind of race, for example, the IPv6 stack has + // not been enabled when test code sees the RS, then kernel will not process RA even if we + // replies immediately after receiving RS. Always waiting for the first RS show up after + // interface is brought up helps prevent the race. + waitForRouterSolicitation(); + mCb = mock(IIpClientCallbacks.class); if (useNetworkStackSignature()) { setUpMocks(); setUpIpClient(); @@ -1806,9 +1814,10 @@ mPacketReader.popPacket(PACKET_TIMEOUT_MS, this::isRouterSolicitation)); } - private void sendRouterAdvertisement(boolean waitForRs, short lifetime) throws Exception { + private void sendRouterAdvertisement(boolean waitForRs, short lifetime, int valid, + int preferred) throws Exception { final String dnsServer = "2001:4860:4860::64"; - final ByteBuffer pio = buildPioOption(3600, 1800, "2001:db8:1::/64"); + final ByteBuffer pio = buildPioOption(valid, preferred, "2001:db8:1::/64"); final ByteBuffer rdnss = buildRdnssOption(3600, dnsServer); sendRouterAdvertisement(waitForRs, lifetime, pio, rdnss); } @@ -1823,11 +1832,13 @@ } private void sendBasicRouterAdvertisement(boolean waitForRs) throws Exception { - sendRouterAdvertisement(waitForRs, (short) 1800); + sendRouterAdvertisement(waitForRs, (short) 1800 /* lifetime */, 3600 /* valid */, + 1800 /* preferred */); } - private void sendRouterAdvertisementWithZeroLifetime() throws Exception { - sendRouterAdvertisement(false /* waitForRs */, (short) 0); + private void sendRouterAdvertisementWithZeroRouterLifetime() throws Exception { + sendRouterAdvertisement(false /* waitForRs */, (short) 0 /* lifetime */, 3600 /* valid */, + 1800 /* preferred */); } // TODO: move this and the following method to a common location and use them in ApfTest. @@ -2868,7 +2879,7 @@ // Send RA with 0-lifetime and wait until all IPv6-related default route and DNS servers // have been removed, then verify if there is IPv4-only info left in the LinkProperties. - sendRouterAdvertisementWithZeroLifetime(); + sendRouterAdvertisementWithZeroRouterLifetime(); verify(mCb, timeout(TEST_TIMEOUT_MS).atLeastOnce()).onLinkPropertiesChange( argThat(x -> { final boolean isOnlyIPv4Provisioned = (x.getLinkAddresses().size() == 1 @@ -2907,7 +2918,7 @@ // Send RA with 0-lifetime and wait until all global IPv6 addresses, IPv6-related default // route and DNS servers have been removed, then verify if there is IPv4-only, IPv6 link // local address and route to fe80::/64 info left in the LinkProperties. - sendRouterAdvertisementWithZeroLifetime(); + sendRouterAdvertisementWithZeroRouterLifetime(); verify(mCb, timeout(TEST_TIMEOUT_MS).atLeastOnce()).onLinkPropertiesChange( argThat(x -> { // Only IPv4 provisioned and IPv6 link-local address @@ -4008,7 +4019,7 @@ // Unblock the IpClient handler and ENOBUFS should happen then. latch.countDown(); - HandlerUtils.waitForIdle(handler, TEST_TIMEOUT_MS); + HandlerUtils.waitForIdle(handler, TEST_WAIT_ENOBUFS_TIMEOUT_MS); reset(mCb); @@ -4016,7 +4027,7 @@ // Due to ignoring the ENOBUFS and wait until handler gets idle, IpClient should be still // able to see the RA with 0 router lifetime and the IPv6 default route will be removed. // LinkProperties should not include any route to the new prefix 2001:db8:dead:beef::/64. - sendRouterAdvertisementWithZeroLifetime(); + sendRouterAdvertisementWithZeroRouterLifetime(); final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(captor.capture()); final LinkProperties lp = captor.getValue(); @@ -4051,4 +4062,34 @@ } assertEquals(2, nsList.size()); // from privacy address and stable privacy address } + + @Test + public void testDeprecatedGlobalUnicastAddress() throws Exception { + ProvisioningConfiguration config = new ProvisioningConfiguration.Builder() + .withoutIPv4() + .build(); + startIpClientProvisioning(config); + doIpv6OnlyProvisioning(); + + // Send RA with PIO(0 preferred but valid lifetime) to deprecate the global IPv6 addresses. + // Check all of global IPv6 addresses will become deprecated, but still valid. + // NetworkStackUtils#isIPv6GUA() will return false for deprecated addresses, however, when + // checking if the DNS is still reachable, deprecated addresses are not acceptable, that + // results in the on-link DNS server gets lost from LinkProperties, and provisioning failure + // happened. + // TODO: update the logic of checking reachable on-link DNS server to accept the deprecated + // addresses, then onProvisioningFailure callback should never happen. + sendRouterAdvertisement(false /* waitForRs*/, (short) 1800 /* router lifetime */, + 3600 /* valid */, 0 /* preferred */); + final ArgumentCaptor<LinkProperties> captor = ArgumentCaptor.forClass(LinkProperties.class); + verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningFailure(captor.capture()); + final LinkProperties lp = captor.getValue(); + assertNotNull(lp); + assertFalse(lp.hasGlobalIpv6Address()); + assertEquals(3, lp.getLinkAddresses().size()); // IPv6 privacy, stable privacy, link-local + for (LinkAddress la : lp.getLinkAddresses()) { + final Inet6Address address = (Inet6Address) la.getAddress(); + assertFalse(NetworkStackUtils.isIPv6GUA(la)); + } + } }
diff --git a/tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java b/tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java index 1177f96..043ec49 100644 --- a/tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java +++ b/tests/unit/src/com/android/networkstack/netlink/TcpSocketTrackerTest.java
@@ -21,8 +21,6 @@ import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; import static android.system.OsConstants.AF_INET; -import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; - import static com.android.net.module.util.netlink.NetlinkConstants.SOCKDIAG_MSG_HEADER_SIZE; import static junit.framework.Assert.assertEquals; @@ -35,14 +33,19 @@ import static org.mockito.Mockito.any; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; import android.net.INetd; import android.net.MarkMaskParcel; import android.net.Network; import android.os.Build; +import android.os.PowerManager; import android.util.Log; import android.util.Log.TerribleFailureHandler; @@ -62,6 +65,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -190,6 +194,8 @@ private final Network mNetwork = new Network(TEST_NETID1); private final Network mOtherNetwork = new Network(TEST_NETID2); private TerribleFailureHandler mOldWtfHandler; + @Mock private Context mContext; + @Mock private PowerManager mPowerManager; @Rule public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(); @@ -211,6 +217,7 @@ when(mNetd.getFwmarkForNetwork(eq(TEST_NETID1))) .thenReturn(makeMarkMaskParcel(NETID_MASK, TEST_NETID1_FWMARK)); + doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class); } @After @@ -262,7 +269,7 @@ @Test @IgnoreUpTo(Build.VERSION_CODES.Q) // TCP info parsing is not supported on Q public void testPollSocketsInfo() throws Exception { // This test requires shims that provide API 30 access - assumeTrue(ConstantsShim.VERSION >= 30); + assumeTrue(ConstantsShim.VERSION >= Build.VERSION_CODES.R); when(mDependencies.isTcpInfoParsingSupported()).thenReturn(false); final TcpSocketTracker tst = new TcpSocketTracker(mDependencies, mNetwork); assertFalse(tst.pollSocketsInfo()); @@ -283,9 +290,7 @@ assertEquals(-1, tst.getLatestPacketFailPercentage()); assertEquals(0, tst.getSentSinceLastRecv()); - final ByteBuffer tcpBufferV6 = getByteBuffer(TEST_RESPONSE_BYTES); - final ByteBuffer tcpBufferV4 = getByteBuffer(TEST_RESPONSE_BYTES); - doReturn(tcpBufferV6, tcpBufferV4).when(mDependencies).recvMessage(any()); + setupNormalTestTcpInfo(); assertTrue(tst.pollSocketsInfo()); assertEquals(10, tst.getSentSinceLastRecv()); @@ -315,17 +320,60 @@ verify(mDependencies, atLeastOnce()).isTcpInfoParsingSupported(); verifyNoMoreInteractions(mDependencies); + + // Verify that no un-registration for the device configuration listener and broadcast + // receiver if TcpInfo parsing is not supported. + tst.quit(); + verify(mDependencies, never()).removeDeviceConfigChangedListener(any()); + verify(mDependencies, never()).removeBroadcastReceiver(any()); + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) + public void testTcpInfoParsingWithDozeMode() throws Exception { + // This test requires shims that provide API 30 access + assumeTrue(ConstantsShim.VERSION >= Build.VERSION_CODES.R); + + final TcpSocketTracker tst = new TcpSocketTracker(mDependencies, mNetwork); + final ArgumentCaptor<BroadcastReceiver> receiverCaptor = + ArgumentCaptor.forClass(BroadcastReceiver.class); + + verify(mDependencies).addDeviceIdleReceiver(receiverCaptor.capture()); + setupNormalTestTcpInfo(); + assertTrue(tst.pollSocketsInfo()); + + // Lower the threshold. + when(mDependencies.getDeviceConfigPropertyInt(any(), eq(CONFIG_TCP_PACKETS_FAIL_PERCENTAGE), + anyInt())).thenReturn(40); + + // Trigger a config update + tst.mConfigListener.onPropertiesChanged(null /* properties */); + assertEquals(10, tst.getSentSinceLastRecv()); + assertEquals(50, tst.getLatestPacketFailPercentage()); + assertTrue(tst.isDataStallSuspected()); + + // Enable doze mode + doReturn(true).when(mPowerManager).isDeviceIdleMode(); + final BroadcastReceiver receiver = receiverCaptor.getValue(); + receiver.onReceive(mContext, new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)); + assertFalse(tst.pollSocketsInfo()); + assertFalse(tst.isDataStallSuspected()); + } + + private void setupNormalTestTcpInfo() throws Exception { + final ByteBuffer tcpBufferV6 = getByteBuffer(TEST_RESPONSE_BYTES); + final ByteBuffer tcpBufferV4 = getByteBuffer(TEST_RESPONSE_BYTES); + doReturn(tcpBufferV6, tcpBufferV4).when(mDependencies).recvMessage(any()); } @Test @IgnoreAfter(Build.VERSION_CODES.Q) public void testTcpInfoParsingNotSupportedOnQ() { - assertFalse(new TcpSocketTracker.Dependencies(getInstrumentation().getContext()) + assertFalse(new TcpSocketTracker.Dependencies(mContext) .isTcpInfoParsingSupported()); } @Test @IgnoreUpTo(Build.VERSION_CODES.Q) public void testTcpInfoParsingSupportedFromR() { - assertTrue(new TcpSocketTracker.Dependencies(getInstrumentation().getContext()) + assertTrue(new TcpSocketTracker.Dependencies(mContext) .isTcpInfoParsingSupported()); } @@ -359,11 +407,9 @@ @Test @IgnoreUpTo(Build.VERSION_CODES.Q) // TCP info parsing is not supported on Q public void testPollSocketsInfo_BadFormat() throws Exception { // This test requires shims that provide API 30 access - assumeTrue(ConstantsShim.VERSION >= 30); + assumeTrue(ConstantsShim.VERSION >= Build.VERSION_CODES.R); final TcpSocketTracker tst = new TcpSocketTracker(mDependencies, mNetwork); - final ByteBuffer tcpBufferV6 = getByteBuffer(TEST_RESPONSE_BYTES); - final ByteBuffer tcpBufferV4 = getByteBuffer(TEST_RESPONSE_BYTES); - doReturn(tcpBufferV6, tcpBufferV4).when(mDependencies).recvMessage(any()); + setupNormalTestTcpInfo(); assertTrue(tst.pollSocketsInfo()); assertEquals(10, tst.getSentSinceLastRecv()); assertEquals(50, tst.getLatestPacketFailPercentage()); @@ -383,9 +429,7 @@ when(mNetd.getFwmarkForNetwork(eq(TEST_NETID2))) .thenReturn(makeMarkMaskParcel(NETID_MASK, TEST_NETID2_FWMARK)); final TcpSocketTracker tst = new TcpSocketTracker(mDependencies, mOtherNetwork); - final ByteBuffer tcpBufferV6 = getByteBuffer(TEST_RESPONSE_BYTES); - final ByteBuffer tcpBufferV4 = getByteBuffer(TEST_RESPONSE_BYTES); - doReturn(tcpBufferV6, tcpBufferV4).when(mDependencies).recvMessage(any()); + setupNormalTestTcpInfo(); assertTrue(tst.pollSocketsInfo()); assertEquals(0, tst.getSentSinceLastRecv());
diff --git a/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java b/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java index ae9eea4..122ec6e 100644 --- a/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java +++ b/tests/unit/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -58,7 +58,6 @@ import static com.android.networkstack.util.NetworkStackUtils.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS; import static com.android.networkstack.util.NetworkStackUtils.CAPTIVE_PORTAL_USE_HTTPS; import static com.android.networkstack.util.NetworkStackUtils.DEFAULT_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT; -import static com.android.networkstack.util.NetworkStackUtils.DISMISS_PORTAL_IN_VALIDATED_NETWORK; import static com.android.networkstack.util.NetworkStackUtils.DNS_PROBE_PRIVATE_IP_NO_INTERNET_VERSION; import static com.android.server.connectivity.NetworkMonitor.INITIAL_REEVALUATE_DELAY_MS; import static com.android.server.connectivity.NetworkMonitor.extractCharset; @@ -74,7 +73,6 @@ import static org.junit.Assert.fail; import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; -import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.after; @@ -582,7 +580,6 @@ setConsecutiveDnsTimeoutThreshold(5); mCreatedNetworkMonitors = new HashSet<>(); mRegisteredReceivers = new HashSet<>(); - setDismissPortalInValidatedNetwork(false); } @After @@ -2055,7 +2052,8 @@ null /* redirectUrl */); } - public void setupAndLaunchCaptivePortalApp(final NetworkMonitor nm) throws Exception { + public void setupAndLaunchCaptivePortalApp(final NetworkMonitor nm, String expectedUrl) + throws Exception { setSslException(mHttpsConnection); setPortal302(mHttpConnection); doReturn(TEST_LOGIN_URL).when(mHttpConnection).getHeaderField(eq("location")); @@ -2083,15 +2081,27 @@ assertEquals(TEST_NETID, networkCaptor.getValue().netId); // Portal URL should be detection URL. final String redirectUrl = bundle.getString(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL); - assertEquals(TEST_HTTP_URL, redirectUrl); + assertEquals(expectedUrl, redirectUrl); resetCallbacks(); } + @Test - public void testCaptivePortalLogin() throws Exception { + public void testCaptivePortalLogin_beforeR() throws Exception { + assumeFalse(ShimUtils.isAtLeastR()); + testCaptivePortalLogin(TEST_HTTP_URL); + } + + @Test + public void testCaptivePortalLogin_AfterR() throws Exception { + assumeTrue(ShimUtils.isAtLeastR()); + testCaptivePortalLogin(TEST_LOGIN_URL); + } + + private void testCaptivePortalLogin(String expectedUrl) throws Exception { final NetworkMonitor nm = makeMonitor(CELL_METERED_CAPABILITIES); - setupAndLaunchCaptivePortalApp(nm); + setupAndLaunchCaptivePortalApp(nm, expectedUrl); // Have the app report that the captive portal is dismissed, and check that we revalidate. setStatus(mHttpsConnection, 204); @@ -2106,9 +2116,20 @@ } @Test - public void testCaptivePortalUseAsIs() throws Exception { + public void testCaptivePortalUseAsIs_beforeR() throws Exception { + assumeFalse(ShimUtils.isAtLeastR()); + testCaptivePortalUseAsIs(TEST_HTTP_URL); + } + + @Test + public void testCaptivePortalUseAsIs_AfterR() throws Exception { + assumeTrue(ShimUtils.isAtLeastR()); + testCaptivePortalUseAsIs(TEST_LOGIN_URL); + } + + private void testCaptivePortalUseAsIs(String expectedUrl) throws Exception { final NetworkMonitor nm = makeMonitor(CELL_METERED_CAPABILITIES); - setupAndLaunchCaptivePortalApp(nm); + setupAndLaunchCaptivePortalApp(nm, expectedUrl); // The user decides this network is wanted as is, either by encountering an SSL error or // encountering an unknown scheme and then deciding to continue through the browser, or by @@ -2676,7 +2697,6 @@ private void testDismissPortalInValidatedNetworkEnabled(String expectedUrl, String locationUrl) throws Exception { - setDismissPortalInValidatedNetwork(true); setSslException(mHttpsConnection); setPortal302(mHttpConnection); doReturn(locationUrl).when(mHttpConnection).getHeaderField(eq("location")); @@ -2880,9 +2900,6 @@ public void testIsCaptivePortal_FromExternalSource() throws Exception { assumeTrue(CaptivePortalDataShimImpl.isSupported()); assumeTrue(ShimUtils.isAtLeastS()); - doReturn(true).when(mDependencies) - .isFeatureEnabled(any(), eq(NAMESPACE_CONNECTIVITY), - eq(DISMISS_PORTAL_IN_VALIDATED_NETWORK), anyBoolean()); final NetworkMonitor monitor = makeMonitor(WIFI_NOT_METERED_CAPABILITIES); NetworkInformationShim networkShim = NetworkInformationShimImpl.newInstance(); @@ -3058,11 +3075,6 @@ eq(Settings.Global.CAPTIVE_PORTAL_MODE), anyInt()); } - private void setDismissPortalInValidatedNetwork(boolean enabled) { - doReturn(enabled).when(mDependencies).isFeatureEnabled(any(), any(), - eq(DISMISS_PORTAL_IN_VALIDATED_NETWORK), anyBoolean()); - } - private void setDeviceConfig(String key, String value) { doReturn(value).when(mDependencies).getDeviceConfigProperty(eq(NAMESPACE_CONNECTIVITY), eq(key), any() /* defaultValue */);