Loading android/app/src/com/android/bluetooth/gatt/GattService.java +28 −6 Original line number Diff line number Diff line Loading @@ -95,6 +95,7 @@ import com.android.bluetooth.btservice.MetricsLogger; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.flags.FeatureFlags; import com.android.bluetooth.flags.FeatureFlagsImpl; import com.android.bluetooth.flags.Flags; import com.android.bluetooth.util.NumberUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.modules.utils.SynchronousResultReceiver; Loading Loading @@ -534,10 +535,14 @@ public class GattService extends ProfileService { ScanClient client = getScanClient(mScannerId); if (client != null) { if (Flags.leScanFixRemoteException()) { handleDeadScanClient(client); } else { client.appDied = true; stopScan(client.scannerId, getAttributionSource()); } } } private ScanClient getScanClient(int clientIf) { for (ScanClient client : mScanManager.getRegularScanQueue()) { Loading Loading @@ -2097,11 +2102,15 @@ public class GattService extends ProfileService { } } catch (RemoteException | PendingIntent.CanceledException e) { Log.e(TAG, "Exception: " + e); if (Flags.leScanFixRemoteException()) { handleDeadScanClient(client); } else { mScannerMap.remove(client.scannerId); mScanManager.stopScan(client.scannerId); } } } } private void sendResultByPendingIntent(PendingIntentInfo pii, ScanResult result, int callbackType, ScanClient client) { Loading Loading @@ -2203,6 +2212,15 @@ public class GattService extends ProfileService { return new MatchResult(false, MatchOrigin.PSEUDO_ADDRESS); } private void handleDeadScanClient(ScanClient client) { if (client.appDied) { Log.w(TAG, "Already dead client " + client.scannerId); return; } client.appDied = true; stopScan(client.scannerId, getAttributionSource()); } void onClientRegistered(int status, int clientIf, long uuidLsb, long uuidMsb) throws RemoteException { UUID uuid = new UUID(uuidMsb, uuidLsb); Loading Loading @@ -2848,10 +2866,14 @@ public class GattService extends ProfileService { } } catch (RemoteException | PendingIntent.CanceledException e) { Log.e(TAG, "Exception: " + e); if (Flags.leScanFixRemoteException()) { handleDeadScanClient(client); } else { mScannerMap.remove(client.scannerId); mScanManager.stopScan(client.scannerId); } } } // Check and deliver scan results for different scan clients. private void deliverBatchScan(ScanClient client, Set<ScanResult> allResults) Loading android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceTest.java +62 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ import android.os.Binder; import android.os.RemoteException; import android.os.WorkSource; import android.platform.test.annotations.RequiresFlagsEnabled; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.rule.ServiceTestRule; Loading @@ -55,8 +56,10 @@ import com.android.bluetooth.TestUtils; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.btservice.CompanionManager; import com.android.bluetooth.flags.Flags; import org.junit.After; import org.junit.Assert; import org.junit.Assume; import org.junit.Before; import org.junit.Rule; import org.junit.Test; Loading @@ -66,6 +69,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; Loading Loading @@ -487,6 +491,64 @@ public class GattServiceTest { verify(mScanManager).flushBatchScanResults(new ScanClient(scannerId)); } @RequiresFlagsEnabled(Flags.FLAG_LE_SCAN_FIX_REMOTE_EXCEPTION) @Test public void onScanResult_remoteException_clientDied() throws Exception { Assume.assumeTrue(Flags.leScanFixRemoteException()); int scannerId = 1; int eventType = 0; int addressType = 0; String address = "02:00:00:00:00:00"; int primaryPhy = 0; int secondPhy = 0; int advertisingSid = 0; int txPower = 0; int rssi = 0; int periodicAdvInt = 0; byte[] advData = new byte[0]; ScanClient scanClient = new ScanClient(scannerId); scanClient.scannerId = scannerId; scanClient.hasNetworkSettingsPermission = true; scanClient.settings = new ScanSettings.Builder() .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) .setLegacy(false) .build(); AppScanStats appScanStats = mock(AppScanStats.class); IScannerCallback callback = mock(IScannerCallback.class); mApp.callback = callback; mApp.appScanStats = appScanStats; Set<ScanClient> scanClientSet = Collections.singleton(scanClient); doReturn(address).when(mAdapterService).getIdentityAddress(anyString()); doReturn(scanClientSet).when(mScanManager).getRegularScanQueue(); doReturn(mApp).when(mScannerMap).getById(scanClient.scannerId); doReturn(appScanStats).when(mScannerMap).getAppScanStatsById(scanClient.scannerId); // Simulate remote client crash doThrow(new RemoteException()).when(callback).onScanResult(any()); mService.onScanResult( eventType, addressType, address, primaryPhy, secondPhy, advertisingSid, txPower, rssi, periodicAdvInt, advData, address); assertThat(scanClient.appDied).isTrue(); verify(appScanStats).recordScanStop(scannerId); } @Test public void readCharacteristic() { int clientIf = 1; Loading Loading
android/app/src/com/android/bluetooth/gatt/GattService.java +28 −6 Original line number Diff line number Diff line Loading @@ -95,6 +95,7 @@ import com.android.bluetooth.btservice.MetricsLogger; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.flags.FeatureFlags; import com.android.bluetooth.flags.FeatureFlagsImpl; import com.android.bluetooth.flags.Flags; import com.android.bluetooth.util.NumberUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.modules.utils.SynchronousResultReceiver; Loading Loading @@ -534,10 +535,14 @@ public class GattService extends ProfileService { ScanClient client = getScanClient(mScannerId); if (client != null) { if (Flags.leScanFixRemoteException()) { handleDeadScanClient(client); } else { client.appDied = true; stopScan(client.scannerId, getAttributionSource()); } } } private ScanClient getScanClient(int clientIf) { for (ScanClient client : mScanManager.getRegularScanQueue()) { Loading Loading @@ -2097,11 +2102,15 @@ public class GattService extends ProfileService { } } catch (RemoteException | PendingIntent.CanceledException e) { Log.e(TAG, "Exception: " + e); if (Flags.leScanFixRemoteException()) { handleDeadScanClient(client); } else { mScannerMap.remove(client.scannerId); mScanManager.stopScan(client.scannerId); } } } } private void sendResultByPendingIntent(PendingIntentInfo pii, ScanResult result, int callbackType, ScanClient client) { Loading Loading @@ -2203,6 +2212,15 @@ public class GattService extends ProfileService { return new MatchResult(false, MatchOrigin.PSEUDO_ADDRESS); } private void handleDeadScanClient(ScanClient client) { if (client.appDied) { Log.w(TAG, "Already dead client " + client.scannerId); return; } client.appDied = true; stopScan(client.scannerId, getAttributionSource()); } void onClientRegistered(int status, int clientIf, long uuidLsb, long uuidMsb) throws RemoteException { UUID uuid = new UUID(uuidMsb, uuidLsb); Loading Loading @@ -2848,10 +2866,14 @@ public class GattService extends ProfileService { } } catch (RemoteException | PendingIntent.CanceledException e) { Log.e(TAG, "Exception: " + e); if (Flags.leScanFixRemoteException()) { handleDeadScanClient(client); } else { mScannerMap.remove(client.scannerId); mScanManager.stopScan(client.scannerId); } } } // Check and deliver scan results for different scan clients. private void deliverBatchScan(ScanClient client, Set<ScanResult> allResults) Loading
android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceTest.java +62 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ import android.os.Binder; import android.os.RemoteException; import android.os.WorkSource; import android.platform.test.annotations.RequiresFlagsEnabled; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.rule.ServiceTestRule; Loading @@ -55,8 +56,10 @@ import com.android.bluetooth.TestUtils; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.btservice.CompanionManager; import com.android.bluetooth.flags.Flags; import org.junit.After; import org.junit.Assert; import org.junit.Assume; import org.junit.Before; import org.junit.Rule; import org.junit.Test; Loading @@ -66,6 +69,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; Loading Loading @@ -487,6 +491,64 @@ public class GattServiceTest { verify(mScanManager).flushBatchScanResults(new ScanClient(scannerId)); } @RequiresFlagsEnabled(Flags.FLAG_LE_SCAN_FIX_REMOTE_EXCEPTION) @Test public void onScanResult_remoteException_clientDied() throws Exception { Assume.assumeTrue(Flags.leScanFixRemoteException()); int scannerId = 1; int eventType = 0; int addressType = 0; String address = "02:00:00:00:00:00"; int primaryPhy = 0; int secondPhy = 0; int advertisingSid = 0; int txPower = 0; int rssi = 0; int periodicAdvInt = 0; byte[] advData = new byte[0]; ScanClient scanClient = new ScanClient(scannerId); scanClient.scannerId = scannerId; scanClient.hasNetworkSettingsPermission = true; scanClient.settings = new ScanSettings.Builder() .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) .setLegacy(false) .build(); AppScanStats appScanStats = mock(AppScanStats.class); IScannerCallback callback = mock(IScannerCallback.class); mApp.callback = callback; mApp.appScanStats = appScanStats; Set<ScanClient> scanClientSet = Collections.singleton(scanClient); doReturn(address).when(mAdapterService).getIdentityAddress(anyString()); doReturn(scanClientSet).when(mScanManager).getRegularScanQueue(); doReturn(mApp).when(mScannerMap).getById(scanClient.scannerId); doReturn(appScanStats).when(mScannerMap).getAppScanStatsById(scanClient.scannerId); // Simulate remote client crash doThrow(new RemoteException()).when(callback).onScanResult(any()); mService.onScanResult( eventType, addressType, address, primaryPhy, secondPhy, advertisingSid, txPower, rssi, periodicAdvInt, advData, address); assertThat(scanClient.appDied).isTrue(); verify(appScanStats).recordScanStop(scannerId); } @Test public void readCharacteristic() { int clientIf = 1; Loading