From 696c164c2dd078f5c16bf29aabfc39eb2a188bb8 Mon Sep 17 00:00:00 2001 From: Quang Anh Luong Date: Thu, 30 Jan 2025 09:36:51 +0900 Subject: [PATCH] Add basic implementation of stopTetheringRequest Add a basic implementation of stopTetheringRequest that simply stops tethering for that specific type if it is active, or fail with TETHER_ERROR_UNKNOWN_REQUEST if not. In the future, we will do fuzzy matching to ensure the correct request is removed. Bug: 216524590 Test: atest TetheringManagerTest#testStopTetheringRequest Change-Id: Ib4a660aacdb83e645e39ceb61b7cda45bb24d89d --- .../src/android/net/ITetheringConnector.aidl | 4 +++ .../src/android/net/TetheringManager.java | 20 +++++++++++- .../networkstack/tethering/Tethering.java | 32 +++++++++++++++++++ .../tethering/TetheringService.java | 12 +++++++ .../net/cts/util/CtsTetheringUtils.java | 18 +++++------ .../tethering/cts/TetheringManagerTest.java | 21 ++++++++++-- 6 files changed, 95 insertions(+), 12 deletions(-) diff --git a/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl b/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl index 77e78bd2ac..7d244e2af4 100644 --- a/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl +++ b/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl @@ -18,6 +18,7 @@ package android.net; import android.net.IIntResultListener; import android.net.ITetheringEventCallback; import android.net.TetheringRequestParcel; +import android.net.TetheringManager.TetheringRequest; import android.os.ResultReceiver; /** @hide */ @@ -37,6 +38,9 @@ oneway interface ITetheringConnector { void stopTethering(int type, String callerPkg, String callingAttributionTag, IIntResultListener receiver); + void stopTetheringRequest(in TetheringRequest request, String callerPkg, + String callingAttributionTag, IIntResultListener receiver); + void requestLatestTetheringEntitlementResult(int type, in ResultReceiver receiver, boolean showEntitlementUi, String callerPkg, String callingAttributionTag); diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index aa7a244799..f123dca0dd 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -1417,7 +1417,25 @@ public class TetheringManager { @FlaggedApi(Flags.FLAG_TETHERING_WITH_SOFT_AP_CONFIG) public void stopTethering(@NonNull TetheringRequest request, @NonNull final Executor executor, @NonNull final StopTetheringCallback callback) { - throw new UnsupportedOperationException(); + Objects.requireNonNull(request); + Objects.requireNonNull(executor); + Objects.requireNonNull(callback); + + final String callerPkg = mContext.getOpPackageName(); + Log.i(TAG, "stopTethering: request=" + request + ", caller=" + callerPkg); + getConnector(c -> c.stopTetheringRequest(request, callerPkg, getAttributionTag(), + new IIntResultListener.Stub() { + @Override + public void onResult(final int resultCode) { + executor.execute(() -> { + if (resultCode == TETHER_ERROR_NO_ERROR) { + callback.onStopTetheringSucceeded(); + } else { + callback.onStopTetheringFailed(resultCode); + } + }); + } + })); } /** diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 1c8ea3a1b0..60263ac436 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -47,6 +47,7 @@ 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_UNAVAIL_IFACE; import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_IFACE; +import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_REQUEST; import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_TYPE; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; @@ -727,6 +728,37 @@ public class Tethering { stopTetheringInternal(type); }); } + + private boolean isTetheringTypePendingOrServing(final int type) { + for (int i = 0; i < mPendingTetheringRequests.size(); i++) { + if (mPendingTetheringRequests.valueAt(i).getTetheringType() == type) return true; + } + for (TetherState state : mTetherStates.values()) { + if (state.isCurrentlyServing() && state.ipServer.interfaceType() == type) return true; + } + return false; + } + + void stopTetheringRequest(@NonNull final TetheringRequest request, + @NonNull final IIntResultListener listener) { + if (!isTetheringWithSoftApConfigEnabled()) return; + mHandler.post(() -> { + final int type = request.getTetheringType(); + if (isTetheringTypePendingOrServing(type)) { + stopTetheringInternal(type); + try { + listener.onResult(TETHER_ERROR_NO_ERROR); + } catch (RemoteException ignored) { } + return; + } + + // Request doesn't match any active requests, ignore. + try { + listener.onResult(TETHER_ERROR_UNKNOWN_REQUEST); + } catch (RemoteException ignored) { } + }); + } + void stopTetheringInternal(int type) { mPendingTetheringRequests.remove(type); diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringService.java b/Tethering/src/com/android/networkstack/tethering/TetheringService.java index 4f00332782..b553f464bc 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringService.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringService.java @@ -158,6 +158,18 @@ public class TetheringService extends Service { } catch (RemoteException e) { } } + @Override + public void stopTetheringRequest(TetheringRequest request, + String callerPkg, String callingAttributionTag, + IIntResultListener listener) { + if (request == null) return; + if (listener == null) return; + if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return; + request.setUid(getBinderCallingUid()); + request.setPackageName(callerPkg); + mTethering.stopTetheringRequest(request, listener); + } + @Override public void requestLatestTetheringEntitlementResult(int type, ResultReceiver receiver, boolean showEntitlementUi, String callerPkg, String callingAttributionTag) { diff --git a/tests/cts/net/util/java/android/net/cts/util/CtsTetheringUtils.java b/tests/cts/net/util/java/android/net/cts/util/CtsTetheringUtils.java index 82a295d851..75b2814b7c 100644 --- a/tests/cts/net/util/java/android/net/cts/util/CtsTetheringUtils.java +++ b/tests/cts/net/util/java/android/net/cts/util/CtsTetheringUtils.java @@ -22,6 +22,7 @@ import static android.Manifest.permission.NETWORK_SETTINGS; import static android.Manifest.permission.TETHER_PRIVILEGED; import static android.net.TetheringManager.TETHERING_WIFI; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; +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; @@ -637,17 +638,16 @@ public final class CtsTetheringUtils { /** * Calls {@link TetheringManager#stopTethering(TetheringRequest, Executor, - * TetheringManager.StopTetheringCallback)} and verifies it throws an - * UnsupportedOperationException. + * TetheringManager.StopTetheringCallback)} and verifies if it succeeded or failed. */ - public void stopTethering(final TetheringRequest request) { - final StopTetheringCallback callback = new StopTetheringCallback(); + public void stopTethering(final TetheringRequest request, boolean expectSuccess) { + final StopTetheringCallback stopTetheringCallback = new StopTetheringCallback(); runAsShell(TETHER_PRIVILEGED, () -> { - try { - mTm.stopTethering(request, Runnable::run /* Executor */, callback); - fail("stopTethering should throw UnsupportedOperationException"); - } catch (UnsupportedOperationException expected) { - // Success. + mTm.stopTethering(request, c -> c.run() /* executor */, stopTetheringCallback); + if (expectSuccess) { + stopTetheringCallback.verifyStopTetheringSucceeded(); + } else { + stopTetheringCallback.expectStopTetheringFailed(TETHER_ERROR_UNKNOWN_REQUEST); } }); } diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index a2cac697ff..7ce99eb8e5 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -458,8 +458,25 @@ public class TetheringManagerTest { @Test public void testStopTetheringRequest() throws Exception { assumeTrue(isTetheringWithSoftApConfigEnabled()); - TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build(); - mCtsTetheringUtils.stopTethering(request); + final TestTetheringEventCallback tetherEventCallback = + mCtsTetheringUtils.registerTetheringEventCallback(); + try { + tetherEventCallback.assumeWifiTetheringSupported(mContext); + + // stopTethering without any tethering active should fail. + TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build(); + mCtsTetheringUtils.stopTethering(request, false /* succeeded */); + + // Start wifi tethering + mCtsTetheringUtils.startWifiTethering(tetherEventCallback); + + // stopTethering should succeed now that there's a request. + mCtsTetheringUtils.stopTethering(request, true /* succeeded */); + tetherEventCallback.expectNoTetheringActive(); + } finally { + mCtsTetheringUtils.stopAllTethering(); + mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback); + } } private boolean isTetheringWithSoftApConfigEnabled() {