Add methods to distinguish TetheringRequest types
Add TetheringRequest#RequestType to distinguish the type of
TetheringRequest (i.e. from startTethering, from implicit broadcasts, or
from the legacy tether API) as well as helper methods to create these
requests. These will be used in a future CL.
Bug: 216524590
Test: build
Change-Id: Ibfda48f59e80d423c9b6ee0d244cbdab14be1bd2
diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index 21f36e8..aa7a244 100644
--- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -807,6 +807,46 @@
*/
@SuppressLint("UnflaggedApi")
public static final class TetheringRequest implements Parcelable {
+ /**
+ * Tethering started by an explicit call to startTethering.
+ * @hide
+ */
+ public static final int REQUEST_TYPE_EXPLICIT = 0;
+
+ /**
+ * Tethering implicitly started by broadcasts (LOHS and P2P). Can never be pending.
+ * @hide
+ */
+ public static final int REQUEST_TYPE_IMPLICIT = 1;
+
+ /**
+ * Tethering started by the legacy tether() call. Can only happen on V-.
+ * @hide
+ */
+ public static final int REQUEST_TYPE_LEGACY = 2;
+
+ /**
+ * Tethering started but there was no pending request found. This may happen if Tethering is
+ * started and immediately stopped before the link layer goes up, or if we get a link layer
+ * event without a prior call to startTethering (e.g. adb shell cmd wifi start-softap).
+ * @hide
+ */
+ public static final int REQUEST_TYPE_PLACEHOLDER = 3;
+
+ /**
+ * Type of request, used to keep track of whether the request was explicitly sent by
+ * startTethering, implicitly created by broadcasts, or via legacy tether().
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "TYPE_", value = {
+ REQUEST_TYPE_EXPLICIT,
+ REQUEST_TYPE_IMPLICIT,
+ REQUEST_TYPE_LEGACY,
+ REQUEST_TYPE_PLACEHOLDER,
+ })
+ public @interface RequestType {}
+
/** A configuration set for TetheringRequest. */
private final TetheringRequestParcel mRequestParcel;
@@ -866,6 +906,7 @@
mBuilderParcel.uid = Process.INVALID_UID;
mBuilderParcel.softApConfig = null;
mBuilderParcel.interfaceName = null;
+ mBuilderParcel.requestType = REQUEST_TYPE_EXPLICIT;
}
/**
@@ -1161,6 +1202,14 @@
}
/**
+ * Get the type of the request.
+ * @hide
+ */
+ public @RequestType int getRequestType() {
+ return mRequestParcel.requestType;
+ }
+
+ /**
* String of TetheringRequest detail.
* @hide
*/
@@ -1168,6 +1217,13 @@
public String toString() {
StringJoiner sj = new StringJoiner(", ", "TetheringRequest[ ", " ]");
sj.add(typeToString(mRequestParcel.tetheringType));
+ if (mRequestParcel.requestType == REQUEST_TYPE_IMPLICIT) {
+ sj.add("IMPLICIT");
+ } else if (mRequestParcel.requestType == REQUEST_TYPE_LEGACY) {
+ sj.add("LEGACY");
+ } else if (mRequestParcel.requestType == REQUEST_TYPE_PLACEHOLDER) {
+ sj.add("PLACEHOLDER");
+ }
if (mRequestParcel.localIPv4Address != null) {
sj.add("localIpv4Address=" + mRequestParcel.localIPv4Address);
}
@@ -1217,7 +1273,8 @@
public boolean equalsIgnoreUidPackage(TetheringRequest otherRequest) {
TetheringRequestParcel parcel = getParcel();
TetheringRequestParcel otherParcel = otherRequest.getParcel();
- return parcel.tetheringType == otherParcel.tetheringType
+ return parcel.requestType == otherParcel.requestType
+ && parcel.tetheringType == otherParcel.tetheringType
&& Objects.equals(parcel.localIPv4Address, otherParcel.localIPv4Address)
&& Objects.equals(parcel.staticClientAddress, otherParcel.staticClientAddress)
&& parcel.exemptFromEntitlementCheck == otherParcel.exemptFromEntitlementCheck
diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl b/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl
index 97c9b9a..9863385 100644
--- a/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl
+++ b/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl
@@ -24,6 +24,7 @@
* @hide
*/
parcelable TetheringRequestParcel {
+ int requestType;
int tetheringType;
LinkAddress localIPv4Address;
LinkAddress staticClientAddress;
diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java
index a388624..11b14ed 100644
--- a/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -51,6 +51,7 @@
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;
+import static android.net.TetheringManager.TetheringRequest.REQUEST_TYPE_PLACEHOLDER;
import static android.net.TetheringManager.toIfaces;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
@@ -1031,6 +1032,49 @@
}
/**
+ * Create a legacy tethering request for calls to the legacy tether() API, which doesn't take an
+ * explicit request.
+ */
+ private TetheringRequest createLegacyTetheringRequest(int type, int connectivityScope) {
+ final TetheringRequest request = new TetheringRequest.Builder(type).build();
+ request.getParcel().requestType = TetheringRequest.REQUEST_TYPE_LEGACY;
+ request.getParcel().connectivityScope = connectivityScope;
+ return request;
+ }
+
+ /**
+ * Create a local-only implicit tethering request. This is used for Wifi local-only hotspot and
+ * Wifi P2P, which start tethering based on the WIFI_(AP/P2P)_STATE_CHANGED broadcasts.
+ */
+ @NonNull
+ private TetheringRequest createImplicitLocalOnlyTetheringRequest(int type) {
+ final TetheringRequest request = new TetheringRequest.Builder(type).build();
+ request.getParcel().requestType = TetheringRequest.REQUEST_TYPE_IMPLICIT;
+ request.getParcel().connectivityScope = CONNECTIVITY_SCOPE_LOCAL;
+ return request;
+ }
+
+ /**
+ * Gets the TetheringRequest that #startTethering was called with but is waiting for the link
+ * layer event to indicate the interface is available to tether.
+ * Note: There are edge cases where the pending request is absent and we must temporarily
+ * synthesize a placeholder request, such as if stopTethering was called before link layer
+ * went up, or if the link layer goes up without us poking it (e.g. adb shell cmd wifi
+ * start-softap).
+ */
+ @NonNull
+ private TetheringRequest getOrCreatePendingTetheringRequest(int type) {
+ TetheringRequest pending = mActiveTetheringRequests.get(type);
+ if (pending != null) return pending;
+
+ Log.w(TAG, "No pending TetheringRequest for type " + type + " found, creating a placeholder"
+ + " request");
+ TetheringRequest placeholder = new TetheringRequest.Builder(type).build();
+ placeholder.getParcel().requestType = REQUEST_TYPE_PLACEHOLDER;
+ return placeholder;
+ }
+
+ /**
* Legacy tether API that starts tethering with CONNECTIVITY_SCOPE_GLOBAL on the given iface.
*
* This API relies on the IpServer having been started for the interface by
@@ -1043,7 +1087,7 @@
* WIFI_(AP/P2P_STATE_CHANGED broadcasts, which makes this API redundant for those types unless
* those broadcasts are disabled by OEM.
*/
- void tether(String iface, int requestedState, final IIntResultListener listener) {
+ void legacyTether(String iface, int requestedState, final IIntResultListener listener) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.VANILLA_ICE_CREAM) {
// After V, the TetheringManager and ConnectivityManager tether and untether methods
// throw UnsupportedOperationException, so this cannot happen in normal use. Ensure
@@ -1052,7 +1096,7 @@
return;
}
mHandler.post(() -> {
- int result = tether(iface, requestedState);
+ int result = tetherInternal(iface, requestedState);
switch (ifaceNameToType(iface)) {
case TETHERING_WIFI:
TerribleErrorLog.logTerribleError(TetheringStatsLog::write,
@@ -1088,7 +1132,7 @@
});
}
- private int tether(String iface, int requestedState) {
+ private int tetherInternal(String iface, int requestedState) {
if (DBG) Log.d(TAG, "Tethering " + iface);
TetherState tetherState = mTetherStates.get(iface);
if (tetherState == null) {
@@ -1114,7 +1158,7 @@
return TETHER_ERROR_NO_ERROR;
}
- void untether(String iface, final IIntResultListener listener) {
+ void legacyUntether(String iface, final IIntResultListener listener) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.VANILLA_ICE_CREAM) {
// After V, the TetheringManager and ConnectivityManager tether and untether methods
// throw UnsupportedOperationException, so this cannot happen in normal use. Ensure
@@ -1124,13 +1168,13 @@
}
mHandler.post(() -> {
try {
- listener.onResult(untether(iface));
+ listener.onResult(legacyUntetherInternal(iface));
} catch (RemoteException e) {
}
});
}
- int untether(String iface) {
+ int legacyUntetherInternal(String iface) {
if (DBG) Log.d(TAG, "Untethering " + iface);
TetherState tetherState = mTetherStates.get(iface);
if (tetherState == null) {
@@ -1145,7 +1189,7 @@
return TETHER_ERROR_NO_ERROR;
}
- void untetherAll() {
+ void stopAllTethering() {
stopTethering(TETHERING_WIFI);
stopTethering(TETHERING_WIFI_P2P);
stopTethering(TETHERING_USB);
@@ -1315,7 +1359,7 @@
mLog.log("OBSERVED data saver changed");
handleDataSaverChanged();
} else if (action.equals(TetheringNotificationUpdater.ACTION_DISABLE_TETHERING)) {
- untetherAll();
+ stopAllTethering();
}
}
@@ -1479,7 +1523,7 @@
mDataSaverEnabled = isDataSaverEnabled;
if (mDataSaverEnabled) {
- untetherAll();
+ stopAllTethering();
}
}
}
@@ -1538,7 +1582,7 @@
mNotificationUpdater.notifyTetheringDisabledByRestriction();
// Untether from all downstreams since tethering is disallowed.
- mTethering.untetherAll();
+ mTethering.stopAllTethering();
}
return true;
@@ -1553,7 +1597,7 @@
private void enableIpServing(int tetheringType, String ifname, int ipServingMode,
boolean isNcm) {
ensureIpServerStarted(ifname, tetheringType, isNcm);
- if (tether(ifname, ipServingMode) != TETHER_ERROR_NO_ERROR) {
+ if (tetherInternal(ifname, ipServingMode) != TETHER_ERROR_NO_ERROR) {
Log.e(TAG, "unable start tethering on iface " + ifname);
}
}
diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringService.java b/Tethering/src/com/android/networkstack/tethering/TetheringService.java
index 0c44a38..153b0f7 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetheringService.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetheringService.java
@@ -111,7 +111,7 @@
IIntResultListener listener) {
if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
- mTethering.tether(iface, IpServer.STATE_TETHERED, listener);
+ mTethering.legacyTether(iface, IpServer.STATE_TETHERED, listener);
}
@Override
@@ -119,7 +119,7 @@
IIntResultListener listener) {
if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
- mTethering.untether(iface, listener);
+ mTethering.legacyUntether(iface, listener);
}
@Override
@@ -200,7 +200,7 @@
if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
try {
- mTethering.untetherAll();
+ mTethering.stopAllTethering();
listener.onResult(TETHER_ERROR_NO_ERROR);
} catch (RemoteException e) { }
}
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 cc80251..da9b68e 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
@@ -219,7 +219,7 @@
mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
verify(mTethering).isTetheringSupported();
verify(mTethering).isTetheringAllowed();
- verify(mTethering).tether(TEST_IFACE_NAME, IpServer.STATE_TETHERED, result);
+ verify(mTethering).legacyTether(TEST_IFACE_NAME, IpServer.STATE_TETHERED, result);
}
@Test
@@ -267,7 +267,7 @@
result);
verify(mTethering).isTetheringSupported();
verify(mTethering).isTetheringAllowed();
- verify(mTethering).untether(eq(TEST_IFACE_NAME), eq(result));
+ verify(mTethering).legacyUntether(eq(TEST_IFACE_NAME), eq(result));
}
@Test
@@ -661,7 +661,7 @@
mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
verify(mTethering).isTetheringSupported();
verify(mTethering).isTetheringAllowed();
- verify(mTethering).untetherAll();
+ verify(mTethering).stopAllTethering();
result.assertResult(TETHER_ERROR_NO_ERROR);
}
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 97758cf..e50a7fd 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -2098,7 +2098,7 @@
verify(mNotificationUpdater, times(expectedInteractionsWithShowNotification))
.notifyTetheringDisabledByRestriction();
- verify(mockTethering, times(expectedInteractionsWithShowNotification)).untetherAll();
+ verify(mockTethering, times(expectedInteractionsWithShowNotification)).stopAllTethering();
}
@Test
@@ -3426,7 +3426,7 @@
mTethering.interfaceStatusChanged(TEST_BT_IFNAME, false);
mTethering.interfaceStatusChanged(TEST_BT_IFNAME, true);
final ResultListener tetherResult = new ResultListener(TETHER_ERROR_NO_ERROR);
- mTethering.tether(TEST_BT_IFNAME, IpServer.STATE_TETHERED, tetherResult);
+ mTethering.legacyTether(TEST_BT_IFNAME, IpServer.STATE_TETHERED, tetherResult);
mLooper.dispatchAll();
tetherResult.assertHasResult();
@@ -3446,7 +3446,7 @@
mTethering.stopTethering(TETHERING_BLUETOOTH);
mLooper.dispatchAll();
final ResultListener untetherResult = new ResultListener(TETHER_ERROR_NO_ERROR);
- mTethering.untether(TEST_BT_IFNAME, untetherResult);
+ mTethering.legacyUntether(TEST_BT_IFNAME, untetherResult);
mLooper.dispatchAll();
untetherResult.assertHasResult();
verifySetBluetoothTethering(false /* enable */, false /* bindToPanService */);
@@ -3476,7 +3476,7 @@
mTethering.interfaceStatusChanged(TEST_BT_IFNAME, false);
mTethering.interfaceStatusChanged(TEST_BT_IFNAME, true);
final ResultListener tetherResult = new ResultListener(TETHER_ERROR_NO_ERROR);
- mTethering.tether(TEST_BT_IFNAME, IpServer.STATE_TETHERED, tetherResult);
+ mTethering.legacyTether(TEST_BT_IFNAME, IpServer.STATE_TETHERED, tetherResult);
mLooper.dispatchAll();
tetherResult.assertHasResult();
}