From 2782b3bddf2d6a125b685c9919ab82e36d00d15a Mon Sep 17 00:00:00 2001 From: Quang Anh Luong Date: Thu, 5 Dec 2024 13:34:15 +0900 Subject: [PATCH] Remove WRITE_SETTINGS permission from Tethering APIs As TetheringManager moves to a Public API, remove the weak WRITE_SETTINGS permission and use TETHER_PRIVILEGED instead. System callers can still aquire TETHER_PRIVILEGED, and public callers must be Device Owner or Carrier App to bypass (to be done in a future CL) Bug: 374400379 Test: atest TetheringTest TetheringServiceTest CtsTetheringTests Change-Id: Ia192021ac48f9eb3f27cc8c412f17629ad16a587 --- Tethering/Android.bp | 1 + .../TetheringLib/api/module-lib-current.txt | 2 +- .../TetheringLib/api/system-current.txt | 6 +- .../src/android/net/TetheringManager.java | 28 +--- .../networkstack/tethering/Tethering.java | 4 + .../tethering/TetheringDependencies.java | 9 ++ .../tethering/TetheringService.java | 4 + .../tethering/TetheringServiceTest.java | 132 +++++++++++++++--- tests/cts/tethering/Android.bp | 1 + .../tethering/cts/TetheringManagerTest.java | 22 ++- 10 files changed, 157 insertions(+), 52 deletions(-) diff --git a/Tethering/Android.bp b/Tethering/Android.bp index 5cf552895d..4d173a5d23 100644 --- a/Tethering/Android.bp +++ b/Tethering/Android.bp @@ -63,6 +63,7 @@ java_defaults { static_libs: [ "androidx.annotation_annotation", "connectivity-net-module-utils-bpf", + "com.android.net.flags-aconfig-java", "modules-utils-build", "modules-utils-statemachine", "networkstack-client", diff --git a/Tethering/common/TetheringLib/api/module-lib-current.txt b/Tethering/common/TetheringLib/api/module-lib-current.txt index 01bd98363b..3ba8e1b738 100644 --- a/Tethering/common/TetheringLib/api/module-lib-current.txt +++ b/Tethering/common/TetheringLib/api/module-lib-current.txt @@ -22,7 +22,7 @@ package android.net { method public boolean isTetheringSupported(@NonNull String); method public void requestLatestTetheringEntitlementResult(int, @NonNull android.os.ResultReceiver, boolean); method @Deprecated public int setUsbTethering(boolean); - method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback); + method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback); method @Deprecated public int tether(@NonNull String); method @Deprecated public int untether(@NonNull String); } diff --git a/Tethering/common/TetheringLib/api/system-current.txt b/Tethering/common/TetheringLib/api/system-current.txt index 3b9708eb3c..c0c0abc7c6 100644 --- a/Tethering/common/TetheringLib/api/system-current.txt +++ b/Tethering/common/TetheringLib/api/system-current.txt @@ -20,9 +20,9 @@ package android.net { } public class TetheringManager { - method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener); - method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering(); - method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int); + method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener); + method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopAllTethering(); + method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int); field @Deprecated public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED"; field public static final int CONNECTIVITY_SCOPE_LOCAL = 2; // 0x2 field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY"; diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index e0ea0d493e..1dffeae515 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -1299,18 +1299,12 @@ public class TetheringManager { * Starts tethering and runs tether provisioning for the given type if needed. If provisioning * fails, stopTethering will be called automatically. * - *

Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will - * fail if a tethering entitlement check is required. - * * @param type The tethering type, on of the {@code TetheringManager#TETHERING_*} constants. * @param executor {@link Executor} to specify the thread upon which the callback of * TetheringRequest will be invoked. * @hide */ - @RequiresPermission(anyOf = { - android.Manifest.permission.TETHER_PRIVILEGED, - android.Manifest.permission.WRITE_SETTINGS - }) + @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) @SystemApi(client = MODULE_LIBRARIES) public void startTethering(int type, @NonNull final Executor executor, @NonNull final StartTetheringCallback callback) { @@ -1321,14 +1315,9 @@ public class TetheringManager { * Stops tethering for the given type. Also cancels any provisioning rechecks for that type if * applicable. * - *

Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will - * fail if a tethering entitlement check is required. * @hide */ - @RequiresPermission(anyOf = { - android.Manifest.permission.TETHER_PRIVILEGED, - android.Manifest.permission.WRITE_SETTINGS - }) + @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) @SystemApi public void stopTethering(@TetheringType final int type) { final String callerPkg = mContext.getOpPackageName(); @@ -1383,9 +1372,6 @@ public class TetheringManager { * {@link #TETHER_ERROR_ENTITLEMENT_UNKNOWN} will be returned. If {@code showEntitlementUi} is * true, entitlement will be run. * - *

Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will - * fail if a tethering entitlement check is required. - * * @param type the downstream type of tethering. Must be one of {@code #TETHERING_*} constants. * @param showEntitlementUi a boolean indicating whether to check result for the UI-based * entitlement check or the silent entitlement check. @@ -1396,10 +1382,7 @@ public class TetheringManager { * @hide */ @SystemApi - @RequiresPermission(anyOf = { - android.Manifest.permission.TETHER_PRIVILEGED, - android.Manifest.permission.WRITE_SETTINGS - }) + @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void requestLatestTetheringEntitlementResult(@TetheringType int type, boolean showEntitlementUi, @NonNull Executor executor, @@ -2082,10 +2065,7 @@ public class TetheringManager { * @hide */ @SystemApi - @RequiresPermission(anyOf = { - android.Manifest.permission.TETHER_PRIVILEGED, - android.Manifest.permission.WRITE_SETTINGS - }) + @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopAllTethering() { final String callerPkg = mContext.getOpPackageName(); Log.i(TAG, "stopAllTethering caller:" + callerPkg); diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index a96f66c76c..e374f17e48 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -451,6 +451,10 @@ public class Tethering { return mSettingsObserver; } + boolean isTetheringWithSoftApConfigEnabled() { + return mDeps.isTetheringWithSoftApConfigEnabled(); + } + /** * Start to register callbacks. * Call this function when tethering is ready to handle callback events. diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java index d89bf4df4f..8e170856cc 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java @@ -37,6 +37,7 @@ import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; import com.android.modules.utils.build.SdkLevel; +import com.android.net.flags.Flags; import com.android.net.module.util.RoutingCoordinatorManager; import com.android.net.module.util.RoutingCoordinatorService; import com.android.net.module.util.SharedLog; @@ -208,4 +209,12 @@ public abstract class TetheringDependencies { public int getBinderCallingUid() { return Binder.getCallingUid(); } + + /** + * Wrapper for tethering_with_soft_ap_config feature flag. + */ + public boolean isTetheringWithSoftApConfigEnabled() { + return Build.VERSION.SDK_INT > Build.VERSION_CODES.VANILLA_ICE_CREAM + && Flags.tetheringWithSoftApConfig(); + } } diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringService.java b/Tethering/src/com/android/networkstack/tethering/TetheringService.java index 6485ffd643..0c44a3836c 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringService.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringService.java @@ -310,6 +310,10 @@ public class TetheringService extends Service { if (hasTetherPrivilegedPermission()) return true; + // After TetheringManager moves to public API, prevent third-party apps from being able + // to change tethering with only WRITE_SETTINGS permission. + if (mTethering.isTetheringWithSoftApConfigEnabled()) return false; + if (mTethering.isTetherProvisioningRequired()) return false; int uid = getBinderCallingUid(); diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java index d94852ef13..cc802517f5 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java @@ -154,31 +154,43 @@ public final class TetheringServiceTest { } private void runAsNoPermission(final TestTetheringCall test) throws Exception { - runTetheringCall(test, true /* isTetheringAllowed */, new String[0]); + runTetheringCall(test, true /* isTetheringAllowed */, false /* isWriteSettingsAllowed */, + new String[0]); } private void runAsTetherPrivileged(final TestTetheringCall test) throws Exception { - runTetheringCall(test, true /* isTetheringAllowed */, TETHER_PRIVILEGED); + runTetheringCall(test, true /* isTetheringAllowed */, false /* isWriteSettingsAllowed */, + TETHER_PRIVILEGED); } private void runAsAccessNetworkState(final TestTetheringCall test) throws Exception { - runTetheringCall(test, true /* isTetheringAllowed */, ACCESS_NETWORK_STATE); + runTetheringCall(test, true /* isTetheringAllowed */, false /* isWriteSettingsAllowed */, + ACCESS_NETWORK_STATE); } private void runAsWriteSettings(final TestTetheringCall test) throws Exception { - runTetheringCall(test, true /* isTetheringAllowed */, WRITE_SETTINGS); + runTetheringCall(test, true /* isTetheringAllowed */, false /* isWriteSettingsAllowed */, + WRITE_SETTINGS); + } + + private void runAsWriteSettingsWhenWriteSettingsAllowed( + final TestTetheringCall test) throws Exception { + runTetheringCall(test, true /* isTetheringAllowed */, true /* isWriteSettingsAllowed */, + WRITE_SETTINGS); } private void runAsTetheringDisallowed(final TestTetheringCall test) throws Exception { - runTetheringCall(test, false /* isTetheringAllowed */, TETHER_PRIVILEGED); + runTetheringCall(test, false /* isTetheringAllowed */, false /* isWriteSettingsAllowed */, + TETHER_PRIVILEGED); } private void runAsNetworkSettings(final TestTetheringCall test) throws Exception { - runTetheringCall(test, true /* isTetheringAllowed */, NETWORK_SETTINGS, TETHER_PRIVILEGED); + runTetheringCall(test, true /* isTetheringAllowed */, false /* isWriteSettingsAllowed */, + NETWORK_SETTINGS, TETHER_PRIVILEGED); } private void runTetheringCall(final TestTetheringCall test, boolean isTetheringAllowed, - String... permissions) throws Exception { + boolean isWriteSettingsAllowed, String... permissions) throws Exception { // Allow the test to run even if ACCESS_NETWORK_STATE was granted at the APK level if (!CollectionUtils.contains(permissions, ACCESS_NETWORK_STATE)) { mMockConnector.setPermission(ACCESS_NETWORK_STATE, PERMISSION_DENIED); @@ -188,6 +200,8 @@ public final class TetheringServiceTest { try { when(mTethering.isTetheringSupported()).thenReturn(true); when(mTethering.isTetheringAllowed()).thenReturn(isTetheringAllowed); + when(mTethering.isTetheringWithSoftApConfigEnabled()) + .thenReturn(!isWriteSettingsAllowed); test.runTetheringCall(new TestTetheringResult()); } finally { mUiAutomation.dropShellPermissionIdentity(); @@ -213,7 +227,7 @@ public final class TetheringServiceTest { runAsNoPermission((result) -> { mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); - verify(mTethering).isTetherProvisioningRequired(); + verify(mTethering).isTetheringWithSoftApConfigEnabled(); result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); verifyNoMoreInteractionsForTethering(); }); @@ -224,7 +238,16 @@ public final class TetheringServiceTest { }); runAsWriteSettings((result) -> { + mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, + result); + verify(mTethering).isTetheringWithSoftApConfigEnabled(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettingsWhenWriteSettingsAllowed((result) -> { runTether(result); + verify(mTethering).isTetheringWithSoftApConfigEnabled(); verify(mTethering).isTetherProvisioningRequired(); verifyNoMoreInteractionsForTethering(); }); @@ -252,7 +275,7 @@ public final class TetheringServiceTest { runAsNoPermission((result) -> { mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); - verify(mTethering).isTetherProvisioningRequired(); + verify(mTethering).isTetheringWithSoftApConfigEnabled(); result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); verifyNoMoreInteractionsForTethering(); }); @@ -263,7 +286,16 @@ public final class TetheringServiceTest { }); runAsWriteSettings((result) -> { + mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, + result); + verify(mTethering).isTetheringWithSoftApConfigEnabled(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettingsWhenWriteSettingsAllowed((result) -> { runUnTether(result); + verify(mTethering).isTetheringWithSoftApConfigEnabled(); verify(mTethering).isTetherProvisioningRequired(); verifyNoMoreInteractionsForTethering(); }); @@ -297,7 +329,7 @@ public final class TetheringServiceTest { runAsNoPermission((result) -> { mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); - verify(mTethering).isTetherProvisioningRequired(); + verify(mTethering).isTetheringWithSoftApConfigEnabled(); result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); verifyNoMoreInteractionsForTethering(); }); @@ -308,7 +340,16 @@ public final class TetheringServiceTest { }); runAsWriteSettings((result) -> { + mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG, + TEST_ATTRIBUTION_TAG, result); + verify(mTethering).isTetheringWithSoftApConfigEnabled(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettingsWhenWriteSettingsAllowed((result) -> { runSetUsbTethering(result); + verify(mTethering).isTetheringWithSoftApConfigEnabled(); verify(mTethering).isTetherProvisioningRequired(); verifyNoMoreInteractionsForTethering(); }); @@ -341,7 +382,7 @@ public final class TetheringServiceTest { runAsNoPermission((result) -> { mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); - verify(mTethering).isTetherProvisioningRequired(); + verify(mTethering).isTetheringWithSoftApConfigEnabled(); result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); verifyNoMoreInteractionsForTethering(); }); @@ -361,7 +402,16 @@ public final class TetheringServiceTest { }); runAsWriteSettings((result) -> { + mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, + result); + verify(mTethering).isTetheringWithSoftApConfigEnabled(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettingsWhenWriteSettingsAllowed((result) -> { runStartTethering(result, request); + verify(mTethering).isTetheringWithSoftApConfigEnabled(); verify(mTethering).isTetherProvisioningRequired(); verifyNoMoreInteractionsForTethering(); }); @@ -446,7 +496,7 @@ public final class TetheringServiceTest { runAsNoPermission((result) -> { mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); - verify(mTethering).isTetherProvisioningRequired(); + verify(mTethering).isTetheringWithSoftApConfigEnabled(); result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); verifyNoMoreInteractionsForTethering(); }); @@ -457,7 +507,16 @@ public final class TetheringServiceTest { }); runAsWriteSettings((result) -> { + mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG, + TEST_ATTRIBUTION_TAG, result); + verify(mTethering).isTetheringWithSoftApConfigEnabled(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettingsWhenWriteSettingsAllowed((result) -> { runStopTethering(result); + verify(mTethering).isTetheringWithSoftApConfigEnabled(); verify(mTethering).isTetherProvisioningRequired(); verifyNoMoreInteractionsForTethering(); }); @@ -486,11 +545,13 @@ public final class TetheringServiceTest { public void testRequestLatestTetheringEntitlementResult() throws Exception { // Run as no permission. final MyResultReceiver result = new MyResultReceiver(null); - mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result, - true /* showEntitlementUi */, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG); - verify(mTethering).isTetherProvisioningRequired(); - result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); - verifyNoMoreInteractions(mTethering); + runAsNoPermission((none) -> { + mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result, + true /* showEntitlementUi */, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG); + verify(mTethering).isTetheringWithSoftApConfigEnabled(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); runAsTetherPrivileged((none) -> { runRequestLatestTetheringEntitlementResult(); @@ -501,22 +562,30 @@ public final class TetheringServiceTest { mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result, true /* showEntitlementUi */, TEST_WRONG_PACKAGE, TEST_ATTRIBUTION_TAG); result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); - verifyNoMoreInteractions(mTethering); + verifyNoMoreInteractionsForTethering(); }); runAsWriteSettings((none) -> { + mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result, + true /* showEntitlementUi */, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG); + verify(mTethering).isTetheringWithSoftApConfigEnabled(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettingsWhenWriteSettingsAllowed((none) -> { runRequestLatestTetheringEntitlementResult(); + verify(mTethering).isTetheringWithSoftApConfigEnabled(); verify(mTethering).isTetherProvisioningRequired(); verifyNoMoreInteractionsForTethering(); }); runAsTetheringDisallowed((none) -> { - final MyResultReceiver receiver = new MyResultReceiver(null); - mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, + mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result, true /* showEntitlementUi */, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG); verify(mTethering).isTetheringSupported(); verify(mTethering).isTetheringAllowed(); - receiver.assertResult(TETHER_ERROR_UNSUPPORTED); + result.assertResult(TETHER_ERROR_UNSUPPORTED); verifyNoMoreInteractionsForTethering(); }); } @@ -600,7 +669,7 @@ public final class TetheringServiceTest { public void testStopAllTethering() throws Exception { runAsNoPermission((result) -> { mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); - verify(mTethering).isTetherProvisioningRequired(); + verify(mTethering).isTetheringWithSoftApConfigEnabled(); result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); verifyNoMoreInteractionsForTethering(); }); @@ -611,7 +680,15 @@ public final class TetheringServiceTest { }); runAsWriteSettings((result) -> { + mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); + verify(mTethering).isTetheringWithSoftApConfigEnabled(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettingsWhenWriteSettingsAllowed((result) -> { runStopAllTethering(result); + verify(mTethering).isTetheringWithSoftApConfigEnabled(); verify(mTethering).isTetherProvisioningRequired(); verifyNoMoreInteractionsForTethering(); }); @@ -637,7 +714,7 @@ public final class TetheringServiceTest { runAsNoPermission((result) -> { mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result); - verify(mTethering).isTetherProvisioningRequired(); + verify(mTethering).isTetheringWithSoftApConfigEnabled(); result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); verifyNoMoreInteractionsForTethering(); }); @@ -648,7 +725,16 @@ public final class TetheringServiceTest { }); runAsWriteSettings((result) -> { + mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, + result); + verify(mTethering).isTetheringWithSoftApConfigEnabled(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettingsWhenWriteSettingsAllowed((result) -> { runIsTetheringSupported(result); + verify(mTethering).isTetheringWithSoftApConfigEnabled(); verify(mTethering).isTetherProvisioningRequired(); verifyNoMoreInteractionsForTethering(); }); diff --git a/tests/cts/tethering/Android.bp b/tests/cts/tethering/Android.bp index d9bc7f7a98..d1678364d1 100644 --- a/tests/cts/tethering/Android.bp +++ b/tests/cts/tethering/Android.bp @@ -34,6 +34,7 @@ java_defaults { static_libs: [ "TetheringCommonTests", + "com.android.net.flags-aconfig-java", "compatibility-device-util-axt", "cts-net-utils", "net-tests-utils", diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java index e0e22e5edd..5e94c06acf 100644 --- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java +++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java @@ -17,6 +17,7 @@ package android.tethering.test; import static android.Manifest.permission.MODIFY_PHONE_STATE; import static android.Manifest.permission.TETHER_PRIVILEGED; +import static android.Manifest.permission.WRITE_SETTINGS; import static android.content.pm.PackageManager.FEATURE_TELEPHONY; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; @@ -71,6 +72,7 @@ import android.net.cts.util.CtsTetheringUtils.TestTetheringEventCallback; import android.net.wifi.SoftApConfiguration; import android.net.wifi.WifiManager; import android.net.wifi.WifiSsid; +import android.os.Build; import android.os.Bundle; import android.os.PersistableBundle; import android.os.ResultReceiver; @@ -83,6 +85,7 @@ import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import com.android.modules.utils.build.SdkLevel; +import com.android.net.flags.Flags; import com.android.testutils.ParcelUtils; import org.junit.After; @@ -457,12 +460,29 @@ public class TetheringManagerTest { } catch (UnsupportedOperationException expect) { } } + private boolean isTetheringWithSoftApConfigEnabled() { + return Build.VERSION.SDK_INT > Build.VERSION_CODES.VANILLA_ICE_CREAM + && Flags.tetheringWithSoftApConfig(); + } + @Test - public void testEnableTetheringPermission() throws Exception { + public void testStartTetheringNoPermission() throws Exception { final StartTetheringCallback startTetheringCallback = new StartTetheringCallback(); + + // No permission mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), c -> c.run() /* executor */, startTetheringCallback); startTetheringCallback.expectTetheringFailed(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + + // WRITE_SETTINGS not sufficient + if (isTetheringWithSoftApConfigEnabled()) { + runAsShell(WRITE_SETTINGS, () -> { + mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), + c -> c.run() /* executor */, startTetheringCallback); + startTetheringCallback.expectTetheringFailed( + TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + }); + } } private class EntitlementResultListener implements OnTetheringEntitlementResultListener {