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
This commit is contained in:
parent
42f38d0bdf
commit
f2e9409f55
2 changed files with 76 additions and 39 deletions
|
|
@ -1297,7 +1297,7 @@ public class Tethering {
|
||||||
|
|
||||||
// Finally bring up serving on the new interface
|
// Finally bring up serving on the new interface
|
||||||
mWifiP2pTetherInterface = group.getInterface();
|
mWifiP2pTetherInterface = group.getInterface();
|
||||||
enableWifiIpServing(mWifiP2pTetherInterface, IFACE_IP_MODE_LOCAL_ONLY);
|
enableWifiP2pIpServing(mWifiP2pTetherInterface);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleUserRestrictionAction() {
|
private void handleUserRestrictionAction() {
|
||||||
|
|
@ -1388,20 +1388,22 @@ public class Tethering {
|
||||||
changeInterfaceState(ifname, ipServingMode);
|
changeInterfaceState(ifname, ipServingMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void disableWifiIpServingCommon(int tetheringType, String ifname, int apState) {
|
private void disableWifiIpServingCommon(int tetheringType, String ifname) {
|
||||||
mLog.log("Canceling WiFi tethering request -"
|
if (!TextUtils.isEmpty(ifname) && mTetherStates.containsKey(ifname)) {
|
||||||
+ " type=" + tetheringType
|
mTetherStates.get(ifname).ipServer.unwanted();
|
||||||
+ " interface=" + ifname
|
return;
|
||||||
+ " state=" + apState);
|
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(ifname)) {
|
|
||||||
final TetherState ts = mTetherStates.get(ifname);
|
|
||||||
if (ts != null) {
|
|
||||||
ts.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++) {
|
for (int i = 0; i < mTetherStates.size(); i++) {
|
||||||
final IpServer ipServer = mTetherStates.valueAt(i).ipServer;
|
final IpServer ipServer = mTetherStates.valueAt(i).ipServer;
|
||||||
if (ipServer.interfaceType() == tetheringType) {
|
if (ipServer.interfaceType() == tetheringType) {
|
||||||
|
|
@ -1409,7 +1411,6 @@ public class Tethering {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mLog.log("Error disabling Wi-Fi IP serving; "
|
mLog.log("Error disabling Wi-Fi IP serving; "
|
||||||
+ (TextUtils.isEmpty(ifname) ? "no interface name specified"
|
+ (TextUtils.isEmpty(ifname) ? "no interface name specified"
|
||||||
: "specified interface: " + ifname));
|
: "specified interface: " + ifname));
|
||||||
|
|
@ -1418,20 +1419,39 @@ public class Tethering {
|
||||||
private void disableWifiIpServing(String ifname, int apState) {
|
private void disableWifiIpServing(String ifname, int apState) {
|
||||||
// Regardless of whether we requested this transition, the AP has gone
|
// 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.
|
// 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;
|
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) {
|
private void disableWifiP2pIpServingIfNeeded(String ifname) {
|
||||||
if (TextUtils.isEmpty(ifname)) return;
|
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) {
|
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
|
// Map wifiIpMode values to IpServer.Callback serving states, inferring
|
||||||
// from mWifiTetherRequested as a final "best guess".
|
// from mWifiTetherRequested as a final "best guess".
|
||||||
final int ipServingMode;
|
final int ipServingMode;
|
||||||
|
|
@ -1447,13 +1467,18 @@ public class Tethering {
|
||||||
return;
|
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)) {
|
if (!TextUtils.isEmpty(ifname)) {
|
||||||
ensureIpServerStarted(ifname);
|
enableIpServing(type, ifname, ipServingMode);
|
||||||
changeInterfaceState(ifname, ipServingMode);
|
|
||||||
} else {
|
} else {
|
||||||
mLog.e(String.format(
|
mLog.e("Cannot enable IP serving on missing interface name");
|
||||||
"Cannot enable IP serving in mode %s on missing interface name",
|
|
||||||
ipServingMode));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2724,23 +2749,28 @@ public class Tethering {
|
||||||
mTetherMainSM.sendMessage(which, state, 0, newLp);
|
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) {
|
private void ensureIpServerStarted(final String iface) {
|
||||||
// If we don't care about this type of interface, ignore.
|
// If we don't care about this type of interface, ignore.
|
||||||
final int interfaceType = ifaceNameToType(iface);
|
final int interfaceType = ifaceNameToType(iface);
|
||||||
if (interfaceType == TETHERING_INVALID) {
|
if (!checkTetherableType(interfaceType)) {
|
||||||
mLog.log(iface + " is not a tetherable iface, ignoring");
|
mLog.log(iface + " is used for " + interfaceType + " which is not tetherable");
|
||||||
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");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,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.EXTRA_WIFI_AP_STATE;
|
||||||
import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY;
|
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.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.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
|
||||||
import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
|
import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
|
||||||
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
||||||
|
|
@ -946,7 +947,7 @@ public class TetheringTest {
|
||||||
|
|
||||||
// Emulate externally-visible WifiManager effects, when hotspot mode
|
// Emulate externally-visible WifiManager effects, when hotspot mode
|
||||||
// is being torn down.
|
// 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);
|
mTethering.interfaceRemoved(TEST_WLAN_IFNAME);
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
|
|
||||||
|
|
@ -1521,7 +1522,7 @@ public class TetheringTest {
|
||||||
|
|
||||||
// Emulate externally-visible WifiManager effects, when tethering mode
|
// Emulate externally-visible WifiManager effects, when tethering mode
|
||||||
// is being torn down.
|
// 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);
|
mTethering.interfaceRemoved(TEST_WLAN_IFNAME);
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
|
|
||||||
|
|
@ -1922,7 +1923,13 @@ public class TetheringTest {
|
||||||
mTethering.unregisterTetheringEventCallback(callback);
|
mTethering.unregisterTetheringEventCallback(callback);
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
mTethering.stopTethering(TETHERING_WIFI);
|
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();
|
tetherState = callback2.pollTetherStatesChanged();
|
||||||
assertArrayEquals(tetherState.availableList, new TetheringInterface[] {wifiIface});
|
assertArrayEquals(tetherState.availableList, new TetheringInterface[] {wifiIface});
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue