From: Seungkeun Lee Date: Tue, 16 Jun 2020 01:23:45 +0000 (+0900) Subject: [NFC] Fix Native callback GC issue (#1675) X-Git-Tag: submit/tizen_5.5/20200617.005147~1^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=15bc42d91c4e7fdec0d68abce05a5ad5a724b746;p=platform%2Fcore%2Fcsapi%2Ftizenfx.git [NFC] Fix Native callback GC issue (#1675) Co-authored-by: WonYoung Choi --- diff --git a/src/Tizen.Network.Nfc/Tizen.Network.Nfc/NfcTag.cs b/src/Tizen.Network.Nfc/Tizen.Network.Nfc/NfcTag.cs old mode 100755 new mode 100644 index def9c3753..8e7c8c638 --- a/src/Tizen.Network.Nfc/Tizen.Network.Nfc/NfcTag.cs +++ b/src/Tizen.Network.Nfc/Tizen.Network.Nfc/NfcTag.cs @@ -29,6 +29,26 @@ namespace Tizen.Network.Nfc { private bool disposed = false; private IntPtr _tagHandle = IntPtr.Zero; + int _requestId = 0; + + Dictionary> _transceiveTaskSource = new Dictionary>(); + Interop.Nfc.TagTransceiveCompletedCallback _nativeTransceiveCallback; + + Dictionary> _voidTaskSource = new Dictionary>(); + Interop.Nfc.VoidCallback _nativeVoidCallback; + + Dictionary> _readNdefTaskSource = new Dictionary>(); + Interop.Nfc.TagReadCompletedCallback _nativeTagReadCallback; + + /// + /// Constructor of NfcTag + /// + public NfcTag() + { + _nativeTransceiveCallback = TransceiveCompletedCallback; + _nativeVoidCallback = VoidCallback; + _nativeTagReadCallback = ReadNdefCallback; + } /// /// The type of the NFC tag. @@ -186,27 +206,21 @@ namespace Tizen.Network.Nfc /// Thrown when the the method fails due to an invalid operation. public Task TransceiveAsync(byte[] buffer) { + int requestId = 0; var task = new TaskCompletionSource(); - - byte[] resultBuffer = null; - Interop.Nfc.TagTransceiveCompletedCallback callback = (int result, IntPtr resultData, int dataSize, IntPtr userData) => + lock (this) { - if (result == (int)NfcError.None) - { - resultBuffer = new byte[dataSize]; - Marshal.Copy(resultData, resultBuffer, 0, dataSize); - task.SetResult(resultBuffer); - } - return; - }; + requestId = _requestId++; + _transceiveTaskSource[requestId] = task; + } - int ret = Interop.Nfc.Tag.Transceive(_tagHandle, buffer, buffer.Length, callback, IntPtr.Zero); + int ret = Interop.Nfc.Tag.Transceive(_tagHandle, buffer, buffer.Length, _nativeTransceiveCallback, (IntPtr)requestId); if (ret != (int)NfcError.None) { Log.Error(Globals.LogTag, "Failed to transceive data, Error - " + (NfcError)ret); + _transceiveTaskSource.Remove(requestId); NfcErrorFactory.ThrowNfcException(ret); } - return task.Task; } @@ -219,28 +233,22 @@ namespace Tizen.Network.Nfc /// Thrown when the method fails due to an invalid operation. public Task ReadNdefMessageAsync() { + int requestId = 0; var task = new TaskCompletionSource(); - NfcNdefMessage ndefMsg = null; - Interop.Nfc.TagReadCompletedCallback callback = (int result, IntPtr ndefMessage, IntPtr userData) => + lock (this) { - if (result == (int)NfcError.None) - { - ndefMsg = new NfcNdefMessage(ndefMessage); - task.SetResult(ndefMsg); - - return true; - } - return false; - }; + requestId = _requestId++; + _readNdefTaskSource[requestId] = task; + } - int ret = Interop.Nfc.Tag.ReadNdef(_tagHandle, callback, IntPtr.Zero); + int ret = Interop.Nfc.Tag.ReadNdef(_tagHandle, _nativeTagReadCallback, (IntPtr)requestId); if (ret != (int)NfcError.None) { Log.Error(Globals.LogTag, "Failed to read ndef message, Error - " + (NfcError)ret); + _readNdefTaskSource.Remove(requestId); NfcErrorFactory.ThrowNfcException(ret); } - return task.Task; } @@ -255,18 +263,21 @@ namespace Tizen.Network.Nfc /// Thrown when the method fails due to an invalid operation. public Task WriteNdefMessageAsync(NfcNdefMessage ndefMessage) { + int requestId = 0; var task = new TaskCompletionSource(); - Interop.Nfc.VoidCallback callback = (int result, IntPtr userData) => + lock (this) { - task.SetResult((NfcError)result); - return; - }; + requestId = _requestId++; + _voidTaskSource[requestId] = task; + } + + int ret = Interop.Nfc.Tag.WriteNdef(_tagHandle, ndefMessage.GetHandle(), _nativeVoidCallback, (IntPtr)requestId); - int ret = Interop.Nfc.Tag.WriteNdef(_tagHandle, ndefMessage.GetHandle(), callback, IntPtr.Zero); if (ret != (int)NfcError.None) { Log.Error(Globals.LogTag, "Failed to write ndef message, Error - " + (NfcError)ret); + _voidTaskSource.Remove(requestId); NfcErrorFactory.ThrowNfcException(ret); } @@ -284,22 +295,67 @@ namespace Tizen.Network.Nfc /// Thrown when the method fails due to an invalid operation. public Task FormatNdefMessageAsync(byte[] keyValue) { + int requestId = 0; var task = new TaskCompletionSource(); - Interop.Nfc.VoidCallback callback = (int result, IntPtr userData) => + lock (this) { - task.SetResult((NfcError)result); - return; - }; + requestId = _requestId++; + _voidTaskSource[requestId] = task; + } - int ret = Interop.Nfc.Tag.FormatNdef(_tagHandle, keyValue, keyValue.Length, callback, IntPtr.Zero); + int ret = Interop.Nfc.Tag.FormatNdef(_tagHandle, keyValue, keyValue.Length, _nativeVoidCallback, (IntPtr)requestId); if (ret != (int)NfcError.None) { Log.Error(Globals.LogTag, "Failed to format ndef message, Error - " + (NfcError)ret); + _voidTaskSource.Remove(requestId); NfcErrorFactory.ThrowNfcException(ret); } return task.Task; } + + void TransceiveCompletedCallback(int result, IntPtr resultData, int dataSize, IntPtr userData) + { + int requestId = (int)userData; + if (_transceiveTaskSource.ContainsKey(requestId)) + { + if (result == (int)NfcError.None) + { + byte[] resultBuffer = new byte[dataSize]; + Marshal.Copy(resultData, resultBuffer, 0, dataSize); + _transceiveTaskSource[requestId].TrySetResult(resultBuffer); + } + _transceiveTaskSource.Remove(requestId); + } + return; + } + + void VoidCallback(int result, IntPtr userData) + { + int requestId = (int)userData; + if (_voidTaskSource.ContainsKey(requestId)) + { + _voidTaskSource[requestId].TrySetResult((NfcError)result); + _voidTaskSource.Remove(requestId); + } + } + + bool ReadNdefCallback(int result, IntPtr ndefMessage, IntPtr userData) + { + bool ret = false; + int requestId = (int)userData; + if (_readNdefTaskSource.ContainsKey(requestId)) + { + if (result == (int)NfcError.None) + { + var ndefMsg = new NfcNdefMessage(ndefMessage); + _readNdefTaskSource[requestId].TrySetResult(ndefMsg); + ret = true; + } + _readNdefTaskSource.Remove(requestId); + } + return ret; + } } }