diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index f123dca0dd..0ac97f06e5 100644 --- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -333,6 +333,11 @@ public class TetheringManager { public static final int TETHER_ERROR_UNKNOWN_REQUEST = 17; @FlaggedApi(Flags.FLAG_TETHERING_WITH_SOFT_AP_CONFIG) public static final int TETHER_ERROR_DUPLICATE_REQUEST = 18; + /** + * Never used outside Tethering.java. + * @hide + */ + public static final int TETHER_ERROR_BLUETOOTH_SERVICE_PENDING = 19; /** @hide */ @Retention(RetentionPolicy.SOURCE) diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java index c0192ddc7e..b50831d56a 100644 --- a/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -43,6 +43,7 @@ import static android.net.TetheringManager.TETHERING_VIRTUAL; import static android.net.TetheringManager.TETHERING_WIFI; import static android.net.TetheringManager.TETHERING_WIFI_P2P; import static android.net.TetheringManager.TETHERING_WIGIG; +import static android.net.TetheringManager.TETHER_ERROR_BLUETOOTH_SERVICE_PENDING; import static android.net.TetheringManager.TETHER_ERROR_INTERNAL_ERROR; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; import static android.net.TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL; @@ -707,8 +708,7 @@ public class Tethering { // If tethering is already enabled with a different request, // disable before re-enabling. if (unfinishedRequest != null && !unfinishedRequest.equalsIgnoreUidPackage(request)) { - enableTetheringInternal(type, false /* disabled */, - unfinishedRequest.getInterfaceName(), null); + enableTetheringInternal(false /* disabled */, unfinishedRequest, null); mEntitlementMgr.stopProvisioningIfNeeded(type); } mPendingTetheringRequests.put(type, request); @@ -719,7 +719,7 @@ public class Tethering { mEntitlementMgr.startProvisioningIfNeeded(type, request.getShouldShowEntitlementUi()); } - enableTetheringInternal(type, true /* enabled */, request.getInterfaceName(), listener); + enableTetheringInternal(true /* enabled */, request, listener); mTetheringMetrics.createBuilder(type, callerPkg); }); } @@ -766,7 +766,10 @@ public class Tethering { void stopTetheringInternal(int type) { mPendingTetheringRequests.remove(type); - enableTetheringInternal(type, false /* disabled */, null, null); + // Using a placeholder here is ok since none of the disable APIs use the request for + // anything. We simply need the tethering type to know which link layer to poke for removal. + // TODO: Remove the placeholder here and loop through each pending/serving request. + enableTetheringInternal(false /* disabled */, createPlaceholderRequest(type), null); mEntitlementMgr.stopProvisioningIfNeeded(type); } @@ -774,9 +777,10 @@ public class Tethering { * Enables or disables tethering for the given type. If provisioning is required, it will * schedule provisioning rechecks for the specified interface. */ - private void enableTetheringInternal(int type, boolean enable, - String iface, final IIntResultListener listener) { - int result = TETHER_ERROR_NO_ERROR; + private void enableTetheringInternal(boolean enable, @NonNull final TetheringRequest request, + final IIntResultListener listener) { + final int type = request.getTetheringType(); + final int result; switch (type) { case TETHERING_WIFI: result = setWifiTethering(enable); @@ -785,7 +789,7 @@ public class Tethering { result = setUsbTethering(enable); break; case TETHERING_BLUETOOTH: - setBluetoothTethering(enable, listener); + result = setBluetoothTethering(enable, listener); break; case TETHERING_NCM: result = setNcmTethering(enable); @@ -794,17 +798,17 @@ public class Tethering { result = setEthernetTethering(enable); break; case TETHERING_VIRTUAL: - result = setVirtualMachineTethering(enable, iface); + result = setVirtualMachineTethering(enable, request); break; default: Log.w(TAG, "Invalid tether type."); result = TETHER_ERROR_UNKNOWN_TYPE; } - // The result of Bluetooth tethering will be sent by #setBluetoothTethering. - if (type != TETHERING_BLUETOOTH) { - sendTetherResult(listener, result, type); - } + // The result of Bluetooth tethering will be sent after the pan service connects. + if (result == TETHER_ERROR_BLUETOOTH_SERVICE_PENDING) return; + + sendTetherResult(listener, result, type); } private void sendTetherResult(final IIntResultListener listener, final int result, @@ -843,13 +847,12 @@ public class Tethering { return TETHER_ERROR_INTERNAL_ERROR; } - private void setBluetoothTethering(final boolean enable, final IIntResultListener listener) { + private int setBluetoothTethering(final boolean enable, final IIntResultListener listener) { final BluetoothAdapter adapter = mDeps.getBluetoothAdapter(); if (adapter == null || !adapter.isEnabled()) { Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: " + (adapter == null)); - sendTetherResult(listener, TETHER_ERROR_SERVICE_UNAVAIL, TETHERING_BLUETOOTH); - return; + return TETHER_ERROR_SERVICE_UNAVAIL; } if (mBluetoothPanListener != null && mBluetoothPanListener.isConnected()) { @@ -857,8 +860,7 @@ public class Tethering { // When bluetooth tethering is enabled, any time a PAN client pairs with this // host, bluetooth will bring up a bt-pan interface and notify tethering to // enable IP serving. - setBluetoothTetheringSettings(mBluetoothPan, enable, listener); - return; + return setBluetoothTetheringSettings(mBluetoothPan, enable); } if (!enable) { @@ -870,8 +872,7 @@ public class Tethering { TETHERING_BLUETOOTH); } mPendingPanRequestListeners.clear(); - sendTetherResult(listener, TETHER_ERROR_NO_ERROR, TETHERING_BLUETOOTH); - return; + return TETHER_ERROR_NO_ERROR; } mPendingPanRequestListeners.add(listener); @@ -883,6 +884,7 @@ public class Tethering { mBluetoothPanListener = new PanServiceListener(); adapter.getProfileProxy(mContext, mBluetoothPanListener, BluetoothProfile.PAN); } + return TETHER_ERROR_BLUETOOTH_SERVICE_PENDING; } private class PanServiceListener implements ServiceListener { @@ -900,8 +902,9 @@ public class Tethering { mIsConnected = true; for (IIntResultListener pendingListener : mPendingPanRequestListeners) { - setBluetoothTetheringSettings(mBluetoothPan, true /* enable */, - pendingListener); + final int result = setBluetoothTetheringSettings(mBluetoothPan, + true /* enable */); + sendTetherResult(pendingListener, result, TETHERING_BLUETOOTH); } mPendingPanRequestListeners.clear(); }); @@ -930,8 +933,8 @@ public class Tethering { } } - private void setBluetoothTetheringSettings(@NonNull final BluetoothPan bluetoothPan, - final boolean enable, final IIntResultListener listener) { + private int setBluetoothTetheringSettings(@NonNull final BluetoothPan bluetoothPan, + final boolean enable) { if (SdkLevel.isAtLeastT()) { changeBluetoothTetheringSettings(bluetoothPan, enable); } else { @@ -940,9 +943,8 @@ public class Tethering { // Enabling bluetooth tethering settings can silently fail. Send internal error if the // result is not expected. - final int result = bluetoothPan.isTetheringOn() == enable + return bluetoothPan.isTetheringOn() == enable ? TETHER_ERROR_NO_ERROR : TETHER_ERROR_INTERNAL_ERROR; - sendTetherResult(listener, result, TETHERING_BLUETOOTH); } private void changeBluetoothTetheringSettingsPreT(@NonNull final BluetoothPan bluetoothPan, @@ -1061,14 +1063,15 @@ public class Tethering { } } - private int setVirtualMachineTethering(final boolean enable, String iface) { + private int setVirtualMachineTethering(final boolean enable, + @NonNull final TetheringRequest request) { + final String iface = request.getInterfaceName(); if (enable) { if (TextUtils.isEmpty(iface)) { mConfiguredVirtualIface = "avf_tap_fixed"; } else { mConfiguredVirtualIface = iface; } - final TetheringRequest request = getOrCreatePendingTetheringRequest(TETHERING_VIRTUAL); enableIpServing(request, mConfiguredVirtualIface); } else if (mConfiguredVirtualIface != null) { ensureIpServerStopped(mConfiguredVirtualIface); @@ -1100,6 +1103,19 @@ public class Tethering { return request; } + /** + * Create a placeholder request. This is used in case we try to find a pending request but there + * is none (e.g. stopTethering removed a pending request), or for cases where we only have the + * tethering type (e.g. stopTethering(int)). + */ + @NonNull + private TetheringRequest createPlaceholderRequest(int type) { + final TetheringRequest request = new TetheringRequest.Builder(type).build(); + request.getParcel().requestType = TetheringRequest.REQUEST_TYPE_LEGACY; + request.getParcel().connectivityScope = CONNECTIVITY_SCOPE_GLOBAL; + 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. @@ -1116,9 +1132,7 @@ public class Tethering { 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; + return createPlaceholderRequest(type); } private void handleLegacyTether(String iface, final IIntResultListener listener) { @@ -2414,9 +2428,14 @@ public class Tethering { break; } case EVENT_REQUEST_CHANGE_DOWNSTREAM: { - final int tetheringType = message.arg1; + final int type = message.arg1; final Boolean enabled = (Boolean) message.obj; - enableTetheringInternal(tetheringType, enabled, null, null); + // Using a placeholder here is ok since we just need to the type of + // tethering to poke the link layer. When the link layer comes up, we won't + // have a pending request to use, but this matches the historical behavior. + // TODO: Get the TetheringRequest from IpServer and make sure to put it in + // the pending list too. + enableTetheringInternal(enabled, createPlaceholderRequest(type), null); break; } default: