blob: 38706459e00c39a1014dfcff779538c30d031590 [file] [log] [blame]
// 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 "flutter/shell/platform/darwin/ios/platform_message_handler_ios.h"
#import "flutter/fml/trace_event.h"
#import "flutter/lib/ui/window/platform_message.h"
#import "flutter/shell/platform/darwin/common/buffer_conversions.h"
#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterBinaryMessenger.h"
static uint64_t platform_message_counter = 1;
@interface FLTSerialTaskQueue : NSObject <FlutterTaskQueueDispatch>
@property(nonatomic, strong) dispatch_queue_t queue;
@end
@implementation FLTSerialTaskQueue
- (instancetype)init {
self = [super init];
if (self) {
_queue = dispatch_queue_create("FLTSerialTaskQueue", DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (void)dealloc {
dispatch_release(_queue);
[super dealloc];
}
- (void)dispatch:(dispatch_block_t)block {
dispatch_async(self.queue, block);
}
@end
namespace flutter {
NSObject<FlutterTaskQueue>* PlatformMessageHandlerIos::MakeBackgroundTaskQueue() {
return [[[FLTSerialTaskQueue alloc] init] autorelease];
}
PlatformMessageHandlerIos::PlatformMessageHandlerIos(
fml::RefPtr<fml::TaskRunner> platform_task_runner)
: platform_task_runner_(std::move(platform_task_runner)) {}
void PlatformMessageHandlerIos::HandlePlatformMessage(std::unique_ptr<PlatformMessage> message) {
// This can be called from any isolate's thread.
@autoreleasepool {
fml::RefPtr<flutter::PlatformMessageResponse> completer = message->response();
HandlerInfo handler_info;
{
// TODO(gaaclarke): This mutex is a bottleneck for multiple isolates sending
// messages at the same time. This could be potentially changed to a
// read-write lock.
std::lock_guard lock(message_handlers_mutex_);
auto it = message_handlers_.find(message->channel());
if (it != message_handlers_.end()) {
handler_info = it->second;
}
}
if (handler_info.handler) {
FlutterBinaryMessageHandler handler = handler_info.handler;
NSData* data = nil;
if (message->hasData()) {
data = ConvertMappingToNSData(message->releaseData());
}
uint64_t platform_message_id = platform_message_counter++;
TRACE_EVENT_ASYNC_BEGIN1("flutter", "PlatformChannel ScheduleHandler", platform_message_id,
"channel", message->channel().c_str());
dispatch_block_t run_handler = ^{
handler(data, ^(NSData* reply) {
TRACE_EVENT_ASYNC_END0("flutter", "PlatformChannel ScheduleHandler", platform_message_id);
// Called from any thread.
if (completer) {
if (reply) {
completer->Complete(ConvertNSDataToMappingPtr(reply));
} else {
completer->CompleteEmpty();
}
}
});
};
if (handler_info.task_queue.get()) {
[handler_info.task_queue.get() dispatch:run_handler];
} else {
dispatch_async(dispatch_get_main_queue(), run_handler);
}
} else {
if (completer) {
completer->CompleteEmpty();
}
}
}
}
bool PlatformMessageHandlerIos::DoesHandlePlatformMessageOnPlatformThread() const {
return false;
}
void PlatformMessageHandlerIos::InvokePlatformMessageResponseCallback(
int response_id,
std::unique_ptr<fml::Mapping> mapping) {
// Called from any thread.
// TODO(gaaclarke): This vestigal from the Android implementation, find a way
// to migrate this to PlatformMessageHandlerAndroid.
}
void PlatformMessageHandlerIos::InvokePlatformMessageEmptyResponseCallback(int response_id) {
// Called from any thread.
// TODO(gaaclarke): This vestigal from the Android implementation, find a way
// to migrate this to PlatformMessageHandlerAndroid.
}
void PlatformMessageHandlerIos::SetMessageHandler(const std::string& channel,
FlutterBinaryMessageHandler handler,
NSObject<FlutterTaskQueue>* task_queue) {
FML_CHECK(platform_task_runner_->RunsTasksOnCurrentThread());
// Use `respondsToSelector` instead of `conformsToProtocol` to accomodate
// injecting your own `FlutterTaskQueue`. This is not a supported usage but
// not one worth breaking.
FML_CHECK(!task_queue || [task_queue respondsToSelector:@selector(dispatch:)]);
/// TODO(gaaclarke): This should be migrated to a lockfree datastructure.
std::lock_guard lock(message_handlers_mutex_);
message_handlers_.erase(channel);
if (handler) {
message_handlers_[channel] = {
.task_queue = fml::scoped_nsprotocol(
[static_cast<NSObject<FlutterTaskQueueDispatch>*>(task_queue) retain]),
.handler =
fml::ScopedBlock<FlutterBinaryMessageHandler>{
handler, fml::scoped_policy::OwnershipPolicy::kRetain},
};
}
}
} // namespace flutter