Merge "Interop fix to not read PPCP for devices that report incompatible values." into main
diff --git a/OWNERS b/OWNERS
index f3eb92e..4df6c99 100644
--- a/OWNERS
+++ b/OWNERS
@@ -8,8 +8,8 @@
# Per-file ownership
-# Build files / test_config / presubmit / preupload
-per-file PREUPLOAD.cfg,TEST_MAPPING,*.bp,*.xml=file:/OWNERS_build
+# Build files / test_config / presubmit / preupload / linter file
+per-file PREUPLOAD.cfg,TEST_MAPPING,*.bp,*.xml,pyrightconfig.json=file:/OWNERS_build
# ChromeOS team owns Linux build files
# - build.py is used for Linux build
diff --git a/android/pandora/mmi2grpc/mmi2grpc/l2cap.py b/android/pandora/mmi2grpc/mmi2grpc/l2cap.py
index 09ef10d..09136be 100644
--- a/android/pandora/mmi2grpc/mmi2grpc/l2cap.py
+++ b/android/pandora/mmi2grpc/mmi2grpc/l2cap.py
@@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import time
import sys
from mmi2grpc._helpers import assert_description
@@ -22,15 +21,16 @@
from pandora.host_grpc import Host
from pandora.host_pb2 import PUBLIC, RANDOM, Connection
+from pandora.l2cap_grpc import L2CAP
+from pandora.l2cap_pb2 import CreditBasedChannelRequest
from pandora.security_pb2 import PairingEventAnswer
from pandora.security_grpc import Security
-from pandora_experimental.l2cap_grpc import L2CAP
-from typing import Optional
+from typing import Optional, Dict
class L2CAPProxy(ProfileProxy):
- test_status_map = {} # record test status and pass them between MMI
+ test_status_map: Dict[str, str] = {} # record test status and pass them between MMI
LE_DATA_PACKET_LARGE = "data: LE_DATA_PACKET_LARGE"
LE_DATA_PACKET1 = "data: LE_PACKET1"
connection: Optional[Connection] = None
@@ -44,6 +44,7 @@
self.connection = None
self.pairing_events = None
+ self.channel = None
def test_started(self, test: str, **kwargs):
self.rootcanal.select_pts_dongle(Dongle.CSR_RCK_PTS_DONGLE)
@@ -63,16 +64,12 @@
tests_target_to_fail = [
'L2CAP/LE/CFC/BV-01-C',
'L2CAP/LE/CFC/BV-04-C',
- 'L2CAP/LE/CFC/BV-10-C',
- 'L2CAP/LE/CFC/BV-11-C',
- 'L2CAP/LE/CFC/BV-12-C',
'L2CAP/LE/CFC/BV-14-C',
'L2CAP/LE/CFC/BV-16-C',
'L2CAP/LE/CFC/BV-18-C',
'L2CAP/LE/CFC/BV-19-C',
"L2CAP/LE/CFC/BV-21-C",
]
- tests_require_secure_connection = []
# This MMI is called twice in 'L2CAP/LE/CFC/BV-04-C'
# We are not sure whether the lower tester’s BluetoothServerSocket
@@ -97,10 +94,13 @@
if test == 'L2CAP/LE/CFC/BV-12-C':
psm = 0xF3 # default TSPX_psm_authorization_required value
- secure_connection = test in tests_require_secure_connection
-
try:
- self.l2cap.CreateLECreditBasedChannel(connection=self.connection, psm=psm, secure=secure_connection)
+ connect_response = self.l2cap.Connect(connection=self.connection,
+ le_credit_based=CreditBasedChannelRequest(spsm=psm))
+ if connect_response.HasField('channel'):
+ self.channel = connect_response.channel
+ else:
+ raise Exception(connect_response.error)
except Exception as e:
if test in tests_target_to_fail:
self.test_status_map[test] = 'OK'
@@ -117,11 +117,13 @@
"""
Place the IUT into LE connectable mode.
"""
+
self.advertise = self.host.Advertise(
legacy=True,
connectable=True,
own_address_type=PUBLIC,
)
+
# not strictly necessary, but can save time on waiting connection
tests_to_open_bluetooth_server_socket = [
"L2CAP/COS/CFC/BV-01-C",
@@ -129,31 +131,19 @@
"L2CAP/COS/CFC/BV-03-C",
"L2CAP/COS/CFC/BV-04-C",
"L2CAP/LE/CFC/BV-03-C",
- "L2CAP/LE/CFC/BV-05-C",
"L2CAP/LE/CFC/BV-06-C",
"L2CAP/LE/CFC/BV-09-C",
- "L2CAP/LE/CFC/BV-13-C",
"L2CAP/LE/CFC/BV-20-C",
"L2CAP/LE/CFC/BI-01-C",
]
- tests_require_secure_connection = [
- "L2CAP/LE/CFC/BV-13-C",
- ]
- tests_connection_target_to_failed = [
- "L2CAP/LE/CFC/BV-05-C",
- ]
if test in tests_to_open_bluetooth_server_socket:
- secure_connection = test in tests_require_secure_connection
- self.l2cap.ListenL2CAPChannel(connection=self.connection, secure=secure_connection)
- try:
- self.l2cap.AcceptL2CAPChannel(connection=self.connection)
- except Exception as e:
- if test in tests_connection_target_to_failed:
- self.test_status_map[test] = 'OK'
- print(test, 'connection targets to fail', file=sys.stderr)
- else:
- raise e
+ wait_connection_response = self.l2cap.WaitConnection(le_credit_based=CreditBasedChannelRequest(spsm=0))
+ if wait_connection_response.HasField('channel'):
+ self.channel = wait_connection_response.channel
+ else:
+ raise Exception(wait_connection_response.error)
+
return "OK"
@assert_description
@@ -171,7 +161,8 @@
# all data frames arrived
# it seemed like when the time gap between the 1st frame and 2nd frame
# larger than 100ms this problem will occur
- self.l2cap.SendData(connection=self.connection, data=bytes(self.LE_DATA_PACKET_LARGE, "utf-8"))
+ assert self.channel
+ self.l2cap.Send(channel=self.channel, data=bytes(self.LE_DATA_PACKET_LARGE, "utf-8"))
return "OK"
@match_description
@@ -198,8 +189,9 @@
Upper Tester command IUT to send at least 4 frames of LE data packets to
the PTS.
"""
- self.l2cap.SendData(
- connection=self.connection,
+ assert self.channel
+ self.l2cap.Send(
+ channel=self.channel,
data=b"this is a large data package with at least 4 frames: MMI_UPPER_TESTER_SEND_LE_DATA_PACKET_LARGE")
return "OK"
@@ -208,8 +200,9 @@
"""
IUT continue to send LE data packet(s) to the PTS.
"""
- self.l2cap.SendData(
- connection=self.connection,
+ assert self.channel
+ self.l2cap.Send(
+ channel=self.channel,
data=b"this is a large data package with at least 4 frames: MMI_UPPER_TESTER_SEND_LE_DATA_PACKET_LARGE")
return "OK"
@@ -232,7 +225,8 @@
"""
Please confirm the Upper Tester receive data
"""
- data = self.l2cap.ReceiveData(connection=self.connection)
+ assert self.channel
+ data = next(self.l2cap.Receive(channel=self.channel)).data
assert data, "data received should not be empty"
return "OK"
@@ -504,7 +498,8 @@
Description : The Implementation Under Test(IUT)
should send none segmantation LE frame of LE data to the PTS.
"""
- self.l2cap.SendData(connection=self.connection, data=bytes(self.LE_DATA_PACKET1, "utf-8"))
+ assert self.channel
+ self.l2cap.Send(channel=self.channel, data=bytes(self.LE_DATA_PACKET1, "utf-8"))
return "OK"
@assert_description
diff --git a/android/pandora/mmi2grpc/pyrightconfig.json b/android/pandora/mmi2grpc/pyrightconfig.json
deleted file mode 100644
index fab9f61..0000000
--- a/android/pandora/mmi2grpc/pyrightconfig.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "typeCheckingMode": "strict",
- "useLibraryCodeForTypes": true,
- "verboseOutput": false,
- "reportMissingTypeStubs": false,
- "reportUnknownLambdaType": false,
- "reportImportCycles": false,
- "reportPrivateUsage": false,
- "extraPaths": [
- "../../../pandora/server",
- "../../../../../../out/soong/.intermediates/external/pandora/bt-test-interfaces/python/pandora-python-gen-src/gen/",
- "../../../../../../out/soong/.intermediates/packages/modules/Bluetooth/pandora/interfaces/python/pandora_experimental-python-gen-src/gen/"
- ]
-}
diff --git a/android/pandora/server/configs/pts_bot_tests_config.json b/android/pandora/server/configs/pts_bot_tests_config.json
index 9310292..3cfbe0d2 100644
--- a/android/pandora/server/configs/pts_bot_tests_config.json
+++ b/android/pandora/server/configs/pts_bot_tests_config.json
@@ -1048,6 +1048,7 @@
"L2CAP/CMC/BV-13-C",
"L2CAP/CMC/BV-14-C",
"L2CAP/CMC/BV-15-C",
+ "L2CAP/COS/CED/BI-02-C",
"L2CAP/COS/CED/BV-10-C",
"L2CAP/COS/CED/BV-12-C",
"L2CAP/COS/CED/BV-13-C",
diff --git a/android/pandora/server/src/L2cap.kt b/android/pandora/server/src/L2cap.kt
index 77b9603..1d1e9c8 100644
--- a/android/pandora/server/src/L2cap.kt
+++ b/android/pandora/server/src/L2cap.kt
@@ -16,46 +16,35 @@
package com.android.pandora
+import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothManager
-import android.bluetooth.BluetoothServerSocket
+import android.bluetooth.BluetoothSocket
import android.content.Context
import android.util.Log
+import com.google.protobuf.Any
import com.google.protobuf.ByteString
import io.grpc.stub.StreamObserver
import java.io.Closeable
-import java.io.IOException
-import java.io.InputStream
-import java.io.OutputStream
+import java.util.concurrent.atomic.AtomicLong
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
-import kotlinx.coroutines.withContext
-import pandora.HostProto.Connection
-import pandora.L2CAPGrpc.L2CAPImplBase
-import pandora.L2capProto.AcceptL2CAPChannelRequest
-import pandora.L2capProto.AcceptL2CAPChannelResponse
-import pandora.L2capProto.CreateLECreditBasedChannelRequest
-import pandora.L2capProto.CreateLECreditBasedChannelResponse
-import pandora.L2capProto.ListenL2CAPChannelRequest
-import pandora.L2capProto.ListenL2CAPChannelResponse
-import pandora.L2capProto.ReceiveDataRequest
-import pandora.L2capProto.ReceiveDataResponse
-import pandora.L2capProto.SendDataRequest
-import pandora.L2capProto.SendDataResponse
+import kotlinx.coroutines.flow.flow
+import pandora.l2cap.L2CAPGrpc.L2CAPImplBase
+import pandora.l2cap.L2CAPProto.*
@kotlinx.coroutines.ExperimentalCoroutinesApi
class L2cap(val context: Context) : L2CAPImplBase(), Closeable {
private val TAG = "PandoraL2cap"
private val scope: CoroutineScope
private val BLUETOOTH_SERVER_SOCKET_TIMEOUT: Int = 10000
+ private val channelIdCounter = AtomicLong(1)
private val BUFFER_SIZE = 512
private val bluetoothManager =
context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
private val bluetoothAdapter = bluetoothManager.adapter
- private var connectionInStreamMap: HashMap<Connection, InputStream> = hashMapOf()
- private var connectionOutStreamMap: HashMap<Connection, OutputStream> = hashMapOf()
- private var connectionServerSocketMap: HashMap<Connection, BluetoothServerSocket> = hashMapOf()
+ private val channels: HashMap<Long, BluetoothSocket> = hashMapOf()
init {
// Init the CoroutineScope
@@ -67,127 +56,117 @@
scope.cancel()
}
- suspend fun receive(inStream: InputStream): ByteArray {
- return withContext(Dispatchers.IO) {
- val buf = ByteArray(BUFFER_SIZE)
- inStream.read(buf, 0, BUFFER_SIZE) // blocking
- Log.i(TAG, "receive: $buf")
- buf
- }
- }
-
- /** Open a BluetoothServerSocket to accept connections */
- override fun listenL2CAPChannel(
- request: ListenL2CAPChannelRequest,
- responseObserver: StreamObserver<ListenL2CAPChannelResponse>,
+ override fun connect(
+ request: ConnectRequest,
+ responseObserver: StreamObserver<ConnectResponse>,
) {
grpcUnary(scope, responseObserver) {
- Log.i(TAG, "listenL2CAPChannel: secure=${request.secure}")
- val connection = request.connection
- val bluetoothServerSocket =
- if (request.secure) {
- bluetoothAdapter.listenUsingL2capChannel()
- } else {
- bluetoothAdapter.listenUsingInsecureL2capChannel()
- }
- connectionServerSocketMap[connection] = bluetoothServerSocket
- ListenL2CAPChannelResponse.newBuilder().build()
- }
- }
-
- override fun acceptL2CAPChannel(
- request: AcceptL2CAPChannelRequest,
- responseObserver: StreamObserver<AcceptL2CAPChannelResponse>,
- ) {
- grpcUnary(scope, responseObserver) {
- Log.i(TAG, "acceptL2CAPChannel")
-
- val connection = request.connection
- val bluetoothServerSocket = connectionServerSocketMap[connection]
- try {
- val bluetoothSocket =
- bluetoothServerSocket!!.accept(BLUETOOTH_SERVER_SOCKET_TIMEOUT)
- connectionInStreamMap[connection] = bluetoothSocket.getInputStream()!!
- connectionOutStreamMap[connection] = bluetoothSocket.getOutputStream()!!
- } catch (e: IOException) {
- Log.e(TAG, "bluetoothServerSocket not accepted", e)
- throw e
- }
-
- AcceptL2CAPChannelResponse.newBuilder().build()
- }
- }
-
- /** Set device to send LE based connection request */
- override fun createLECreditBasedChannel(
- request: CreateLECreditBasedChannelRequest,
- responseObserver: StreamObserver<CreateLECreditBasedChannelResponse>,
- ) {
- // Creates a gRPC coroutine in a given coroutine scope which executes a given suspended
- // function
- // returning a gRPC response and sends it on a given gRPC stream observer.
- grpcUnary(scope, responseObserver) {
- Log.i(TAG, "createLECreditBasedChannel: secure=${request.secure}, psm=${request.psm}")
- val connection = request.connection
val device = request.connection.toBluetoothDevice(bluetoothAdapter)
- val psm = request.psm
- try {
- val bluetoothSocket =
- if (request.secure) {
- device.createL2capChannel(psm)
- } else {
- device.createInsecureL2capChannel(psm)
- }
- bluetoothSocket.connect()
- connectionInStreamMap[connection] = bluetoothSocket.getInputStream()!!
- connectionOutStreamMap[connection] = bluetoothSocket.getOutputStream()!!
- } catch (e: IOException) {
- Log.d(TAG, "bluetoothSocket not connected: $e")
- throw e
- }
-
- // Response sent to client
- CreateLECreditBasedChannelResponse.newBuilder().build()
- }
- }
-
- /** send data packet */
- override fun sendData(
- request: SendDataRequest,
- responseObserver: StreamObserver<SendDataResponse>,
- ) {
- grpcUnary(scope, responseObserver) {
- Log.i(TAG, "sendDataPacket: data=${request.data}")
- val buffer = request.data!!.toByteArray()
- val connection = request.connection
- val outputStream = connectionOutStreamMap[connection]!!
-
- withContext(Dispatchers.IO) {
- try {
- outputStream.write(buffer)
- outputStream.flush()
- } catch (e: IOException) {
- Log.e(TAG, "Exception during writing to sendDataPacket output stream", e)
+ val psm =
+ when {
+ request.hasBasic() -> request.basic.psm
+ request.hasLeCreditBased() -> request.leCreditBased.spsm
+ request.hasEnhancedCreditBased() -> request.enhancedCreditBased.spsm
+ else -> throw RuntimeException("unreachable")
}
- }
+ Log.i(TAG, "connect: $device psm: $psm")
- // Response sent to client
- SendDataResponse.newBuilder().build()
+ val bluetoothSocket = device.createInsecureL2capChannel(psm)
+ bluetoothSocket.connect()
+ val channelId = getNewChannelId()
+ channels.put(channelId, bluetoothSocket)
+
+ Log.d(TAG, "connect: channelId=$channelId")
+ ConnectResponse.newBuilder().setChannel(craftChannel(channelId)).build()
}
}
- override fun receiveData(
- request: ReceiveDataRequest,
- responseObserver: StreamObserver<ReceiveDataResponse>,
+ override fun waitConnection(
+ request: WaitConnectionRequest,
+ responseObserver: StreamObserver<WaitConnectionResponse>,
) {
grpcUnary(scope, responseObserver) {
- Log.i(TAG, "receiveData")
- val connection = request.connection
- val inputStream = connectionInStreamMap[connection]!!
- val buf = receive(inputStream)
+ val device: BluetoothDevice? =
+ try {
+ request.connection.toBluetoothDevice(bluetoothAdapter)
+ } catch (e: Exception) {
+ Log.w(TAG, e)
+ null
+ }
- ReceiveDataResponse.newBuilder().setData(ByteString.copyFrom(buf)).build()
+ Log.i(TAG, "waitConnection: $device")
+
+ val psm =
+ when {
+ request.hasBasic() -> request.basic.psm
+ request.hasLeCreditBased() -> request.leCreditBased.spsm
+ request.hasEnhancedCreditBased() -> request.enhancedCreditBased.spsm
+ else -> throw RuntimeException("unreachable")
+ }
+
+ var bluetoothSocket: BluetoothSocket?
+
+ while (true) {
+ val bluetoothServerSocket =
+ if (psm == 0) {
+ bluetoothAdapter.listenUsingInsecureL2capChannel()
+ } else {
+ bluetoothAdapter.listenUsingInsecureL2capOn(psm)
+ }
+ bluetoothSocket = bluetoothServerSocket.accept()
+ bluetoothServerSocket.close()
+ if (device != null && !bluetoothSocket.getRemoteDevice().equals(device)) continue
+ break
+ }
+
+ val channelId = getNewChannelId()
+ channels.put(channelId, bluetoothSocket!!)
+
+ Log.d(TAG, "waitConnection: channelId=$channelId")
+ WaitConnectionResponse.newBuilder().setChannel(craftChannel(channelId)).build()
}
}
+
+ override fun send(request: SendRequest, responseObserver: StreamObserver<SendResponse>) {
+ grpcUnary(scope, responseObserver) {
+ Log.i(TAG, "send")
+ val bluetoothSocket = request.channel.toBluetoothSocket(channels)
+ val outputStream = bluetoothSocket.outputStream
+
+ outputStream.write(request.data.toByteArray())
+ outputStream.flush()
+
+ SendResponse.newBuilder().build()
+ }
+ }
+
+ override fun receive(
+ request: ReceiveRequest,
+ responseObserver: StreamObserver<ReceiveResponse>,
+ ) {
+ Log.i(TAG, "receive")
+ val bluetoothSocket = request.channel.toBluetoothSocket(channels)
+ val inputStream = bluetoothSocket.inputStream
+ grpcServerStream(scope, responseObserver) {
+ flow {
+ val buffer = ByteArray(BUFFER_SIZE)
+ inputStream.read(buffer, 0, BUFFER_SIZE)
+ val data = ByteString.copyFrom(buffer)
+ val response = ReceiveResponse.newBuilder().setData(data).build()
+ emit(response)
+ }
+ }
+ }
+
+ fun getNewChannelId(): Long = channelIdCounter.getAndIncrement()
+
+ fun craftChannel(id: Long): Channel {
+ val cookie = Any.newBuilder().setValue(ByteString.copyFromUtf8(id.toString())).build()
+ val channel = Channel.newBuilder().setCookie(cookie).build()
+ return channel
+ }
+
+ fun Channel.toBluetoothSocket(channels: HashMap<Long, BluetoothSocket>): BluetoothSocket =
+ channels.get(this.cookie.value.toStringUtf8().toLong())!!
}
diff --git a/android/pandora/test/pyrightconfig.json b/android/pandora/test/pyrightconfig.json
deleted file mode 100644
index ea458b5c6..0000000
--- a/android/pandora/test/pyrightconfig.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "typeCheckingMode": "strict",
- "useLibraryCodeForTypes": true,
- "verboseOutput": false,
- "reportMissingTypeStubs": false,
- "reportUnknownLambdaType": false,
- "reportImportCycles": false,
- "reportPrivateUsage": false,
- "extraPaths": [
- "../../../pandora/server",
- "../../../../../../external/pandora/avatar",
- "../../../../../../external/python/bumble",
- "../../../../../../external/python/mobly",
- "../../../../../../external/python/pyee",
- "../../../../../../external/python/portpicker/src",
- "../../../../../../out/soong/.intermediates/external/pandora/bt-test-interfaces/python/pandora-python-gen-src/gen/",
- "../../../../../../out/soong/.intermediates/packages/modules/Bluetooth/pandora/interfaces/python/pandora_experimental-python-gen-src/gen/"
- ]
-}
\ No newline at end of file
diff --git a/pandora/interfaces/pandora_experimental/l2cap.proto b/pandora/interfaces/pandora_experimental/l2cap.proto
deleted file mode 100644
index 443010a..0000000
--- a/pandora/interfaces/pandora_experimental/l2cap.proto
+++ /dev/null
@@ -1,62 +0,0 @@
-syntax = "proto3";
-
-package pandora;
-
-option java_outer_classname = "L2capProto";
-
-import "google/protobuf/empty.proto";
-import "pandora/host.proto";
-
-service L2CAP {
- // Create a L2CAP connection to a peer.
- rpc CreateLECreditBasedChannel(CreateLECreditBasedChannelRequest) returns (CreateLECreditBasedChannelResponse);
- // Send some data
- rpc SendData(SendDataRequest) returns (SendDataResponse);
- // Receive data
- rpc ReceiveData(ReceiveDataRequest) returns (ReceiveDataResponse);
- // Listen L2CAP channel for connection
- rpc ListenL2CAPChannel(ListenL2CAPChannelRequest) returns (ListenL2CAPChannelResponse);
- // Accept L2CAP connection
- rpc AcceptL2CAPChannel(AcceptL2CAPChannelRequest) returns (AcceptL2CAPChannelResponse);
-}
-
-// Request for the `OpenSource` method.
-message CreateLECreditBasedChannelRequest {
- // The connection that will open the stream.
- Connection connection = 1;
- int32 psm = 2;
- bool secure = 3;
-}
-
-// Request for the `OpenSource` method.
-message CreateLECreditBasedChannelResponse {}
-
-message SendDataRequest {
- // The connection that will open the stream.
- Connection connection = 1;
- bytes data = 2;
-}
-
-message SendDataResponse {}
-
-message ReceiveDataRequest {
- // The connection that will open the stream.
- Connection connection = 1;
-}
-
-message ReceiveDataResponse {
- bytes data = 1;
-}
-
-message ListenL2CAPChannelRequest{
- Connection connection = 1;
- bool secure = 2;
-}
-
-message ListenL2CAPChannelResponse {}
-
-message AcceptL2CAPChannelRequest{
- Connection connection = 1;
-}
-
-message AcceptL2CAPChannelResponse {}
\ No newline at end of file
diff --git a/pandora/interfaces/python/Android.bp b/pandora/interfaces/python/Android.bp
index 4532716..2abac30 100644
--- a/pandora/interfaces/python/Android.bp
+++ b/pandora/interfaces/python/Android.bp
@@ -54,10 +54,6 @@
"pandora_experimental/hid_grpc_aio.py",
"pandora_experimental/hid_pb2.py",
"pandora_experimental/hid_pb2.pyi",
- "pandora_experimental/l2cap_grpc.py",
- "pandora_experimental/l2cap_grpc_aio.py",
- "pandora_experimental/l2cap_pb2.py",
- "pandora_experimental/l2cap_pb2.pyi",
"pandora_experimental/le_audio_grpc.py",
"pandora_experimental/le_audio_grpc_aio.py",
"pandora_experimental/le_audio_pb2.py",
@@ -118,7 +114,6 @@
":pandora_experimental-python-gen-src{pandora_experimental/hap_pb2.pyi}",
":pandora_experimental-python-gen-src{pandora_experimental/hfp_pb2.pyi}",
":pandora_experimental-python-gen-src{pandora_experimental/hid_pb2.pyi}",
- ":pandora_experimental-python-gen-src{pandora_experimental/l2cap_pb2.pyi}",
":pandora_experimental-python-gen-src{pandora_experimental/le_audio_pb2.pyi}",
":pandora_experimental-python-gen-src{pandora_experimental/map_pb2.pyi}",
":pandora_experimental-python-gen-src{pandora_experimental/mediaplayer_pb2.pyi}",
diff --git a/pyrightconfig.json b/pyrightconfig.json
new file mode 100644
index 0000000..e2b62af
--- /dev/null
+++ b/pyrightconfig.json
@@ -0,0 +1,34 @@
+{
+ "typeCheckingMode": "strict",
+ "useLibraryCodeForTypes": true,
+ "verboseOutput": false,
+ "reportMissingTypeStubs": false,
+ "reportUnknownLambdaType": false,
+ "reportImportCycles": false,
+ "reportPrivateUsage": false,
+ "executionEnvironments": [
+ {
+ "root": "android/pandora/test",
+ "extraPaths": ["pandora/server"]
+ },
+ {
+ "root": "android/pandora/mmi2grpc"
+ },
+ {
+ "root": "pandora/server/bumble_experimental"
+ },
+ {
+ "root": "framework/tests/bumble/src/bumble_server.py",
+ "extraPaths": ["pandora/server"]
+ }
+ ],
+ "extraPaths": [
+ "../../../external/pandora/avatar",
+ "../../../external/python/bumble",
+ "../../../external/python/mobly",
+ "../../../external/python/pyee",
+ "../../../external/python/portpicker/src",
+ "../../../out/soong/.intermediates/external/pandora/bt-test-interfaces/python/pandora-python-gen-src/gen/",
+ "../../../out/soong/.intermediates/packages/modules/Bluetooth/pandora/interfaces/python/pandora_experimental-python-gen-src/gen/"
+ ]
+}
diff --git a/system/bta/gatt/bta_gattc_act.cc b/system/bta/gatt/bta_gattc_act.cc
index 636951c..95eb0a7 100644
--- a/system/bta/gatt/bta_gattc_act.cc
+++ b/system/bta/gatt/bta_gattc_act.cc
@@ -297,7 +297,7 @@
/* close all CLCB related to this app */
if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) {
for (auto& p_clcb : bta_gattc_cb.clcb_set) {
- if (p_clcb->p_rcb != p_clreg) {
+ if (!p_clcb->in_use || p_clcb->p_rcb != p_clreg) {
continue;
}
p_clreg->dereg_pending = true;
@@ -1504,7 +1504,8 @@
tBTA_GATTC_CLCB* p_clcb = &bta_gattc_cb.clcb[0];
if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) {
for (auto& p_clcb_i : bta_gattc_cb.clcb_set) {
- if (p_clcb_i->p_srcb == p_srvc_cb) {
+ if (p_clcb_i->in_use && p_clcb_i->p_srcb == p_srvc_cb) {
+ p_clcb = p_clcb_i.get();
found = true;
break;
}
@@ -1576,7 +1577,7 @@
if (p_clcb == NULL || (p_clcb && p_clcb->p_q_cmd != NULL)) {
if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) {
for (auto& p_clcb_i : bta_gattc_cb.clcb_set) {
- if (p_clcb_i->p_srcb == p_srcb && p_clcb_i->p_q_cmd == NULL) {
+ if (p_clcb_i->in_use && p_clcb_i->p_srcb == p_srcb && p_clcb_i->p_q_cmd == NULL) {
p_clcb = p_clcb_i.get();
break;
}
diff --git a/system/bta/gatt/bta_gattc_utils.cc b/system/bta/gatt/bta_gattc_utils.cc
index 36e05ba..ca911de 100644
--- a/system/bta/gatt/bta_gattc_utils.cc
+++ b/system/bta/gatt/bta_gattc_utils.cc
@@ -145,7 +145,7 @@
tBTA_GATTC_CLCB* bta_gattc_find_clcb_by_conn_id(tCONN_ID conn_id) {
if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) {
for (auto& p_clcb : bta_gattc_cb.clcb_set) {
- if (p_clcb->bta_conn_id == conn_id) {
+ if (p_clcb->in_use && p_clcb->bta_conn_id == conn_id) {
return p_clcb.get();
}
}
@@ -960,6 +960,9 @@
if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) {
stream << " ->clcb (dynamic)\n";
for (auto& p_clcb : bta_gattc_cb.clcb_set) {
+ if (!p_clcb->in_use) {
+ continue;
+ }
entry_count++;
stream << " conn_id: " << loghex(p_clcb->bta_conn_id)
<< " address: " << ADDRESS_TO_LOGGABLE_STR(p_clcb->bda)
diff --git a/system/btif/include/btif_sock_l2cap.h b/system/btif/include/btif_sock_l2cap.h
index d527ed8..c08ef53 100644
--- a/system/btif/include/btif_sock_l2cap.h
+++ b/system/btif/include/btif_sock_l2cap.h
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
/*******************************************************************************
* L2CAP Socket Interface
******************************************************************************/
diff --git a/system/btif/src/btif_sock.cc b/system/btif/src/btif_sock.cc
index 95f2789..04b43dd 100644
--- a/system/btif/src/btif_sock.cc
+++ b/system/btif/src/btif_sock.cc
@@ -114,7 +114,7 @@
return BT_STATUS_SUCCESS;
-error:;
+error:
thread_free(thread);
thread = NULL;
if (thread_handle != -1) {