diff --git a/packages/tizen_rpc_port/CHANGELOG.md b/packages/tizen_rpc_port/CHANGELOG.md index 4c94f3df9..bcdd57233 100644 --- a/packages/tizen_rpc_port/CHANGELOG.md +++ b/packages/tizen_rpc_port/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.1.7 + +* Guard Tizen 10.0+ specific Parcel APIs (`reader`, `dataSize`, and `reserve`) to throw `UnsupportedError` on unsupported versions of Tizen instead of crashing. +* Add integration test cases for the guarded Tizen 10.0+ specific Parcel APIs. +* Update README to mention system requirements for these APIs. + ## 0.1.6 * Read byte values as unsigned (0-255) so `Parcel.readByte` is consistent diff --git a/packages/tizen_rpc_port/README.md b/packages/tizen_rpc_port/README.md index 072e656ed..0ab555006 100644 --- a/packages/tizen_rpc_port/README.md +++ b/packages/tizen_rpc_port/README.md @@ -47,3 +47,6 @@ The following privileges may be added to the client app's `tizen-manifest.xml` f ## Supported devices This plugin is supported on Tizen devices running Tizen 6.5 or above. + +> **Note** +> Some `Parcel` APIs (`reader`, `dataSize`, and `reserve`) are supported only on Tizen 10.0 or above. Calling these APIs on unsupported versions of Tizen will throw an `UnsupportedError`. diff --git a/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart b/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart index 4e1f00661..80564563c 100644 --- a/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart +++ b/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart @@ -283,4 +283,39 @@ void main() { expect(proxy.portName, 'TestPort'); }); }); + + // --------------------------------------------------------------------------- + // Tizen 10.0+ Parcel APIs (reader, dataSize, reserve) with safety guards + // --------------------------------------------------------------------------- + + group('Tizen 10.0+ Parcel APIs', () { + testWidgets('reader getter/setter', (WidgetTester _) async { + final Parcel parcel = Parcel(); + try { + parcel.reader = 10; + expect(parcel.reader, 10); + } on UnsupportedError catch (e) { + expect(e.message, contains('not supported on this version of Tizen')); + } + }); + + testWidgets('dataSize getter/setter', (WidgetTester _) async { + final Parcel parcel = Parcel(); + try { + parcel.dataSize = 20; + expect(parcel.dataSize, 20); + } on UnsupportedError catch (e) { + expect(e.message, contains('not supported on this version of Tizen')); + } + }); + + testWidgets('reserve', (WidgetTester _) async { + final Parcel parcel = Parcel(); + try { + parcel.reserve(100); + } on UnsupportedError catch (e) { + expect(e.message, contains('not supported on this version of Tizen')); + } + }); + }); } diff --git a/packages/tizen_rpc_port/lib/src/parcel.dart b/packages/tizen_rpc_port/lib/src/parcel.dart index 2ec3c61d2..7c73cf864 100644 --- a/packages/tizen_rpc_port/lib/src/parcel.dart +++ b/packages/tizen_rpc_port/lib/src/parcel.dart @@ -484,4 +484,179 @@ class Parcel { return ParcelHeader._fromHandle(pHeader.value); }); } + + /// Gets the reader position of this parcel. + int get reader { + _ensureFunctionsLoaded(); + final int Function(rpc_port_parcel_h, Pointer)? func = + _rpcPortParcelGetReader; + if (func == null) { + throw UnsupportedError( + 'The reader property is not supported on this version of Tizen.', + ); + } + return using((Arena arena) { + final Pointer pValue = arena(); + final int ret = func(_handle, pValue); + if (ret != 0) { + throw PlatformException( + code: ret.toString(), + message: tizen.get_error_message(ret).toDartString(), + ); + } + return pValue.value; + }); + } + + /// Sets the reader position of this parcel. + set reader(int value) { + RangeError.checkNotNegative(value, 'value'); + _ensureFunctionsLoaded(); + final int Function(rpc_port_parcel_h, int)? func = _rpcPortParcelSetReader; + if (func == null) { + throw UnsupportedError( + 'The reader property is not supported on this version of Tizen.', + ); + } + final int ret = func(_handle, value); + if (ret != 0) { + throw PlatformException( + code: ret.toString(), + message: tizen.get_error_message(ret).toDartString(), + ); + } + } + + /// Gets the data size of this parcel. + int get dataSize { + _ensureFunctionsLoaded(); + final int Function(rpc_port_parcel_h, Pointer)? func = + _rpcPortParcelGetDataSize; + if (func == null) { + throw UnsupportedError( + 'The dataSize property is not supported on this version of Tizen.', + ); + } + return using((Arena arena) { + final Pointer pValue = arena(); + final int ret = func(_handle, pValue); + if (ret != 0) { + throw PlatformException( + code: ret.toString(), + message: tizen.get_error_message(ret).toDartString(), + ); + } + return pValue.value; + }); + } + + /// Sets the data size of this parcel. + set dataSize(int value) { + RangeError.checkNotNegative(value, 'value'); + _ensureFunctionsLoaded(); + final int Function(rpc_port_parcel_h, int)? func = + _rpcPortParcelSetDataSize; + if (func == null) { + throw UnsupportedError( + 'The dataSize property is not supported on this version of Tizen.', + ); + } + final int ret = func(_handle, value); + if (ret != 0) { + throw PlatformException( + code: ret.toString(), + message: tizen.get_error_message(ret).toDartString(), + ); + } + } + + /// Reserves the capacity of this parcel. + void reserve(int size) { + RangeError.checkNotNegative(size, 'size'); + _ensureFunctionsLoaded(); + final int Function(rpc_port_parcel_h, int)? func = _rpcPortParcelReserve; + if (func == null) { + throw UnsupportedError( + 'The reserve method is not supported on this version of Tizen.', + ); + } + final int ret = func(_handle, size); + if (ret != 0) { + throw PlatformException( + code: ret.toString(), + message: tizen.get_error_message(ret).toDartString(), + ); + } + } +} + +DynamicLibrary? _libRpcPort; +bool _libRpcPortLoaded = false; + +DynamicLibrary? _getLibRpcPort() { + if (!_libRpcPortLoaded) { + try { + _libRpcPort = DynamicLibrary.open('librpc-port.so.1'); + } catch (_) { + _libRpcPort = null; + } + _libRpcPortLoaded = true; + } + return _libRpcPort; +} + +int Function(rpc_port_parcel_h, Pointer)? _rpcPortParcelGetReader; +int Function(rpc_port_parcel_h, int)? _rpcPortParcelSetReader; +int Function(rpc_port_parcel_h, Pointer)? _rpcPortParcelGetDataSize; +int Function(rpc_port_parcel_h, int)? _rpcPortParcelSetDataSize; +int Function(rpc_port_parcel_h, int)? _rpcPortParcelReserve; + +bool _functionsLoaded = false; + +void _ensureFunctionsLoaded() { + if (_functionsLoaded) { + return; + } + _functionsLoaded = true; + final DynamicLibrary? lib = _getLibRpcPort(); + if (lib == null) { + return; + } + try { + _rpcPortParcelGetReader = lib + .lookup< + NativeFunction)>>( + 'rpc_port_parcel_get_reader', + ) + .asFunction(); + } catch (_) {} + try { + _rpcPortParcelSetReader = lib + .lookup>( + 'rpc_port_parcel_set_reader', + ) + .asFunction(); + } catch (_) {} + try { + _rpcPortParcelGetDataSize = lib + .lookup< + NativeFunction)>>( + 'rpc_port_parcel_get_data_size', + ) + .asFunction(); + } catch (_) {} + try { + _rpcPortParcelSetDataSize = lib + .lookup>( + 'rpc_port_parcel_set_data_size', + ) + .asFunction(); + } catch (_) {} + try { + _rpcPortParcelReserve = lib + .lookup>( + 'rpc_port_parcel_reserve', + ) + .asFunction(); + } catch (_) {} } diff --git a/packages/tizen_rpc_port/pubspec.yaml b/packages/tizen_rpc_port/pubspec.yaml index 3d2e9905d..f5f031d8f 100644 --- a/packages/tizen_rpc_port/pubspec.yaml +++ b/packages/tizen_rpc_port/pubspec.yaml @@ -2,7 +2,7 @@ name: tizen_rpc_port description: Tizen RPC Port APIs. Used to make remote procedure calls between Tizen apps. homepage: https://github.com/flutter-tizen/plugins repository: https://github.com/flutter-tizen/plugins/tree/master/packages/tizen_rpc_port -version: 0.1.6 +version: 0.1.7 environment: sdk: ">=3.1.0 <4.0.0"