Merge "Add methods to distinguish TetheringRequest types" into main

This commit is contained in:
Quang Luong 2025-01-21 17:57:31 -08:00 • committed by Gerrit Code Review
commit 134d017940
6 changed files with 124 additions and 22 deletions

View file

@ -807,6 +807,46 @@ public class TetheringManager {
*/
@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 @@ public class TetheringManager {
mBuilderParcel.uid = Process.INVALID_UID;
mBuilderParcel.softApConfig = null;
mBuilderParcel.interfaceName = null;
mBuilderParcel.requestType = REQUEST_TYPE_EXPLICIT;
}
/**
@ -1160,6 +1201,14 @@ public class TetheringManager {
return mRequestParcel;
}
/**
* Get the type of the request.
* @hide
*/
public @RequestType int getRequestType() {
return mRequestParcel.requestType;
}
/**
* String of TetheringRequest detail.
* @hide
@ -1168,6 +1217,13 @@ public class TetheringManager {
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 class TetheringManager {
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

View file

@ -24,6 +24,7 @@ import android.net.wifi.SoftApConfiguration;
* @hide
*/
parcelable TetheringRequestParcel {
int requestType;
int tetheringType;
LinkAddress localIPv4Address;
LinkAddress staticClientAddress;

View file

@ -51,6 +51,7 @@ import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_TYPE;
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;
@ -1030,6 +1031,49 @@ public class Tethering {
return TETHER_ERROR_NO_ERROR;
}
/**
* 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.
*
@ -1043,7 +1087,7 @@ public class Tethering {
* 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 @@ public class Tethering {
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 @@ public class Tethering {
});
}
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 @@ public class Tethering {
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 @@ public class Tethering {
}
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 @@ public class Tethering {
return TETHER_ERROR_NO_ERROR;
}
void untetherAll() {
void stopAllTethering() {
stopTethering(TETHERING_WIFI);
stopTethering(TETHERING_WIFI_P2P);
stopTethering(TETHERING_USB);
@ -1315,7 +1359,7 @@ public class Tethering {
mLog.log("OBSERVED data saver changed");
handleDataSaverChanged();
} else if (action.equals(TetheringNotificationUpdater.ACTION_DISABLE_TETHERING)) {
untetherAll();
stopAllTethering();
}
}
@ -1479,7 +1523,7 @@ public class Tethering {
mDataSaverEnabled = isDataSaverEnabled;
if (mDataSaverEnabled) {
untetherAll();
stopAllTethering();
}
}
}
@ -1538,7 +1582,7 @@ public class Tethering {
mNotificationUpdater.notifyTetheringDisabledByRestriction();
// Untether from all downstreams since tethering is disallowed.
mTethering.untetherAll();
mTethering.stopAllTethering();
}
return true;
@ -1553,7 +1597,7 @@ public class Tethering {
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);
}
}

View file

@ -111,7 +111,7 @@ public class TetheringService extends Service {
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 @@ public class TetheringService extends Service {
IIntResultListener listener) {
if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
mTethering.untether(iface, listener);
mTethering.legacyUntether(iface, listener);
}
@Override
@ -200,7 +200,7 @@ public class TetheringService extends Service {
if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
try {
mTethering.untetherAll();
mTethering.stopAllTethering();
listener.onResult(TETHER_ERROR_NO_ERROR);
} catch (RemoteException e) { }
}

View file

@ -219,7 +219,7 @@ public final class TetheringServiceTest {
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 @@ public final class TetheringServiceTest {
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 @@ public final class TetheringServiceTest {
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);
}

View file

@ -2098,7 +2098,7 @@ public class TetheringTest {
verify(mNotificationUpdater, times(expectedInteractionsWithShowNotification))
.notifyTetheringDisabledByRestriction();
verify(mockTethering, times(expectedInteractionsWithShowNotification)).untetherAll();
verify(mockTethering, times(expectedInteractionsWithShowNotification)).stopAllTethering();
}
@Test
@ -3426,7 +3426,7 @@ public class TetheringTest {
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 @@ public class TetheringTest {
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 @@ public class TetheringTest {
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();
}