From 2d60a20c38a744ee9ffac58e4b9741faa4cf09ad Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 31 Jan 2025 12:08:51 -0500 Subject: [PATCH 01/10] Add integration tests, remove background_platform_channels.dart --- .../pigeons/background_platform_channels.dart | 11 -- packages/pigeon/pigeons/core_tests.dart | 11 ++ .../AlternateLanguageTestPlugin.java | 11 ++ .../CoreTests.java | 31 +++++ .../ios/Classes/AlternateLanguageTestPlugin.m | 13 ++ .../ios/Classes/CoreTests.gen.h | 5 + .../ios/Classes/CoreTests.gen.m | 26 ++++ .../Classes/AlternateLanguageTestPlugin.m | 13 ++ .../macos/Classes/CoreTests.gen.h | 5 + .../macos/Classes/CoreTests.gen.m | 26 ++++ .../lib/integration_tests.dart | 19 +++ .../lib/src/generated/core_tests.gen.dart | 31 +++++ .../com/example/test_plugin/CoreTests.gen.kt | 27 +++++ .../com/example/test_plugin/TestPlugin.kt | 8 ++ .../ios/Classes/CoreTests.gen.swift | 21 ++++ .../test_plugin/ios/Classes/TestPlugin.swift | 8 ++ .../linux/pigeon/core_tests.gen.cc | 114 ++++++++++++++++++ .../test_plugin/linux/pigeon/core_tests.gen.h | 35 ++++++ .../test_plugin/linux/test_plugin.cc | 21 ++++ .../macos/Classes/CoreTests.gen.swift | 21 ++++ .../macos/Classes/TestPlugin.swift | 8 ++ .../windows/pigeon/core_tests.gen.cpp | 27 +++++ .../windows/pigeon/core_tests.gen.h | 3 + .../test_plugin/windows/test_plugin.cpp | 12 +- .../test_plugin/windows/test_plugin.h | 3 + packages/pigeon/tool/shared/generation.dart | 9 +- 26 files changed, 500 insertions(+), 19 deletions(-) delete mode 100644 packages/pigeon/pigeons/background_platform_channels.dart diff --git a/packages/pigeon/pigeons/background_platform_channels.dart b/packages/pigeon/pigeons/background_platform_channels.dart deleted file mode 100644 index 643b880aa48..00000000000 --- a/packages/pigeon/pigeons/background_platform_channels.dart +++ /dev/null @@ -1,11 +0,0 @@ -// 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. - -import 'package:pigeon/pigeon.dart'; - -@HostApi() -abstract class BackgroundApi2Host { - @TaskQueue(type: TaskQueueType.serialBackgroundThread) - int add(int x, int y); -} diff --git a/packages/pigeon/pigeons/core_tests.dart b/packages/pigeon/pigeons/core_tests.dart index a644ce5b3e0..8a154c8b62d 100644 --- a/packages/pigeon/pigeons/core_tests.dart +++ b/packages/pigeon/pigeons/core_tests.dart @@ -838,6 +838,17 @@ abstract class HostIntegrationCoreApi { @SwiftFunction('echoAsyncNullable(_:)') AnotherEnum? echoAnotherAsyncNullableEnum(AnotherEnum? anotherEnum); + // ========== TaskQueue tests ========== + + /// Returns true if the handler is run on a main thread, which should be + /// true since there is no TaskQueue annotation. + bool defaultIsMainThread(); + + /// Returns true if the handler is run on a non-main thread, which should be + /// true for any platform with TaskQueue support. + @TaskQueue(type: TaskQueueType.serialBackgroundThread) + bool taskQueueIsBackgroundThread(); + // ========== Flutter API test wrappers ========== @async diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/AlternateLanguageTestPlugin.java b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/AlternateLanguageTestPlugin.java index 8580645a27d..a6a39ecec94 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/AlternateLanguageTestPlugin.java +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/AlternateLanguageTestPlugin.java @@ -4,6 +4,7 @@ package com.example.alternate_language_test_plugin; +import android.os.Looper; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.example.alternate_language_test_plugin.CoreTests.AllClassesWrapper; @@ -615,6 +616,16 @@ public void echoAnotherAsyncNullableEnum( result.success(anotherEnum); } + @Override + public @NonNull Boolean defaultIsMainThread() { + return Thread.currentThread() == Looper.getMainLooper().getThread(); + } + + @Override + public @NonNull Boolean taskQueueIsBackgroundThread() { + return Thread.currentThread() != Looper.getMainLooper().getThread(); + } + @Override public void callFlutterNoop(@NonNull VoidResult result) { assert flutterApi != null; diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java index 4707969aab1..374c27e46d4 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java @@ -3166,6 +3166,12 @@ void echoAsyncNullableClassMap( /** Returns the passed enum, to test asynchronous serialization and deserialization. */ void echoAnotherAsyncNullableEnum( @Nullable AnotherEnum anotherEnum, @NonNull NullableResult result); + /** + * Returns true if the handler is run on a non-main thread, which should be true for any + * platform with TaskQueue support. + */ + @NonNull + Boolean isBackgroundThread(); void callFlutterNoop(@NonNull VoidResult result); @@ -6109,6 +6115,31 @@ public void error(Throwable error) { channel.setMessageHandler(null); } } + { + BinaryMessenger.TaskQueue taskQueue = binaryMessenger.makeBackgroundTaskQueue(); + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.isBackgroundThread" + + messageChannelSuffix, + getCodec(), + taskQueue); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList<>(); + try { + Boolean output = api.isBackgroundThread(); + wrapped.add(0, output); + } catch (Throwable exception) { + wrapped = wrapError(exception); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } { BasicMessageChannel channel = new BasicMessageChannel<>( diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/AlternateLanguageTestPlugin.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/AlternateLanguageTestPlugin.m index d684acfd55e..4f2b9d69450 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/AlternateLanguageTestPlugin.m +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/AlternateLanguageTestPlugin.m @@ -600,6 +600,19 @@ - (void)echoAnotherAsyncNullableEnum:(nullable FLTAnotherEnumBox *)AnotherEnumBo completion(AnotherEnumBoxed, nil); } +- (nullable NSNumber *)defaultIsMainThreadWithError:(FlutterError *_Nullable *_Nonnull)error { + // Using boxing on an inline expression results in the Dart side receiving an int, so + // force the right type via numberWithBool. + return [NSNumber numberWithBool:NSThread.isMainThread]; +} + +- (nullable NSNumber *)taskQueueIsBackgroundThreadWithError: + (FlutterError *_Nullable *_Nonnull)error { + // Using boxing on an inline expression results in the Dart side receiving an int, so + // force the right type via numberWithBool. + return [NSNumber numberWithBool:!NSThread.isMainThread]; +} + - (void)callFlutterNoopWithCompletion:(void (^)(FlutterError *_Nullable))completion { [self.flutterAPI noopWithCompletion:^(FlutterError *error) { completion(error); diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.h b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.h index bd913ca95a9..533b22ab2fb 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.h +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.h @@ -695,6 +695,11 @@ NSObject *FLTGetCoreTestsCodec(void); - (void)echoAnotherAsyncNullableEnum:(nullable FLTAnotherEnumBox *)anotherEnumBoxed completion:(void (^)(FLTAnotherEnumBox *_Nullable, FlutterError *_Nullable))completion; +/// Returns true if the handler is run on a non-main thread, which should be +/// true for any platform with TaskQueue support. +/// +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)isBackgroundThreadWithError:(FlutterError *_Nullable *_Nonnull)error; - (void)callFlutterNoopWithCompletion:(void (^)(FlutterError *_Nullable))completion; - (void)callFlutterThrowErrorWithCompletion:(void (^)(id _Nullable, FlutterError *_Nullable))completion; diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.m index 2cc3da7877d..f58b56f991b 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.m +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.m @@ -3319,6 +3319,32 @@ void SetUpFLTHostIntegrationCoreApiWithSuffix(id binaryM [channel setMessageHandler:nil]; } } + /// Returns true if the handler is run on a non-main thread, which should be + /// true for any platform with TaskQueue support. + { + NSObject *taskQueue = [binaryMessenger makeBackgroundTaskQueue]; + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.pigeon_integration_tests." + @"HostIntegrationCoreApi.isBackgroundThread", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FLTGetCoreTestsCodec() + taskQueue:taskQueue]; + if (api) { + NSCAssert([api respondsToSelector:@selector(isBackgroundThreadWithError:)], + @"FLTHostIntegrationCoreApi api (%@) doesn't respond to " + @"@selector(isBackgroundThreadWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api isBackgroundThreadWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] initWithName:[NSString stringWithFormat:@"%@%@", diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/AlternateLanguageTestPlugin.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/AlternateLanguageTestPlugin.m index d684acfd55e..4f2b9d69450 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/AlternateLanguageTestPlugin.m +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/AlternateLanguageTestPlugin.m @@ -600,6 +600,19 @@ - (void)echoAnotherAsyncNullableEnum:(nullable FLTAnotherEnumBox *)AnotherEnumBo completion(AnotherEnumBoxed, nil); } +- (nullable NSNumber *)defaultIsMainThreadWithError:(FlutterError *_Nullable *_Nonnull)error { + // Using boxing on an inline expression results in the Dart side receiving an int, so + // force the right type via numberWithBool. + return [NSNumber numberWithBool:NSThread.isMainThread]; +} + +- (nullable NSNumber *)taskQueueIsBackgroundThreadWithError: + (FlutterError *_Nullable *_Nonnull)error { + // Using boxing on an inline expression results in the Dart side receiving an int, so + // force the right type via numberWithBool. + return [NSNumber numberWithBool:!NSThread.isMainThread]; +} + - (void)callFlutterNoopWithCompletion:(void (^)(FlutterError *_Nullable))completion { [self.flutterAPI noopWithCompletion:^(FlutterError *error) { completion(error); diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/CoreTests.gen.h b/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/CoreTests.gen.h index bd913ca95a9..533b22ab2fb 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/CoreTests.gen.h +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/CoreTests.gen.h @@ -695,6 +695,11 @@ NSObject *FLTGetCoreTestsCodec(void); - (void)echoAnotherAsyncNullableEnum:(nullable FLTAnotherEnumBox *)anotherEnumBoxed completion:(void (^)(FLTAnotherEnumBox *_Nullable, FlutterError *_Nullable))completion; +/// Returns true if the handler is run on a non-main thread, which should be +/// true for any platform with TaskQueue support. +/// +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)isBackgroundThreadWithError:(FlutterError *_Nullable *_Nonnull)error; - (void)callFlutterNoopWithCompletion:(void (^)(FlutterError *_Nullable))completion; - (void)callFlutterThrowErrorWithCompletion:(void (^)(id _Nullable, FlutterError *_Nullable))completion; diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/CoreTests.gen.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/CoreTests.gen.m index 2cc3da7877d..f58b56f991b 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/CoreTests.gen.m +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/CoreTests.gen.m @@ -3319,6 +3319,32 @@ void SetUpFLTHostIntegrationCoreApiWithSuffix(id binaryM [channel setMessageHandler:nil]; } } + /// Returns true if the handler is run on a non-main thread, which should be + /// true for any platform with TaskQueue support. + { + NSObject *taskQueue = [binaryMessenger makeBackgroundTaskQueue]; + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.pigeon_integration_tests." + @"HostIntegrationCoreApi.isBackgroundThread", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FLTGetCoreTestsCodec() + taskQueue:taskQueue]; + if (api) { + NSCAssert([api respondsToSelector:@selector(isBackgroundThreadWithError:)], + @"FLTHostIntegrationCoreApi api (%@) doesn't respond to " + @"@selector(isBackgroundThreadWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api isBackgroundThreadWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } { FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] initWithName:[NSString stringWithFormat:@"%@%@", diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart index 8b5da977702..7039bc74bcd 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart @@ -2871,6 +2871,25 @@ void runPigeonIntegrationTests(TargetGenerator targetGenerator) { expect(unused, unused); }); + /// Task queues + + const List taskQueueSupported = [ + TargetGenerator.java, + TargetGenerator.kotlin, + TargetGenerator.objc, + TargetGenerator.swift, + ]; + + testWidgets('non-task-queue handlers run on a the main thread', (_) async { + final HostIntegrationCoreApi api = HostIntegrationCoreApi(); + expect(await api.defaultIsMainThread(), true); + }); + + testWidgets('task queue handlers run on a background thread', (_) async { + final HostIntegrationCoreApi api = HostIntegrationCoreApi(); + expect(await api.taskQueueIsBackgroundThread(), true); + }, skip: !taskQueueSupported.contains(targetGenerator)); + /// Event channels const List eventChannelSupported = [ diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart index 234361ada5a..e82a42b8286 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart @@ -3539,6 +3539,37 @@ class HostIntegrationCoreApi { } } + /// Returns true if the handler is run on a non-main thread, which should be + /// true for any platform with TaskQueue support. + Future isBackgroundThread() async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.isBackgroundThread$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send(null) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + Future callFlutterNoop() async { final String pigeonVar_channelName = 'dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterNoop$pigeonVar_messageChannelSuffix'; diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt index c5ba2d8b0ca..4bf99edfb7a 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt @@ -890,6 +890,11 @@ interface HostIntegrationCoreApi { anotherEnum: AnotherEnum?, callback: (Result) -> Unit ) + /** + * Returns true if the handler is run on a non-main thread, which should be true for any platform + * with TaskQueue support. + */ + fun isBackgroundThread(): Boolean fun callFlutterNoop(callback: (Result) -> Unit) @@ -3373,6 +3378,28 @@ interface HostIntegrationCoreApi { channel.setMessageHandler(null) } } + run { + val taskQueue = binaryMessenger.makeBackgroundTaskQueue() + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.isBackgroundThread$separatedMessageChannelSuffix", + codec, + taskQueue) + if (api != null) { + channel.setMessageHandler { _, reply -> + val wrapped: List = + try { + listOf(api.isBackgroundThread()) + } catch (exception: Throwable) { + wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } run { val channel = BasicMessageChannel( diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt index 3177d6cdc8d..7c6707c25a4 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt @@ -526,6 +526,14 @@ class TestPlugin : FlutterPlugin, HostIntegrationCoreApi { callback(Result.success(anotherEnum)) } + override fun defaultIsMainThread(): Boolean { + return Thread.currentThread() == Looper.getMainLooper().getThread() + } + + override fun taskQueueIsBackgroundThread(): Boolean { + return Thread.currentThread() != Looper.getMainLooper().getThread() + } + override fun callFlutterNoop(callback: (Result) -> Unit) { flutterApi!!.noop { callback(Result.success(Unit)) } } diff --git a/packages/pigeon/platform_tests/test_plugin/ios/Classes/CoreTests.gen.swift b/packages/pigeon/platform_tests/test_plugin/ios/Classes/CoreTests.gen.swift index 4647a66d1aa..781fda9eff1 100644 --- a/packages/pigeon/platform_tests/test_plugin/ios/Classes/CoreTests.gen.swift +++ b/packages/pigeon/platform_tests/test_plugin/ios/Classes/CoreTests.gen.swift @@ -967,6 +967,9 @@ protocol HostIntegrationCoreApi { /// Returns the passed enum, to test asynchronous serialization and deserialization. func echoAsyncNullable( _ anotherEnum: AnotherEnum?, completion: @escaping (Result) -> Void) + /// Returns true if the handler is run on a non-main thread, which should be + /// true for any platform with TaskQueue support. + func isBackgroundThread() throws -> Bool func callFlutterNoop(completion: @escaping (Result) -> Void) func callFlutterThrowError(completion: @escaping (Result) -> Void) func callFlutterThrowErrorFromVoid(completion: @escaping (Result) -> Void) @@ -3059,6 +3062,24 @@ class HostIntegrationCoreApiSetup { } else { echoAnotherAsyncNullableEnumChannel.setMessageHandler(nil) } + /// Returns true if the handler is run on a non-main thread, which should be + /// true for any platform with TaskQueue support. + let isBackgroundThreadChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.isBackgroundThread\(channelSuffix)", + binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + isBackgroundThreadChannel.setMessageHandler { _, reply in + do { + let result = try api.isBackgroundThread() + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + isBackgroundThreadChannel.setMessageHandler(nil) + } let callFlutterNoopChannel = FlutterBasicMessageChannel( name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterNoop\(channelSuffix)", diff --git a/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift b/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift index ddfba5c6d1e..5059fedfeaf 100644 --- a/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift +++ b/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift @@ -514,6 +514,14 @@ public class TestPlugin: NSObject, FlutterPlugin, HostIntegrationCoreApi { completion(.success(anotherEnum)) } + func defaultIsMainThread() -> Bool { + return Thread.isMainThread + } + + func taskQueueIsBackgroundThread() -> Bool { + return !Thread.isMainThread + } + func callFlutterNoop(completion: @escaping (Result) -> Void) { flutterAPI.noop { response in switch response { diff --git a/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.cc b/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.cc index 8dee0b40e5e..e29b6875ff9 100644 --- a/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.cc +++ b/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.cc @@ -9725,6 +9725,72 @@ core_tests_pigeon_test_host_integration_core_api_echo_another_async_nullable_enu return self; } +struct _CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse { + GObject parent_instance; + + FlValue* value; +}; + +G_DEFINE_TYPE( + CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse, + core_tests_pigeon_test_host_integration_core_api_is_background_thread_response, + G_TYPE_OBJECT) + +static void +core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_dispose( + GObject* object) { + CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_IS_BACKGROUND_THREAD_RESPONSE( + object); + g_clear_pointer(&self->value, fl_value_unref); + G_OBJECT_CLASS( + core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_parent_class) + ->dispose(object); +} + +static void +core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_init( + CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse* self) { +} + +static void +core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_class_init( + CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponseClass* + klass) { + G_OBJECT_CLASS(klass)->dispose = + core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_dispose; +} + +CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse* +core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_new( + gboolean return_value) { + CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_IS_BACKGROUND_THREAD_RESPONSE( + g_object_new( + core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_get_type(), + nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_bool(return_value)); + return self; +} + +CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse* +core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_new_error( + const gchar* code, const gchar* message, FlValue* details) { + CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_IS_BACKGROUND_THREAD_RESPONSE( + g_object_new( + core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_get_type(), + nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_string(code)); + fl_value_append_take(self->value, + fl_value_new_string(message != nullptr ? message : "")); + fl_value_append_take(self->value, details != nullptr ? fl_value_ref(details) + : fl_value_new_null()); + return self; +} + G_DECLARE_FINAL_TYPE( CoreTestsPigeonTestHostIntegrationCoreApiCallFlutterNoopResponse, core_tests_pigeon_test_host_integration_core_api_call_flutter_noop_response, @@ -16327,6 +16393,34 @@ core_tests_pigeon_test_host_integration_core_api_echo_another_async_nullable_enu self->user_data); } +static void +core_tests_pigeon_test_host_integration_core_api_is_background_thread_cb( + FlBasicMessageChannel* channel, FlValue* message_, + FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { + CoreTestsPigeonTestHostIntegrationCoreApi* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API(user_data); + + if (self->vtable == nullptr || + self->vtable->is_background_thread == nullptr) { + return; + } + + g_autoptr(CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse) + response = self->vtable->is_background_thread(self->user_data); + if (response == nullptr) { + g_warning("No response returned to %s.%s", "HostIntegrationCoreApi", + "isBackgroundThread"); + return; + } + + g_autoptr(GError) error = NULL; + if (!fl_basic_message_channel_respond(channel, response_handle, + response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "HostIntegrationCoreApi", + "isBackgroundThread", error->message); + } +} + static void core_tests_pigeon_test_host_integration_core_api_call_flutter_noop_cb( FlBasicMessageChannel* channel, FlValue* message_, @@ -18641,6 +18735,17 @@ void core_tests_pigeon_test_host_integration_core_api_set_method_handlers( echo_another_async_nullable_enum_channel, core_tests_pigeon_test_host_integration_core_api_echo_another_async_nullable_enum_cb, g_object_ref(api_data), g_object_unref); + g_autofree gchar* is_background_thread_channel_name = g_strdup_printf( + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "isBackgroundThread%s", + dot_suffix); + g_autoptr(FlBasicMessageChannel) is_background_thread_channel = + fl_basic_message_channel_new(messenger, is_background_thread_channel_name, + FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler( + is_background_thread_channel, + core_tests_pigeon_test_host_integration_core_api_is_background_thread_cb, + g_object_ref(api_data), g_object_unref); g_autofree gchar* call_flutter_noop_channel_name = g_strdup_printf( "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." "callFlutterNoop%s", @@ -20317,6 +20422,15 @@ void core_tests_pigeon_test_host_integration_core_api_clear_method_handlers( FL_MESSAGE_CODEC(codec)); fl_basic_message_channel_set_message_handler( echo_another_async_nullable_enum_channel, nullptr, nullptr, nullptr); + g_autofree gchar* is_background_thread_channel_name = g_strdup_printf( + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "isBackgroundThread%s", + dot_suffix); + g_autoptr(FlBasicMessageChannel) is_background_thread_channel = + fl_basic_message_channel_new(messenger, is_background_thread_channel_name, + FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(is_background_thread_channel, + nullptr, nullptr, nullptr); g_autofree gchar* call_flutter_noop_channel_name = g_strdup_printf( "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." "callFlutterNoop%s", diff --git a/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.h b/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.h index dcd6cac75f5..4a6d6631427 100644 --- a/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.h +++ b/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.h @@ -3448,6 +3448,39 @@ CoreTestsPigeonTestHostIntegrationCoreApiEchoNamedNullableStringResponse* core_tests_pigeon_test_host_integration_core_api_echo_named_nullable_string_response_new_error( const gchar* code, const gchar* message, FlValue* details); +G_DECLARE_FINAL_TYPE( + CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse, + core_tests_pigeon_test_host_integration_core_api_is_background_thread_response, + CORE_TESTS_PIGEON_TEST, + HOST_INTEGRATION_CORE_API_IS_BACKGROUND_THREAD_RESPONSE, GObject) + +/** + * core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_new: + * + * Creates a new response to HostIntegrationCoreApi.isBackgroundThread. + * + * Returns: a new + * #CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse + */ +CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse* +core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_new( + gboolean return_value); + +/** + * core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_new_error: + * @code: error code. + * @message: error message. + * @details: (allow-none): error details or %NULL. + * + * Creates a new error response to HostIntegrationCoreApi.isBackgroundThread. + * + * Returns: a new + * #CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse + */ +CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse* +core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_new_error( + const gchar* code, const gchar* message, FlValue* details); + /** * CoreTestsPigeonTestHostIntegrationCoreApiVTable: * @@ -3753,6 +3786,8 @@ typedef struct { CoreTestsPigeonTestAnotherEnum* another_enum, CoreTestsPigeonTestHostIntegrationCoreApiResponseHandle* response_handle, gpointer user_data); + CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse* ( + *is_background_thread)(gpointer user_data); void (*call_flutter_noop)( CoreTestsPigeonTestHostIntegrationCoreApiResponseHandle* response_handle, gpointer user_data); diff --git a/packages/pigeon/platform_tests/test_plugin/linux/test_plugin.cc b/packages/pigeon/platform_tests/test_plugin/linux/test_plugin.cc index 14938e9980f..0092cc27644 100644 --- a/packages/pigeon/platform_tests/test_plugin/linux/test_plugin.cc +++ b/packages/pigeon/platform_tests/test_plugin/linux/test_plugin.cc @@ -9,6 +9,7 @@ #include #include +#include #include "pigeon/core_tests.gen.h" #include "test_plugin_private.h" @@ -24,6 +25,8 @@ struct _TestPlugin { CoreTestsPigeonTestFlutterSmallApi* flutter_small_api_two; GCancellable* cancellable; + + int main_thread_id; }; G_DEFINE_TYPE(TestPlugin, test_plugin, G_TYPE_OBJECT) @@ -789,6 +792,20 @@ static void echo_another_async_nullable_enum( response_handle, another_enum); } +static CoreTestsPigeonTestHostIntegrationCoreApiDefaultIsMainThreadResponse* +default_is_main_thread(gpointer user_data) { + TestPlugin* self = TEST_PLUGIN(user_data); + return core_tests_pigeon_test_host_integration_core_api_default_is_main_thread_response_new( + std::this_thread::get_id() == this->main_thread_id); +} + +static CoreTestsPigeonTestHostIntegrationCoreApiTaskQueueIsBackgroundThreadResponse* +task_queue_is_background_thread(gpointer user_data) { + TestPlugin* self = TEST_PLUGIN(user_data); + return core_tests_pigeon_test_host_integration_core_api_task_queue_is_background_thread_response_new( + std::this_thread::get_id() != this->main_thread_id); +} + static void noop_cb(GObject* object, GAsyncResult* result, gpointer user_data) { g_autoptr(CallbackData) data = static_cast(user_data); @@ -3280,6 +3297,8 @@ static CoreTestsPigeonTestHostIntegrationCoreApiVTable host_core_api_vtable = { .echo_async_nullable_class_map = echo_async_nullable_class_map, .echo_async_nullable_enum = echo_async_nullable_enum, .echo_another_async_nullable_enum = echo_another_async_nullable_enum, + .default_is_main_thread = default_is_main_thread, + .task_queue_is_background_thread = task_queue_is_background_thread, .call_flutter_noop = call_flutter_noop, .call_flutter_throw_error = call_flutter_throw_error, .call_flutter_throw_error_from_void = call_flutter_throw_error_from_void, @@ -3416,6 +3435,8 @@ static TestPlugin* test_plugin_new(FlBinaryMessenger* messenger) { self->flutter_small_api_two = core_tests_pigeon_test_flutter_small_api_new(messenger, "suffixTwo"); + self->main_thread_id = std::this_thread::get_id(); + return self; } diff --git a/packages/pigeon/platform_tests/test_plugin/macos/Classes/CoreTests.gen.swift b/packages/pigeon/platform_tests/test_plugin/macos/Classes/CoreTests.gen.swift index 4647a66d1aa..781fda9eff1 100644 --- a/packages/pigeon/platform_tests/test_plugin/macos/Classes/CoreTests.gen.swift +++ b/packages/pigeon/platform_tests/test_plugin/macos/Classes/CoreTests.gen.swift @@ -967,6 +967,9 @@ protocol HostIntegrationCoreApi { /// Returns the passed enum, to test asynchronous serialization and deserialization. func echoAsyncNullable( _ anotherEnum: AnotherEnum?, completion: @escaping (Result) -> Void) + /// Returns true if the handler is run on a non-main thread, which should be + /// true for any platform with TaskQueue support. + func isBackgroundThread() throws -> Bool func callFlutterNoop(completion: @escaping (Result) -> Void) func callFlutterThrowError(completion: @escaping (Result) -> Void) func callFlutterThrowErrorFromVoid(completion: @escaping (Result) -> Void) @@ -3059,6 +3062,24 @@ class HostIntegrationCoreApiSetup { } else { echoAnotherAsyncNullableEnumChannel.setMessageHandler(nil) } + /// Returns true if the handler is run on a non-main thread, which should be + /// true for any platform with TaskQueue support. + let isBackgroundThreadChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.isBackgroundThread\(channelSuffix)", + binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + isBackgroundThreadChannel.setMessageHandler { _, reply in + do { + let result = try api.isBackgroundThread() + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + isBackgroundThreadChannel.setMessageHandler(nil) + } let callFlutterNoopChannel = FlutterBasicMessageChannel( name: "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.callFlutterNoop\(channelSuffix)", diff --git a/packages/pigeon/platform_tests/test_plugin/macos/Classes/TestPlugin.swift b/packages/pigeon/platform_tests/test_plugin/macos/Classes/TestPlugin.swift index c23056111ed..295a6440875 100644 --- a/packages/pigeon/platform_tests/test_plugin/macos/Classes/TestPlugin.swift +++ b/packages/pigeon/platform_tests/test_plugin/macos/Classes/TestPlugin.swift @@ -513,6 +513,14 @@ public class TestPlugin: NSObject, FlutterPlugin, HostIntegrationCoreApi { completion(.success(anotherEnum)) } + func defaultIsMainThread() -> Bool { + return Thread.isMainThread + } + + func taskQueueIsBackgroundThread() -> Bool { + return !Thread.isMainThread + } + func callFlutterNoop(completion: @escaping (Result) -> Void) { flutterAPI.noop { response in switch response { diff --git a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp index c47e3a16e2e..1bb01a159d2 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp +++ b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp @@ -6049,6 +6049,33 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, channel.SetMessageHandler(nullptr); } } + { + BasicMessageChannel<> channel(binary_messenger, + "dev.flutter.pigeon.pigeon_integration_tests." + "HostIntegrationCoreApi.isBackgroundThread" + + prepended_suffix, + &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler( + [api](const EncodableValue& message, + const flutter::MessageReply& reply) { + try { + ErrorOr output = api->IsBackgroundThread(); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } { BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.pigeon_integration_tests." diff --git a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h index 7f19e1a19cb..21540f9f077 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h +++ b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h @@ -1156,6 +1156,9 @@ class HostIntegrationCoreApi { const AnotherEnum* another_enum, std::function> reply)> result) = 0; + // Returns true if the handler is run on a non-main thread, which should be + // true for any platform with TaskQueue support. + virtual ErrorOr IsBackgroundThread() = 0; virtual void CallFlutterNoop( std::function reply)> result) = 0; virtual void CallFlutterThrowError( diff --git a/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.cpp b/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.cpp index c6f69c0a8c0..470507a9024 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.cpp +++ b/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "pigeon/core_tests.gen.h" @@ -77,7 +78,8 @@ TestPlugin::TestPlugin(flutter::BinaryMessenger* binary_messenger, host_small_api_one_(std::move(host_small_api_one)), host_small_api_two_(std::move(host_small_api_two)), flutter_api_( - std::make_unique(binary_messenger)) {} + std::make_unique(binary_messenger)), + main_thread_id_(std::this_thread::get_id()) {} TestPlugin::~TestPlugin() {} @@ -711,6 +713,14 @@ void TestPlugin::EchoAnotherAsyncNullableEnum( : std::nullopt); } +ErrorOr TestPlugin::DefaultIsMainThread() { + return std::this_thread::get_id() == main_thread_id_; +} + +ErrorOr TestPlugin::TaskQueueIsBackgroundThread() { + return std::this_thread::get_id() != main_thread_id_; +} + void TestPlugin::CallFlutterNoop( std::function reply)> result) { flutter_api_->Noop([result]() { result(std::nullopt); }, diff --git a/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h b/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h index cabbe665ed5..c1ad02c26ae 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h +++ b/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h @@ -393,6 +393,8 @@ class TestPlugin : public flutter::Plugin, std::optional> reply)> result) override; + ErrorOr DefaultIsMainThread() override; + ErrorOr TaskQueueIsBackgroundThread() override; void CallFlutterNoop( std::function< void(std::optional reply)> @@ -679,6 +681,7 @@ class TestPlugin : public flutter::Plugin, flutter_small_api_two_; std::unique_ptr host_small_api_one_; std::unique_ptr host_small_api_two_; + std::this_thread::id main_thread_id_; }; } // namespace test_plugin diff --git a/packages/pigeon/tool/shared/generation.dart b/packages/pigeon/tool/shared/generation.dart index 12b85a4973e..f03b0735556 100644 --- a/packages/pigeon/tool/shared/generation.dart +++ b/packages/pigeon/tool/shared/generation.dart @@ -86,7 +86,6 @@ Future generateTestPigeons( // TODO(stuartmorgan): Make this dynamic rather than hard-coded. Or eliminate // it entirely; see https://github.com/flutter/flutter/issues/115169. const Set inputs = { - 'background_platform_channels', 'core_tests', 'enum', 'event_channel_tests', @@ -112,15 +111,13 @@ Future generateTestPigeons( final Set skipLanguages = _unsupportedFiles[input] ?? {}; - final bool kotlinErrorClassGenerationTestFiles = - input == 'core_tests' || input == 'background_platform_channels'; + final bool kotlinErrorClassGenerationTestFiles = input == 'core_tests'; final String kotlinErrorName = kotlinErrorClassGenerationTestFiles ? 'FlutterError' : '${pascalCaseName}Error'; - final bool swiftErrorUseDefaultErrorName = - input == 'core_tests' || input == 'background_platform_channels'; + final bool swiftErrorUseDefaultErrorName = input == 'core_tests'; final String? swiftErrorClassName = swiftErrorUseDefaultErrorName ? null : '${pascalCaseName}Error'; @@ -146,7 +143,6 @@ Future generateTestPigeons( ? null : '$outputBase/ios/Classes/$pascalCaseName.gen.swift', swiftErrorClassName: swiftErrorClassName, - swiftIncludeErrorClass: input != 'background_platform_channels', // Linux gobjectHeaderOut: skipLanguages.contains(GeneratorLanguage.gobject) ? null @@ -178,7 +174,6 @@ Future generateTestPigeons( ? null : '$outputBase/macos/Classes/$pascalCaseName.gen.swift', swiftErrorClassName: swiftErrorClassName, - swiftIncludeErrorClass: input != 'background_platform_channels', suppressVersion: true, dartPackageName: 'pigeon_integration_tests', injectOverflowTypes: includeOverflow && input == 'core_tests', From 709a20d40cccdcfb1c0e7b04d62b8fbf3d0e6884 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 3 Feb 2025 16:35:06 -0500 Subject: [PATCH 02/10] Fix Obj-C, implement Swift --- .../pigeon/lib/src/objc/objc_generator.dart | 33 ++- .../pigeon/lib/src/swift/swift_generator.dart | 51 ++++- .../CoreTests.java | 35 ++- .../ios/Classes/CoreTests.gen.h | 8 +- .../ios/Classes/CoreTests.gen.m | 49 ++++- .../macos/Classes/CoreTests.gen.h | 8 +- .../macos/Classes/CoreTests.gen.m | 49 ++++- .../lib/integration_tests.dart | 21 +- .../lib/src/generated/core_tests.gen.dart | 35 ++- .../com/example/test_plugin/CoreTests.gen.kt | 31 ++- .../ios/Classes/CoreTests.gen.swift | 49 ++++- .../linux/pigeon/core_tests.gen.cc | 202 ++++++++++++++---- .../test_plugin/linux/pigeon/core_tests.gen.h | 66 ++++-- .../macos/Classes/CoreTests.gen.swift | 49 ++++- .../windows/pigeon/core_tests.gen.cpp | 32 ++- .../windows/pigeon/core_tests.gen.h | 5 +- 16 files changed, 603 insertions(+), 120 deletions(-) diff --git a/packages/pigeon/lib/src/objc/objc_generator.dart b/packages/pigeon/lib/src/objc/objc_generator.dart index e37d3bbcba8..40e75726961 100644 --- a/packages/pigeon/lib/src/objc/objc_generator.dart +++ b/packages/pigeon/lib/src/objc/objc_generator.dart @@ -860,24 +860,33 @@ if (self.wrapped == nil) { indent.addScoped('{', '}', () { indent.writeln( 'messageChannelSuffix = messageChannelSuffix.length > 0 ? [NSString stringWithFormat: @".%@", messageChannelSuffix] : @"";'); + String? serialBackgroundQueue; + if (api.methods.any((Method m) => + m.taskQueueType == TaskQueueType.serialBackgroundThread)) { + serialBackgroundQueue = 'taskQueue'; + // See https://github.com/flutter/flutter/issues/162613 for why this + // is an ifdef instead of just a respondsToSelector: check. + indent.format(''' +#if TARGET_OS_IOS + NSObject *$serialBackgroundQueue = [binaryMessenger makeBackgroundTaskQueue]; +#else + NSObject *$serialBackgroundQueue = nil; +#endif'''); + } for (final Method func in api.methods) { addDocumentationComments( indent, func.documentationComments, _docCommentSpec); indent.writeScoped('{', '}', () { - String? taskQueue; - if (func.taskQueueType != TaskQueueType.serial) { - taskQueue = 'taskQueue'; - indent.writeln( - 'NSObject *$taskQueue = [binaryMessenger makeBackgroundTaskQueue];'); - } _writeChannelAllocation( generatorOptions, indent, api, func, channelName, - taskQueue, + func.taskQueueType == TaskQueueType.serialBackgroundThread + ? serialBackgroundQueue + : null, dartPackageName: dartPackageName, ); indent.write('if (api) '); @@ -1112,7 +1121,15 @@ static FlutterError *createConnectionError(NSString *channelName) { if (taskQueue != null) { indent.newln(); - indent.addln('taskQueue:$taskQueue];'); + // See https://github.com/flutter/flutter/issues/162613 for why this + // is in an ifdef instead of just relying on the parameter being + // nullable. + indent.format(''' +#ifdef TARGET_OS_IOS +taskQueue:$taskQueue +#endif +]; +'''); } else { indent.addln('];'); } diff --git a/packages/pigeon/lib/src/swift/swift_generator.dart b/packages/pigeon/lib/src/swift/swift_generator.dart index 848c4bfa323..d568a434fbc 100644 --- a/packages/pigeon/lib/src/swift/swift_generator.dart +++ b/packages/pigeon/lib/src/swift/swift_generator.dart @@ -9,6 +9,7 @@ import '../ast.dart'; import '../functional.dart'; import '../generator.dart'; import '../generator_tools.dart'; +import '../pigeon_lib.dart'; import 'templates.dart'; /// Documentation comment open symbol. @@ -736,6 +737,21 @@ if (wrapped == nil) { indent.addScoped('{', '}', () { indent.writeln( r'let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : ""'); + String? serialBackgroundQueue; + if (api.methods.any((Method m) => + m.taskQueueType == TaskQueueType.serialBackgroundThread)) { + serialBackgroundQueue = 'taskQueue'; + // TODO(stuartmorgan): Remove the ? once macOS supports task queues + // and this is no longer an optional protocol method. + // See https://github.com/flutter/flutter/issues/162613 for why this + // is an ifdef instead of just relying on the optionality check. + indent.format(''' +#if os(iOS) + let $serialBackgroundQueue = binaryMessenger.makeBackgroundTaskQueue?() +#else + let $serialBackgroundQueue: FlutterTaskQueue? = nil +#endif'''); + } for (final Method method in api.methods) { _writeHostMethodMessageHandler( indent, @@ -747,6 +763,10 @@ if (wrapped == nil) { isAsynchronous: method.isAsynchronous, swiftFunction: method.swiftFunction, documentationComments: method.documentationComments, + serialBackgroundQueue: + method.taskQueueType == TaskQueueType.serialBackgroundThread + ? serialBackgroundQueue + : null, ); } }); @@ -1404,7 +1424,7 @@ private func nilOrValue(_ value: Any?) -> T? { func endOfStream() { sink(FlutterEndOfEventStream) } - + } '''); } @@ -1413,7 +1433,7 @@ private func nilOrValue(_ value: Any?) -> T? { for (final Method func in api.methods) { indent.format(''' class ${toUpperCamelCase(func.name)}StreamHandler: PigeonEventChannelWrapper<${_swiftTypeForDartType(func.returnType)}> { - static func register(with messenger: FlutterBinaryMessenger, + static func register(with messenger: FlutterBinaryMessenger, instanceName: String = "", streamHandler: ${toUpperCamelCase(func.name)}StreamHandler) { var channelName = "${makeChannelName(api, func, dartPackageName)}" @@ -1535,6 +1555,7 @@ private func nilOrValue(_ value: Any?) -> T? { required TypeDeclaration returnType, required bool isAsynchronous, required String? swiftFunction, + String? serialBackgroundQueue, String setHandlerCondition = 'let api = api', List documentationComments = const [], String Function(List safeArgNames, {required String apiVarName})? @@ -1549,8 +1570,30 @@ private func nilOrValue(_ value: Any?) -> T? { final String varChannelName = '${name}Channel'; addDocumentationComments(indent, documentationComments, _docCommentSpec); - indent.writeln( - 'let $varChannelName = FlutterBasicMessageChannel(name: "$channelName", binaryMessenger: binaryMessenger, codec: codec)'); + final String baseArgs = 'name: "$channelName", ' + 'binaryMessenger: binaryMessenger, codec: codec'; + // The version with taskQueue: is an optional protocol method that isn't + // implemented on macOS yet, so the call has to be conditionalized even + // though the taskQueue argument is nullable. The runtime branching can be + // removed once macOS supports task queues. The condition is on the task + // queue variable not being nil because the earlier code to set it will + // return nil on macOS where the optional parts of the protocol are not + // implemented. + final String channelCreationWithoutTaskQueue = + 'FlutterBasicMessageChannel($baseArgs)'; + if (serialBackgroundQueue == null) { + indent.writeln('let $varChannelName = $channelCreationWithoutTaskQueue'); + } else { + final String channelCreationWithTaskQueue = + 'FlutterBasicMessageChannel($baseArgs, taskQueue: $serialBackgroundQueue)'; + + indent.write('let $varChannelName = $serialBackgroundQueue == nil'); + indent.addScoped('', '', () { + indent.writeln('? $channelCreationWithoutTaskQueue'); + indent.writeln(': $channelCreationWithTaskQueue'); + }); + } + indent.write('if $setHandlerCondition '); indent.addScoped('{', '}', () { indent.write('$varChannelName.setMessageHandler '); diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java index 374c27e46d4..ba931d5bad2 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java @@ -3166,12 +3166,18 @@ void echoAsyncNullableClassMap( /** Returns the passed enum, to test asynchronous serialization and deserialization. */ void echoAnotherAsyncNullableEnum( @Nullable AnotherEnum anotherEnum, @NonNull NullableResult result); + /** + * Returns true if the handler is run on a main thread, which should be true since there is no + * TaskQueue annotation. + */ + @NonNull + Boolean defaultIsMainThread(); /** * Returns true if the handler is run on a non-main thread, which should be true for any * platform with TaskQueue support. */ @NonNull - Boolean isBackgroundThread(); + Boolean taskQueueIsBackgroundThread(); void callFlutterNoop(@NonNull VoidResult result); @@ -6115,12 +6121,35 @@ public void error(Throwable error) { channel.setMessageHandler(null); } } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.defaultIsMainThread" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList<>(); + try { + Boolean output = api.defaultIsMainThread(); + wrapped.add(0, output); + } catch (Throwable exception) { + wrapped = wrapError(exception); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } { BinaryMessenger.TaskQueue taskQueue = binaryMessenger.makeBackgroundTaskQueue(); BasicMessageChannel channel = new BasicMessageChannel<>( binaryMessenger, - "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.isBackgroundThread" + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.taskQueueIsBackgroundThread" + messageChannelSuffix, getCodec(), taskQueue); @@ -6129,7 +6158,7 @@ public void error(Throwable error) { (message, reply) -> { ArrayList wrapped = new ArrayList<>(); try { - Boolean output = api.isBackgroundThread(); + Boolean output = api.taskQueueIsBackgroundThread(); wrapped.add(0, output); } catch (Throwable exception) { wrapped = wrapError(exception); diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.h b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.h index 533b22ab2fb..3a7b01778b9 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.h +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.h @@ -695,11 +695,17 @@ NSObject *FLTGetCoreTestsCodec(void); - (void)echoAnotherAsyncNullableEnum:(nullable FLTAnotherEnumBox *)anotherEnumBoxed completion:(void (^)(FLTAnotherEnumBox *_Nullable, FlutterError *_Nullable))completion; +/// Returns true if the handler is run on a main thread, which should be +/// true since there is no TaskQueue annotation. +/// +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)defaultIsMainThreadWithError:(FlutterError *_Nullable *_Nonnull)error; /// Returns true if the handler is run on a non-main thread, which should be /// true for any platform with TaskQueue support. /// /// @return `nil` only when `error != nil`. -- (nullable NSNumber *)isBackgroundThreadWithError:(FlutterError *_Nullable *_Nonnull)error; +- (nullable NSNumber *)taskQueueIsBackgroundThreadWithError: + (FlutterError *_Nullable *_Nonnull)error; - (void)callFlutterNoopWithCompletion:(void (^)(FlutterError *_Nullable))completion; - (void)callFlutterThrowErrorWithCompletion:(void (^)(id _Nullable, FlutterError *_Nullable))completion; diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.m index f58b56f991b..36fb0a516f5 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.m +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.m @@ -696,6 +696,11 @@ void SetUpFLTHostIntegrationCoreApiWithSuffix(id binaryM messageChannelSuffix = messageChannelSuffix.length > 0 ? [NSString stringWithFormat:@".%@", messageChannelSuffix] : @""; +#if TARGET_OS_IOS + NSObject *taskQueue = [binaryMessenger makeBackgroundTaskQueue]; +#else + NSObject *taskQueue = nil; +#endif /// A no-op function taking no arguments and returning no value, to sanity /// test basic calling. { @@ -3319,26 +3324,54 @@ void SetUpFLTHostIntegrationCoreApiWithSuffix(id binaryM [channel setMessageHandler:nil]; } } - /// Returns true if the handler is run on a non-main thread, which should be - /// true for any platform with TaskQueue support. + /// Returns true if the handler is run on a main thread, which should be + /// true since there is no TaskQueue annotation. { - NSObject *taskQueue = [binaryMessenger makeBackgroundTaskQueue]; FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.pigeon_integration_tests." - @"HostIntegrationCoreApi.isBackgroundThread", + @"HostIntegrationCoreApi.defaultIsMainThread", messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FLTGetCoreTestsCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(defaultIsMainThreadWithError:)], + @"FLTHostIntegrationCoreApi api (%@) doesn't respond to " + @"@selector(defaultIsMainThreadWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api defaultIsMainThreadWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Returns true if the handler is run on a non-main thread, which should be + /// true for any platform with TaskQueue support. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.pigeon_integration_tests." + @"HostIntegrationCoreApi.taskQueueIsBackgroundThread", + messageChannelSuffix] binaryMessenger:binaryMessenger codec:FLTGetCoreTestsCodec() - taskQueue:taskQueue]; +#ifdef TARGET_OS_IOS + taskQueue:taskQueue +#endif + ]; + if (api) { - NSCAssert([api respondsToSelector:@selector(isBackgroundThreadWithError:)], + NSCAssert([api respondsToSelector:@selector(taskQueueIsBackgroundThreadWithError:)], @"FLTHostIntegrationCoreApi api (%@) doesn't respond to " - @"@selector(isBackgroundThreadWithError:)", + @"@selector(taskQueueIsBackgroundThreadWithError:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { FlutterError *error; - NSNumber *output = [api isBackgroundThreadWithError:&error]; + NSNumber *output = [api taskQueueIsBackgroundThreadWithError:&error]; callback(wrapResult(output, error)); }]; } else { diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/CoreTests.gen.h b/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/CoreTests.gen.h index 533b22ab2fb..3a7b01778b9 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/CoreTests.gen.h +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/CoreTests.gen.h @@ -695,11 +695,17 @@ NSObject *FLTGetCoreTestsCodec(void); - (void)echoAnotherAsyncNullableEnum:(nullable FLTAnotherEnumBox *)anotherEnumBoxed completion:(void (^)(FLTAnotherEnumBox *_Nullable, FlutterError *_Nullable))completion; +/// Returns true if the handler is run on a main thread, which should be +/// true since there is no TaskQueue annotation. +/// +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)defaultIsMainThreadWithError:(FlutterError *_Nullable *_Nonnull)error; /// Returns true if the handler is run on a non-main thread, which should be /// true for any platform with TaskQueue support. /// /// @return `nil` only when `error != nil`. -- (nullable NSNumber *)isBackgroundThreadWithError:(FlutterError *_Nullable *_Nonnull)error; +- (nullable NSNumber *)taskQueueIsBackgroundThreadWithError: + (FlutterError *_Nullable *_Nonnull)error; - (void)callFlutterNoopWithCompletion:(void (^)(FlutterError *_Nullable))completion; - (void)callFlutterThrowErrorWithCompletion:(void (^)(id _Nullable, FlutterError *_Nullable))completion; diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/CoreTests.gen.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/CoreTests.gen.m index f58b56f991b..36fb0a516f5 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/CoreTests.gen.m +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/macos/Classes/CoreTests.gen.m @@ -696,6 +696,11 @@ void SetUpFLTHostIntegrationCoreApiWithSuffix(id binaryM messageChannelSuffix = messageChannelSuffix.length > 0 ? [NSString stringWithFormat:@".%@", messageChannelSuffix] : @""; +#if TARGET_OS_IOS + NSObject *taskQueue = [binaryMessenger makeBackgroundTaskQueue]; +#else + NSObject *taskQueue = nil; +#endif /// A no-op function taking no arguments and returning no value, to sanity /// test basic calling. { @@ -3319,26 +3324,54 @@ void SetUpFLTHostIntegrationCoreApiWithSuffix(id binaryM [channel setMessageHandler:nil]; } } - /// Returns true if the handler is run on a non-main thread, which should be - /// true for any platform with TaskQueue support. + /// Returns true if the handler is run on a main thread, which should be + /// true since there is no TaskQueue annotation. { - NSObject *taskQueue = [binaryMessenger makeBackgroundTaskQueue]; FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.pigeon_integration_tests." - @"HostIntegrationCoreApi.isBackgroundThread", + @"HostIntegrationCoreApi.defaultIsMainThread", messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FLTGetCoreTestsCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(defaultIsMainThreadWithError:)], + @"FLTHostIntegrationCoreApi api (%@) doesn't respond to " + @"@selector(defaultIsMainThreadWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api defaultIsMainThreadWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Returns true if the handler is run on a non-main thread, which should be + /// true for any platform with TaskQueue support. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.pigeon_integration_tests." + @"HostIntegrationCoreApi.taskQueueIsBackgroundThread", + messageChannelSuffix] binaryMessenger:binaryMessenger codec:FLTGetCoreTestsCodec() - taskQueue:taskQueue]; +#ifdef TARGET_OS_IOS + taskQueue:taskQueue +#endif + ]; + if (api) { - NSCAssert([api respondsToSelector:@selector(isBackgroundThreadWithError:)], + NSCAssert([api respondsToSelector:@selector(taskQueueIsBackgroundThreadWithError:)], @"FLTHostIntegrationCoreApi api (%@) doesn't respond to " - @"@selector(isBackgroundThreadWithError:)", + @"@selector(taskQueueIsBackgroundThreadWithError:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { FlutterError *error; - NSNumber *output = [api isBackgroundThreadWithError:&error]; + NSNumber *output = [api taskQueueIsBackgroundThreadWithError:&error]; callback(wrapResult(output, error)); }]; } else { diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart index 7039bc74bcd..d14db88cbd6 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart @@ -2873,13 +2873,6 @@ void runPigeonIntegrationTests(TargetGenerator targetGenerator) { /// Task queues - const List taskQueueSupported = [ - TargetGenerator.java, - TargetGenerator.kotlin, - TargetGenerator.objc, - TargetGenerator.swift, - ]; - testWidgets('non-task-queue handlers run on a the main thread', (_) async { final HostIntegrationCoreApi api = HostIntegrationCoreApi(); expect(await api.defaultIsMainThread(), true); @@ -2887,8 +2880,18 @@ void runPigeonIntegrationTests(TargetGenerator targetGenerator) { testWidgets('task queue handlers run on a background thread', (_) async { final HostIntegrationCoreApi api = HostIntegrationCoreApi(); - expect(await api.taskQueueIsBackgroundThread(), true); - }, skip: !taskQueueSupported.contains(targetGenerator)); + // Currently only Android and iOS have task queue support. See + // https://github.com/flutter/flutter/issues/93945 + // Rather than skip the test, this changes the expectation, so that there + // is test coverage of the code path, even though the actual backgrounding + // doesn't happen. This is especially important for macOS, which may need to + // share generated code with iOS, falling back to the main thread since + // background is not supported. + final bool taskQueuesSupported = + defaultTargetPlatform == TargetPlatform.android || + defaultTargetPlatform == TargetPlatform.iOS; + expect(await api.taskQueueIsBackgroundThread(), taskQueuesSupported); + }); /// Event channels diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart index e82a42b8286..7a42a15724b 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart @@ -3539,11 +3539,42 @@ class HostIntegrationCoreApi { } } + /// Returns true if the handler is run on a main thread, which should be + /// true since there is no TaskQueue annotation. + Future defaultIsMainThread() async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.defaultIsMainThread$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send(null) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + /// Returns true if the handler is run on a non-main thread, which should be /// true for any platform with TaskQueue support. - Future isBackgroundThread() async { + Future taskQueueIsBackgroundThread() async { final String pigeonVar_channelName = - 'dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.isBackgroundThread$pigeonVar_messageChannelSuffix'; + 'dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.taskQueueIsBackgroundThread$pigeonVar_messageChannelSuffix'; final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt index 4bf99edfb7a..beb4604c375 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt @@ -890,11 +890,16 @@ interface HostIntegrationCoreApi { anotherEnum: AnotherEnum?, callback: (Result) -> Unit ) + /** + * Returns true if the handler is run on a main thread, which should be true since there is no + * TaskQueue annotation. + */ + fun defaultIsMainThread(): Boolean /** * Returns true if the handler is run on a non-main thread, which should be true for any platform * with TaskQueue support. */ - fun isBackgroundThread(): Boolean + fun taskQueueIsBackgroundThread(): Boolean fun callFlutterNoop(callback: (Result) -> Unit) @@ -3378,19 +3383,39 @@ interface HostIntegrationCoreApi { channel.setMessageHandler(null) } } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.defaultIsMainThread$separatedMessageChannelSuffix", + codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + val wrapped: List = + try { + listOf(api.defaultIsMainThread()) + } catch (exception: Throwable) { + wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } run { val taskQueue = binaryMessenger.makeBackgroundTaskQueue() val channel = BasicMessageChannel( binaryMessenger, - "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.isBackgroundThread$separatedMessageChannelSuffix", + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.taskQueueIsBackgroundThread$separatedMessageChannelSuffix", codec, taskQueue) if (api != null) { channel.setMessageHandler { _, reply -> val wrapped: List = try { - listOf(api.isBackgroundThread()) + listOf(api.taskQueueIsBackgroundThread()) } catch (exception: Throwable) { wrapError(exception) } diff --git a/packages/pigeon/platform_tests/test_plugin/ios/Classes/CoreTests.gen.swift b/packages/pigeon/platform_tests/test_plugin/ios/Classes/CoreTests.gen.swift index 781fda9eff1..b4c2173b388 100644 --- a/packages/pigeon/platform_tests/test_plugin/ios/Classes/CoreTests.gen.swift +++ b/packages/pigeon/platform_tests/test_plugin/ios/Classes/CoreTests.gen.swift @@ -967,9 +967,12 @@ protocol HostIntegrationCoreApi { /// Returns the passed enum, to test asynchronous serialization and deserialization. func echoAsyncNullable( _ anotherEnum: AnotherEnum?, completion: @escaping (Result) -> Void) + /// Returns true if the handler is run on a main thread, which should be + /// true since there is no TaskQueue annotation. + func defaultIsMainThread() throws -> Bool /// Returns true if the handler is run on a non-main thread, which should be /// true for any platform with TaskQueue support. - func isBackgroundThread() throws -> Bool + func taskQueueIsBackgroundThread() throws -> Bool func callFlutterNoop(completion: @escaping (Result) -> Void) func callFlutterThrowError(completion: @escaping (Result) -> Void) func callFlutterThrowErrorFromVoid(completion: @escaping (Result) -> Void) @@ -1092,6 +1095,11 @@ class HostIntegrationCoreApiSetup { messageChannelSuffix: String = "" ) { let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" + #if os(iOS) + let taskQueue = binaryMessenger.makeBackgroundTaskQueue?() + #else + let taskQueue: FlutterTaskQueue? = nil + #endif /// A no-op function taking no arguments and returning no value, to sanity /// test basic calling. let noopChannel = FlutterBasicMessageChannel( @@ -3062,23 +3070,48 @@ class HostIntegrationCoreApiSetup { } else { echoAnotherAsyncNullableEnumChannel.setMessageHandler(nil) } - /// Returns true if the handler is run on a non-main thread, which should be - /// true for any platform with TaskQueue support. - let isBackgroundThreadChannel = FlutterBasicMessageChannel( + /// Returns true if the handler is run on a main thread, which should be + /// true since there is no TaskQueue annotation. + let defaultIsMainThreadChannel = FlutterBasicMessageChannel( name: - "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.isBackgroundThread\(channelSuffix)", + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.defaultIsMainThread\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) if let api = api { - isBackgroundThreadChannel.setMessageHandler { _, reply in + defaultIsMainThreadChannel.setMessageHandler { _, reply in + do { + let result = try api.defaultIsMainThread() + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + defaultIsMainThreadChannel.setMessageHandler(nil) + } + /// Returns true if the handler is run on a non-main thread, which should be + /// true for any platform with TaskQueue support. + let taskQueueIsBackgroundThreadChannel = + taskQueue == nil + ? FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.taskQueueIsBackgroundThread\(channelSuffix)", + binaryMessenger: binaryMessenger, codec: codec) + : FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.taskQueueIsBackgroundThread\(channelSuffix)", + binaryMessenger: binaryMessenger, codec: codec, taskQueue: taskQueue) + + if let api = api { + taskQueueIsBackgroundThreadChannel.setMessageHandler { _, reply in do { - let result = try api.isBackgroundThread() + let result = try api.taskQueueIsBackgroundThread() reply(wrapResult(result)) } catch { reply(wrapError(error)) } } } else { - isBackgroundThreadChannel.setMessageHandler(nil) + taskQueueIsBackgroundThreadChannel.setMessageHandler(nil) } let callFlutterNoopChannel = FlutterBasicMessageChannel( name: diff --git a/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.cc b/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.cc index e29b6875ff9..2f2c55132f8 100644 --- a/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.cc +++ b/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.cc @@ -9725,62 +9725,130 @@ core_tests_pigeon_test_host_integration_core_api_echo_another_async_nullable_enu return self; } -struct _CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse { +struct _CoreTestsPigeonTestHostIntegrationCoreApiDefaultIsMainThreadResponse { GObject parent_instance; FlValue* value; }; G_DEFINE_TYPE( - CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse, - core_tests_pigeon_test_host_integration_core_api_is_background_thread_response, + CoreTestsPigeonTestHostIntegrationCoreApiDefaultIsMainThreadResponse, + core_tests_pigeon_test_host_integration_core_api_default_is_main_thread_response, G_TYPE_OBJECT) static void -core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_dispose( +core_tests_pigeon_test_host_integration_core_api_default_is_main_thread_response_dispose( GObject* object) { - CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse* self = - CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_IS_BACKGROUND_THREAD_RESPONSE( + CoreTestsPigeonTestHostIntegrationCoreApiDefaultIsMainThreadResponse* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_DEFAULT_IS_MAIN_THREAD_RESPONSE( object); g_clear_pointer(&self->value, fl_value_unref); G_OBJECT_CLASS( - core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_parent_class) + core_tests_pigeon_test_host_integration_core_api_default_is_main_thread_response_parent_class) ->dispose(object); } static void -core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_init( - CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse* self) { +core_tests_pigeon_test_host_integration_core_api_default_is_main_thread_response_init( + CoreTestsPigeonTestHostIntegrationCoreApiDefaultIsMainThreadResponse* + self) {} + +static void +core_tests_pigeon_test_host_integration_core_api_default_is_main_thread_response_class_init( + CoreTestsPigeonTestHostIntegrationCoreApiDefaultIsMainThreadResponseClass* + klass) { + G_OBJECT_CLASS(klass)->dispose = + core_tests_pigeon_test_host_integration_core_api_default_is_main_thread_response_dispose; +} + +CoreTestsPigeonTestHostIntegrationCoreApiDefaultIsMainThreadResponse* +core_tests_pigeon_test_host_integration_core_api_default_is_main_thread_response_new( + gboolean return_value) { + CoreTestsPigeonTestHostIntegrationCoreApiDefaultIsMainThreadResponse* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_DEFAULT_IS_MAIN_THREAD_RESPONSE( + g_object_new( + core_tests_pigeon_test_host_integration_core_api_default_is_main_thread_response_get_type(), + nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_bool(return_value)); + return self; +} + +CoreTestsPigeonTestHostIntegrationCoreApiDefaultIsMainThreadResponse* +core_tests_pigeon_test_host_integration_core_api_default_is_main_thread_response_new_error( + const gchar* code, const gchar* message, FlValue* details) { + CoreTestsPigeonTestHostIntegrationCoreApiDefaultIsMainThreadResponse* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_DEFAULT_IS_MAIN_THREAD_RESPONSE( + g_object_new( + core_tests_pigeon_test_host_integration_core_api_default_is_main_thread_response_get_type(), + nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_string(code)); + fl_value_append_take(self->value, + fl_value_new_string(message != nullptr ? message : "")); + fl_value_append_take(self->value, details != nullptr ? fl_value_ref(details) + : fl_value_new_null()); + return self; +} + +struct + _CoreTestsPigeonTestHostIntegrationCoreApiTaskQueueIsBackgroundThreadResponse { + GObject parent_instance; + + FlValue* value; +}; + +G_DEFINE_TYPE( + CoreTestsPigeonTestHostIntegrationCoreApiTaskQueueIsBackgroundThreadResponse, + core_tests_pigeon_test_host_integration_core_api_task_queue_is_background_thread_response, + G_TYPE_OBJECT) + +static void +core_tests_pigeon_test_host_integration_core_api_task_queue_is_background_thread_response_dispose( + GObject* object) { + CoreTestsPigeonTestHostIntegrationCoreApiTaskQueueIsBackgroundThreadResponse* + self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_TASK_QUEUE_IS_BACKGROUND_THREAD_RESPONSE( + object); + g_clear_pointer(&self->value, fl_value_unref); + G_OBJECT_CLASS( + core_tests_pigeon_test_host_integration_core_api_task_queue_is_background_thread_response_parent_class) + ->dispose(object); } static void -core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_class_init( - CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponseClass* +core_tests_pigeon_test_host_integration_core_api_task_queue_is_background_thread_response_init( + CoreTestsPigeonTestHostIntegrationCoreApiTaskQueueIsBackgroundThreadResponse* + self) {} + +static void +core_tests_pigeon_test_host_integration_core_api_task_queue_is_background_thread_response_class_init( + CoreTestsPigeonTestHostIntegrationCoreApiTaskQueueIsBackgroundThreadResponseClass* klass) { G_OBJECT_CLASS(klass)->dispose = - core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_dispose; + core_tests_pigeon_test_host_integration_core_api_task_queue_is_background_thread_response_dispose; } -CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse* -core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_new( +CoreTestsPigeonTestHostIntegrationCoreApiTaskQueueIsBackgroundThreadResponse* +core_tests_pigeon_test_host_integration_core_api_task_queue_is_background_thread_response_new( gboolean return_value) { - CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse* self = - CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_IS_BACKGROUND_THREAD_RESPONSE( + CoreTestsPigeonTestHostIntegrationCoreApiTaskQueueIsBackgroundThreadResponse* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_TASK_QUEUE_IS_BACKGROUND_THREAD_RESPONSE( g_object_new( - core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_get_type(), + core_tests_pigeon_test_host_integration_core_api_task_queue_is_background_thread_response_get_type(), nullptr)); self->value = fl_value_new_list(); fl_value_append_take(self->value, fl_value_new_bool(return_value)); return self; } -CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse* -core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_new_error( +CoreTestsPigeonTestHostIntegrationCoreApiTaskQueueIsBackgroundThreadResponse* +core_tests_pigeon_test_host_integration_core_api_task_queue_is_background_thread_response_new_error( const gchar* code, const gchar* message, FlValue* details) { - CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse* self = - CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_IS_BACKGROUND_THREAD_RESPONSE( + CoreTestsPigeonTestHostIntegrationCoreApiTaskQueueIsBackgroundThreadResponse* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API_TASK_QUEUE_IS_BACKGROUND_THREAD_RESPONSE( g_object_new( - core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_get_type(), + core_tests_pigeon_test_host_integration_core_api_task_queue_is_background_thread_response_get_type(), nullptr)); self->value = fl_value_new_list(); fl_value_append_take(self->value, fl_value_new_string(code)); @@ -16394,22 +16462,52 @@ core_tests_pigeon_test_host_integration_core_api_echo_another_async_nullable_enu } static void -core_tests_pigeon_test_host_integration_core_api_is_background_thread_cb( +core_tests_pigeon_test_host_integration_core_api_default_is_main_thread_cb( + FlBasicMessageChannel* channel, FlValue* message_, + FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { + CoreTestsPigeonTestHostIntegrationCoreApi* self = + CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API(user_data); + + if (self->vtable == nullptr || + self->vtable->default_is_main_thread == nullptr) { + return; + } + + g_autoptr( + CoreTestsPigeonTestHostIntegrationCoreApiDefaultIsMainThreadResponse) + response = self->vtable->default_is_main_thread(self->user_data); + if (response == nullptr) { + g_warning("No response returned to %s.%s", "HostIntegrationCoreApi", + "defaultIsMainThread"); + return; + } + + g_autoptr(GError) error = NULL; + if (!fl_basic_message_channel_respond(channel, response_handle, + response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "HostIntegrationCoreApi", + "defaultIsMainThread", error->message); + } +} + +static void +core_tests_pigeon_test_host_integration_core_api_task_queue_is_background_thread_cb( FlBasicMessageChannel* channel, FlValue* message_, FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { CoreTestsPigeonTestHostIntegrationCoreApi* self = CORE_TESTS_PIGEON_TEST_HOST_INTEGRATION_CORE_API(user_data); if (self->vtable == nullptr || - self->vtable->is_background_thread == nullptr) { + self->vtable->task_queue_is_background_thread == nullptr) { return; } - g_autoptr(CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse) - response = self->vtable->is_background_thread(self->user_data); + g_autoptr( + CoreTestsPigeonTestHostIntegrationCoreApiTaskQueueIsBackgroundThreadResponse) + response = self->vtable->task_queue_is_background_thread(self->user_data); if (response == nullptr) { g_warning("No response returned to %s.%s", "HostIntegrationCoreApi", - "isBackgroundThread"); + "taskQueueIsBackgroundThread"); return; } @@ -16417,7 +16515,7 @@ core_tests_pigeon_test_host_integration_core_api_is_background_thread_cb( if (!fl_basic_message_channel_respond(channel, response_handle, response->value, &error)) { g_warning("Failed to send response to %s.%s: %s", "HostIntegrationCoreApi", - "isBackgroundThread", error->message); + "taskQueueIsBackgroundThread", error->message); } } @@ -18735,16 +18833,30 @@ void core_tests_pigeon_test_host_integration_core_api_set_method_handlers( echo_another_async_nullable_enum_channel, core_tests_pigeon_test_host_integration_core_api_echo_another_async_nullable_enum_cb, g_object_ref(api_data), g_object_unref); - g_autofree gchar* is_background_thread_channel_name = g_strdup_printf( + g_autofree gchar* default_is_main_thread_channel_name = g_strdup_printf( "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." - "isBackgroundThread%s", + "defaultIsMainThread%s", dot_suffix); - g_autoptr(FlBasicMessageChannel) is_background_thread_channel = - fl_basic_message_channel_new(messenger, is_background_thread_channel_name, + g_autoptr(FlBasicMessageChannel) default_is_main_thread_channel = + fl_basic_message_channel_new(messenger, + default_is_main_thread_channel_name, FL_MESSAGE_CODEC(codec)); fl_basic_message_channel_set_message_handler( - is_background_thread_channel, - core_tests_pigeon_test_host_integration_core_api_is_background_thread_cb, + default_is_main_thread_channel, + core_tests_pigeon_test_host_integration_core_api_default_is_main_thread_cb, + g_object_ref(api_data), g_object_unref); + g_autofree gchar* task_queue_is_background_thread_channel_name = + g_strdup_printf( + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "taskQueueIsBackgroundThread%s", + dot_suffix); + g_autoptr(FlBasicMessageChannel) task_queue_is_background_thread_channel = + fl_basic_message_channel_new(messenger, + task_queue_is_background_thread_channel_name, + FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler( + task_queue_is_background_thread_channel, + core_tests_pigeon_test_host_integration_core_api_task_queue_is_background_thread_cb, g_object_ref(api_data), g_object_unref); g_autofree gchar* call_flutter_noop_channel_name = g_strdup_printf( "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." @@ -20422,15 +20534,27 @@ void core_tests_pigeon_test_host_integration_core_api_clear_method_handlers( FL_MESSAGE_CODEC(codec)); fl_basic_message_channel_set_message_handler( echo_another_async_nullable_enum_channel, nullptr, nullptr, nullptr); - g_autofree gchar* is_background_thread_channel_name = g_strdup_printf( + g_autofree gchar* default_is_main_thread_channel_name = g_strdup_printf( "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." - "isBackgroundThread%s", + "defaultIsMainThread%s", dot_suffix); - g_autoptr(FlBasicMessageChannel) is_background_thread_channel = - fl_basic_message_channel_new(messenger, is_background_thread_channel_name, + g_autoptr(FlBasicMessageChannel) default_is_main_thread_channel = + fl_basic_message_channel_new(messenger, + default_is_main_thread_channel_name, FL_MESSAGE_CODEC(codec)); - fl_basic_message_channel_set_message_handler(is_background_thread_channel, + fl_basic_message_channel_set_message_handler(default_is_main_thread_channel, nullptr, nullptr, nullptr); + g_autofree gchar* task_queue_is_background_thread_channel_name = + g_strdup_printf( + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "taskQueueIsBackgroundThread%s", + dot_suffix); + g_autoptr(FlBasicMessageChannel) task_queue_is_background_thread_channel = + fl_basic_message_channel_new(messenger, + task_queue_is_background_thread_channel_name, + FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler( + task_queue_is_background_thread_channel, nullptr, nullptr, nullptr); g_autofree gchar* call_flutter_noop_channel_name = g_strdup_printf( "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." "callFlutterNoop%s", diff --git a/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.h b/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.h index 4a6d6631427..8d33236b071 100644 --- a/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.h +++ b/packages/pigeon/platform_tests/test_plugin/linux/pigeon/core_tests.gen.h @@ -3449,36 +3449,70 @@ core_tests_pigeon_test_host_integration_core_api_echo_named_nullable_string_resp const gchar* code, const gchar* message, FlValue* details); G_DECLARE_FINAL_TYPE( - CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse, - core_tests_pigeon_test_host_integration_core_api_is_background_thread_response, + CoreTestsPigeonTestHostIntegrationCoreApiDefaultIsMainThreadResponse, + core_tests_pigeon_test_host_integration_core_api_default_is_main_thread_response, CORE_TESTS_PIGEON_TEST, - HOST_INTEGRATION_CORE_API_IS_BACKGROUND_THREAD_RESPONSE, GObject) + HOST_INTEGRATION_CORE_API_DEFAULT_IS_MAIN_THREAD_RESPONSE, GObject) /** - * core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_new: + * core_tests_pigeon_test_host_integration_core_api_default_is_main_thread_response_new: * - * Creates a new response to HostIntegrationCoreApi.isBackgroundThread. + * Creates a new response to HostIntegrationCoreApi.defaultIsMainThread. * * Returns: a new - * #CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse + * #CoreTestsPigeonTestHostIntegrationCoreApiDefaultIsMainThreadResponse */ -CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse* -core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_new( +CoreTestsPigeonTestHostIntegrationCoreApiDefaultIsMainThreadResponse* +core_tests_pigeon_test_host_integration_core_api_default_is_main_thread_response_new( gboolean return_value); /** - * core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_new_error: + * core_tests_pigeon_test_host_integration_core_api_default_is_main_thread_response_new_error: * @code: error code. * @message: error message. * @details: (allow-none): error details or %NULL. * - * Creates a new error response to HostIntegrationCoreApi.isBackgroundThread. + * Creates a new error response to HostIntegrationCoreApi.defaultIsMainThread. * * Returns: a new - * #CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse + * #CoreTestsPigeonTestHostIntegrationCoreApiDefaultIsMainThreadResponse */ -CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse* -core_tests_pigeon_test_host_integration_core_api_is_background_thread_response_new_error( +CoreTestsPigeonTestHostIntegrationCoreApiDefaultIsMainThreadResponse* +core_tests_pigeon_test_host_integration_core_api_default_is_main_thread_response_new_error( + const gchar* code, const gchar* message, FlValue* details); + +G_DECLARE_FINAL_TYPE( + CoreTestsPigeonTestHostIntegrationCoreApiTaskQueueIsBackgroundThreadResponse, + core_tests_pigeon_test_host_integration_core_api_task_queue_is_background_thread_response, + CORE_TESTS_PIGEON_TEST, + HOST_INTEGRATION_CORE_API_TASK_QUEUE_IS_BACKGROUND_THREAD_RESPONSE, GObject) + +/** + * core_tests_pigeon_test_host_integration_core_api_task_queue_is_background_thread_response_new: + * + * Creates a new response to HostIntegrationCoreApi.taskQueueIsBackgroundThread. + * + * Returns: a new + * #CoreTestsPigeonTestHostIntegrationCoreApiTaskQueueIsBackgroundThreadResponse + */ +CoreTestsPigeonTestHostIntegrationCoreApiTaskQueueIsBackgroundThreadResponse* +core_tests_pigeon_test_host_integration_core_api_task_queue_is_background_thread_response_new( + gboolean return_value); + +/** + * core_tests_pigeon_test_host_integration_core_api_task_queue_is_background_thread_response_new_error: + * @code: error code. + * @message: error message. + * @details: (allow-none): error details or %NULL. + * + * Creates a new error response to + * HostIntegrationCoreApi.taskQueueIsBackgroundThread. + * + * Returns: a new + * #CoreTestsPigeonTestHostIntegrationCoreApiTaskQueueIsBackgroundThreadResponse + */ +CoreTestsPigeonTestHostIntegrationCoreApiTaskQueueIsBackgroundThreadResponse* +core_tests_pigeon_test_host_integration_core_api_task_queue_is_background_thread_response_new_error( const gchar* code, const gchar* message, FlValue* details); /** @@ -3786,8 +3820,10 @@ typedef struct { CoreTestsPigeonTestAnotherEnum* another_enum, CoreTestsPigeonTestHostIntegrationCoreApiResponseHandle* response_handle, gpointer user_data); - CoreTestsPigeonTestHostIntegrationCoreApiIsBackgroundThreadResponse* ( - *is_background_thread)(gpointer user_data); + CoreTestsPigeonTestHostIntegrationCoreApiDefaultIsMainThreadResponse* ( + *default_is_main_thread)(gpointer user_data); + CoreTestsPigeonTestHostIntegrationCoreApiTaskQueueIsBackgroundThreadResponse* ( + *task_queue_is_background_thread)(gpointer user_data); void (*call_flutter_noop)( CoreTestsPigeonTestHostIntegrationCoreApiResponseHandle* response_handle, gpointer user_data); diff --git a/packages/pigeon/platform_tests/test_plugin/macos/Classes/CoreTests.gen.swift b/packages/pigeon/platform_tests/test_plugin/macos/Classes/CoreTests.gen.swift index 781fda9eff1..b4c2173b388 100644 --- a/packages/pigeon/platform_tests/test_plugin/macos/Classes/CoreTests.gen.swift +++ b/packages/pigeon/platform_tests/test_plugin/macos/Classes/CoreTests.gen.swift @@ -967,9 +967,12 @@ protocol HostIntegrationCoreApi { /// Returns the passed enum, to test asynchronous serialization and deserialization. func echoAsyncNullable( _ anotherEnum: AnotherEnum?, completion: @escaping (Result) -> Void) + /// Returns true if the handler is run on a main thread, which should be + /// true since there is no TaskQueue annotation. + func defaultIsMainThread() throws -> Bool /// Returns true if the handler is run on a non-main thread, which should be /// true for any platform with TaskQueue support. - func isBackgroundThread() throws -> Bool + func taskQueueIsBackgroundThread() throws -> Bool func callFlutterNoop(completion: @escaping (Result) -> Void) func callFlutterThrowError(completion: @escaping (Result) -> Void) func callFlutterThrowErrorFromVoid(completion: @escaping (Result) -> Void) @@ -1092,6 +1095,11 @@ class HostIntegrationCoreApiSetup { messageChannelSuffix: String = "" ) { let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" + #if os(iOS) + let taskQueue = binaryMessenger.makeBackgroundTaskQueue?() + #else + let taskQueue: FlutterTaskQueue? = nil + #endif /// A no-op function taking no arguments and returning no value, to sanity /// test basic calling. let noopChannel = FlutterBasicMessageChannel( @@ -3062,23 +3070,48 @@ class HostIntegrationCoreApiSetup { } else { echoAnotherAsyncNullableEnumChannel.setMessageHandler(nil) } - /// Returns true if the handler is run on a non-main thread, which should be - /// true for any platform with TaskQueue support. - let isBackgroundThreadChannel = FlutterBasicMessageChannel( + /// Returns true if the handler is run on a main thread, which should be + /// true since there is no TaskQueue annotation. + let defaultIsMainThreadChannel = FlutterBasicMessageChannel( name: - "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.isBackgroundThread\(channelSuffix)", + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.defaultIsMainThread\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) if let api = api { - isBackgroundThreadChannel.setMessageHandler { _, reply in + defaultIsMainThreadChannel.setMessageHandler { _, reply in + do { + let result = try api.defaultIsMainThread() + reply(wrapResult(result)) + } catch { + reply(wrapError(error)) + } + } + } else { + defaultIsMainThreadChannel.setMessageHandler(nil) + } + /// Returns true if the handler is run on a non-main thread, which should be + /// true for any platform with TaskQueue support. + let taskQueueIsBackgroundThreadChannel = + taskQueue == nil + ? FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.taskQueueIsBackgroundThread\(channelSuffix)", + binaryMessenger: binaryMessenger, codec: codec) + : FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi.taskQueueIsBackgroundThread\(channelSuffix)", + binaryMessenger: binaryMessenger, codec: codec, taskQueue: taskQueue) + + if let api = api { + taskQueueIsBackgroundThreadChannel.setMessageHandler { _, reply in do { - let result = try api.isBackgroundThread() + let result = try api.taskQueueIsBackgroundThread() reply(wrapResult(result)) } catch { reply(wrapError(error)) } } } else { - isBackgroundThreadChannel.setMessageHandler(nil) + taskQueueIsBackgroundThreadChannel.setMessageHandler(nil) } let callFlutterNoopChannel = FlutterBasicMessageChannel( name: diff --git a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp index 1bb01a159d2..8fd4949f06e 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp +++ b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp @@ -6052,7 +6052,7 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, { BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.pigeon_integration_tests." - "HostIntegrationCoreApi.isBackgroundThread" + + "HostIntegrationCoreApi.defaultIsMainThread" + prepended_suffix, &GetCodec()); if (api != nullptr) { @@ -6060,7 +6060,35 @@ void HostIntegrationCoreApi::SetUp(flutter::BinaryMessenger* binary_messenger, [api](const EncodableValue& message, const flutter::MessageReply& reply) { try { - ErrorOr output = api->IsBackgroundThread(); + ErrorOr output = api->DefaultIsMainThread(); + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel( + binary_messenger, + "dev.flutter.pigeon.pigeon_integration_tests.HostIntegrationCoreApi." + "taskQueueIsBackgroundThread" + + prepended_suffix, + &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler( + [api](const EncodableValue& message, + const flutter::MessageReply& reply) { + try { + ErrorOr output = api->TaskQueueIsBackgroundThread(); if (output.has_error()) { reply(WrapError(output.error())); return; diff --git a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h index 21540f9f077..7455ab574be 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h +++ b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h @@ -1156,9 +1156,12 @@ class HostIntegrationCoreApi { const AnotherEnum* another_enum, std::function> reply)> result) = 0; + // Returns true if the handler is run on a main thread, which should be + // true since there is no TaskQueue annotation. + virtual ErrorOr DefaultIsMainThread() = 0; // Returns true if the handler is run on a non-main thread, which should be // true for any platform with TaskQueue support. - virtual ErrorOr IsBackgroundThread() = 0; + virtual ErrorOr TaskQueueIsBackgroundThread() = 0; virtual void CallFlutterNoop( std::function reply)> result) = 0; virtual void CallFlutterThrowError( From be83e5f561e5b44fb7fc9f61b37b0e7cad018390 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Tue, 4 Feb 2025 13:27:16 -0500 Subject: [PATCH 03/10] Fix Java and Kotlin --- .../pigeon/lib/src/java/java_generator.dart | 39 +++++++++---------- .../lib/src/kotlin/kotlin_generator.dart | 28 +++++++------ .../CoreTests.java | 2 +- .../com/example/test_plugin/CoreTests.gen.kt | 2 +- 4 files changed, 38 insertions(+), 33 deletions(-) diff --git a/packages/pigeon/lib/src/java/java_generator.dart b/packages/pigeon/lib/src/java/java_generator.dart index c5fd0007b8f..6ad033a5459 100644 --- a/packages/pigeon/lib/src/java/java_generator.dart +++ b/packages/pigeon/lib/src/java/java_generator.dart @@ -835,15 +835,21 @@ if (wrapped == null) { indent.addScoped('{', '}', () { indent.writeln( 'messageChannelSuffix = messageChannelSuffix.isEmpty() ? "" : "." + messageChannelSuffix;'); + String? serialBackgroundQueue; + if (api.methods.any((Method m) => + m.taskQueueType == TaskQueueType.serialBackgroundThread)) { + serialBackgroundQueue = 'taskQueue'; + indent.writeln( + 'BinaryMessenger.TaskQueue $serialBackgroundQueue = binaryMessenger.makeBackgroundTaskQueue();'); + } for (final Method method in api.methods) { - _writeMethodSetUp( - generatorOptions, - root, - indent, - api, - method, - dartPackageName: dartPackageName, - ); + _writeHostMethodMessageHandler( + generatorOptions, root, indent, api, method, + dartPackageName: dartPackageName, + serialBackgroundQueue: + method.taskQueueType == TaskQueueType.serialBackgroundThread + ? serialBackgroundQueue + : null); } }); }); @@ -887,34 +893,27 @@ if (wrapped == null) { indent.writeln('$returnType ${method.name}(${argSignature.join(', ')});'); } - /// Write a static setUp function in the interface. - /// Example: - /// static void setUp(BinaryMessenger binaryMessenger, Foo api) {...} - void _writeMethodSetUp( + /// Write a single method's handler for the setUp function. + void _writeHostMethodMessageHandler( JavaOptions generatorOptions, Root root, Indent indent, Api api, final Method method, { required String dartPackageName, + String? serialBackgroundQueue, }) { final String channelName = makeChannelName(api, method, dartPackageName); indent.write(''); indent.addScoped('{', '}', () { - String? taskQueue; - if (method.taskQueueType != TaskQueueType.serial) { - taskQueue = 'taskQueue'; - indent.writeln( - 'BinaryMessenger.TaskQueue taskQueue = binaryMessenger.makeBackgroundTaskQueue();'); - } indent.writeln('BasicMessageChannel channel ='); indent.nest(2, () { indent.writeln('new BasicMessageChannel<>('); indent.nest(2, () { indent.write( 'binaryMessenger, "$channelName" + messageChannelSuffix, getCodec()'); - if (taskQueue != null) { - indent.addln(', $taskQueue);'); + if (serialBackgroundQueue != null) { + indent.addln(', $serialBackgroundQueue);'); } else { indent.addln(');'); } diff --git a/packages/pigeon/lib/src/kotlin/kotlin_generator.dart b/packages/pigeon/lib/src/kotlin/kotlin_generator.dart index 6a59d7594d0..41614263baa 100644 --- a/packages/pigeon/lib/src/kotlin/kotlin_generator.dart +++ b/packages/pigeon/lib/src/kotlin/kotlin_generator.dart @@ -654,6 +654,14 @@ if (wrapped == null) { indent.addScoped('{', '}', () { indent.writeln( r'val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""'); + String? serialBackgroundQueue; + if (api.methods.any((Method m) => + m.taskQueueType == TaskQueueType.serialBackgroundThread)) { + serialBackgroundQueue = 'taskQueue'; + serialBackgroundQueue = 'taskQueue'; + indent.writeln( + 'val $serialBackgroundQueue = binaryMessenger.makeBackgroundTaskQueue()'); + } for (final Method method in api.methods) { _writeHostMethodMessageHandler( indent, @@ -664,6 +672,10 @@ if (wrapped == null) { parameters: method.parameters, returnType: method.returnType, isAsynchronous: method.isAsynchronous, + serialBackgroundQueue: + method.taskQueueType == TaskQueueType.serialBackgroundThread + ? serialBackgroundQueue + : null, ); } }); @@ -1071,8 +1083,8 @@ if (wrapped == null) { fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) { sink.error(errorCode, errorMessage, errorDetails) } - - fun endOfStream() { + + fun endOfStream() { sink.endOfStream() } } @@ -1249,24 +1261,18 @@ if (wrapped == null) { required TypeDeclaration returnType, String setHandlerCondition = 'api != null', bool isAsynchronous = false, + String? serialBackgroundQueue, String Function(List safeArgNames, {required String apiVarName})? onCreateCall, }) { indent.write('run '); indent.addScoped('{', '}', () { - String? taskQueue; - if (taskQueueType != TaskQueueType.serial) { - taskQueue = 'taskQueue'; - indent.writeln( - 'val $taskQueue = binaryMessenger.makeBackgroundTaskQueue()'); - } - indent.write( 'val channel = BasicMessageChannel(binaryMessenger, "$channelName", codec', ); - if (taskQueue != null) { - indent.addln(', $taskQueue)'); + if (serialBackgroundQueue != null) { + indent.addln(', $serialBackgroundQueue)'); } else { indent.addln(')'); } diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java index ba931d5bad2..7cd093e4996 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java @@ -3352,6 +3352,7 @@ static void setUp( @NonNull String messageChannelSuffix, @Nullable HostIntegrationCoreApi api) { messageChannelSuffix = messageChannelSuffix.isEmpty() ? "" : "." + messageChannelSuffix; + BinaryMessenger.TaskQueue taskQueue = binaryMessenger.makeBackgroundTaskQueue(); { BasicMessageChannel channel = new BasicMessageChannel<>( @@ -6145,7 +6146,6 @@ public void error(Throwable error) { } } { - BinaryMessenger.TaskQueue taskQueue = binaryMessenger.makeBackgroundTaskQueue(); BasicMessageChannel channel = new BasicMessageChannel<>( binaryMessenger, diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt index beb4604c375..efd9cb613df 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt @@ -1109,6 +1109,7 @@ interface HostIntegrationCoreApi { ) { val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val taskQueue = binaryMessenger.makeBackgroundTaskQueue() run { val channel = BasicMessageChannel( @@ -3404,7 +3405,6 @@ interface HostIntegrationCoreApi { } } run { - val taskQueue = binaryMessenger.makeBackgroundTaskQueue() val channel = BasicMessageChannel( binaryMessenger, From 72e2b6f4c8db713c9a909d41dd840ef31cb6432d Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 13 Feb 2025 13:45:33 -0500 Subject: [PATCH 04/10] Version bump --- packages/pigeon/CHANGELOG.md | 6 ++++++ packages/pigeon/lib/src/generator_tools.dart | 2 +- packages/pigeon/pubspec.yaml | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md index 14ee5daa917..b56081a0600 100644 --- a/packages/pigeon/CHANGELOG.md +++ b/packages/pigeon/CHANGELOG.md @@ -1,3 +1,9 @@ +## 24.2.0 + +* Adjusts task queues to use a shared task queue for all methods in a single + API instance, to give the same ordering guarantees as non-task-queue usage. +* [swift] Adds task queue support to the Swift generator. + ## 24.1.1 * [swift, kotlin] Adds an error message when a ProxyAPI callback method that returns a non-null diff --git a/packages/pigeon/lib/src/generator_tools.dart b/packages/pigeon/lib/src/generator_tools.dart index e6d7be1623b..e6cc6cde6ce 100644 --- a/packages/pigeon/lib/src/generator_tools.dart +++ b/packages/pigeon/lib/src/generator_tools.dart @@ -14,7 +14,7 @@ import 'ast.dart'; /// The current version of pigeon. /// /// This must match the version in pubspec.yaml. -const String pigeonVersion = '24.1.1'; +const String pigeonVersion = '24.2.0'; /// Read all the content from [stdin] to a String. String readStdin() { diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml index 3fb7a94a35e..6f85a9899b2 100644 --- a/packages/pigeon/pubspec.yaml +++ b/packages/pigeon/pubspec.yaml @@ -2,7 +2,7 @@ name: pigeon description: Code generator tool to make communication between Flutter and the host platform type-safe and easier. repository: https://github.com/flutter/packages/tree/main/packages/pigeon issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+pigeon%22 -version: 24.1.1 # This must match the version in lib/src/generator_tools.dart +version: 24.2.0 # This must match the version in lib/src/generator_tools.dart environment: sdk: ^3.4.0 From 7a2acebbef940301b23890a31b782be2756df51e Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 14 Feb 2025 15:16:18 -0500 Subject: [PATCH 05/10] Move TaskQueueType to its own file --- .../pigeon/lib/src/java/java_generator.dart | 2 +- .../lib/src/kotlin/kotlin_generator.dart | 2 +- .../pigeon/lib/src/objc/objc_generator.dart | 3 ++- packages/pigeon/lib/src/pigeon_lib.dart | 18 +++--------------- .../pigeon/lib/src/swift/swift_generator.dart | 2 +- packages/pigeon/lib/src/types/task_queue.dart | 18 ++++++++++++++++++ 6 files changed, 26 insertions(+), 19 deletions(-) create mode 100644 packages/pigeon/lib/src/types/task_queue.dart diff --git a/packages/pigeon/lib/src/java/java_generator.dart b/packages/pigeon/lib/src/java/java_generator.dart index 6ad033a5459..818639d2a92 100644 --- a/packages/pigeon/lib/src/java/java_generator.dart +++ b/packages/pigeon/lib/src/java/java_generator.dart @@ -6,7 +6,7 @@ import '../ast.dart'; import '../functional.dart'; import '../generator.dart'; import '../generator_tools.dart'; -import '../pigeon_lib.dart' show TaskQueueType; +import '../types/task_queue.dart'; /// Documentation open symbol. const String _docCommentPrefix = '/**'; diff --git a/packages/pigeon/lib/src/kotlin/kotlin_generator.dart b/packages/pigeon/lib/src/kotlin/kotlin_generator.dart index 41614263baa..65151a19328 100644 --- a/packages/pigeon/lib/src/kotlin/kotlin_generator.dart +++ b/packages/pigeon/lib/src/kotlin/kotlin_generator.dart @@ -8,7 +8,7 @@ import '../ast.dart'; import '../functional.dart'; import '../generator.dart'; import '../generator_tools.dart'; -import '../pigeon_lib.dart' show TaskQueueType; +import '../types/task_queue.dart'; import 'templates.dart'; /// Documentation open symbol. diff --git a/packages/pigeon/lib/src/objc/objc_generator.dart b/packages/pigeon/lib/src/objc/objc_generator.dart index 40e75726961..84780c894a1 100644 --- a/packages/pigeon/lib/src/objc/objc_generator.dart +++ b/packages/pigeon/lib/src/objc/objc_generator.dart @@ -6,7 +6,8 @@ import '../ast.dart'; import '../functional.dart'; import '../generator.dart'; import '../generator_tools.dart'; -import '../pigeon_lib.dart' show Error, TaskQueueType; +import '../pigeon_lib.dart' show Error; +import '../types/task_queue.dart'; /// Documentation comment open symbol. const String _docCommentPrefix = '///'; diff --git a/packages/pigeon/lib/src/pigeon_lib.dart b/packages/pigeon/lib/src/pigeon_lib.dart index 45ed062ca52..72eb4f50942 100644 --- a/packages/pigeon/lib/src/pigeon_lib.dart +++ b/packages/pigeon/lib/src/pigeon_lib.dart @@ -36,6 +36,9 @@ import 'java/java_generator.dart'; import 'kotlin/kotlin_generator.dart'; import 'objc/objc_generator.dart'; import 'swift/swift_generator.dart'; +import 'types/task_queue.dart'; + +export 'types/task_queue.dart' show TaskQueueType; class _Asynchronous { const _Asynchronous(); @@ -211,21 +214,6 @@ class SwiftClass { const SwiftClass(); } -/// Type of TaskQueue which determines how handlers are dispatched for -/// HostApi's. -enum TaskQueueType { - /// Handlers are invoked serially on the default thread. This is the value if - /// unspecified. - serial, - - /// Handlers are invoked serially on a background thread. - serialBackgroundThread, - - // TODO(gaaclarke): Add support for concurrent task queues. - // /// Handlers are invoked concurrently on a background thread. - // concurrentBackgroundThread, -} - /// Metadata annotation to control how handlers are dispatched for HostApi's. /// Note that the TaskQueue API might not be available on the target version of /// Flutter, see also: diff --git a/packages/pigeon/lib/src/swift/swift_generator.dart b/packages/pigeon/lib/src/swift/swift_generator.dart index d568a434fbc..843b45595fa 100644 --- a/packages/pigeon/lib/src/swift/swift_generator.dart +++ b/packages/pigeon/lib/src/swift/swift_generator.dart @@ -9,7 +9,7 @@ import '../ast.dart'; import '../functional.dart'; import '../generator.dart'; import '../generator_tools.dart'; -import '../pigeon_lib.dart'; +import '../types/task_queue.dart'; import 'templates.dart'; /// Documentation comment open symbol. diff --git a/packages/pigeon/lib/src/types/task_queue.dart b/packages/pigeon/lib/src/types/task_queue.dart new file mode 100644 index 00000000000..63869f5dfab --- /dev/null +++ b/packages/pigeon/lib/src/types/task_queue.dart @@ -0,0 +1,18 @@ +// 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. + +/// Type of TaskQueue which determines how handlers are dispatched for +/// HostApi's. +enum TaskQueueType { + /// Handlers are invoked serially on the default thread. This is the value if + /// unspecified. + serial, + + /// Handlers are invoked serially on a background thread. + serialBackgroundThread, + + // TODO(gaaclarke): Add support for concurrent task queues. + // /// Handlers are invoked concurrently on a background thread. + // concurrentBackgroundThread, +} From 293789ba37a5342102dca2531638bd3faf2bdc60 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 14 Feb 2025 15:41:51 -0500 Subject: [PATCH 06/10] Fix Kotlin tests --- .../kotlin/com/example/test_plugin/CoreTests.gen.kt | 13 +++++++++++++ packages/pigeon/tool/shared/generation.dart | 10 +++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt index efd9cb613df..467de3c5f29 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt @@ -36,6 +36,19 @@ private fun createConnectionError(channelName: String): FlutterError { "channel-error", "Unable to establish connection on channel: '$channelName'.", "") } +/** + * Error class for passing custom error details to Flutter via a thrown PlatformException. + * + * @property code The error code. + * @property message The error message. + * @property details The error details. Must be a datatype supported by the api codec. + */ +class FlutterError( + val code: String, + override val message: String? = null, + val details: Any? = null +) : Throwable() + enum class AnEnum(val raw: Int) { ONE(0), TWO(1), diff --git a/packages/pigeon/tool/shared/generation.dart b/packages/pigeon/tool/shared/generation.dart index f03b0735556..7e33c7b3fab 100644 --- a/packages/pigeon/tool/shared/generation.dart +++ b/packages/pigeon/tool/shared/generation.dart @@ -111,13 +111,15 @@ Future generateTestPigeons( final Set skipLanguages = _unsupportedFiles[input] ?? {}; - final bool kotlinErrorClassGenerationTestFiles = input == 'core_tests'; + final bool kotlinErrorClassGenerationTestFiles = + input == 'core_tests' || input == 'primitive'; final String kotlinErrorName = kotlinErrorClassGenerationTestFiles ? 'FlutterError' : '${pascalCaseName}Error'; - final bool swiftErrorUseDefaultErrorName = input == 'core_tests'; + final bool swiftErrorUseDefaultErrorName = + input == 'core_tests' || input == 'primitive'; final String? swiftErrorClassName = swiftErrorUseDefaultErrorName ? null : '${pascalCaseName}Error'; @@ -137,12 +139,13 @@ Future generateTestPigeons( : '$outputBase/android/src/main/kotlin/com/example/test_plugin/$pascalCaseName.gen.kt', kotlinPackage: 'com.example.test_plugin', kotlinErrorClassName: kotlinErrorName, - kotlinIncludeErrorClass: input != 'core_tests', + kotlinIncludeErrorClass: input != 'primitive', // iOS swiftOut: skipLanguages.contains(GeneratorLanguage.swift) ? null : '$outputBase/ios/Classes/$pascalCaseName.gen.swift', swiftErrorClassName: swiftErrorClassName, + swiftIncludeErrorClass: input != 'primitive', // Linux gobjectHeaderOut: skipLanguages.contains(GeneratorLanguage.gobject) ? null @@ -174,6 +177,7 @@ Future generateTestPigeons( ? null : '$outputBase/macos/Classes/$pascalCaseName.gen.swift', swiftErrorClassName: swiftErrorClassName, + swiftIncludeErrorClass: input != 'primitive', suppressVersion: true, dartPackageName: 'pigeon_integration_tests', injectOverflowTypes: includeOverflow && input == 'core_tests', From f09630f505c90037ac7c5182853267fe577f71d9 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 14 Feb 2025 15:57:39 -0500 Subject: [PATCH 07/10] Windows fixes --- .../pigeon/platform_tests/test_plugin/windows/test_plugin.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h b/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h index c1ad02c26ae..7f5de3593a3 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h +++ b/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h @@ -393,8 +393,8 @@ class TestPlugin : public flutter::Plugin, std::optional> reply)> result) override; - ErrorOr DefaultIsMainThread() override; - ErrorOr TaskQueueIsBackgroundThread() override; + core_tests_pigeontest::ErrorOr DefaultIsMainThread() override; + core_tests_pigeontest::ErrorOr TaskQueueIsBackgroundThread() override; void CallFlutterNoop( std::function< void(std::optional reply)> @@ -681,7 +681,7 @@ class TestPlugin : public flutter::Plugin, flutter_small_api_two_; std::unique_ptr host_small_api_one_; std::unique_ptr host_small_api_two_; - std::this_thread::id main_thread_id_; + std::thread::id main_thread_id_; }; } // namespace test_plugin From 3e4320c52198f76df43b7f89dc0a06cf26e697d1 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 14 Feb 2025 15:58:49 -0500 Subject: [PATCH 08/10] Remove duplicate line --- packages/pigeon/lib/src/kotlin/kotlin_generator.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/pigeon/lib/src/kotlin/kotlin_generator.dart b/packages/pigeon/lib/src/kotlin/kotlin_generator.dart index 65151a19328..963ac46e9ee 100644 --- a/packages/pigeon/lib/src/kotlin/kotlin_generator.dart +++ b/packages/pigeon/lib/src/kotlin/kotlin_generator.dart @@ -658,7 +658,6 @@ if (wrapped == null) { if (api.methods.any((Method m) => m.taskQueueType == TaskQueueType.serialBackgroundThread)) { serialBackgroundQueue = 'taskQueue'; - serialBackgroundQueue = 'taskQueue'; indent.writeln( 'val $serialBackgroundQueue = binaryMessenger.makeBackgroundTaskQueue()'); } From 46388dfc99cbebc35955e3460462da191ad81d23 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 14 Feb 2025 16:35:22 -0500 Subject: [PATCH 09/10] Missing Windows include --- packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h b/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h index 7f5de3593a3..74fa192257e 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h +++ b/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h @@ -11,6 +11,7 @@ #include #include #include +#include #include "pigeon/core_tests.gen.h" From 551066e4f45920b263bbaa1e6dcaaaf2450c1674 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Fri, 14 Feb 2025 20:19:36 -0500 Subject: [PATCH 10/10] Linux fixes --- .../pigeon/platform_tests/test_plugin/linux/test_plugin.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/pigeon/platform_tests/test_plugin/linux/test_plugin.cc b/packages/pigeon/platform_tests/test_plugin/linux/test_plugin.cc index 0092cc27644..6f72865481d 100644 --- a/packages/pigeon/platform_tests/test_plugin/linux/test_plugin.cc +++ b/packages/pigeon/platform_tests/test_plugin/linux/test_plugin.cc @@ -26,7 +26,7 @@ struct _TestPlugin { GCancellable* cancellable; - int main_thread_id; + std::thread::id main_thread_id; }; G_DEFINE_TYPE(TestPlugin, test_plugin, G_TYPE_OBJECT) @@ -796,14 +796,14 @@ static CoreTestsPigeonTestHostIntegrationCoreApiDefaultIsMainThreadResponse* default_is_main_thread(gpointer user_data) { TestPlugin* self = TEST_PLUGIN(user_data); return core_tests_pigeon_test_host_integration_core_api_default_is_main_thread_response_new( - std::this_thread::get_id() == this->main_thread_id); + std::this_thread::get_id() == self->main_thread_id); } static CoreTestsPigeonTestHostIntegrationCoreApiTaskQueueIsBackgroundThreadResponse* task_queue_is_background_thread(gpointer user_data) { TestPlugin* self = TEST_PLUGIN(user_data); return core_tests_pigeon_test_host_integration_core_api_task_queue_is_background_thread_response_new( - std::this_thread::get_id() != this->main_thread_id); + std::this_thread::get_id() != self->main_thread_id); } static void noop_cb(GObject* object, GAsyncResult* result, gpointer user_data) {