From e72faa10ed49e6998e1f16b3da726b60c06cde53 Mon Sep 17 00:00:00 2001 From: "Priyanka Advani (xWF)" Date: Thu, 13 Mar 2025 10:22:16 -0700 Subject: [PATCH 1/2] Revert "Stop tethering request only if fuzzy-matched to existing..." Revert submission 3527440 Reason for revert: Droidmonitor created revert due to b/403261952. Will be verifying through ABTD before submission. Reverted changes: /q/submissionid:3527440 Change-Id: I31ae861d5151c9db7e559ba19db7f07c9545d422 --- .../tethering/RequestTracker.java | 17 ---- .../networkstack/tethering/Tethering.java | 19 ++++- .../networkstack/tethering/TetheringTest.java | 80 ------------------- .../tethering/cts/TetheringManagerTest.java | 66 +++------------ 4 files changed, 25 insertions(+), 157 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/RequestTracker.java b/Tethering/src/com/android/networkstack/tethering/RequestTracker.java index 9c61716206..37ad86a45c 100644 --- a/Tethering/src/com/android/networkstack/tethering/RequestTracker.java +++ b/Tethering/src/com/android/networkstack/tethering/RequestTracker.java @@ -239,21 +239,4 @@ public class RequestTracker { public void removeAllServingRequests(final int type) { mServingRequests.entrySet().removeIf(e -> e.getValue().getTetheringType() == type); } - - /** - * Returns an existing (pending or serving) request that fuzzy matches the given request. - * Optionally specify matchUid to only return requests with the same uid. - */ - public TetheringRequest findFuzzyMatchedRequest( - @NonNull final TetheringRequest tetheringRequest, boolean matchUid) { - List allRequests = new ArrayList<>(); - allRequests.addAll(getPendingTetheringRequests()); - allRequests.addAll(mServingRequests.values()); - for (TetheringRequest request : allRequests) { - if (!request.fuzzyMatches(tetheringRequest)) continue; - if (matchUid && tetheringRequest.getUid() != request.getUid()) continue; - return request; - } - return null; - } } diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 59f05ed39a..7b67095697 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -737,13 +737,26 @@ public class Tethering { }); } + private boolean isTetheringTypePendingOrServing(final int type) { + if (mRequestTracker.getNextPendingRequest(type) != null) return true; + for (TetherState state : mTetherStates.values()) { + // TODO: isCurrentlyServing only starts returning true once the IpServer has processed + // the CMD_TETHER_REQUESTED. Ensure that we consider the request to be serving even when + // that has not happened yet. This already works if the sync state machine is enabled + // (which includes all B+ devices). + if (state.isCurrentlyServing() && state.ipServer.interfaceType() == type) return true; + } + return false; + } + void stopTetheringRequest(@NonNull final TetheringRequest request, @NonNull final IIntResultListener listener) { if (!isTetheringWithSoftApConfigEnabled()) return; - final boolean hasNetworkSettings = hasCallingPermission(NETWORK_SETTINGS); mHandler.post(() -> { - if (mRequestTracker.findFuzzyMatchedRequest(request, !hasNetworkSettings) != null) { - final int type = request.getTetheringType(); + final int type = request.getTetheringType(); + // TODO: when fuzzy-matching is enabled, check whether any pending request + // fuzzy-matches this request instead of just checking the type. + if (isTetheringTypePendingOrServing(type)) { stopTetheringInternal(type); // TODO: We should send the success result after the waiting for tethering to // actually stop. diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index 8ecaec9619..970409601d 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -56,7 +56,6 @@ import static android.net.TetheringManager.TETHER_ERROR_INTERNAL_ERROR; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; import static android.net.TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL; import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_IFACE; -import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_REQUEST; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; @@ -2780,85 +2779,6 @@ public class TetheringTest { successListener2.assertHasResult(); } - @Test - public void testStopTetheringWithMatchingRequest() throws Exception { - assumeTrue(isTetheringWithSoftApConfigEnabled()); - when(mContext.checkCallingOrSelfPermission(NETWORK_SETTINGS)).thenReturn(PERMISSION_DENIED); - initTetheringOnTestThread(); - UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState(); - initTetheringUpstream(upstreamState); - when(mWifiManager.startTetheredHotspot(null)).thenReturn(true); - - // Enable wifi tethering. - SoftApConfiguration softApConfig = new SoftApConfiguration.Builder() - .setSsid("SoftApConfig") - .build(); - final TetheringRequest tetheringRequest = new TetheringRequest.Builder(TETHERING_WIFI) - .setSoftApConfiguration(softApConfig).build(); - tetheringRequest.setUid(TEST_CALLER_UID); - mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, null); - mLooper.dispatchAll(); - - // Stop tethering with non-matching config. Should fail with TETHER_ERROR_UNKNOWN_REQUEST. - SoftApConfiguration softApConfig2 = new SoftApConfiguration.Builder() - .setSsid("SoftApConfig2") - .build(); - IIntResultListener differentConfigListener = mock(IIntResultListener.class); - mTethering.stopTetheringRequest(new TetheringRequest.Builder(TETHERING_WIFI) - .setSoftApConfiguration(softApConfig2).build(), differentConfigListener); - mLooper.dispatchAll(); - verify(differentConfigListener).onResult(eq(TETHER_ERROR_UNKNOWN_REQUEST)); - verify(mWifiManager, never()).stopSoftAp(); - - // Stop tethering with non-matching UID. Should fail with TETHER_ERROR_UNKNOWN_REQUEST. - final TetheringRequest nonMatchingUid = new TetheringRequest.Builder(TETHERING_WIFI) - .setSoftApConfiguration(softApConfig).build(); - IIntResultListener nonMatchingUidListener = mock(IIntResultListener.class); - nonMatchingUid.setUid(TEST_CALLER_UID_2); - mTethering.stopTetheringRequest(nonMatchingUid, nonMatchingUidListener); - mLooper.dispatchAll(); - verify(nonMatchingUidListener).onResult(eq(TETHER_ERROR_UNKNOWN_REQUEST)); - verify(mWifiManager, never()).stopSoftAp(); - - // Stop tethering with matching request. Should succeed now. - IIntResultListener matchingListener = mock(IIntResultListener.class); - mTethering.stopTetheringRequest(tetheringRequest, matchingListener); - mLooper.dispatchAll(); - verify(matchingListener).onResult(eq(TETHER_ERROR_NO_ERROR)); - verify(mWifiManager).stopSoftAp(); - } - - @Test - public void testStopTetheringWithSettingsPermission() throws Exception { - assumeTrue(isTetheringWithSoftApConfigEnabled()); - initTetheringOnTestThread(); - UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState(); - initTetheringUpstream(upstreamState); - when(mWifiManager.startTetheredHotspot(null)).thenReturn(true); - - // Enable wifi tethering. - SoftApConfiguration softApConfig = new SoftApConfiguration.Builder() - .setSsid("SoftApConfig") - .build(); - final TetheringRequest tetheringRequest = new TetheringRequest.Builder(TETHERING_WIFI) - .setSoftApConfiguration(softApConfig).build(); - tetheringRequest.setUid(TEST_CALLER_UID); - mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, null); - mLooper.dispatchAll(); - - // Stop tethering with non-matching UID and Settings permission. Should succeed. - final TetheringRequest nonMatchingUid = new TetheringRequest.Builder(TETHERING_WIFI) - .setSoftApConfiguration(softApConfig).build(); - IIntResultListener nonMatchingUidListener = mock(IIntResultListener.class); - nonMatchingUid.setUid(TEST_CALLER_UID_2); - when(mContext.checkCallingOrSelfPermission(NETWORK_SETTINGS)) - .thenReturn(PERMISSION_GRANTED); - mTethering.stopTetheringRequest(nonMatchingUid, nonMatchingUidListener); - mLooper.dispatchAll(); - verify(nonMatchingUidListener).onResult(eq(TETHER_ERROR_NO_ERROR)); - verify(mWifiManager).stopSoftAp(); - } - @Test public void testReportFailCallbackIfOffloadNotSupported() throws Exception { initTetheringOnTestThread(); diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index ed6107bd22..52799abbb7 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -483,73 +483,25 @@ public class TetheringManagerTest { } @Test - public void testStopTetheringRequestNoMatchFailure() throws Exception { - assumeTrue(isTetheringWithSoftApConfigEnabled()); - final TestTetheringEventCallback tetherEventCallback = - mCtsTetheringUtils.registerTetheringEventCallback(); - try { - final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); - mTM.startTethering(new TetheringRequest.Builder(TETHERING_VIRTUAL).build(), - c -> c.run(), startTetheringCallback); - - // Stopping a non-matching request should have no effect - TetheringRequest nonMatchingRequest = new TetheringRequest.Builder(TETHERING_VIRTUAL) - .setInterfaceName("iface") - .build(); - mCtsTetheringUtils.stopTethering(nonMatchingRequest, false /* success */); - } finally { - mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); - } - } - - @Test - public void testStopTetheringRequestMatchSuccess() throws Exception { + public void testStopTetheringRequest() throws Exception { assumeTrue(isTetheringWithSoftApConfigEnabled()); final TestTetheringEventCallback tetherEventCallback = mCtsTetheringUtils.registerTetheringEventCallback(); try { tetherEventCallback.assumeWifiTetheringSupported(mContext); - SoftApConfiguration softApConfig = new SoftApConfiguration.Builder() - .setWifiSsid(WifiSsid.fromBytes("This is one config" - .getBytes(StandardCharsets.UTF_8))).build(); - mCtsTetheringUtils.startWifiTethering(tetherEventCallback, softApConfig); + // stopTethering without any tethering active should fail. + TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build(); + mCtsTetheringUtils.stopTethering(request, false /* expectSuccess */); - // Stopping the active request should stop tethering. - TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI) - .setSoftApConfiguration(softApConfig) - .build(); - mCtsTetheringUtils.stopTethering(request, true /* success */); - tetherEventCallback.expectNoTetheringActive(); - } finally { - mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); - } - } + // Start wifi tethering + mCtsTetheringUtils.startWifiTethering(tetherEventCallback); - @Test - public void testStopTetheringRequestFuzzyMatchSuccess() throws Exception { - assumeTrue(isTetheringWithSoftApConfigEnabled()); - final TestTetheringEventCallback tetherEventCallback = - mCtsTetheringUtils.registerTetheringEventCallback(); - try { - tetherEventCallback.assumeWifiTetheringSupported(mContext); - - SoftApConfiguration softApConfig = new SoftApConfiguration.Builder() - .setWifiSsid(WifiSsid.fromBytes("This is one config" - .getBytes(StandardCharsets.UTF_8))).build(); - mCtsTetheringUtils.startWifiTethering(tetherEventCallback, softApConfig); - - // Stopping with a fuzzy matching request should stop tethering. - final LinkAddress localAddr = new LinkAddress("192.168.24.5/24"); - final LinkAddress clientAddr = new LinkAddress("192.168.24.100/24"); - TetheringRequest fuzzyMatchingRequest = new TetheringRequest.Builder(TETHERING_WIFI) - .setSoftApConfiguration(softApConfig) - .setShouldShowEntitlementUi(true) - .setStaticIpv4Addresses(localAddr, clientAddr) - .build(); - mCtsTetheringUtils.stopTethering(fuzzyMatchingRequest, true /* success */); + // stopTethering should succeed now that there's a request. + mCtsTetheringUtils.stopTethering(request, true /* expectSuccess */); tetherEventCallback.expectNoTetheringActive(); } finally { + mCtsTetheringUtils.stopAllTethering(); mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); } } From 01b6b070ad32bf61b75582c772e84baefa96eddb Mon Sep 17 00:00:00 2001 From: "Priyanka Advani (xWF)" Date: Thu, 13 Mar 2025 10:22:16 -0700 Subject: [PATCH 2/2] Revert "Reject TetheringRequests that fuzzy-match existing ones" Revert submission 3527440 Reason for revert: Droidmonitor created revert due to b/403261952. Will be verifying through ABTD before submission. Reverted changes: /q/submissionid:3527440 Change-Id: Ife596c639899528778f53fef797749fa88596dd6 --- .../src/android/net/TetheringManager.java | 41 --- Tethering/src/android/net/ip/IpServer.java | 6 + .../tethering/RequestTracker.java | 150 +++------ .../networkstack/tethering/Tethering.java | 123 +++----- .../tethering/RequestTrackerTest.java | 204 +----------- .../networkstack/tethering/TetheringTest.java | 291 ++---------------- .../tethering/cts/TetheringManagerTest.java | 34 +- 7 files changed, 116 insertions(+), 733 deletions(-) diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index 2f9c3bce50..0a66f01c7e 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -37,7 +37,6 @@ import android.os.Parcelable; import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; -import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; @@ -1259,44 +1258,6 @@ public class TetheringManager { return sj.toString(); } - @SuppressLint("UnflaggedApi") - private static boolean supportsInterfaceName(int tetheringType) { - // TODO: Check the interface name for TETHERING_WIFI and TETHERING_WIFI_P2P once - // they're actually used. - // Suppress lint for TETHERING_VIRTUAL since this method is only used internally. - return tetheringType == TETHERING_VIRTUAL; - } - - private static boolean supportsConcurrentConnectivityScopes(int tetheringType) { - // Currently, only WIFI supports simultaneous local and global connectivity. - // This can't happen for REQUEST_TYPE_EXPLICIT requests, because - // TetheringRequest.Builder will not allow building an explicit TetheringRequest - // with TETHERING_WIFI and CONNECTIVITY_SCOPE_LOCAL, but when local-only hotspot - // is running, there is a REQUEST_TYPE_IMPLICIT request in the serving request list. - return tetheringType == TETHERING_WIFI; - } - - /** - * Returns true if the other TetheringRequest "fuzzy" matches this one. This is used - * internally to match tracked requests with external requests from API calls, and to reject - * additional requests that the link layer has no capacity for. - * @hide - */ - public boolean fuzzyMatches(final TetheringRequest other) { - if (other == null) return false; - final int type = getTetheringType(); - if (type != other.getTetheringType()) return false; - if (supportsInterfaceName(type) - && !TextUtils.equals(getInterfaceName(), other.getInterfaceName())) { - return false; - } - if (supportsConcurrentConnectivityScopes(type) - && getConnectivityScope() != other.getConnectivityScope()) { - return false; - } - return true; - } - /** * @hide */ @@ -1318,8 +1279,6 @@ public class TetheringManager { public boolean equalsIgnoreUidPackage(TetheringRequest otherRequest) { TetheringRequestParcel parcel = getParcel(); TetheringRequestParcel otherParcel = otherRequest.getParcel(); - // Note: Changes here should also be reflected in fuzzyMatches(TetheringRequest) when - // appropriate. return parcel.requestType == otherParcel.requestType && parcel.tetheringType == otherParcel.tetheringType && Objects.equals(parcel.localIPv4Address, otherParcel.localIPv4Address) diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java index 70a3442c5a..d0ba43174c 100644 --- a/Tethering/src/android/net/ip/IpServer.java +++ b/Tethering/src/android/net/ip/IpServer.java @@ -415,6 +415,12 @@ public class IpServer extends StateMachineShim { return mIpv4PrefixRequest; } + /** The TetheringRequest the IpServer started with. */ + @Nullable + public TetheringRequest getTetheringRequest() { + return mTetheringRequest; + } + /** * Get the latest list of DHCP leases that was reported. Must be called on the IpServer looper * thread. diff --git a/Tethering/src/com/android/networkstack/tethering/RequestTracker.java b/Tethering/src/com/android/networkstack/tethering/RequestTracker.java index 37ad86a45c..3ebe4f772a 100644 --- a/Tethering/src/com/android/networkstack/tethering/RequestTracker.java +++ b/Tethering/src/com/android/networkstack/tethering/RequestTracker.java @@ -19,8 +19,6 @@ package com.android.networkstack.tethering; import static com.android.networkstack.tethering.util.TetheringUtils.createPlaceholderRequest; import android.net.TetheringManager.TetheringRequest; -import android.net.ip.IpServer; -import android.util.ArrayMap; import android.util.Log; import androidx.annotation.NonNull; @@ -30,7 +28,6 @@ import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.List; -import java.util.Map; /** * Helper class to keep track of tethering requests. @@ -39,17 +36,29 @@ import java.util.Map; * layer to start. * 2) When the link layer is up, use {@link #getOrCreatePendingRequest(int)} to get a request to * start IP serving with. - * 3) Remove pending request with {@link #removePendingRequest(TetheringRequest)}. + * 3) Remove all pending requests with {@link #removeAllPendingRequests(int)}. * Note: This class is not thread-safe. + * TODO: Add the pending IIntResultListeners at the same time as the pending requests, and + * call them when we get the tether result. + * TODO: Add support for multiple Bluetooth requests before the PAN service connects instead of + * using a separate mPendingPanRequestListeners. + * TODO: Add support for fuzzy-matched requests. */ public class RequestTracker { private static final String TAG = RequestTracker.class.getSimpleName(); - @NonNull - private final boolean mUseFuzzyMatching; + private class PendingRequest { + @NonNull + private final TetheringRequest mTetheringRequest; - public RequestTracker(boolean useFuzzyMatching) { - mUseFuzzyMatching = useFuzzyMatching; + private PendingRequest(@NonNull TetheringRequest tetheringRequest) { + mTetheringRequest = tetheringRequest; + } + + @NonNull + TetheringRequest getTetheringRequest() { + return mTetheringRequest; + } } public enum AddResult { @@ -60,51 +69,24 @@ public class RequestTracker { /** * Failure indicating that the request could not be added due to a request of the same type * with conflicting parameters already pending. If so, we must stop tethering for the - * pending request before trying to add the result again. Only returned on V-. + * pending request before trying to add the result again. */ - FAILURE_DUPLICATE_REQUEST_RESTART, - /** - * Failure indicating that the request could not be added due to a fuzzy-matched request - * already pending or serving. Only returned on B+. - */ - FAILURE_DUPLICATE_REQUEST_ERROR, + FAILURE_CONFLICTING_PENDING_REQUEST } /** - * List of pending requests added by {@link #addPendingRequest(TetheringRequest)} - * There can be only one per type, since we remove every request of the - * same type when we add a request. + * List of pending requests added by {@link #addPendingRequest(TetheringRequest)}. There can be + * only one per type, since we remove every request of the same type when we add a request. */ - private final List mPendingRequests = new ArrayList<>(); - /** - * List of serving requests added by - * {@link #promoteRequestToServing(IpServer, TetheringRequest)}. - */ - private final Map mServingRequests = new ArrayMap<>(); + private final List mPendingRequests = new ArrayList<>(); @VisibleForTesting List getPendingTetheringRequests() { - return new ArrayList<>(mPendingRequests); - } - - /** - * Adds a pending request or fails with FAILURE_CONFLICTING_REQUEST_FAIL if the request - * fuzzy-matches an existing request (either pending or serving). - */ - public AddResult addPendingRequestFuzzyMatched(@NonNull final TetheringRequest newRequest) { - List existingRequests = new ArrayList<>(); - existingRequests.addAll(mServingRequests.values()); - existingRequests.addAll(mPendingRequests); - for (TetheringRequest request : existingRequests) { - if (request.fuzzyMatches(newRequest)) { - Log.i(TAG, "Cannot add pending request due to existing fuzzy-matched " - + "request: " + request); - return AddResult.FAILURE_DUPLICATE_REQUEST_ERROR; - } + List requests = new ArrayList<>(); + for (PendingRequest pendingRequest : mPendingRequests) { + requests.add(pendingRequest.getTetheringRequest()); } - - mPendingRequests.add(newRequest); - return AddResult.SUCCESS; + return requests; } /** @@ -113,12 +95,9 @@ public class RequestTracker { * layer comes up. The result of the add operation will be returned as an AddResult code. */ public AddResult addPendingRequest(@NonNull final TetheringRequest newRequest) { - if (mUseFuzzyMatching) { - return addPendingRequestFuzzyMatched(newRequest); - } - // Check the existing requests to see if it is OK to add the new request. - for (TetheringRequest existingRequest : mPendingRequests) { + for (PendingRequest request : mPendingRequests) { + TetheringRequest existingRequest = request.getTetheringRequest(); if (existingRequest.getTetheringType() != newRequest.getTetheringType()) { continue; } @@ -126,7 +105,7 @@ public class RequestTracker { // Can't add request if there's a request of the same type with different // parameters. if (!existingRequest.equalsIgnoreUidPackage(newRequest)) { - return AddResult.FAILURE_DUPLICATE_REQUEST_RESTART; + return AddResult.FAILURE_CONFLICTING_PENDING_REQUEST; } } @@ -134,7 +113,7 @@ public class RequestTracker { // conflicting parameters above, so these would have been equivalent anyway (except for // UID). removeAllPendingRequests(newRequest.getTetheringType()); - mPendingRequests.add(newRequest); + mPendingRequests.add(new PendingRequest(newRequest)); return AddResult.SUCCESS; } @@ -166,8 +145,10 @@ public class RequestTracker { */ @Nullable public TetheringRequest getNextPendingRequest(int type) { - for (TetheringRequest request : mPendingRequests) { - if (request.getTetheringType() == type) return request; + for (PendingRequest pendingRequest : mPendingRequests) { + TetheringRequest tetheringRequest = + pendingRequest.getTetheringRequest(); + if (tetheringRequest.getTetheringType() == type) return tetheringRequest; } return null; } @@ -177,66 +158,7 @@ public class RequestTracker { * * @param type Tethering type */ - public void removeAllPendingRequests(final int type) { - mPendingRequests.removeIf(r -> r.getTetheringType() == type); - } - - /** - * Removes a specific pending request. - * - * Note: For V-, this will be the same as removeAllPendingRequests to align with historical - * behavior. - * - * @param request Request to be removed - */ - public void removePendingRequest(@NonNull TetheringRequest request) { - if (!mUseFuzzyMatching) { - // Remove all requests of the same type to match the historical behavior. - removeAllPendingRequests(request.getTetheringType()); - return; - } - - mPendingRequests.removeIf(r -> r.equals(request)); - } - - /** - * Removes a tethering request from the pending list and promotes it to serving with the - * IpServer that is using it. - * Note: If mUseFuzzyMatching is false, then the request will be removed from the pending list, - * but it will not be added to serving list. - */ - public void promoteRequestToServing(@NonNull final IpServer ipServer, - @NonNull final TetheringRequest tetheringRequest) { - removePendingRequest(tetheringRequest); - if (!mUseFuzzyMatching) return; - mServingRequests.put(ipServer, tetheringRequest); - } - - - /** - * Returns the serving request tied to the given IpServer, or null if there is none. - * Note: If mUseFuzzyMatching is false, then this will always return null. - */ - @Nullable - public TetheringRequest getServingRequest(@NonNull final IpServer ipServer) { - return mServingRequests.get(ipServer); - } - - /** - * Removes the serving request tied to the given IpServer. - * Note: If mUseFuzzyMatching is false, then this is a no-op since serving requests are unused - * for that configuration. - */ - public void removeServingRequest(@NonNull final IpServer ipServer) { - mServingRequests.remove(ipServer); - } - - /** - * Removes all serving requests of the given tethering type. - * - * @param type Tethering type - */ - public void removeAllServingRequests(final int type) { - mServingRequests.entrySet().removeIf(e -> e.getValue().getTetheringType() == type); + public void removeAllPendingRequests(int type) { + mPendingRequests.removeIf(r -> r.getTetheringRequest().getTetheringType() == type); } } diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 7b67095697..1a26658c7a 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -43,7 +43,6 @@ import static android.net.TetheringManager.TETHERING_WIFI; import static android.net.TetheringManager.TETHERING_WIFI_P2P; import static android.net.TetheringManager.TETHERING_WIGIG; import static android.net.TetheringManager.TETHER_ERROR_BLUETOOTH_SERVICE_PENDING; -import static android.net.TetheringManager.TETHER_ERROR_DUPLICATE_REQUEST; import static android.net.TetheringManager.TETHER_ERROR_INTERNAL_ERROR; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; import static android.net.TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL; @@ -68,8 +67,6 @@ import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; -import static com.android.networkstack.tethering.RequestTracker.AddResult.FAILURE_DUPLICATE_REQUEST_ERROR; -import static com.android.networkstack.tethering.RequestTracker.AddResult.FAILURE_DUPLICATE_REQUEST_RESTART; import static com.android.networkstack.tethering.TetheringConfiguration.TETHER_FORCE_USB_FUNCTIONS; import static com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE; import static com.android.networkstack.tethering.UpstreamNetworkMonitor.isCellular; @@ -312,7 +309,7 @@ public class Tethering { mLooper = mDeps.makeTetheringLooper(); mNotificationUpdater = mDeps.makeNotificationUpdater(mContext, mLooper); mTetheringMetrics = mDeps.makeTetheringMetrics(mContext); - mRequestTracker = new RequestTracker(isTetheringWithSoftApConfigEnabled()); + mRequestTracker = new RequestTracker(); mTetherStates = new ArrayMap<>(); mConnectedClientsTracker = new ConnectedClientsTracker(); @@ -463,7 +460,6 @@ public class Tethering { return mSettingsObserver; } - // TODO: Replace with SdkLevel.isAtLeastB() once the feature is fully implemented. boolean isTetheringWithSoftApConfigEnabled() { return SdkLevel.isAtLeastB() && Flags.tetheringWithSoftApConfig(); } @@ -708,16 +704,9 @@ public class Tethering { RequestTracker.AddResult result = mRequestTracker.addPendingRequest(request); // If tethering is already pending with a conflicting request, stop tethering before // starting. - if (result == FAILURE_DUPLICATE_REQUEST_RESTART) { + if (result == RequestTracker.AddResult.FAILURE_CONFLICTING_PENDING_REQUEST) { stopTetheringInternal(type); // Also removes the request from the tracker. mRequestTracker.addPendingRequest(request); - } else if (result == FAILURE_DUPLICATE_REQUEST_ERROR) { - // Reject any fuzzy matched request. - // TODO: Add a CTS test to verify back-to-back start/stop calls succeed. This must - // be for a non-Wifi type, since Wifi will reject the start calls if it hasn't - // brought down the SoftAP yet. - sendTetherResult(listener, TETHER_ERROR_DUPLICATE_REQUEST); - return; } if (request.isExemptFromEntitlementCheck()) { @@ -742,8 +731,7 @@ public class Tethering { for (TetherState state : mTetherStates.values()) { // TODO: isCurrentlyServing only starts returning true once the IpServer has processed // the CMD_TETHER_REQUESTED. Ensure that we consider the request to be serving even when - // that has not happened yet. This already works if the sync state machine is enabled - // (which includes all B+ devices). + // that has not happened yet. if (state.isCurrentlyServing() && state.ipServer.interfaceType() == type) return true; } return false; @@ -754,24 +742,23 @@ public class Tethering { if (!isTetheringWithSoftApConfigEnabled()) return; mHandler.post(() -> { final int type = request.getTetheringType(); - // TODO: when fuzzy-matching is enabled, check whether any pending request - // fuzzy-matches this request instead of just checking the type. if (isTetheringTypePendingOrServing(type)) { stopTetheringInternal(type); - // TODO: We should send the success result after the waiting for tethering to - // actually stop. - sendTetherResult(listener, TETHER_ERROR_NO_ERROR); + try { + listener.onResult(TETHER_ERROR_NO_ERROR); + } catch (RemoteException ignored) { } return; } // Request doesn't match any active requests, ignore. - sendTetherResult(listener, TETHER_ERROR_UNKNOWN_REQUEST); + try { + listener.onResult(TETHER_ERROR_UNKNOWN_REQUEST); + } catch (RemoteException ignored) { } }); } void stopTetheringInternal(int type) { mRequestTracker.removeAllPendingRequests(type); - mRequestTracker.removeAllServingRequests(type); // Using a placeholder here is ok since none of the disable APIs use the request for // anything. We simply need the tethering type to know which link layer to poke for removal. @@ -815,25 +802,21 @@ public class Tethering { // The result of Bluetooth tethering will be sent after the pan service connects. if (result == TETHER_ERROR_BLUETOOTH_SERVICE_PENDING) return; - sendTetherResultAndRemoveOnError(request, listener, result); + sendTetherResult(listener, result, type); } - private void sendTetherResult(final IIntResultListener listener, final int result) { + private void sendTetherResult(final IIntResultListener listener, final int result, + final int type) { if (listener != null) { try { listener.onResult(result); - } catch (RemoteException e) { - } + } catch (RemoteException e) { } } - } - - private void sendTetherResultAndRemoveOnError(TetheringRequest request, - final IIntResultListener listener, final int result) { - sendTetherResult(listener, result); + // If changing tethering fail, remove corresponding request + // no matter who trigger the start/stop. if (result != TETHER_ERROR_NO_ERROR) { - mRequestTracker.removePendingRequest(request); - final int type = request.getTetheringType(); + mRequestTracker.removeAllPendingRequests(type); mTetheringMetrics.updateErrorCode(type, result); mTetheringMetrics.sendReport(type); } @@ -879,7 +862,8 @@ public class Tethering { // the service just to stop tethering since tethering is not started. Just remove // any pending request to enable tethering, and notify them that they have failed. if (mPendingPanRequestListener != null) { - sendTetherResult(mPendingPanRequestListener, TETHER_ERROR_SERVICE_UNAVAIL); + sendTetherResult(mPendingPanRequestListener, TETHER_ERROR_SERVICE_UNAVAIL, + TETHERING_BLUETOOTH); } mPendingPanRequestListener = null; return TETHER_ERROR_NO_ERROR; @@ -920,10 +904,7 @@ public class Tethering { if (mPendingPanRequestListener != null) { final int result = setBluetoothTetheringSettings(mBluetoothPan, true /* enable */); - sendTetherResultAndRemoveOnError( - mRequestTracker.getOrCreatePendingRequest(TETHERING_BLUETOOTH), - mPendingPanRequestListener, - result); + sendTetherResult(mPendingPanRequestListener, result, TETHERING_BLUETOOTH); } mPendingPanRequestListener = null; }); @@ -937,10 +918,8 @@ public class Tethering { mIsConnected = false; if (mPendingPanRequestListener != null) { - sendTetherResultAndRemoveOnError( - mRequestTracker.getOrCreatePendingRequest(TETHERING_BLUETOOTH), - mPendingPanRequestListener, - TETHER_ERROR_SERVICE_UNAVAIL); + sendTetherResult(mPendingPanRequestListener, TETHER_ERROR_SERVICE_UNAVAIL, + TETHERING_BLUETOOTH); } mPendingPanRequestListener = null; mBluetoothIfaceRequest = null; @@ -1114,7 +1093,9 @@ public class Tethering { final int type = ifaceNameToType(iface); if (type == TETHERING_INVALID) { Log.e(TAG, "Ignoring call to legacy tether for unknown iface " + iface); - sendTetherResult(listener, TETHER_ERROR_UNKNOWN_IFACE); + try { + listener.onResult(TETHER_ERROR_UNKNOWN_IFACE); + } catch (RemoteException e) { } } TetheringRequest request = mRequestTracker.getNextPendingRequest(type); @@ -1151,7 +1132,9 @@ public class Tethering { // Do nothing break; } - sendTetherResult(listener, result); + try { + listener.onResult(result); + } catch (RemoteException e) { } } /** @@ -1184,9 +1167,11 @@ public class Tethering { Log.e(TAG, "Tried to Tether an unavailable iface: " + iface + ", ignoring"); return TETHER_ERROR_UNAVAIL_IFACE; } - mRequestTracker.promoteRequestToServing(tetherState.ipServer, request); // NOTE: If a CMD_TETHER_REQUESTED message is already in the IpServer's queue but not yet // processed, this will be a no-op and it will not return an error. + // + // This code cannot race with untether() because they both run on the handler thread. + mRequestTracker.removeAllPendingRequests(request.getTetheringType()); tetherState.ipServer.enable(request); if (request.getRequestType() == REQUEST_TYPE_PLACEHOLDER) { TerribleErrorLog.logTerribleError(TetheringStatsLog::write, @@ -1206,7 +1191,10 @@ public class Tethering { return; } mHandler.post(() -> { - sendTetherResult(listener, legacyUntetherInternal(iface)); + try { + listener.onResult(legacyUntetherInternal(iface)); + } catch (RemoteException e) { + } }); } @@ -1221,7 +1209,7 @@ public class Tethering { Log.e(TAG, "Tried to untether an inactive iface :" + iface + ", ignoring"); return TETHER_ERROR_UNAVAIL_IFACE; } - ensureIpServerUnwanted(tetherState.ipServer); + tetherState.ipServer.unwanted(); return TETHER_ERROR_NO_ERROR; } @@ -1301,12 +1289,7 @@ public class Tethering { final TetherState tetherState = mTetherStates.valueAt(i); final int type = tetherState.ipServer.interfaceType(); final String iface = mTetherStates.keyAt(i); - // Note: serving requests are only populated on B+. B+ also uses the sync state - // machine by default. This ensures that the serving request is (correctly) populated - // after the IpServer enters the available state and before it enters the serving - // state. - final TetheringRequest request = - mRequestTracker.getServingRequest(tetherState.ipServer); + final TetheringRequest request = tetherState.ipServer.getTetheringRequest(); final boolean includeSoftApConfig = request != null && cookie != null && (cookie.uid == request.getUid() || cookie.hasSystemPrivilege); final TetheringInterface tetheringIface = new TetheringInterface(type, iface, @@ -1628,7 +1611,7 @@ public class Tethering { private void disableWifiIpServingCommon(int tetheringType, String ifname) { if (!TextUtils.isEmpty(ifname) && mTetherStates.containsKey(ifname)) { - ensureIpServerUnwanted(mTetherStates.get(ifname).ipServer); + mTetherStates.get(ifname).ipServer.unwanted(); return; } @@ -1645,7 +1628,7 @@ public class Tethering { for (int i = 0; i < mTetherStates.size(); i++) { final IpServer ipServer = mTetherStates.valueAt(i).ipServer; if (ipServer.interfaceType() == tetheringType) { - ensureIpServerUnwanted(ipServer); + ipServer.unwanted(); return; } } @@ -1792,7 +1775,9 @@ public class Tethering { void setUsbTethering(boolean enable, IIntResultListener listener) { mHandler.post(() -> { - sendTetherResult(listener, setUsbTethering(enable)); + try { + listener.onResult(setUsbTethering(enable)); + } catch (RemoteException e) { } }); } @@ -2919,9 +2904,6 @@ public class Tethering { tetherState.lastState = state; tetherState.lastError = lastError; } else { - // Note: Even if an IpServer exists for this iface, it may be different from "who" - // if a new IpServer fills the gap before the IpServer.STATE_UNAVAILABLE transition. - // TODO: remove this comment once the sync state machine is enabled everywhere. if (DBG) Log.d(TAG, "got notification from stale iface " + iface); } @@ -2936,19 +2918,7 @@ public class Tethering { int which; switch (state) { case IpServer.STATE_UNAVAILABLE: - which = TetherMainSM.EVENT_IFACE_SERVING_STATE_INACTIVE; - break; case IpServer.STATE_AVAILABLE: - if (lastError != TETHER_ERROR_NO_ERROR) { - // IpServer transitioned from an enabled state (STATE_TETHERED or - // STATE_LOCAL_ONLY) back to STATE_AVAILABLE due to an error, so make sure - // we remove the serving request from RequestTracker. - // TODO: don't continue to use IpServers after they have hit an error, and - // instead move them to STATE_UNAVAILABLE. This code can then - // unconditionally remove the serving request whenever the IpServer enters - // STATE_UNAVAILABLE. - mRequestTracker.removeServingRequest(who); - } which = TetherMainSM.EVENT_IFACE_SERVING_STATE_INACTIVE; break; case IpServer.STATE_TETHERED: @@ -3044,18 +3014,11 @@ public class Tethering { final TetherState tetherState = mTetherStates.get(iface); if (tetherState == null) return; - mRequestTracker.removeServingRequest(tetherState.ipServer); tetherState.ipServer.stop(); mLog.i("removing IpServer for: " + iface); mTetherStates.remove(iface); } - private void ensureIpServerUnwanted(final IpServer ipServer) { - mLog.i("unrequesting IpServer: " + ipServer); - mRequestTracker.removeServingRequest(ipServer); - ipServer.unwanted(); - } - private static String[] copy(String[] strarray) { return Arrays.copyOf(strarray, strarray.length); } @@ -3063,7 +3026,9 @@ public class Tethering { void setPreferTestNetworks(final boolean prefer, IIntResultListener listener) { mHandler.post(() -> { mUpstreamNetworkMonitor.setPreferTestNetworks(prefer); - sendTetherResult(listener, TETHER_ERROR_NO_ERROR); + try { + listener.onResult(TETHER_ERROR_NO_ERROR); + } catch (RemoteException e) { } }); } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/RequestTrackerTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/RequestTrackerTest.java index 086f2d2070..e00e9f001f 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/RequestTrackerTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/RequestTrackerTest.java @@ -18,22 +18,19 @@ package com.android.networkstack.tethering; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; -import static android.net.TetheringManager.TETHERING_VIRTUAL; import static com.android.networkstack.tethering.util.TetheringUtils.createPlaceholderRequest; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.mock; - import android.net.TetheringManager.TetheringRequest; -import android.net.ip.IpServer; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.networkstack.tethering.RequestTracker.AddResult; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -42,10 +39,13 @@ import org.junit.runner.RunWith; public class RequestTrackerTest { private RequestTracker mRequestTracker; + @Before + public void setUp() { + mRequestTracker = new RequestTracker(); + } + @Test public void testNoRequestsAdded_noPendingRequests() { - mRequestTracker = new RequestTracker(false); - assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isNull(); assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI)) .isEqualTo(createPlaceholderRequest(TETHERING_WIFI)); @@ -53,7 +53,6 @@ public class RequestTrackerTest { @Test public void testAddRequest_successResultAndBecomesNextPending() { - mRequestTracker = new RequestTracker(false); final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build(); final AddResult result = mRequestTracker.addPendingRequest(request); @@ -65,7 +64,6 @@ public class RequestTrackerTest { @Test public void testAddRequest_equalRequestExists_successResultAndBecomesNextPending() { - mRequestTracker = new RequestTracker(false); final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build(); mRequestTracker.addPendingRequest(request); @@ -79,7 +77,6 @@ public class RequestTrackerTest { @Test public void testAddRequest_equalButDifferentUidRequest_successResultAndBecomesNextPending() { - mRequestTracker = new RequestTracker(false); final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build(); request.setUid(1000); request.setPackageName("package"); @@ -97,8 +94,7 @@ public class RequestTrackerTest { } @Test - public void testAddRequest_conflictingPendingRequest_returnsFailureConflictingRequestRestart() { - mRequestTracker = new RequestTracker(false); + public void testAddConflictingRequest_returnsFailureConflictingPendingRequest() { final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build(); final TetheringRequest conflictingRequest = new TetheringRequest.Builder(TETHERING_WIFI) .setExemptFromEntitlementCheck(true).build(); @@ -106,139 +102,13 @@ public class RequestTrackerTest { final AddResult result = mRequestTracker.addPendingRequest(conflictingRequest); - assertThat(result).isEqualTo(AddResult.FAILURE_DUPLICATE_REQUEST_RESTART); + assertThat(result).isEqualTo(AddResult.FAILURE_CONFLICTING_PENDING_REQUEST); assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isEqualTo(request); assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI)).isEqualTo(request); } - @Test - public void testAddRequest_noExistingRequestsFuzzyMatching_returnsSuccess() { - mRequestTracker = new RequestTracker(true); - final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build(); - - final AddResult result = mRequestTracker.addPendingRequest(request); - - assertThat(result).isEqualTo(AddResult.SUCCESS); - assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isEqualTo(request); - assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI)).isEqualTo(request); - } - - @Test - public void testAddRequest_conflictingPendingRequestFuzzyMatching_returnsFailure() { - mRequestTracker = new RequestTracker(true); - final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build(); - final TetheringRequest conflictingRequest = new TetheringRequest.Builder(TETHERING_WIFI) - .setExemptFromEntitlementCheck(true).build(); - mRequestTracker.addPendingRequest(request); - - final AddResult result = mRequestTracker.addPendingRequest(conflictingRequest); - - assertThat(result).isEqualTo(AddResult.FAILURE_DUPLICATE_REQUEST_ERROR); - assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isEqualTo(request); - assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI)).isEqualTo(request); - } - - @Test - public void testAddRequest_conflictingServingRequestFuzzyMatching_returnsFailure() { - mRequestTracker = new RequestTracker(true); - final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build(); - final TetheringRequest conflictingRequest = new TetheringRequest.Builder(TETHERING_WIFI) - .setExemptFromEntitlementCheck(true).build(); - mRequestTracker.promoteRequestToServing(mock(IpServer.class), request); - - final AddResult result = mRequestTracker.addPendingRequest(conflictingRequest); - - assertThat(result).isEqualTo(AddResult.FAILURE_DUPLICATE_REQUEST_ERROR); - assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isNull(); - assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI)) - .isEqualTo(createPlaceholderRequest(TETHERING_WIFI)); - } - - @Test - public void testAddRequest_nonMatchingPendingRequestFuzzyMatching_returnsSuccess() { - mRequestTracker = new RequestTracker(true); - final TetheringRequest request = new TetheringRequest.Builder(TETHERING_VIRTUAL).build(); - final TetheringRequest nonFuzzyMatched = new TetheringRequest.Builder(TETHERING_VIRTUAL) - .setInterfaceName("iface") - .build(); - mRequestTracker.addPendingRequest(request); - - final AddResult result = mRequestTracker.addPendingRequest(nonFuzzyMatched); - - assertThat(result).isEqualTo(AddResult.SUCCESS); - // Next request is still the first, but verify RequestTracker contains the second request by - // seeing if it rejects anything matching the second request - assertThat(mRequestTracker.getNextPendingRequest(TETHERING_VIRTUAL)).isEqualTo(request); - assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_VIRTUAL)) - .isEqualTo(request); - assertThat(mRequestTracker.addPendingRequestFuzzyMatched(nonFuzzyMatched)) - .isEqualTo(AddResult.FAILURE_DUPLICATE_REQUEST_ERROR); - } - - @Test - public void testAddRequest_nonMatchingServingRequestFuzzyMatching_returnsSuccess() { - mRequestTracker = new RequestTracker(true); - final TetheringRequest request = new TetheringRequest.Builder(TETHERING_VIRTUAL).build(); - final TetheringRequest nonFuzzyMatched = new TetheringRequest.Builder(TETHERING_VIRTUAL) - .setInterfaceName("iface") - .build(); - mRequestTracker.promoteRequestToServing(mock(IpServer.class), request); - - final AddResult result = mRequestTracker.addPendingRequest(nonFuzzyMatched); - - assertThat(result).isEqualTo(AddResult.SUCCESS); - assertThat(mRequestTracker.getNextPendingRequest(TETHERING_VIRTUAL)) - .isEqualTo(nonFuzzyMatched); - assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_VIRTUAL)) - .isEqualTo(nonFuzzyMatched); - } - - @Test - public void testRemovePendingRequest_removesAllPendingRequestsOfType() { - mRequestTracker = new RequestTracker(false); - final TetheringRequest request1 = new TetheringRequest.Builder(TETHERING_WIFI).build(); - request1.setUid(1000); - request1.setPackageName("package"); - mRequestTracker.addPendingRequest(request1); - final TetheringRequest request2 = new TetheringRequest.Builder(TETHERING_WIFI).build(); - request2.setUid(2000); - request2.setPackageName("package2"); - - mRequestTracker.removePendingRequest(request2); - - // Verify request1 isn't pending even though we tried to remove a different request - assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isNull(); - assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI)) - .isEqualTo(createPlaceholderRequest(TETHERING_WIFI)); - } - - @Test - public void testRemovePendingRequest_fuzzyMatching_onlyTheEqualRequestIsRemoved() { - mRequestTracker = new RequestTracker(true); - final TetheringRequest request1 = new TetheringRequest.Builder(TETHERING_VIRTUAL).build(); - final TetheringRequest request2 = new TetheringRequest.Builder(TETHERING_VIRTUAL) - .setInterfaceName("iface") - .build(); - mRequestTracker.addPendingRequest(request1); - mRequestTracker.addPendingRequest(request2); - - mRequestTracker.removePendingRequest(request2); - - // Verify request1 is still pending. - assertThat(mRequestTracker.getNextPendingRequest(TETHERING_VIRTUAL)).isEqualTo(request1); - assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_VIRTUAL)) - .isEqualTo(request1); - assertThat(mRequestTracker.addPendingRequestFuzzyMatched(request1)) - .isEqualTo(AddResult.FAILURE_DUPLICATE_REQUEST_ERROR); - // Verify we've removed request2 by checking if it can be added back without - // FAILURE_CONFLICTING_REQUEST_FAIL. - assertThat(mRequestTracker.addPendingRequestFuzzyMatched(request2)) - .isEqualTo(AddResult.SUCCESS); - } - @Test public void testRemoveAllPendingRequests_noPendingRequestsLeft() { - mRequestTracker = new RequestTracker(false); final TetheringRequest firstRequest = new TetheringRequest.Builder(TETHERING_WIFI).build(); firstRequest.setUid(1000); firstRequest.setPackageName("package"); @@ -257,7 +127,6 @@ public class RequestTrackerTest { @Test public void testRemoveAllPendingRequests_differentTypeExists_doesNotRemoveDifferentType() { - mRequestTracker = new RequestTracker(false); final TetheringRequest differentType = new TetheringRequest.Builder(TETHERING_USB).build(); mRequestTracker.addPendingRequest(differentType); @@ -267,61 +136,4 @@ public class RequestTrackerTest { assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_USB)) .isEqualTo(differentType); } - - @Test - public void testPromoteRequestToServing_requestIsntPendingAnymore() { - mRequestTracker = new RequestTracker(false); - final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build(); - mRequestTracker.addPendingRequest(request); - - mRequestTracker.promoteRequestToServing(mock(IpServer.class), request); - - assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isNull(); - assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI)) - .isEqualTo(createPlaceholderRequest(TETHERING_WIFI)); - } - - @Test - public void testPromoteRequestToServing_fuzzyMatching_requestIsntPendingAnymore() { - mRequestTracker = new RequestTracker(true); - final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build(); - mRequestTracker.addPendingRequest(request); - - mRequestTracker.promoteRequestToServing(mock(IpServer.class), request); - - assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isNull(); - assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI)) - .isEqualTo(createPlaceholderRequest(TETHERING_WIFI)); - } - - @Test - public void testRemoveServingRequest_fuzzyMatching_requestCanBeAddedAgain() { - mRequestTracker = new RequestTracker(true); - final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build(); - mRequestTracker.addPendingRequest(request); - IpServer ipServer = mock(IpServer.class); - mRequestTracker.promoteRequestToServing(ipServer, request); - - mRequestTracker.removeServingRequest(ipServer); - - AddResult result = mRequestTracker.addPendingRequest(request); - assertThat(result).isEqualTo(AddResult.SUCCESS); - assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isEqualTo(request); - assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI)).isEqualTo(request); - } - - @Test - public void testRemoveAllServingRequests_fuzzyMatching_requestCanBeAddedAgain() { - mRequestTracker = new RequestTracker(true); - final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build(); - mRequestTracker.addPendingRequest(request); - mRequestTracker.promoteRequestToServing(mock(IpServer.class), request); - - mRequestTracker.removeAllServingRequests(TETHERING_WIFI); - - AddResult result = mRequestTracker.addPendingRequest(request); - assertThat(result).isEqualTo(AddResult.SUCCESS); - assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isEqualTo(request); - assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI)).isEqualTo(request); - } } diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index 970409601d..2a22c6d998 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -50,7 +50,6 @@ import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_VIRTUAL; import static android.net.TetheringManager.TETHERING_WIFI; import static android.net.TetheringManager.TETHERING_WIFI_P2P; -import static android.net.TetheringManager.TETHER_ERROR_DUPLICATE_REQUEST; import static android.net.TetheringManager.TETHER_ERROR_IFACE_CFG_ERROR; import static android.net.TetheringManager.TETHER_ERROR_INTERNAL_ERROR; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; @@ -60,7 +59,6 @@ import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; -import static android.net.dhcp.IDhcpServer.STATUS_UNKNOWN_ERROR; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE; @@ -95,7 +93,6 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.notNull; @@ -200,7 +197,6 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.FakeSettingsProvider; import com.android.modules.utils.build.SdkLevel; -import com.android.net.flags.Flags; import com.android.net.module.util.CollectionUtils; import com.android.net.module.util.InterfaceParams; import com.android.net.module.util.PrivateAddressCoordinator; @@ -312,7 +308,8 @@ public class TetheringTest { @Mock private TetheringMetrics mTetheringMetrics; @Mock private PrivateAddressCoordinator.Dependencies mPrivateAddressCoordinatorDependencies; - private MockIpServerDependencies mIpServerDependencies; + private final MockIpServerDependencies mIpServerDependencies = + spy(new MockIpServerDependencies()); private final MockTetheringDependencies mTetheringDependencies = new MockTetheringDependencies(); @@ -399,9 +396,6 @@ public class TetheringTest { } public class MockIpServerDependencies extends IpServer.Dependencies { - - private int mOnDhcpServerCreatedResult = STATUS_SUCCESS; - @Override public DadProxy getDadProxy( Handler handler, InterfaceParams ifParams) { @@ -443,7 +437,7 @@ public class TetheringTest { DhcpServerCallbacks cb) { new Thread(() -> { try { - cb.onDhcpServerCreated(mOnDhcpServerCreatedResult, mDhcpServer); + cb.onDhcpServerCreated(STATUS_SUCCESS, mDhcpServer); } catch (RemoteException e) { fail(e.getMessage()); } @@ -454,10 +448,6 @@ public class TetheringTest { IpNeighborMonitor.NeighborEventConsumer c) { return mIpNeighborMonitor; } - - public void setOnDhcpServerCreatedResult(final int result) { - mOnDhcpServerCreatedResult = result; - } } public class MockTetheringDependencies extends TetheringDependencies { @@ -718,7 +708,6 @@ public class TetheringTest { when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)).thenReturn(true); when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)).thenReturn(true); - mIpServerDependencies = spy(new MockIpServerDependencies()); } // In order to interact with syncSM from the test, tethering must be created in test thread. @@ -2436,7 +2425,7 @@ public class TetheringTest { @Test public void testSoftApConfigInTetheringEventCallback() throws Exception { - assumeTrue(isTetheringWithSoftApConfigEnabled()); + assumeTrue(SdkLevel.isAtLeastV()); when(mContext.checkCallingOrSelfPermission(NETWORK_SETTINGS)) .thenReturn(PERMISSION_DENIED); when(mContext.checkCallingOrSelfPermission(NETWORK_STACK)) @@ -2493,12 +2482,14 @@ public class TetheringTest { // Enable wifi tethering mBinderCallingUid = TEST_CALLER_UID; mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, null); - mLooper.dispatchAll(); mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true); mLooper.dispatchAll(); - // Netd "up" event should not trigger a state change callback in B+. - callback.assertNoStateChangeCallback(); + if (SdkLevel.isAtLeastB()) { + // Starting in B, ignore the interfaceStatusChanged + callback.assertNoStateChangeCallback(); + } sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED); + mLooper.dispatchAll(); // Verify we see Available -> Tethered states assertArrayEquals(new TetheringInterface[] {wifiIfaceWithoutConfig}, callback.pollTetherStatesChanged().availableList); @@ -2516,15 +2507,20 @@ public class TetheringTest { callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STARTED); // Disable wifi tethering - mTethering.stopTethering(TETHERING_WIFI); mLooper.dispatchAll(); - sendWifiApStateChanged(WIFI_AP_STATE_DISABLED, TEST_WLAN_IFNAME, + mTethering.stopTethering(TETHERING_WIFI); + sendWifiApStateChanged(WIFI_AP_STATE_DISABLED); + if (isAtLeastT()) { + // After T, tethering doesn't support WIFI_AP_STATE_DISABLED with null interface name. + callback.assertNoStateChangeCallback(); + sendWifiApStateChanged(WIFI_AP_STATE_DISABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED); - assertArrayEquals(new TetheringInterface[] {wifiIfaceWithoutConfig}, + } + assertArrayEquals(new TetheringInterface[] {wifiIfaceWithConfig}, callback.pollTetherStatesChanged().availableList); assertArrayEquals(new TetheringInterface[] {wifiIfaceWithoutConfig}, differentCallback.pollTetherStatesChanged().availableList); - assertArrayEquals(new TetheringInterface[] {wifiIfaceWithoutConfig}, + assertArrayEquals(new TetheringInterface[] {wifiIfaceWithConfig}, settingsCallback.pollTetherStatesChanged().availableList); mLooper.dispatchAll(); callback.expectUpstreamChanged(NULL_NETWORK); @@ -2532,253 +2528,6 @@ public class TetheringTest { callback.assertNoCallback(); } - private boolean isTetheringWithSoftApConfigEnabled() { - return SdkLevel.isAtLeastB() && Flags.tetheringWithSoftApConfig(); - } - - @Test - public void testFuzzyMatchedWifiCannotBeAdded() throws Exception { - assumeTrue(isTetheringWithSoftApConfigEnabled()); - initTetheringOnTestThread(); - TestTetheringEventCallback callback = new TestTetheringEventCallback(); - SoftApConfiguration softApConfig = new SoftApConfiguration.Builder().setWifiSsid( - WifiSsid.fromBytes("SoftApConfig".getBytes(StandardCharsets.UTF_8))).build(); - final TetheringInterface wifiIfaceWithoutConfig = new TetheringInterface( - TETHERING_WIFI, TEST_WLAN_IFNAME, null); - final TetheringInterface wifiIfaceWithConfig = new TetheringInterface( - TETHERING_WIFI, TEST_WLAN_IFNAME, softApConfig); - - // Register callback before running any tethering. - mTethering.registerTetheringEventCallback(callback); - mLooper.dispatchAll(); - callback.expectTetheredClientChanged(Collections.emptyList()); - callback.expectUpstreamChanged(NULL_NETWORK); - callback.expectConfigurationChanged( - mTethering.getTetheringConfiguration().toStableParcelable()); - assertTetherStatesNotNullButEmpty(callback.pollTetherStatesChanged()); - callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED); - UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState(); - initTetheringUpstream(upstreamState); - - // Start wifi tethering but don't trigger the link layer event yet. - mBinderCallingUid = TEST_CALLER_UID; - final TetheringRequest tetheringRequest = new TetheringRequest.Builder(TETHERING_WIFI) - .setSoftApConfiguration(softApConfig).build(); - tetheringRequest.setUid(TEST_CALLER_UID); - ResultListener successListener = new ResultListener(TETHER_ERROR_NO_ERROR); - when(mWifiManager.startTetheredHotspot(null)).thenReturn(true); - mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener); - mLooper.dispatchAll(); - successListener.assertHasResult(); - - // Try starting wifi tethering with various fuzzy-matching requests and verify we get - // TETHER_ERROR_DUPLICATE_REQUEST. - - // Different static IP addresses - final TetheringRequest differentIpAddr = new TetheringRequest.Builder(TETHERING_WIFI) - .setSoftApConfiguration(softApConfig) - .setStaticIpv4Addresses(new LinkAddress("192.168.0.123/24"), - new LinkAddress("192.168.0.42/24")) - .build(); - differentIpAddr.setUid(TEST_CALLER_UID); - ResultListener differentIpAddrListener = new ResultListener(TETHER_ERROR_DUPLICATE_REQUEST); - mTethering.startTethering(differentIpAddr, TEST_CALLER_PKG, differentIpAddrListener); - mLooper.dispatchAll(); - verify(mWifiManager, times(1)).startTetheredHotspot(any()); - verify(mWifiManager, never()).stopSoftAp(); - differentIpAddrListener.assertHasResult(); - - // Different UID - final TetheringRequest differentUid = new TetheringRequest.Builder(TETHERING_WIFI) - .setSoftApConfiguration(softApConfig).build(); - differentUid.setUid(TEST_CALLER_UID + 1); - ResultListener differentUidListener = new ResultListener(TETHER_ERROR_DUPLICATE_REQUEST); - mTethering.startTethering(differentUid, TEST_CALLER_PKG, differentUidListener); - mLooper.dispatchAll(); - differentUidListener.assertHasResult(); - verify(mWifiManager, times(1)).startTetheredHotspot(any()); - verify(mWifiManager, never()).stopSoftAp(); - - // Mock the link layer event to start IP serving and verify we still get - // TETHER_ERROR_DUPLICATE_REQUEST even though the request is no longer pending and is - // already serving. - sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED); - assertArrayEquals(new TetheringInterface[] {wifiIfaceWithoutConfig}, - callback.pollTetherStatesChanged().availableList); - assertArrayEquals(new TetheringInterface[] {wifiIfaceWithConfig}, - callback.pollTetherStatesChanged().tetheredList); - callback.expectUpstreamChanged(upstreamState.network); - callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STARTED); - differentIpAddrListener = new ResultListener(TETHER_ERROR_DUPLICATE_REQUEST); - differentUidListener = new ResultListener(TETHER_ERROR_DUPLICATE_REQUEST); - mTethering.startTethering(differentIpAddr, TEST_CALLER_PKG, differentIpAddrListener); - mTethering.startTethering(differentUid, TEST_CALLER_PKG, differentUidListener); - mLooper.dispatchAll(); - differentIpAddrListener.assertHasResult(); - differentUidListener.assertHasResult(); - verify(mWifiManager, times(1)).startTetheredHotspot(any()); - verify(mWifiManager, never()).stopSoftAp(); - } - - @Test - public void testFuzzyMatchedWifiCanBeAddedAfterIpServerStopped() throws Exception { - assumeTrue(isTetheringWithSoftApConfigEnabled()); - when(mWifiManager.startTetheredHotspot(null)).thenReturn(true); - initTetheringOnTestThread(); - - // Start wifi tethering and mock the ap state change. - SoftApConfiguration softApConfig = new SoftApConfiguration.Builder().setWifiSsid( - WifiSsid.fromBytes("SoftApConfig".getBytes(StandardCharsets.UTF_8))).build(); - final TetheringRequest tetheringRequest = new TetheringRequest.Builder(TETHERING_WIFI) - .setSoftApConfiguration(softApConfig).build(); - ResultListener successListener = new ResultListener(TETHER_ERROR_NO_ERROR); - mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener); - mLooper.dispatchAll(); - successListener.assertHasResult(); - sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED); - - // Starting wifi again will cause TETHER_ERROR_DUPLICATE_REQUEST - ResultListener failureListener = new ResultListener(TETHER_ERROR_DUPLICATE_REQUEST); - mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, failureListener); - mLooper.dispatchAll(); - failureListener.assertHasResult(); - - // Trigger Netd callback to stop the IpServer - mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, false); - - // We should be able to request the same Wifi again - ResultListener successListener2 = new ResultListener(TETHER_ERROR_DUPLICATE_REQUEST); - mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener2); - mLooper.dispatchAll(); - successListener2.assertHasResult(); - } - - @Test - public void testFuzzyMatchedWifiCanBeAddedAfterIpServerUnwanted() throws Exception { - assumeTrue(isTetheringWithSoftApConfigEnabled()); - when(mWifiManager.startTetheredHotspot(null)).thenReturn(true); - initTetheringOnTestThread(); - - // Start wifi tethering and mock the ap state change. - SoftApConfiguration softApConfig = new SoftApConfiguration.Builder().setWifiSsid( - WifiSsid.fromBytes("SoftApConfig".getBytes(StandardCharsets.UTF_8))).build(); - final TetheringRequest tetheringRequest = new TetheringRequest.Builder(TETHERING_WIFI) - .setSoftApConfiguration(softApConfig).build(); - ResultListener successListener = new ResultListener(TETHER_ERROR_NO_ERROR); - mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener); - mLooper.dispatchAll(); - successListener.assertHasResult(); - sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED); - - // Starting wifi again will cause TETHER_ERROR_DUPLICATE_REQUEST - ResultListener failureListener = new ResultListener(TETHER_ERROR_DUPLICATE_REQUEST); - mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, failureListener); - mLooper.dispatchAll(); - failureListener.assertHasResult(); - - // Trigger wifi ap state change to tell IpServer it's unwanted. - sendWifiApStateChanged(WIFI_AP_STATE_DISABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED); - - // We should be able to request the same Wifi again - ResultListener successListener2 = new ResultListener(TETHER_ERROR_NO_ERROR); - mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener2); - mLooper.dispatchAll(); - successListener2.assertHasResult(); - } - - @Test - public void testFuzzyMatchedWifiCanBeAddedAfterIpServerError() throws Exception { - assumeTrue(isTetheringWithSoftApConfigEnabled()); - when(mWifiManager.startTetheredHotspot(null)).thenReturn(true); - initTetheringOnTestThread(); - - // Set up the DHCP server to fail creation. - mIpServerDependencies.setOnDhcpServerCreatedResult(STATUS_UNKNOWN_ERROR); - - // Start wifi tethering and mock the ap state change. - SoftApConfiguration softApConfig = new SoftApConfiguration.Builder().setWifiSsid( - WifiSsid.fromBytes("SoftApConfig".getBytes(StandardCharsets.UTF_8))).build(); - final TetheringRequest tetheringRequest = new TetheringRequest.Builder(TETHERING_WIFI) - .setSoftApConfiguration(softApConfig).build(); - ResultListener successListener = new ResultListener(TETHER_ERROR_NO_ERROR); - mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener); - mLooper.dispatchAll(); - successListener.assertHasResult(); - sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED); - - // We should be able to request the same Wifi again since the DHCP server transitioned the - // IpServer back to InitialState. - ResultListener successListener2 = new ResultListener(TETHER_ERROR_NO_ERROR); - mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener2); - mLooper.dispatchAll(); - successListener2.assertHasResult(); - } - - @Test - public void testFuzzyMatchedWifiCanBeAddedAfterStoppingPendingRequest() throws Exception { - assumeTrue(isTetheringWithSoftApConfigEnabled()); - when(mWifiManager.startTetheredHotspot(null)).thenReturn(true); - initTetheringOnTestThread(); - - // Start wifi tethering but keep the request pending by not sending the ap state change. - SoftApConfiguration softApConfig = new SoftApConfiguration.Builder().setWifiSsid( - WifiSsid.fromBytes("SoftApConfig".getBytes(StandardCharsets.UTF_8))).build(); - final TetheringRequest tetheringRequest = new TetheringRequest.Builder(TETHERING_WIFI) - .setSoftApConfiguration(softApConfig).build(); - ResultListener successListener = new ResultListener(TETHER_ERROR_NO_ERROR); - mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener); - mLooper.dispatchAll(); - successListener.assertHasResult(); - - // Starting wifi again will cause TETHER_ERROR_DUPLICATE_REQUEST - ResultListener failureListener = new ResultListener(TETHER_ERROR_DUPLICATE_REQUEST); - mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, failureListener); - mLooper.dispatchAll(); - failureListener.assertHasResult(); - - // Stop Wifi tethering. - mTethering.stopTethering(TETHERING_WIFI); - - // We should be able to request the same Wifi again - ResultListener successListener2 = new ResultListener(TETHER_ERROR_NO_ERROR); - mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener2); - mLooper.dispatchAll(); - successListener2.assertHasResult(); - } - - @Test - public void testFuzzyMatchedWifiCanBeAddedAfterStoppingServingRequest() throws Exception { - assumeTrue(isTetheringWithSoftApConfigEnabled()); - when(mWifiManager.startTetheredHotspot(null)).thenReturn(true); - initTetheringOnTestThread(); - - // Start wifi tethering and mock the ap state change. - SoftApConfiguration softApConfig = new SoftApConfiguration.Builder().setWifiSsid( - WifiSsid.fromBytes("SoftApConfig".getBytes(StandardCharsets.UTF_8))).build(); - final TetheringRequest tetheringRequest = new TetheringRequest.Builder(TETHERING_WIFI) - .setSoftApConfiguration(softApConfig).build(); - ResultListener successListener = new ResultListener(TETHER_ERROR_NO_ERROR); - mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener); - mLooper.dispatchAll(); - successListener.assertHasResult(); - sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED); - - // Starting wifi again will cause TETHER_ERROR_DUPLICATE_REQUEST - ResultListener failureListener = new ResultListener(TETHER_ERROR_DUPLICATE_REQUEST); - mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, failureListener); - mLooper.dispatchAll(); - failureListener.assertHasResult(); - - // Stop Wifi tethering. - mTethering.stopTethering(TETHERING_WIFI); - - // We should be able to request the same Wifi again - ResultListener successListener2 = new ResultListener(TETHER_ERROR_NO_ERROR); - mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener2); - mLooper.dispatchAll(); - successListener2.assertHasResult(); - } - @Test public void testReportFailCallbackIfOffloadNotSupported() throws Exception { initTetheringOnTestThread(); @@ -3045,8 +2794,7 @@ public class TetheringTest { } @Test - public void testMultipleStartTetheringLegacy() throws Exception { - assumeFalse(isTetheringWithSoftApConfigEnabled()); + public void testMultipleStartTethering() throws Exception { initTetheringOnTestThread(); final LinkAddress serverLinkAddr = new LinkAddress("192.168.20.1/24"); final LinkAddress clientLinkAddr = new LinkAddress("192.168.20.42/24"); @@ -3827,7 +3575,6 @@ public class TetheringTest { @Test public void testStartBluetoothTetheringFailsWhenTheresAnExistingRequestWaitingForPanService() throws Exception { - assumeFalse(isTetheringWithSoftApConfigEnabled()); initTetheringOnTestThread(); mockBluetoothSettings(true /* bluetoothOn */, true /* tetheringOn */); diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index 52799abbb7..e645f671ae 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -32,7 +32,6 @@ import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_VIRTUAL; import static android.net.TetheringManager.TETHERING_WIFI; import static android.net.TetheringManager.TETHERING_WIFI_P2P; -import static android.net.TetheringManager.TETHER_ERROR_DUPLICATE_REQUEST; import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN; import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; @@ -235,30 +234,6 @@ public class TetheringManagerTest { } - @Test - public void testStartTetheringDuplicateRequestRejected() throws Exception { - assumeTrue(isTetheringWithSoftApConfigEnabled()); - final TestTetheringEventCallback tetherEventCallback = - mCtsTetheringUtils.registerTetheringEventCallback(); - try { - tetherEventCallback.assumeWifiTetheringSupported(mContext); - tetherEventCallback.expectNoTetheringActive(); - - final String[] wifiRegexs = mTM.getTetherableWifiRegexs(); - mCtsTetheringUtils.startWifiTethering(tetherEventCallback); - mTetherChangeReceiver.expectTethering(true /* active */, wifiRegexs); - - final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); - runAsShell(TETHER_PRIVILEGED, () -> { - mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), - c -> c.run() /* executor */, startTetheringCallback); - startTetheringCallback.expectTetheringFailed(TETHER_ERROR_DUPLICATE_REQUEST); - }); - } finally { - mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); - } - } - private SoftApConfiguration createSoftApConfiguration(@NonNull String ssid) { SoftApConfiguration config; if (SdkLevel.isAtLeastT()) { @@ -405,20 +380,17 @@ public class TetheringManagerTest { tetherEventCallback.assumeWifiTetheringSupported(mContext); tetherEventCallback.expectNoTetheringActive(); - SoftApConfiguration softApConfig = isTetheringWithSoftApConfigEnabled() - ? createSoftApConfiguration("SSID") : null; + SoftApConfiguration softApConfig = createSoftApConfiguration("SSID"); final TetheringInterface tetheredIface = mCtsTetheringUtils.startWifiTethering(tetherEventCallback, softApConfig); assertNotNull(tetheredIface); - if (isTetheringWithSoftApConfigEnabled()) { - assertEquals(softApConfig, tetheredIface.getSoftApConfiguration()); - } + assertEquals(softApConfig, tetheredIface.getSoftApConfiguration()); + final String wifiTetheringIface = tetheredIface.getInterface(); mCtsTetheringUtils.stopWifiTethering(tetherEventCallback); if (!SdkLevel.isAtLeastB()) { - final String wifiTetheringIface = tetheredIface.getInterface(); try { final int ret = runAsShell(TETHER_PRIVILEGED, () -> mTM.tether(wifiTetheringIface));