Remove pending BT request when service disconnects

If the PAN service disconnects before the BT iface is available, the BT
TetheringRequest will be stuck pending and prevent any new BT
startTethering attempts. This may happen if the user turns BT tethering
on and turns off BT without connecting to any device.

Fix this by always removing the pending BT request when the PAN service
disconnects.

Flag: EXEMPT minor bugfix

Bug: 420412916
Test: atest TetheringTest, manually verify turning BT tethering on,
turning off BT, and turning BT tethering on again.

Change-Id: I6bc96d6e4016d83af6cfd8e549d474ce651a44fc
This commit is contained in:
Quang Anh Luong 2025-06-03 14:59:07 +09:00
commit 1a2b238bc1
2 changed files with 54 additions and 15 deletions

View file

@ -960,13 +960,15 @@ public class Tethering {
// reachable before next onServiceConnected.
mIsConnected = false;
if (mPendingPanRequestListener != null) {
sendTetherResultAndRemoveOnError(
mRequestTracker.getOrCreatePendingRequest(TETHERING_BLUETOOTH),
mPendingPanRequestListener,
TETHER_ERROR_SERVICE_UNAVAIL);
}
mPendingPanRequestListener = null;
// Remove any pending request even if bluetooth tethering is not started.
// Call sendTetherResultAndRemoveOnError for convenience (and to update the metrics)
// even though mPendingPanRequestListener is guaranteed to be null here (when the
// service connects onServiceConnected sets it to null, and whenever the service is
// connected, it's never set to non-null).
sendTetherResultAndRemoveOnError(
mRequestTracker.getOrCreatePendingRequest(TETHERING_BLUETOOTH),
null /* listener */,
TETHER_ERROR_SERVICE_UNAVAIL);
mBluetoothIfaceRequest = null;
mBluetoothCallback = null;
maybeDisableBluetoothIpServing();

View file

@ -3292,6 +3292,10 @@ public class TetheringTest {
@Override
public void onResult(final int resultCode) {
if (mHasResult) {
fail("Received result: " + resultCode + ", but we already have a result: "
+ mExpectedResult);
}
mHasResult = true;
if (resultCode != mExpectedResult) {
fail("expected result: " + mExpectedResult + " but actual result: " + resultCode);
@ -3314,11 +3318,9 @@ public class TetheringTest {
final LinkAddress serverLinkAddr = new LinkAddress("192.168.20.1/24");
final LinkAddress clientLinkAddr = new LinkAddress("192.168.20.42/24");
final String serverAddr = "192.168.20.1";
final ResultListener firstResult = new ResultListener(TETHER_ERROR_NO_ERROR);
final ResultListener secondResult = new ResultListener(TETHER_ERROR_NO_ERROR);
final ResultListener thirdResult = new ResultListener(TETHER_ERROR_NO_ERROR);
// Enable USB tethering and check that Tethering starts USB.
final ResultListener firstResult = new ResultListener(TETHER_ERROR_NO_ERROR);
mTethering.startTethering(createTetheringRequest(TETHERING_USB), TEST_CALLER_PKG,
firstResult);
mLooper.dispatchAll();
@ -3327,6 +3329,7 @@ public class TetheringTest {
verifyNoMoreInteractions(mUsbManager);
// Enable USB tethering again with the same request and expect no change to USB.
final ResultListener secondResult = new ResultListener(TETHER_ERROR_NO_ERROR);
mTethering.startTethering(createTetheringRequest(TETHERING_USB), TEST_CALLER_PKG,
secondResult);
mLooper.dispatchAll();
@ -3336,22 +3339,24 @@ public class TetheringTest {
// Enable USB tethering again with the same request but different uid/package and expect no
// change to USB.
final ResultListener thirdResult = new ResultListener(TETHER_ERROR_NO_ERROR);
TetheringRequest differentUidPackage = createTetheringRequest(TETHERING_USB);
differentUidPackage.setUid(TEST_CALLER_UID_2);
differentUidPackage.setPackageName(TEST_CALLER_PKG_2);
mTethering.startTethering(differentUidPackage, TEST_CALLER_PKG_2, secondResult);
mTethering.startTethering(differentUidPackage, TEST_CALLER_PKG_2, thirdResult);
mLooper.dispatchAll();
secondResult.assertHasResult();
thirdResult.assertHasResult();
verify(mUsbManager, never()).setCurrentFunctions(UsbManager.FUNCTION_NONE);
reset(mUsbManager);
// Enable USB tethering with a different request and expect that USB is stopped and
// started.
final ResultListener fourthResult = new ResultListener(TETHER_ERROR_NO_ERROR);
mTethering.startTethering(createTetheringRequest(TETHERING_USB,
serverLinkAddr, clientLinkAddr, false, CONNECTIVITY_SCOPE_GLOBAL, null),
TEST_CALLER_PKG, thirdResult);
TEST_CALLER_PKG, fourthResult);
mLooper.dispatchAll();
thirdResult.assertHasResult();
fourthResult.assertHasResult();
verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_NONE);
verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
@ -3988,6 +3993,38 @@ public class TetheringTest {
verifyNetdCommandForBtTearDown();
}
@Test
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
public void testPendingBluetoothRequestRemovedWhenPanServiceDisconnectsBeforeIfaceAvailable()
throws Exception {
initTetheringOnTestThread();
final ResultListener result = new ResultListener(TETHER_ERROR_NO_ERROR);
mockBluetoothSettings(true /* bluetoothOn */, true /* tetheringOn */);
mTethering.startTethering(createTetheringRequest(TETHERING_BLUETOOTH),
TEST_CALLER_PKG, result);
mLooper.dispatchAll();
ServiceListener serviceListener =
verifySetBluetoothTethering(true /* enable */, true /* bindToPanService */);
result.assertHasResult();
// Mock BT turning off
serviceListener.onServiceDisconnected(BluetoothProfile.PAN);
mLooper.dispatchAll();
// Pending request should be removed
assertTrue(mTethering.getPendingTetheringRequests().isEmpty());
// Mock BT tethering started again should succeed
final ResultListener result2 = new ResultListener(TETHER_ERROR_NO_ERROR);
mockBluetoothSettings(true /* bluetoothOn */, true /* tetheringOn */);
mTethering.startTethering(createTetheringRequest(TETHERING_BLUETOOTH),
TEST_CALLER_PKG, result2);
serviceListener.onServiceConnected(BluetoothProfile.PAN, mBluetoothPan);
mLooper.dispatchAll();
verifySetBluetoothTethering(true /* enable */, false /* bindToPanService */);
result2.assertHasResult();
}
@Test
@IgnoreAfter(Build.VERSION_CODES.S_V2)
public void testBluetoothTetheringBeforeT() throws Exception {
@ -4203,7 +4240,7 @@ public class TetheringTest {
}
verify(mBluetoothPan).isTetheringOn();
verifyNoMoreInteractions(mBluetoothAdapter, mBluetoothPan);
reset(mBluetoothAdapter, mBluetoothPan);
reset(mBluetoothAdapter, mBluetoothPan, mBluetoothPanShim);
return listener;
}