From 6d030981e8d2e07b707ddc18fd84823a98343b36 Mon Sep 17 00:00:00 2001 From: markchien Date: Fri, 22 Apr 2022 15:21:06 +0800 Subject: [PATCH] Prepare for refactoring wifi ipserver start/stop This is a preparing change. 1) In enableWifiIpServing, replace ensureIpServerStarted(ifname) + changeInterfaceState(ifname, ipServingMode) with enableIpServing(TETHERING_WIFI, ifname, ipServingMode). And checking whether corresponding wifi or p2p feature is avaialble before enableWifiIpServing. Note: If the wifi or p2p feature wasn't supported before, it would still call changeInterfaceState without ipServer created but changeInterfaceState would be no-op because there is no corresponding ipServer for changing state. 2) Splitting enableWifiIpServing into enableWifiIpServing and enableWifiP2pIpServing. 3) No longer guess the interface name after T. WIFI_AP_STATE_CHANGED intent should always include ifname and it should be tracked by mTetherStates. If OEM have modification in wifi framework to send empty ifname, tethering no longer support this after T. 4) After T, tethering always trust the ifname which pass by wifi or p2p intent broadcast and treat it as TETHERING_WIFI or TETHERING_WIFI_P2P. This allow tethering to deprecate wifi/p2p regexs after T. Bug: 189410000 Bug: 178116595 Bug: 185451791 Bug: 190145323 Bug: 176048959 Test: atest TetheringTests Change-Id: Ia5f69ddf2d842536ce0df75eeae57866f56df571 (cherry picked from commit f2e9409f55a71846d5ec2dd120ba83e3b3773d09) Merged-In: Ia5f69ddf2d842536ce0df75eeae57866f56df571 --- .../networkstack/tethering/Tethering.java | 104 +++++++++++------- .../networkstack/tethering/TetheringTest.java | 13 ++- 2 files changed, 77 insertions(+), 40 deletions(-) diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index 44935fc8c8..35a394d7f2 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -1288,7 +1288,7 @@ public class Tethering { // Finally bring up serving on the new interface mWifiP2pTetherInterface = group.getInterface(); - enableWifiIpServing(mWifiP2pTetherInterface, IFACE_IP_MODE_LOCAL_ONLY); + enableWifiP2pIpServing(mWifiP2pTetherInterface); } private void handleUserRestrictionAction() { @@ -1379,20 +1379,22 @@ public class Tethering { changeInterfaceState(ifname, ipServingMode); } - private void disableWifiIpServingCommon(int tetheringType, String ifname, int apState) { - mLog.log("Canceling WiFi tethering request -" - + " type=" + tetheringType - + " interface=" + ifname - + " state=" + apState); - - if (!TextUtils.isEmpty(ifname)) { - final TetherState ts = mTetherStates.get(ifname); - if (ts != null) { - ts.ipServer.unwanted(); - return; - } + private void disableWifiIpServingCommon(int tetheringType, String ifname) { + if (!TextUtils.isEmpty(ifname) && mTetherStates.containsKey(ifname)) { + mTetherStates.get(ifname).ipServer.unwanted(); + return; } + if (SdkLevel.isAtLeastT()) { + mLog.e("Tethering no longer handle untracked interface after T: " + ifname); + return; + } + + // Attempt to guess the interface name before T. Pure AOSP code should never enter here + // because WIFI_AP_STATE_CHANGED intent always include ifname and it should be tracked + // by mTetherStates. In case OEMs have some modification in wifi side which pass null + // or empty ifname. Before T, tethering allow to disable the first wifi ipServer if + // given ifname don't match any tracking ipServer. for (int i = 0; i < mTetherStates.size(); i++) { final IpServer ipServer = mTetherStates.valueAt(i).ipServer; if (ipServer.interfaceType() == tetheringType) { @@ -1400,7 +1402,6 @@ public class Tethering { return; } } - mLog.log("Error disabling Wi-Fi IP serving; " + (TextUtils.isEmpty(ifname) ? "no interface name specified" : "specified interface: " + ifname)); @@ -1409,20 +1410,39 @@ public class Tethering { private void disableWifiIpServing(String ifname, int apState) { // Regardless of whether we requested this transition, the AP has gone // down. Don't try to tether again unless we're requested to do so. - // TODO: Remove this altogether, once Wi-Fi reliably gives us an - // interface name with every broadcast. mWifiTetherRequested = false; - disableWifiIpServingCommon(TETHERING_WIFI, ifname, apState); + mLog.log("Canceling WiFi tethering request - interface=" + ifname + " state=" + apState); + + disableWifiIpServingCommon(TETHERING_WIFI, ifname); + } + + private void enableWifiP2pIpServing(String ifname) { + if (TextUtils.isEmpty(ifname)) { + mLog.e("Cannot enable P2P IP serving with invalid interface"); + return; + } + + // After T, tethering always trust the iface pass by state change intent. This allow + // tethering to deprecate tetherable p2p regexs after T. + final int type = SdkLevel.isAtLeastT() ? TETHERING_WIFI_P2P : ifaceNameToType(ifname); + if (!checkTetherableType(type)) { + mLog.e(ifname + " is not a tetherable iface, ignoring"); + return; + } + enableIpServing(type, ifname, IpServer.STATE_LOCAL_ONLY); } private void disableWifiP2pIpServingIfNeeded(String ifname) { if (TextUtils.isEmpty(ifname)) return; - disableWifiIpServingCommon(TETHERING_WIFI_P2P, ifname, /* fake */ 0); + mLog.log("Canceling P2P tethering request - interface=" + ifname); + disableWifiIpServingCommon(TETHERING_WIFI_P2P, ifname); } private void enableWifiIpServing(String ifname, int wifiIpMode) { + mLog.log("request WiFi tethering - interface=" + ifname + " state=" + wifiIpMode); + // Map wifiIpMode values to IpServer.Callback serving states, inferring // from mWifiTetherRequested as a final "best guess". final int ipServingMode; @@ -1438,13 +1458,18 @@ public class Tethering { return; } + // After T, tethering always trust the iface pass by state change intent. This allow + // tethering to deprecate tetherable wifi regexs after T. + final int type = SdkLevel.isAtLeastT() ? TETHERING_WIFI : ifaceNameToType(ifname); + if (!checkTetherableType(type)) { + mLog.e(ifname + " is not a tetherable iface, ignoring"); + return; + } + if (!TextUtils.isEmpty(ifname)) { - ensureIpServerStarted(ifname); - changeInterfaceState(ifname, ipServingMode); + enableIpServing(type, ifname, ipServingMode); } else { - mLog.e(String.format( - "Cannot enable IP serving in mode %s on missing interface name", - ipServingMode)); + mLog.e("Cannot enable IP serving on missing interface name"); } } @@ -2715,23 +2740,28 @@ public class Tethering { mTetherMainSM.sendMessage(which, state, 0, newLp); } + private boolean hasSystemFeature(final String feature) { + return mContext.getPackageManager().hasSystemFeature(feature); + } + + private boolean checkTetherableType(int type) { + if ((type == TETHERING_WIFI || type == TETHERING_WIGIG) + && !hasSystemFeature(PackageManager.FEATURE_WIFI)) { + return false; + } + + if (type == TETHERING_WIFI_P2P && !hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)) { + return false; + } + + return type != TETHERING_INVALID; + } + private void ensureIpServerStarted(final String iface) { // If we don't care about this type of interface, ignore. final int interfaceType = ifaceNameToType(iface); - if (interfaceType == TETHERING_INVALID) { - mLog.log(iface + " is not a tetherable iface, ignoring"); - return; - } - - final PackageManager pm = mContext.getPackageManager(); - if ((interfaceType == TETHERING_WIFI || interfaceType == TETHERING_WIGIG) - && !pm.hasSystemFeature(PackageManager.FEATURE_WIFI)) { - mLog.log(iface + " is not tetherable, because WiFi feature is disabled"); - return; - } - if (interfaceType == TETHERING_WIFI_P2P - && !pm.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)) { - mLog.log(iface + " is not tetherable, because WiFi Direct feature is disabled"); + if (!checkTetherableType(interfaceType)) { + mLog.log(iface + " is used for " + interfaceType + " which is not tetherable"); return; } 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 2fd7f4802d..6ef0e245eb 100644 --- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -57,6 +57,7 @@ import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE; import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY; import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED; +import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; import static android.system.OsConstants.RT_SCOPE_UNIVERSE; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; @@ -936,7 +937,7 @@ public class TetheringTest { // Emulate externally-visible WifiManager effects, when hotspot mode // is being torn down. - sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED); + sendWifiApStateChanged(WIFI_AP_STATE_DISABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_LOCAL_ONLY); mTethering.interfaceRemoved(TEST_WLAN_IFNAME); mLooper.dispatchAll(); @@ -1509,7 +1510,7 @@ public class TetheringTest { // Emulate externally-visible WifiManager effects, when tethering mode // is being torn down. - sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED); + sendWifiApStateChanged(WIFI_AP_STATE_DISABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED); mTethering.interfaceRemoved(TEST_WLAN_IFNAME); mLooper.dispatchAll(); @@ -1903,7 +1904,13 @@ public class TetheringTest { mTethering.unregisterTetheringEventCallback(callback); mLooper.dispatchAll(); mTethering.stopTethering(TETHERING_WIFI); - sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED); + sendWifiApStateChanged(WIFI_AP_STATE_DISABLED); + if (isAtLeastT()) { + // After T, tethering doesn't support WIFI_AP_STATE_DISABLED with null interface name. + callback2.assertNoStateChangeCallback(); + sendWifiApStateChanged(WIFI_AP_STATE_DISABLED, TEST_WLAN_IFNAME, + IFACE_IP_MODE_TETHERED); + } tetherState = callback2.pollTetherStatesChanged(); assertArrayEquals(tetherState.availableList, new TetheringInterface[] {wifiIface}); mLooper.dispatchAll();