[Bluetooth][Non-ACR] Fix Native callback GC issue (#1678) (#1699)
authorwootak <wootak.jung@samsung.com>
Fri, 12 Jun 2020 02:37:18 +0000 (11:37 +0900)
committerGitHub <noreply@github.com>
Fri, 12 Jun 2020 02:37:18 +0000 (11:37 +0900)
Signed-off-by: Wootak Jung <wootak.jung@samsung.com>
src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothEventArgs.cs
src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothGatt.cs
src/Tizen.Network.Bluetooth/Tizen.Network.Bluetooth/BluetoothGattImpl.cs

index ebfa544..114de7b 100644 (file)
@@ -1256,7 +1256,7 @@ namespace Tizen.Network.Bluetooth
         /// The GATT server instance.
         /// </summary>
         /// <since_tizen> 3 </since_tizen>
-        public BluetoothGattServer Server { get; }
+        public BluetoothGattServer Server { get; internal set; }
         /// <summary>
         /// The client address.
         /// </summary>
index e4a10a2..1385dd1 100644 (file)
@@ -34,23 +34,18 @@ namespace Tizen.Network.Bluetooth
         private BluetoothGattServer()
         {
             _impl = new BluetoothGattServerImpl();
+            _impl._notificationSent += (s, e) =>
+            {
+                e.Server = this;
+                NotificationSent?.Invoke(this, e);
+            };
         }
 
         /// <summary>
         /// (event) This event is called when the indication acknowledgement is received for each notified client.
         /// </summary>
         /// <since_tizen> 3 </since_tizen>
-        public event EventHandler<NotificationSentEventArg> NotificationSent
-        {
-            add
-            {
-                _impl._notificationSent += value;
-            }
-            remove
-            {
-                _impl._notificationSent -= value;
-            }
-        }
+        public event EventHandler<NotificationSentEventArg> NotificationSent;
 
         /// <summary>
         /// Creates the Bluetooth GATT server.
index 652326a..291608a 100644 (file)
@@ -27,9 +27,14 @@ namespace Tizen.Network.Bluetooth
     {
         private BluetoothGattServerHandle _handle;
         internal event EventHandler<NotificationSentEventArg> _notificationSent;
+        int _requestId = 0;
+        Dictionary<int, TaskCompletionSource<bool>> _sendIndicationTaskSource = new Dictionary<int, TaskCompletionSource<bool>>();
+        Interop.Bluetooth.BtGattServerNotificationSentCallback _sendIndicationCallback;
 
         internal BluetoothGattServerImpl()
         {
+            _sendIndicationCallback = SendIndicationCallback;
+
             int err = Interop.Bluetooth.BtGattServerInitialize();
             GattUtil.ThrowForError(err, "Failed to initialize server");
 
@@ -113,22 +118,44 @@ namespace Tizen.Network.Bluetooth
             GattUtil.ThrowForError(err, string.Format("Failed to send value changed notification for characteristic uuid {0}", characteristic.Uuid));
         }
 
-        internal Task<bool> SendIndicationAsync(BluetoothGattServer server, BluetoothGattCharacteristic characteristic, string clientAddress)
+        void SendIndicationCallback(int result, string clientAddress, IntPtr serverHandle, IntPtr characteristicHandle, bool completed, IntPtr userData)
         {
-            TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
-            Interop.Bluetooth.BtGattServerNotificationSentCallback cb = (result, address, serverHandle, characteristicHandle, completed, userData) =>
+            int requestId = (int)userData;
+            if (_sendIndicationTaskSource.ContainsKey(requestId))
             {
-                _notificationSent?.Invoke(characteristic, new NotificationSentEventArg(server, address, result, completed));
+                _notificationSent?.Invoke(this, new NotificationSentEventArg(null, clientAddress, result, completed));
                 if (completed)
                 {
-                    tcs.SetResult(true);
+                    _sendIndicationTaskSource[requestId].SetResult(true);
                 }
-            };
+                else
+                {
+                    _sendIndicationTaskSource[requestId].SetResult(false);
+                }
+                _sendIndicationTaskSource.Remove(requestId);
+            }
+        }
 
-            int err = Interop.Bluetooth.BtGattServerNotify(characteristic.GetHandle(), cb, clientAddress, IntPtr.Zero);
-            GattUtil.ThrowForError(err, string.Format("Failed to send value changed indication for characteristic uuid {0}", characteristic.Uuid));
+        internal Task<bool> SendIndicationAsync(BluetoothGattServer server, BluetoothGattCharacteristic characteristic, string clientAddress)
+        {
+            TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
+            int requestId = 0;
 
-            return tcs.Task;
+            lock (this)
+            {
+                requestId = _requestId++;
+                _sendIndicationTaskSource[requestId] = task;
+            }
+
+            int err = Interop.Bluetooth.BtGattServerNotify(characteristic.GetHandle(), _sendIndicationCallback, clientAddress, (IntPtr)requestId);
+            if (err.IsFailed())
+            {
+                GattUtil.Error(err, string.Format("Failed to send value changed indication for characteristic uuid {0}", characteristic.Uuid));
+                task.SetResult(false);
+                _sendIndicationTaskSource.Remove(requestId);
+                BluetoothErrorFactory.ThrowBluetoothException(err);
+            }
+            return task.Task;
         }
 
         internal BluetoothGattServerHandle GetHandle()
@@ -140,9 +167,17 @@ namespace Tizen.Network.Bluetooth
     internal class BluetoothGattClientImpl
     {
         private BluetoothGattClientHandle _handle;
+        int _requestId = 0;
+        Dictionary<int, TaskCompletionSource<bool>> _readValueTaskSource = new Dictionary<int, TaskCompletionSource<bool>>();
+        Interop.Bluetooth.BtGattClientRequestCompletedCallback _readValueCallback;
+        Dictionary<int, TaskCompletionSource<bool>> _writeValueTaskSource = new Dictionary<int, TaskCompletionSource<bool>>();
+        Interop.Bluetooth.BtGattClientRequestCompletedCallback _writeValueCallback;
 
         internal BluetoothGattClientImpl(string remoteAddress)
         {
+            _readValueCallback = ReadValueCallback;
+            _writeValueCallback = WriteValueCallback;
+
             if (BluetoothAdapter.IsBluetoothEnabled)
             {
                 int err = Interop.Bluetooth.BtGattClientCreate(remoteAddress, out _handle);
@@ -211,46 +246,82 @@ namespace Tizen.Network.Bluetooth
             return attribututeList;
         }
 
-        internal Task<bool> ReadValueAsyncTask(BluetoothGattAttributeHandle handle)
+        void ReadValueCallback(int result, IntPtr requestHandle, IntPtr userData)
         {
-            TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
-            Interop.Bluetooth.BtGattClientRequestCompletedCallback cb = (result, requestHandle, userData) =>
+            int requestId = (int)userData;
+            if (_readValueTaskSource.ContainsKey(requestId))
             {
                 if (result == (int)BluetoothError.None)
-                    tcs.SetResult(true);
+                {
+                    _readValueTaskSource[requestId].SetResult(true);
+                }
                 else
-                    tcs.SetResult(false);
-            };
+                {
+                    _readValueTaskSource[requestId].SetResult(false);
+                }
+            }
+            _readValueTaskSource.Remove(requestId);
+        }
+
+        internal Task<bool> ReadValueAsyncTask(BluetoothGattAttributeHandle handle)
+        {
+            TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
+            int requestId = 0;
 
-            int err = Interop.Bluetooth.BtGattClientReadValue(handle, cb, IntPtr.Zero);
+            lock (this)
+            {
+                requestId = _requestId++;
+                _readValueTaskSource[requestId] = task;
+            }
+
+            int err = Interop.Bluetooth.BtGattClientReadValue(handle, _readValueCallback, (IntPtr)requestId);
             if (err.IsFailed())
             {
                 GattUtil.Error(err, "Failed to read value from remote device");
-                tcs.SetResult(false);
+                task.SetResult(false);
+                _readValueTaskSource.Remove(requestId);
                 BluetoothErrorFactory.ThrowBluetoothException(err);
             }
-            return tcs.Task;
+            return task.Task;
         }
 
-        internal Task<bool> WriteValueAsyncTask(BluetoothGattAttributeHandle handle)
+        void WriteValueCallback(int result, IntPtr requestHandle, IntPtr userData)
         {
-            TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
-            Interop.Bluetooth.BtGattClientRequestCompletedCallback cb = (result, requestHandle, userData) =>
+            int requestId = (int)userData;
+            if (_writeValueTaskSource.ContainsKey(requestId))
             {
                 if (result == (int)BluetoothError.None)
-                    tcs.SetResult(true);
+                {
+                    _writeValueTaskSource[requestId].SetResult(true);
+                }
                 else
-                    tcs.SetResult(false);
-            };
+                {
+                    _writeValueTaskSource[requestId].SetResult(false);
+                }
+            }
+            _writeValueTaskSource.Remove(requestId);
+        }
+
+        internal Task<bool> WriteValueAsyncTask(BluetoothGattAttributeHandle handle)
+        {
+            TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
+            int requestId = 0;
+
+            lock (this)
+            {
+                requestId = _requestId++;
+                _writeValueTaskSource[requestId] = task;
+            }
 
-            int err = Interop.Bluetooth.BtGattClientWriteValue(handle, cb, IntPtr.Zero);
+            int err = Interop.Bluetooth.BtGattClientWriteValue(handle, _writeValueCallback, (IntPtr)requestId);
             if (err.IsFailed())
             {
                 GattUtil.Error(err, "Failed to write value to remote device");
-                tcs.SetResult(false);
+                task.SetResult(false);
+                _writeValueTaskSource.Remove(requestId);
                 BluetoothErrorFactory.ThrowBluetoothException(err);
             }
-            return tcs.Task;
+            return task.Task;
         }
 
         internal BluetoothGattClientHandle GetHandle()