diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 0fe8846415154..d377eeb28884c 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1266,11 +1266,14 @@ FILE: ../../../flutter/shell/platform/fuchsia/dart-pkg/fuchsia/lib/fuchsia.dart FILE: ../../../flutter/shell/platform/fuchsia/dart-pkg/fuchsia/sdk_ext/fuchsia.cc FILE: ../../../flutter/shell/platform/fuchsia/dart-pkg/fuchsia/sdk_ext/fuchsia.h FILE: ../../../flutter/shell/platform/fuchsia/dart-pkg/zircon/lib/src/handle.dart +FILE: ../../../flutter/shell/platform/fuchsia/dart-pkg/zircon/lib/src/handle_disposition.dart FILE: ../../../flutter/shell/platform/fuchsia/dart-pkg/zircon/lib/src/handle_waiter.dart FILE: ../../../flutter/shell/platform/fuchsia/dart-pkg/zircon/lib/src/system.dart FILE: ../../../flutter/shell/platform/fuchsia/dart-pkg/zircon/lib/zircon.dart FILE: ../../../flutter/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/handle.cc FILE: ../../../flutter/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/handle.h +FILE: ../../../flutter/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/handle_disposition.cc +FILE: ../../../flutter/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/handle_disposition.h FILE: ../../../flutter/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/handle_waiter.cc FILE: ../../../flutter/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/handle_waiter.h FILE: ../../../flutter/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/natives.cc diff --git a/shell/platform/fuchsia/dart-pkg/zircon/BUILD.gn b/shell/platform/fuchsia/dart-pkg/zircon/BUILD.gn index a89ef0784c745..252203afe43a7 100644 --- a/shell/platform/fuchsia/dart-pkg/zircon/BUILD.gn +++ b/shell/platform/fuchsia/dart-pkg/zircon/BUILD.gn @@ -14,6 +14,8 @@ source_set("zircon") { sources = [ "sdk_ext/handle.cc", "sdk_ext/handle.h", + "sdk_ext/handle_disposition.cc", + "sdk_ext/handle_disposition.h", "sdk_ext/handle_waiter.cc", "sdk_ext/handle_waiter.h", "sdk_ext/natives.cc", diff --git a/shell/platform/fuchsia/dart-pkg/zircon/lib/src/handle_disposition.dart b/shell/platform/fuchsia/dart-pkg/zircon/lib/src/handle_disposition.dart new file mode 100644 index 0000000000000..e79048acc893b --- /dev/null +++ b/shell/platform/fuchsia/dart-pkg/zircon/lib/src/handle_disposition.dart @@ -0,0 +1,29 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +part of zircon; + +// ignore_for_file: native_function_body_in_non_sdk_code +// ignore_for_file: public_member_api_docs + +@pragma('vm:entry-point') +class HandleDisposition extends NativeFieldWrapperClass2 { + @pragma('vm:entry-point') + HandleDisposition(int operation, Handle handle, int type, int rights) { + _constructor(operation, handle, type, rights); + } + + void _constructor(int operation, Handle handle, int type, int rights) + native 'HandleDisposition_constructor'; + + int get operation native 'HandleDisposition_operation'; + Handle get handle native 'HandleDisposition_handle'; + int get type native 'HandleDisposition_type'; + int get rights native 'HandleDisposition_rights'; + int get result native 'HandleDisposition_result'; + + @override + String toString() => + 'HandleDisposition(operation=$operation, handle=$handle, type=$type, rights=$rights, result=$result)'; +} diff --git a/shell/platform/fuchsia/dart-pkg/zircon/lib/src/system.dart b/shell/platform/fuchsia/dart-pkg/zircon/lib/src/system.dart index 96e891d32646a..9d555d172af5b 100644 --- a/shell/platform/fuchsia/dart-pkg/zircon/lib/src/system.dart +++ b/shell/platform/fuchsia/dart-pkg/zircon/lib/src/system.dart @@ -98,6 +98,49 @@ class ReadResult extends _Result { 'ReadResult(status=$status, bytes=$_bytes, numBytes=$_numBytes, handles=$_handles)'; } +@pragma('vm:entry-point') +class HandleInfo { + final Handle handle; + final int type; + final int rights; + + @pragma('vm:entry-point') + const HandleInfo(this.handle, this.type, this.rights); + + @override + String toString() => + 'HandleInfo(handle=$handle, type=$type, rights=$rights)'; +} + +@pragma('vm:entry-point') +class ReadEtcResult extends _Result { + final ByteData? _bytes; + final int? _numBytes; + final List? _handleInfos; + + ByteData get bytes => _bytes!; + int get numBytes => _numBytes!; + List get handleInfos => _handleInfos!; + + @pragma('vm:entry-point') + const ReadEtcResult(final int status, [this._bytes, this._numBytes, this._handleInfos]) + : super(status); + + /// Returns the bytes as a Uint8List. If status != OK this will throw + /// an exception. + Uint8List bytesAsUint8List() { + return _bytes!.buffer.asUint8List(_bytes!.offsetInBytes, _numBytes!); + } + + /// Returns the bytes as a String. If status != OK this will throw + /// an exception. + String bytesAsUTF8String() => utf8.decode(bytesAsUint8List()); + + @override + String toString() => + 'ReadEtcResult(status=$status, bytes=$_bytes, numBytes=$_numBytes, handleInfos=$_handleInfos)'; +} + @pragma('vm:entry-point') class WriteResult extends _Result { final int? _numBytes; @@ -161,8 +204,12 @@ class System extends NativeFieldWrapperClass2 { native 'System_ConnectToService'; static int channelWrite(Handle channel, ByteData data, List handles) native 'System_ChannelWrite'; + static int channelWriteEtc(Handle channel, ByteData data, List handleDispositions) + native 'System_ChannelWriteEtc'; static ReadResult channelQueryAndRead(Handle channel) native 'System_ChannelQueryAndRead'; + static ReadEtcResult channelQueryAndReadEtc(Handle channel) + native 'System_ChannelQueryAndReadEtc'; // Eventpair operations. static HandlePairResult eventpairCreate([int options = 0]) diff --git a/shell/platform/fuchsia/dart-pkg/zircon/lib/zircon.dart b/shell/platform/fuchsia/dart-pkg/zircon/lib/zircon.dart index 5e80671ffb526..04db7daf52060 100644 --- a/shell/platform/fuchsia/dart-pkg/zircon/lib/zircon.dart +++ b/shell/platform/fuchsia/dart-pkg/zircon/lib/zircon.dart @@ -9,5 +9,6 @@ import 'dart:nativewrappers'; import 'dart:typed_data'; part 'src/handle.dart'; +part 'src/handle_disposition.dart'; part 'src/handle_waiter.dart'; part 'src/system.dart'; diff --git a/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/handle_disposition.cc b/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/handle_disposition.cc new file mode 100644 index 0000000000000..c4e558fa16a15 --- /dev/null +++ b/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/handle_disposition.cc @@ -0,0 +1,60 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "handle_disposition.h" + +#include + +#include "third_party/tonic/dart_binding_macros.h" +#include "third_party/tonic/dart_class_library.h" + +using tonic::ToDart; + +namespace zircon { +namespace dart { + +IMPLEMENT_WRAPPERTYPEINFO(zircon, HandleDisposition); + +void HandleDisposition_constructor(Dart_NativeArguments args) { + DartCallConstructor(&HandleDisposition::create, args); +} + +fml::RefPtr HandleDisposition::create( + zx_handle_op_t operation, + fml::RefPtr handle, + zx_obj_type_t type, + zx_rights_t rights) { + return fml::MakeRefCounted(operation, handle, type, rights, + ZX_OK); +} + +// clang-format: off + +#define FOR_EACH_STATIC_BINDING(V) V(HandleDisposition, create) + +#define FOR_EACH_BINDING(V) \ + V(HandleDisposition, operation) \ + V(HandleDisposition, handle) \ + V(HandleDisposition, type) \ + V(HandleDisposition, rights) \ + V(HandleDisposition, result) + +// clang-format: on + +// Tonic is missing a comma. +#define DART_REGISTER_NATIVE_STATIC_(CLASS, METHOD) \ + DART_REGISTER_NATIVE_STATIC(CLASS, METHOD), + +FOR_EACH_STATIC_BINDING(DART_NATIVE_CALLBACK_STATIC) +FOR_EACH_BINDING(DART_NATIVE_NO_UI_CHECK_CALLBACK) + +void HandleDisposition::RegisterNatives(tonic::DartLibraryNatives* natives) { + natives->Register({{"HandleDisposition_constructor", + HandleDisposition_constructor, 5, true}, + FOR_EACH_STATIC_BINDING(DART_REGISTER_NATIVE_STATIC_) + FOR_EACH_BINDING(DART_REGISTER_NATIVE)}); +} + +} // namespace dart +} // namespace zircon diff --git a/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/handle_disposition.h b/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/handle_disposition.h new file mode 100644 index 0000000000000..16cc392ee08cc --- /dev/null +++ b/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/handle_disposition.h @@ -0,0 +1,71 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_FUCHSIA_DART_PKG_ZIRCON_SDK_EXT_HANDLE_DISPOSITION_H_ +#define FLUTTER_SHELL_PLATFORM_FUCHSIA_DART_PKG_ZIRCON_SDK_EXT_HANDLE_DISPOSITION_H_ + +#include + +#include + +#include "flutter/fml/memory/ref_counted.h" +#include "handle.h" +#include "third_party/dart/runtime/include/dart_api.h" +#include "third_party/tonic/dart_library_natives.h" +#include "third_party/tonic/dart_wrappable.h" + +namespace zircon { +namespace dart { +/** + * HandleDisposition is the native peer of a Dart object (HandleDisposition + * in dart:zircon) that holds a Handle and additional properties. + */ +class HandleDisposition : public fml::RefCountedThreadSafe, + public tonic::DartWrappable { + DEFINE_WRAPPERTYPEINFO(); + FML_FRIEND_REF_COUNTED_THREAD_SAFE(HandleDisposition); + FML_FRIEND_MAKE_REF_COUNTED(HandleDisposition); + + public: + static void RegisterNatives(tonic::DartLibraryNatives* natives); + + static fml::RefPtr create(zx_handle_op_t operation, + fml::RefPtr handle, + zx_obj_type_t type, + zx_rights_t rights); + + zx_handle_op_t operation() const { return operation_; } + fml::RefPtr handle() const { return handle_; } + zx_obj_type_t type() const { return type_; } + zx_rights_t rights() const { return rights_; } + zx_status_t result() const { return result_; } + void set_result(zx_status_t result) { result_ = result; } + + private: + explicit HandleDisposition(zx_handle_op_t operation, + fml::RefPtr handle, + zx_obj_type_t type, + zx_rights_t rights, + zx_status_t result) + : operation_(operation), + handle_(handle), + type_(type), + rights_(rights), + result_(result) {} + + void RetainDartWrappableReference() const override { AddRef(); } + + void ReleaseDartWrappableReference() const override { Release(); } + + zx_handle_op_t operation_; + fml::RefPtr handle_; + zx_obj_type_t type_; + zx_rights_t rights_; + zx_status_t result_; +}; + +} // namespace dart +} // namespace zircon + +#endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_DART_PKG_ZIRCON_SDK_EXT_HANDLE_DISPOSITION_H_ diff --git a/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/natives.cc b/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/natives.cc index 3c2f6d54a4bf6..1d5a2ea814f9b 100644 --- a/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/natives.cc +++ b/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/natives.cc @@ -11,6 +11,7 @@ #include #include "handle.h" +#include "handle_disposition.h" #include "handle_waiter.h" #include "system.h" #include "third_party/dart/runtime/include/dart_api.h" @@ -32,6 +33,7 @@ static tonic::DartLibraryNatives* g_natives; tonic::DartLibraryNatives* InitNatives() { tonic::DartLibraryNatives* natives = new tonic::DartLibraryNatives(); + HandleDisposition::RegisterNatives(natives); HandleWaiter::RegisterNatives(natives); Handle::RegisterNatives(natives); System::RegisterNatives(natives); diff --git a/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/system.cc b/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/system.cc index ca12bd3af5ffd..9e8475dac55c1 100644 --- a/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/system.cc +++ b/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/system.cc @@ -32,6 +32,8 @@ constexpr char kGetSizeResult[] = "GetSizeResult"; constexpr char kHandlePairResult[] = "HandlePairResult"; constexpr char kHandleResult[] = "HandleResult"; constexpr char kReadResult[] = "ReadResult"; +constexpr char kHandleInfo[] = "HandleInfo"; +constexpr char kReadEtcResult[] = "ReadEtcResult"; constexpr char kWriteResult[] = "WriteResult"; constexpr char kFromFileResult[] = "FromFileResult"; constexpr char kMapResult[] = "MapResult"; @@ -130,6 +132,29 @@ Dart_Handle ConstructDartObject(const char* class_name, Args&&... args) { return object; } +Dart_Handle MakeHandleInfoList( + const std::vector& in_handles) { + tonic::DartClassLibrary& class_library = + tonic::DartState::Current()->class_library(); + Dart_Handle handle_info_type = class_library.GetClass("zircon", kHandleInfo); + Dart_Handle empty_handle_info = ConstructDartObject( + kHandleInfo, ToDart(Handle::CreateInvalid()), ToDart(-1), ToDart(-1)); + Dart_Handle list = Dart_NewListOfTypeFilled( + handle_info_type, empty_handle_info, in_handles.size()); + if (Dart_IsError(list)) + return list; + for (size_t i = 0; i < in_handles.size(); i++) { + Dart_Handle handle = ToDart(Handle::Create(in_handles[i].handle)); + Dart_Handle result = Dart_ListSetAt( + list, i, + ConstructDartObject(kHandleInfo, handle, ToDart(in_handles[i].type), + ToDart(in_handles[i].rights))); + if (Dart_IsError(result)) + return result; + } + return list; +} + fdio_ns_t* GetNamespace() { // Grab the fdio_ns_t* out of the isolate. Dart_Handle zircon_lib = Dart_LookupLibrary(ToDart("dart:zircon")); @@ -240,6 +265,42 @@ zx_status_t System::ChannelWrite(fml::RefPtr channel, return status; } +zx_status_t System::ChannelWriteEtc( + fml::RefPtr channel, + const tonic::DartByteData& data, + std::vector handle_dispositions) { + if (!channel || !channel->is_valid()) { + data.Release(); + return ZX_ERR_BAD_HANDLE; + } + + std::vector zx_handle_dispositions; + for (HandleDisposition* handle : handle_dispositions) { + FML_DCHECK(handle->result() == ZX_OK); + zx_handle_dispositions.push_back({.operation = handle->operation(), + .handle = handle->handle()->handle(), + .type = handle->type(), + .rights = handle->rights(), + .result = ZX_OK}); + } + + zx_status_t status = zx_channel_write_etc( + channel->handle(), 0, data.data(), data.length_in_bytes(), + zx_handle_dispositions.data(), zx_handle_dispositions.size()); + + for (size_t i = 0; i < handle_dispositions.size(); ++i) { + handle_dispositions[i]->set_result(zx_handle_dispositions[i].result); + + // Handles that are not copied (i.e. moved) are always consumed. + if (handle_dispositions[i]->operation() != ZX_HANDLE_OP_DUPLICATE) { + handle_dispositions[i]->handle()->ReleaseHandle(); + } + } + + data.Release(); + return status; +} + Dart_Handle System::ChannelQueryAndRead(fml::RefPtr channel) { if (!channel || !channel->is_valid()) { return ConstructDartObject(kReadResult, ToDart(ZX_ERR_BAD_HANDLE)); @@ -280,6 +341,47 @@ Dart_Handle System::ChannelQueryAndRead(fml::RefPtr channel) { } } +Dart_Handle System::ChannelQueryAndReadEtc(fml::RefPtr channel) { + if (!channel || !channel->is_valid()) { + return ConstructDartObject(kReadEtcResult, ToDart(ZX_ERR_BAD_HANDLE)); + } + + uint32_t actual_bytes = 0; + uint32_t actual_handles = 0; + + // Query the size of the next message. + zx_status_t status = zx_channel_read(channel->handle(), 0, nullptr, nullptr, + 0, 0, &actual_bytes, &actual_handles); + if (status != ZX_ERR_BUFFER_TOO_SMALL) { + // An empty message or an error. + return ConstructDartObject(kReadEtcResult, ToDart(status)); + } + + // Allocate space for the bytes and handles. + ByteDataScope bytes(actual_bytes); + FML_DCHECK(bytes.is_valid()); + std::vector handles(actual_handles); + + // Make the call to actually get the message. + status = zx_channel_read_etc(channel->handle(), 0, bytes.data(), + handles.data(), bytes.size(), handles.size(), + &actual_bytes, &actual_handles); + FML_DCHECK(status != ZX_OK || bytes.size() == actual_bytes); + + bytes.Release(); + + if (status == ZX_OK) { + FML_DCHECK(handles.size() == actual_handles); + + // return a ReadResult object. + return ConstructDartObject(kReadEtcResult, ToDart(status), + bytes.dart_handle(), ToDart(actual_bytes), + MakeHandleInfoList(handles)); + } else { + return ConstructDartObject(kReadEtcResult, ToDart(status)); + } +} + Dart_Handle System::EventpairCreate(uint32_t options) { zx_handle_t out0 = 0, out1 = 0; zx_status_t status = zx_eventpair_create(0, &out0, &out1); @@ -465,23 +567,25 @@ uint64_t System::ClockGetMonotonic() { // clang-format: off -#define FOR_EACH_STATIC_BINDING(V) \ - V(System, ChannelCreate) \ - V(System, ChannelFromFile) \ - V(System, ChannelWrite) \ - V(System, ChannelQueryAndRead) \ - V(System, EventpairCreate) \ - V(System, ConnectToService) \ - V(System, SocketCreate) \ - V(System, SocketWrite) \ - V(System, SocketRead) \ - V(System, VmoCreate) \ - V(System, VmoFromFile) \ - V(System, VmoGetSize) \ - V(System, VmoSetSize) \ - V(System, VmoRead) \ - V(System, VmoWrite) \ - V(System, VmoMap) \ +#define FOR_EACH_STATIC_BINDING(V) \ + V(System, ChannelCreate) \ + V(System, ChannelFromFile) \ + V(System, ChannelWrite) \ + V(System, ChannelWriteEtc) \ + V(System, ChannelQueryAndRead) \ + V(System, ChannelQueryAndReadEtc) \ + V(System, EventpairCreate) \ + V(System, ConnectToService) \ + V(System, SocketCreate) \ + V(System, SocketWrite) \ + V(System, SocketRead) \ + V(System, VmoCreate) \ + V(System, VmoFromFile) \ + V(System, VmoGetSize) \ + V(System, VmoSetSize) \ + V(System, VmoRead) \ + V(System, VmoWrite) \ + V(System, VmoMap) \ V(System, ClockGetMonotonic) // clang-format: on diff --git a/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/system.h b/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/system.h index 01d6a4c8df001..f5b8abbd4783c 100644 --- a/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/system.h +++ b/shell/platform/fuchsia/dart-pkg/zircon/sdk_ext/system.h @@ -8,6 +8,7 @@ #include #include "handle.h" +#include "handle_disposition.h" #include "third_party/dart/runtime/include/dart_api.h" #include "third_party/tonic/dart_library_natives.h" #include "third_party/tonic/dart_wrappable.h" @@ -37,8 +38,13 @@ class System : public fml::RefCountedThreadSafe, static zx_status_t ChannelWrite(fml::RefPtr channel, const tonic::DartByteData& data, std::vector handles); + static zx_status_t ChannelWriteEtc( + fml::RefPtr channel, + const tonic::DartByteData& data, + std::vector handle_dispositions); // TODO(ianloic): Add ChannelRead static Dart_Handle ChannelQueryAndRead(fml::RefPtr channel); + static Dart_Handle ChannelQueryAndReadEtc(fml::RefPtr channel); static Dart_Handle EventpairCreate(uint32_t options); diff --git a/shell/platform/fuchsia/dart-pkg/zircon/test/channel_test.dart b/shell/platform/fuchsia/dart-pkg/zircon/test/channel_test.dart index 31d04fcb23017..22955cdd36e3f 100644 --- a/shell/platform/fuchsia/dart-pkg/zircon/test/channel_test.dart +++ b/shell/platform/fuchsia/dart-pkg/zircon/test/channel_test.dart @@ -73,6 +73,119 @@ void main() { expect(readResult.handles[0].isValid, isTrue); }); + group('etc functions', () { + test('moved handle', () { + final HandlePairResult pair = System.channelCreate(); + final ByteData data = utf8Bytes(''); + final HandlePairResult transferred = System.channelCreate(); + + final HandleDisposition disposition = HandleDisposition(ZX.HANDLE_OP_MOVE, + transferred.first, ZX.OBJ_TYPE_CHANNEL, ZX.RIGHTS_IO); + final int status = System.channelWriteEtc( + pair.first, data, [disposition]); + expect(status, equals(ZX.OK)); + expect(disposition.result, equals(ZX.OK)); + expect(transferred.first.isValid, isFalse); + + final ReadEtcResult readResult = + System.channelQueryAndReadEtc(pair.second); + expect(readResult.status, equals(ZX.OK)); + expect(readResult.numBytes, equals(0)); + expect(readResult.bytes.lengthInBytes, equals(0)); + expect(readResult.bytesAsUTF8String(), equals('')); + expect(readResult.handleInfos.length, equals(1)); + final HandleInfo handleInfo = readResult.handleInfos[0]; + expect(handleInfo.handle.isValid, isTrue); + expect(handleInfo.type, equals(ZX.OBJ_TYPE_CHANNEL)); + expect(handleInfo.rights, equals(ZX.RIGHTS_IO)); + }); + + test('copied handle', () { + final HandlePairResult pair = System.channelCreate(); + final ByteData data = utf8Bytes(''); + final HandleResult vmo = System.vmoCreate(0); + + final HandleDisposition disposition = HandleDisposition( + ZX.HANDLE_OP_DUPLICATE, + vmo.handle, + ZX.OBJ_TYPE_VMO, + ZX.RIGHT_SAME_RIGHTS); + final int status = System.channelWriteEtc( + pair.first, data, [disposition]); + expect(status, equals(ZX.OK)); + expect(disposition.result, equals(ZX.OK)); + expect(vmo.handle.isValid, isTrue); + + final ReadEtcResult readResult = + System.channelQueryAndReadEtc(pair.second); + expect(readResult.status, equals(ZX.OK)); + expect(readResult.numBytes, equals(0)); + expect(readResult.bytes.lengthInBytes, equals(0)); + expect(readResult.bytesAsUTF8String(), equals('')); + expect(readResult.handleInfos.length, equals(1)); + final HandleInfo handleInfo = readResult.handleInfos[0]; + expect(handleInfo.handle.isValid, isTrue); + expect(handleInfo.type, equals(ZX.OBJ_TYPE_VMO)); + expect(handleInfo.rights, equals(ZX.DEFAULT_VMO_RIGHTS)); + }); + + test('closed handle should error', () { + final HandlePairResult pair = System.channelCreate(); + final ByteData data = utf8Bytes(''); + final HandlePairResult closed = System.channelCreate(); + + final HandleDisposition disposition = HandleDisposition(ZX.HANDLE_OP_MOVE, + closed.first, ZX.OBJ_TYPE_CHANNEL, ZX.RIGHT_SAME_RIGHTS); + closed.first.close(); + final int status = System.channelWriteEtc( + pair.first, data, [disposition]); + expect(status, equals(ZX.ERR_BAD_HANDLE)); + expect(disposition.result, equals(ZX.ERR_BAD_HANDLE)); + expect(closed.first.isValid, isFalse); + + final ReadEtcResult readResult = + System.channelQueryAndReadEtc(pair.second); + expect(readResult.status, equals(ZX.ERR_SHOULD_WAIT)); + }); + + test('multiple handles', () { + final HandlePairResult pair = System.channelCreate(); + final ByteData data = utf8Bytes(''); + final HandlePairResult transferred = System.channelCreate(); + final HandleResult vmo = System.vmoCreate(0); + + final List dispositions = [ + HandleDisposition(ZX.HANDLE_OP_MOVE, transferred.first, + ZX.OBJ_TYPE_CHANNEL, ZX.RIGHTS_IO), + HandleDisposition(ZX.HANDLE_OP_DUPLICATE, vmo.handle, ZX.OBJ_TYPE_VMO, + ZX.RIGHT_SAME_RIGHTS) + ]; + final int status = System.channelWriteEtc(pair.first, data, dispositions); + expect(status, equals(ZX.OK)); + expect(dispositions[0].result, equals(ZX.OK)); + expect(dispositions[1].result, equals(ZX.OK)); + expect(transferred.first.isValid, isFalse); + expect(vmo.handle.isValid, isTrue); + + final ReadEtcResult readResult = + System.channelQueryAndReadEtc(pair.second); + expect(readResult.status, equals(ZX.OK)); + expect(readResult.numBytes, equals(0)); + expect(readResult.bytes.lengthInBytes, equals(0)); + expect(readResult.bytesAsUTF8String(), equals('')); + + expect(readResult.handleInfos.length, equals(2)); + final HandleInfo handleInfo = readResult.handleInfos[0]; + expect(handleInfo.handle.isValid, isTrue); + expect(handleInfo.type, equals(ZX.OBJ_TYPE_CHANNEL)); + expect(handleInfo.rights, equals(ZX.RIGHTS_IO)); + final HandleInfo vmoInfo = readResult.handleInfos[1]; + expect(vmoInfo.handle.isValid, isTrue); + expect(vmoInfo.type, equals(ZX.OBJ_TYPE_VMO)); + expect(vmoInfo.rights, equals(ZX.DEFAULT_VMO_RIGHTS)); + }); + }); + test('async wait channel read', () async { final HandlePairResult pair = System.channelCreate(); final Completer> completer = Completer>(); diff --git a/shell/platform/fuchsia/dart-pkg/zircon/test/handle_disposition_test.dart b/shell/platform/fuchsia/dart-pkg/zircon/test/handle_disposition_test.dart new file mode 100644 index 0000000000000..92819109335f4 --- /dev/null +++ b/shell/platform/fuchsia/dart-pkg/zircon/test/handle_disposition_test.dart @@ -0,0 +1,18 @@ +// Copyright 2021 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:test/test.dart'; +import 'package:zircon/zircon.dart'; + +void main() { + test('store the disposition arguments correctly', () { + final Handle handle = System.channelCreate().first; + final HandleDisposition disposition = HandleDisposition(1, handle, 2, 3); + expect(disposition.operation, equals(1)); + expect(disposition.handle, equals(handle)); + expect(disposition.type, equals(2)); + expect(disposition.rights, equals(3)); + expect(disposition.result, equals(ZX.OK)); + }); +}