diff --git a/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl b/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl index 836761f864..b4e3ba4679 100644 --- a/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl +++ b/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl @@ -36,5 +36,4 @@ oneway interface ITetheringEventCallback void onTetherStatesChanged(in TetherStatesParcel states); void onTetherClientsChanged(in List clients); void onOffloadStatusChanged(int status); - void onSupportedTetheringTypes(long supportedBitmap); } diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl b/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl index f33f846347..253eacbd23 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl +++ b/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl @@ -26,7 +26,7 @@ import android.net.TetherStatesParcel; * @hide */ parcelable TetheringCallbackStartedParcel { - long supportedTypes; + boolean tetheringSupported; Network upstreamNetwork; TetheringConfigurationParcel config; TetherStatesParcel states; diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index b3f0cf2715..6f9b33e96a 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -183,12 +183,6 @@ public class TetheringManager { */ public static final int TETHERING_WIGIG = 6; - /** - * The int value of last tethering type. - * @hide - */ - public static final int MAX_TETHERING_TYPE = TETHERING_WIGIG; - /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(value = { @@ -525,9 +519,6 @@ public class TetheringManager { } } - @Override - public void onSupportedTetheringTypes(long supportedBitmap) { } - @Override public void onUpstreamChanged(Network network) { } @@ -1039,19 +1030,6 @@ public class TetheringManager { * upstream status. */ public interface TetheringEventCallback { - /** - * Called when tethering supported status changed. - * - *

This callback will be called immediately after the callback is - * registered, and never be called if there is changes afterward. - * - *

Tethering may be disabled via system properties, device configuration, or device - * policy restrictions. - * - * @param supported whether any tethering type is supported. - */ - default void onTetheringSupported(boolean supported) {} - /** * Called when tethering supported status changed. * @@ -1061,10 +1039,9 @@ public class TetheringManager { *

Tethering may be disabled via system properties, device configuration, or device * policy restrictions. * - * @param supportedTypes a set of @TetheringType which is supported. - * @hide + * @param supported The new supported status */ - default void onSupportedTetheringTypes(@NonNull Set supportedTypes) {} + default void onTetheringSupported(boolean supported) {} /** * Called when tethering upstream changed. @@ -1362,8 +1339,7 @@ public class TetheringManager { @Override public void onCallbackStarted(TetheringCallbackStartedParcel parcel) { executor.execute(() -> { - callback.onSupportedTetheringTypes(unpackBits(parcel.supportedTypes)); - callback.onTetheringSupported(parcel.supportedTypes != 0); + callback.onTetheringSupported(parcel.tetheringSupported); callback.onUpstreamChanged(parcel.upstreamNetwork); sendErrorCallbacks(parcel.states); sendRegexpsChanged(parcel.config); @@ -1382,13 +1358,6 @@ public class TetheringManager { }); } - @Override - public void onSupportedTetheringTypes(long supportedBitmap) { - executor.execute(() -> { - callback.onSupportedTetheringTypes(unpackBits(supportedBitmap)); - }); - } - private void sendRegexpsChanged(TetheringConfigurationParcel parcel) { callback.onTetherableInterfaceRegexpsChanged(new TetheringInterfaceRegexps( parcel.tetherableBluetoothRegexs, @@ -1426,23 +1395,6 @@ public class TetheringManager { } } - /** - * Unpack bitmap to a set of bit position intergers. - * @hide - */ - public static ArraySet unpackBits(long val) { - final ArraySet result = new ArraySet<>(Long.bitCount(val)); - int bitPos = 0; - while (val != 0) { - if ((val & 1) == 1) result.add(bitPos); - - val = val >>> 1; - bitPos++; - } - - return result; - } - /** * Remove tethering event callback previously registered with * {@link #registerTetheringEventCallback}. diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 47b1bd751d..3f328db207 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -281,11 +281,6 @@ public class Tethering { private BluetoothPan mBluetoothPan; private PanServiceListener mBluetoothPanListener; private ArrayList> mPendingPanRequests; - // AIDL doesn't support Set. Maintain a int bitmap here. When the bitmap is passed to - // TetheringManager, TetheringManager would convert it to a set of Integer types. - // mSupportedTypeBitmap should always be updated inside tethering internal thread but it may be - // read from binder thread which called TetheringService directly. - private volatile long mSupportedTypeBitmap; public Tethering(TetheringDependencies deps) { mLog.mark("Tethering.constructed"); @@ -517,8 +512,6 @@ public class Tethering { mUpstreamNetworkMonitor.setUpstreamConfig(mConfig.chooseUpstreamAutomatically, mConfig.isDunRequired); reportConfigurationChanged(mConfig.toStableParcelable()); - - updateSupportedDownstreams(mConfig); } private void maybeDunSettingChanged() { @@ -1557,6 +1550,26 @@ public class Tethering { return mConfig; } + boolean hasAnySupportedDownstream() { + if ((mConfig.tetherableUsbRegexs.length != 0) + || (mConfig.tetherableWifiRegexs.length != 0) + || (mConfig.tetherableBluetoothRegexs.length != 0)) { + return true; + } + + // Before T, isTetheringSupported would return true if wifi, usb and bluetooth tethering are + // disabled (whole tethering settings would be hidden). This means tethering would also not + // support wifi p2p, ethernet tethering and mirrorlink. This is wrong but probably there are + // some devices in the field rely on this to disable tethering entirely. + if (!SdkLevel.isAtLeastT()) return false; + + return (mConfig.tetherableWifiP2pRegexs.length != 0) + || (mConfig.tetherableNcmRegexs.length != 0) + || isEthernetSupported(); + } + + // TODO: using EtherentManager new API to check whether ethernet is supported when the API is + // ready to use. private boolean isEthernetSupported() { return mContext.getSystemService(Context.ETHERNET_SERVICE) != null; } @@ -2346,7 +2359,7 @@ public class Tethering { mHandler.post(() -> { mTetheringEventCallbacks.register(callback, new CallbackCookie(hasListPermission)); final TetheringCallbackStartedParcel parcel = new TetheringCallbackStartedParcel(); - parcel.supportedTypes = mSupportedTypeBitmap; + parcel.tetheringSupported = isTetheringSupported(); parcel.upstreamNetwork = mTetherUpstream; parcel.config = mConfig.toStableParcelable(); parcel.states = @@ -2385,22 +2398,6 @@ public class Tethering { }); } - private void reportTetheringSupportedChange(final long supportedBitmap) { - final int length = mTetheringEventCallbacks.beginBroadcast(); - try { - for (int i = 0; i < length; i++) { - try { - mTetheringEventCallbacks.getBroadcastItem(i).onSupportedTetheringTypes( - supportedBitmap); - } catch (RemoteException e) { - // Not really very much to do here. - } - } - } finally { - mTetheringEventCallbacks.finishBroadcast(); - } - } - private void reportUpstreamChanged(UpstreamNetworkState ns) { final int length = mTetheringEventCallbacks.beginBroadcast(); final Network network = (ns != null) ? ns.network : null; @@ -2485,56 +2482,18 @@ public class Tethering { } } - private void updateSupportedDownstreams(final TetheringConfiguration config) { - final long preSupportedBitmap = mSupportedTypeBitmap; - - if (!isTetheringAllowed() || mEntitlementMgr.isProvisioningNeededButUnavailable()) { - mSupportedTypeBitmap = 0; - } else { - mSupportedTypeBitmap = makeSupportedDownstreams(config); - } - - if (preSupportedBitmap != mSupportedTypeBitmap) { - reportTetheringSupportedChange(mSupportedTypeBitmap); - } - } - - private long makeSupportedDownstreams(final TetheringConfiguration config) { - long types = 0; - if (config.tetherableUsbRegexs.length != 0) types |= (1 << TETHERING_USB); - - if (config.tetherableWifiRegexs.length != 0) types |= (1 << TETHERING_WIFI); - - if (config.tetherableBluetoothRegexs.length != 0) types |= (1 << TETHERING_BLUETOOTH); - - // Before T, isTetheringSupported would return true if wifi, usb and bluetooth tethering are - // disabled (whole tethering settings would be hidden). This means tethering would also not - // support wifi p2p, ethernet tethering and mirrorlink. This is wrong but probably there are - // some devices in the field rely on this to disable tethering entirely. - if (!SdkLevel.isAtLeastT() && types == 0) return types; - - if (config.tetherableNcmRegexs.length != 0) types |= (1 << TETHERING_NCM); - - if (config.tetherableWifiP2pRegexs.length != 0) types |= (1 << TETHERING_WIFI_P2P); - - if (isEthernetSupported()) types |= (1 << TETHERING_ETHERNET); - - return types; - } - // if ro.tether.denied = true we default to no tethering // gservices could set the secure setting to 1 though to enable it on a build where it // had previously been turned off. - private boolean isTetheringAllowed() { + boolean isTetheringSupported() { final int defaultVal = mDeps.isTetheringDenied() ? 0 : 1; final boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.TETHER_SUPPORTED, defaultVal) != 0; - return tetherSupported + final boolean tetherEnabledInSettings = tetherSupported && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING); - } - boolean isTetheringSupported() { - return mSupportedTypeBitmap > 0; + return tetherEnabledInSettings && hasAnySupportedDownstream() + && !mEntitlementMgr.isProvisioningNeededButUnavailable(); } private void dumpBpf(IndentingPrintWriter pw) { diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java index ef4f0527d8..86dca1c60a 100644 --- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java +++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java @@ -192,13 +192,12 @@ public class EthernetTetheringTest { mUiAutomation.adoptShellPermissionIdentity( MANAGE_TEST_NETWORKS, NETWORK_SETTINGS, TETHER_PRIVILEGED, ACCESS_NETWORK_STATE, CONNECTIVITY_USE_RESTRICTED_NETWORKS, DUMP); + mRunTests = mTm.isTetheringSupported() && mEm != null; + assumeTrue(mRunTests); + mHandlerThread = new HandlerThread(getClass().getSimpleName()); mHandlerThread.start(); mHandler = new Handler(mHandlerThread.getLooper()); - - mRunTests = isEthernetTetheringSupported(); - assumeTrue(mRunTests); - mTetheredInterfaceRequester = new TetheredInterfaceRequester(mHandler, mEm); } @@ -226,6 +225,7 @@ public class EthernetTetheringTest { mHandler.post(() -> reader.stop()); mDownstreamReader = null; } + mHandlerThread.quitSafely(); mTetheredInterfaceRequester.release(); mEm.setIncludeTestInterfaces(false); maybeDeleteTestInterface(); @@ -236,7 +236,6 @@ public class EthernetTetheringTest { try { if (mRunTests) cleanUp(); } finally { - mHandlerThread.quitSafely(); mUiAutomation.dropShellPermissionIdentity(); } } @@ -411,23 +410,6 @@ public class EthernetTetheringTest { // client, which is not possible in this test. } - private boolean isEthernetTetheringSupported() throws Exception { - final CompletableFuture future = new CompletableFuture<>(); - final TetheringEventCallback callback = new TetheringEventCallback() { - @Override - public void onSupportedTetheringTypes(Set supportedTypes) { - future.complete(supportedTypes.contains(TETHERING_ETHERNET)); - } - }; - - try { - mTm.registerTetheringEventCallback(mHandler::post, callback); - return future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); - } finally { - mTm.unregisterTetheringEventCallback(callback); - } - } - private static final class MyTetheringEventCallback implements TetheringEventCallback { private final TetheringManager mTm; private final CountDownLatch mTetheringStartedLatch = new CountDownLatch(1); 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 cc80174dcf..e90d27e820 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -144,7 +144,6 @@ import android.net.TetheredClient.AddressInfo; import android.net.TetheringCallbackStartedParcel; import android.net.TetheringConfigurationParcel; import android.net.TetheringInterface; -import android.net.TetheringManager; import android.net.TetheringRequestParcel; import android.net.dhcp.DhcpLeaseParcelable; import android.net.dhcp.DhcpServerCallbacks; @@ -177,7 +176,6 @@ import android.telephony.CarrierConfigManager; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.test.mock.MockContentResolver; -import android.util.ArraySet; import androidx.annotation.NonNull; import androidx.test.filters.SmallTest; @@ -219,7 +217,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Set; import java.util.Vector; @RunWith(AndroidJUnit4.class) @@ -1732,7 +1729,6 @@ public class TetheringTest { private final ArrayList mTetherStates = new ArrayList<>(); private final ArrayList mOffloadStatus = new ArrayList<>(); private final ArrayList> mTetheredClients = new ArrayList<>(); - private final ArrayList mSupportedBitmaps = new ArrayList<>(); // This function will remove the recorded callbacks, so it must be called once for // each callback. If this is called after multiple callback, the order matters. @@ -1785,10 +1781,6 @@ public class TetheringTest { assertTrue(leases.containsAll(result)); } - public void expectSupportedTetheringTypes(Set expectedTypes) { - assertEquals(expectedTypes, TetheringManager.unpackBits(mSupportedBitmaps.remove(0))); - } - @Override public void onUpstreamChanged(Network network) { mActualUpstreams.add(network); @@ -1821,17 +1813,11 @@ public class TetheringTest { mTetherStates.add(parcel.states); mOffloadStatus.add(parcel.offloadStatus); mTetheredClients.add(parcel.tetheredClients); - mSupportedBitmaps.add(parcel.supportedTypes); } @Override public void onCallbackStopped(int errorCode) { } - @Override - public void onSupportedTetheringTypes(long supportedBitmap) { - mSupportedBitmaps.add(supportedBitmap); - } - public void assertNoUpstreamChangeCallback() { assertTrue(mActualUpstreams.isEmpty()); } @@ -2959,81 +2945,53 @@ public class TetheringTest { runStopUSBTethering(); } - public static ArraySet getAllSupportedTetheringTypes() { - return new ArraySet<>(new Integer[] { TETHERING_USB, TETHERING_NCM, TETHERING_WIFI, - TETHERING_WIFI_P2P, TETHERING_BLUETOOTH, TETHERING_ETHERNET }); - } - @Test public void testTetheringSupported() throws Exception { - final ArraySet expectedTypes = getAllSupportedTetheringTypes(); - // Check tethering is supported after initialization. setTetheringSupported(true /* supported */); - TestTetheringEventCallback callback = new TestTetheringEventCallback(); - mTethering.registerTetheringEventCallback(callback); - mLooper.dispatchAll(); - updateConfigAndVerifySupported(callback, expectedTypes); + updateConfigAndVerifySupported(true /* supported */); // Could disable tethering supported by settings. Settings.Global.putInt(mContentResolver, Settings.Global.TETHER_SUPPORTED, 0); - updateConfigAndVerifySupported(callback, new ArraySet<>()); + updateConfigAndVerifySupported(false /* supported */); // Could disable tethering supported by user restriction. setTetheringSupported(true /* supported */); - updateConfigAndVerifySupported(callback, expectedTypes); when(mUserManager.hasUserRestriction( UserManager.DISALLOW_CONFIG_TETHERING)).thenReturn(true); - updateConfigAndVerifySupported(callback, new ArraySet<>()); + updateConfigAndVerifySupported(false /* supported */); // Tethering is supported if it has any supported downstream. setTetheringSupported(true /* supported */); - updateConfigAndVerifySupported(callback, expectedTypes); - // Usb tethering is not supported: - expectedTypes.remove(TETHERING_USB); when(mResources.getStringArray(R.array.config_tether_usb_regexs)) .thenReturn(new String[0]); - updateConfigAndVerifySupported(callback, expectedTypes); - // Wifi tethering is not supported: - expectedTypes.remove(TETHERING_WIFI); + updateConfigAndVerifySupported(true /* supported */); when(mResources.getStringArray(R.array.config_tether_wifi_regexs)) .thenReturn(new String[0]); - updateConfigAndVerifySupported(callback, expectedTypes); - // Bluetooth tethering is not supported: - expectedTypes.remove(TETHERING_BLUETOOTH); - when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs)) - .thenReturn(new String[0]); + updateConfigAndVerifySupported(true /* supported */); + if (isAtLeastT()) { - updateConfigAndVerifySupported(callback, expectedTypes); - - // P2p tethering is not supported: - expectedTypes.remove(TETHERING_WIFI_P2P); + when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs)) + .thenReturn(new String[0]); + updateConfigAndVerifySupported(true /* supported */); when(mResources.getStringArray(R.array.config_tether_wifi_p2p_regexs)) .thenReturn(new String[0]); - updateConfigAndVerifySupported(callback, expectedTypes); - // Ncm tethering is not supported: - expectedTypes.remove(TETHERING_NCM); + updateConfigAndVerifySupported(true /* supported */); when(mResources.getStringArray(R.array.config_tether_ncm_regexs)) .thenReturn(new String[0]); - updateConfigAndVerifySupported(callback, expectedTypes); - // Ethernet tethering (last supported type) is not supported: - expectedTypes.remove(TETHERING_ETHERNET); + updateConfigAndVerifySupported(true /* supported */); mForceEthernetServiceUnavailable = true; - updateConfigAndVerifySupported(callback, new ArraySet<>()); - + updateConfigAndVerifySupported(false /* supported */); } else { - // If wifi, usb and bluetooth are all not supported, all the types are not supported. - expectedTypes.clear(); - updateConfigAndVerifySupported(callback, expectedTypes); + when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs)) + .thenReturn(new String[0]); + updateConfigAndVerifySupported(false /* supported */); } } - private void updateConfigAndVerifySupported(final TestTetheringEventCallback callback, - final ArraySet expectedTypes) { + private void updateConfigAndVerifySupported(boolean supported) { sendConfigurationChanged(); - - assertEquals(expectedTypes.size() > 0, mTethering.isTetheringSupported()); - callback.expectSupportedTetheringTypes(expectedTypes); + assertEquals(supported, mTethering.isTetheringSupported()); } // TODO: Test that a request for hotspot mode doesn't interfere with an // already operating tethering mode interface.