mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Switch the MacOS Desktop embedder to using a thread configuration where the platform and render task runners are the same. (flutter/engine#13300)
Also creates a new test harness for the desktop embedder framework target and adds a test that launches a headless engine in this new thread configuration. Fixes https://github.com/flutter/flutter/issues/17579
This commit is contained in:
parent
445cbd749c
commit
9e89f4af6f
@ -58,8 +58,10 @@ group("flutter") {
|
||||
# If on the host, compile all unittests targets.
|
||||
if (current_toolchain == host_toolchain) {
|
||||
if (is_mac) {
|
||||
public_deps +=
|
||||
[ "$flutter_root/shell/platform/darwin:flutter_channels_unittests" ]
|
||||
public_deps += [
|
||||
"$flutter_root/shell/platform/darwin:flutter_channels_unittests",
|
||||
"$flutter_root/shell/platform/darwin/macos:flutter_desktop_darwin_unittests",
|
||||
]
|
||||
}
|
||||
|
||||
public_deps += [
|
||||
|
||||
@ -824,6 +824,7 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterAppDe
|
||||
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject.mm
|
||||
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h
|
||||
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm
|
||||
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEngineUnittests.mm
|
||||
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h
|
||||
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterExternalTextureGL.h
|
||||
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterExternalTextureGL.mm
|
||||
@ -835,6 +836,7 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterView.
|
||||
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterView.mm
|
||||
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController.mm
|
||||
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h
|
||||
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/fixtures/flutter_desktop_test.dart
|
||||
FILE: ../../../flutter/shell/platform/darwin/macos/framework/module.modulemap
|
||||
FILE: ../../../flutter/shell/platform/embedder/assets/EmbedderInfo.plist
|
||||
FILE: ../../../flutter/shell/platform/embedder/assets/embedder.modulemap
|
||||
|
||||
@ -8,6 +8,7 @@ import("//build/config/mac/mac_sdk.gni")
|
||||
import("$flutter_root/common/config.gni")
|
||||
import("$flutter_root/shell/platform/darwin/common/framework_shared.gni")
|
||||
import("$flutter_root/shell/platform/glfw/config.gni")
|
||||
import("$flutter_root/testing/testing.gni")
|
||||
|
||||
group("macos") {
|
||||
deps = [
|
||||
@ -41,11 +42,9 @@ _flutter_framework_headers = [
|
||||
_flutter_framework_headers_copy_dir =
|
||||
"$_flutter_framework_dir/Versions/A/Headers"
|
||||
|
||||
shared_library("create_flutter_framework_dylib") {
|
||||
source_set("flutter_framework_source") {
|
||||
visibility = [ ":*" ]
|
||||
|
||||
output_name = "$_flutter_framework_name"
|
||||
|
||||
sources = [
|
||||
"framework/Source/FlutterAppDelegate.mm",
|
||||
"framework/Source/FlutterDartProject.mm",
|
||||
@ -83,6 +82,43 @@ shared_library("create_flutter_framework_dylib") {
|
||||
]
|
||||
}
|
||||
|
||||
shared_library("flutter_framework_dylib") {
|
||||
visibility = [ ":*" ]
|
||||
|
||||
output_name = "$_flutter_framework_name"
|
||||
|
||||
deps = [
|
||||
":flutter_framework_source",
|
||||
]
|
||||
}
|
||||
|
||||
test_fixtures("flutter_desktop_darwin_fixtures") {
|
||||
dart_main = "framework/Source/fixtures/flutter_desktop_test.dart"
|
||||
|
||||
fixtures = [ "//third_party/icu/common/icudtl.dat" ]
|
||||
}
|
||||
|
||||
executable("flutter_desktop_darwin_unittests") {
|
||||
testonly = true
|
||||
|
||||
sources = [
|
||||
"framework/Source/FlutterEngineUnittests.mm",
|
||||
]
|
||||
|
||||
cflags_objcc = [ "-fobjc-arc" ]
|
||||
|
||||
deps = [
|
||||
":flutter_desktop_darwin_fixtures",
|
||||
":flutter_framework_source",
|
||||
"$flutter_root/shell/platform/darwin/common:framework_shared",
|
||||
"$flutter_root/shell/platform/embedder:embedder_with_symbol_prefix",
|
||||
"$flutter_root/testing",
|
||||
"$flutter_root/testing:dart",
|
||||
"$flutter_root/testing:skia",
|
||||
"$flutter_root/testing:testing_lib",
|
||||
]
|
||||
}
|
||||
|
||||
action("copy_dylib_and_update_framework_install_name") {
|
||||
visibility = [ ":*" ]
|
||||
script = "$flutter_root/sky/tools/change_install_name.py"
|
||||
@ -108,7 +144,7 @@ action("copy_dylib_and_update_framework_install_name") {
|
||||
]
|
||||
|
||||
deps = [
|
||||
":create_flutter_framework_dylib",
|
||||
":flutter_framework_dylib",
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@ -72,6 +72,13 @@ FLUTTER_EXPORT
|
||||
*/
|
||||
@property(nonatomic, nonnull, readonly) id<FlutterBinaryMessenger> binaryMessenger;
|
||||
|
||||
/**
|
||||
* Shuts the Flutter engine if it is running. The FlutterEngine instance must always be shutdown
|
||||
* before it may be collected. Not shutting down the FlutterEngine instance before releasing it will
|
||||
* result in the leak of that engine instance.
|
||||
*/
|
||||
- (void)shutDownEngine;
|
||||
|
||||
@end
|
||||
|
||||
#endif // FLUTTER_FLUTTERENGINE_H_
|
||||
|
||||
@ -12,6 +12,8 @@ static NSString* const kAppBundleIdentifier = @"io.flutter.flutter.app";
|
||||
|
||||
@implementation FlutterDartProject {
|
||||
NSBundle* _dartBundle;
|
||||
NSString* _assetsPath;
|
||||
NSString* _ICUDataPath;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
@ -26,7 +28,19 @@ static NSString* const kAppBundleIdentifier = @"io.flutter.flutter.app";
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithAssetsPath:(NSString*)assets ICUDataPath:(NSString*)icuPath {
|
||||
self = [super init];
|
||||
NSAssert(self, @"Super init cannot be nil");
|
||||
_assetsPath = assets;
|
||||
_ICUDataPath = icuPath;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString*)assetsPath {
|
||||
if (_assetsPath) {
|
||||
return _assetsPath;
|
||||
}
|
||||
|
||||
// If there's no App.framework, fall back to checking the main bundle for assets.
|
||||
NSBundle* assetBundle = _dartBundle ?: [NSBundle mainBundle];
|
||||
NSString* flutterAssetsName = [assetBundle objectForInfoDictionaryKey:@"FLTAssetsPath"];
|
||||
@ -41,6 +55,10 @@ static NSString* const kAppBundleIdentifier = @"io.flutter.flutter.app";
|
||||
}
|
||||
|
||||
- (NSString*)ICUDataPath {
|
||||
if (_ICUDataPath) {
|
||||
return _ICUDataPath;
|
||||
}
|
||||
|
||||
NSString* path = [[NSBundle bundleForClass:[self class]] pathForResource:kICUBundlePath
|
||||
ofType:nil];
|
||||
if (!path) {
|
||||
|
||||
@ -33,6 +33,13 @@
|
||||
*/
|
||||
@property(nonatomic, readonly) std::vector<const char*> argv;
|
||||
|
||||
/**
|
||||
* Instead of looking up the assets and ICU data path in the application bundle, this initializer
|
||||
* allows callers to create a Dart project with custom locations specified for the both.
|
||||
*/
|
||||
- (nonnull instancetype)initWithAssetsPath:(nonnull NSString*)assets
|
||||
ICUDataPath:(nonnull NSString*)icuPath NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
#endif // SHELL_PLATFORM_DARWIN_MACOS_FRAMEWORK_SOURCE_FLUTTERDARTPROJECT_INTERNAL_H_
|
||||
|
||||
@ -42,17 +42,18 @@
|
||||
*/
|
||||
- (void)engineCallbackOnPlatformMessage:(const FlutterPlatformMessage*)message;
|
||||
|
||||
/**
|
||||
* Shuts the Flutter engine if it is running.
|
||||
*/
|
||||
- (void)shutDownEngine;
|
||||
|
||||
/**
|
||||
* Forwards texture copy request to the corresponding texture via |textureID|.
|
||||
*/
|
||||
- (BOOL)populateTextureWithIdentifier:(int64_t)textureID
|
||||
openGLTexture:(FlutterOpenGLTexture*)openGLTexture;
|
||||
|
||||
/**
|
||||
* Requests that the task be posted back the to the Flutter engine at the target time. The target
|
||||
* time is in the clock used by the Flutter engine.
|
||||
*/
|
||||
- (void)postMainThreadTask:(FlutterTask)task targetTimeInNanoseconds:(uint64_t)targetTime;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
@ -218,6 +219,26 @@ static bool OnAcquireExternalTexture(FlutterEngine* engine,
|
||||
flutterArguments.command_line_argv = &arguments[0];
|
||||
flutterArguments.platform_message_callback = (FlutterPlatformMessageCallback)OnPlatformMessage;
|
||||
flutterArguments.custom_dart_entrypoint = entrypoint.UTF8String;
|
||||
static size_t sTaskRunnerIdentifiers = 0;
|
||||
const FlutterTaskRunnerDescription cocoa_task_runner_description = {
|
||||
.struct_size = sizeof(FlutterTaskRunnerDescription),
|
||||
.user_data = (void*)CFBridgingRetain(self),
|
||||
.runs_task_on_current_thread_callback = [](void* user_data) -> bool {
|
||||
return [[NSThread currentThread] isMainThread];
|
||||
},
|
||||
.post_task_callback = [](FlutterTask task, uint64_t target_time_nanos,
|
||||
void* user_data) -> void {
|
||||
[((__bridge FlutterEngine*)(user_data)) postMainThreadTask:task
|
||||
targetTimeInNanoseconds:target_time_nanos];
|
||||
},
|
||||
.identifier = ++sTaskRunnerIdentifiers,
|
||||
};
|
||||
const FlutterCustomTaskRunners custom_task_runners = {
|
||||
.struct_size = sizeof(FlutterCustomTaskRunners),
|
||||
.platform_task_runner = &cocoa_task_runner_description,
|
||||
.render_task_runner = &cocoa_task_runner_description,
|
||||
};
|
||||
flutterArguments.custom_task_runners = &custom_task_runners;
|
||||
|
||||
FlutterEngineResult result = FlutterEngineInitialize(
|
||||
FLUTTER_ENGINE_VERSION, &rendererConfig, &flutterArguments, (__bridge void*)(self), &_engine);
|
||||
@ -358,6 +379,9 @@ static bool OnAcquireExternalTexture(FlutterEngine* engine,
|
||||
NSLog(@"Could not de-initialize the Flutter engine: error %d", result);
|
||||
}
|
||||
|
||||
// Balancing release for the retain in the task runner dispatch table.
|
||||
CFRelease((CFTypeRef)self);
|
||||
|
||||
result = FlutterEngineShutdown(_engine);
|
||||
if (result != kSuccess) {
|
||||
NSLog(@"Failed to shut down Flutter engine: error %d", result);
|
||||
@ -459,4 +483,29 @@ static bool OnAcquireExternalTexture(FlutterEngine* engine,
|
||||
[_textures removeObjectForKey:@(textureID)];
|
||||
}
|
||||
|
||||
#pragma mark - Task runner integration
|
||||
|
||||
- (void)postMainThreadTask:(FlutterTask)task targetTimeInNanoseconds:(uint64_t)targetTime {
|
||||
const auto engine_time = FlutterEngineGetCurrentTime();
|
||||
|
||||
__weak FlutterEngine* weak_self = self;
|
||||
auto worker = ^{
|
||||
FlutterEngine* strong_self = weak_self;
|
||||
if (strong_self && strong_self->_engine) {
|
||||
auto result = FlutterEngineRunTask(strong_self->_engine, &task);
|
||||
if (result != kSuccess) {
|
||||
NSLog(@"Could not post a task to the Flutter engine.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (targetTime <= engine_time) {
|
||||
dispatch_async(dispatch_get_main_queue(), worker);
|
||||
|
||||
} else {
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, targetTime - engine_time),
|
||||
dispatch_get_main_queue(), worker);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "flutter/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h"
|
||||
#include "flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h"
|
||||
#include "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h"
|
||||
#include "flutter/testing/testing.h"
|
||||
|
||||
namespace flutter::testing {
|
||||
|
||||
TEST(FlutterEngineTest, FlutterEngineCanLaunch) {
|
||||
NSString* fixtures = @(testing::GetFixturesPath());
|
||||
FlutterDartProject* project = [[FlutterDartProject alloc]
|
||||
initWithAssetsPath:fixtures
|
||||
ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
|
||||
FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"test"
|
||||
project:project
|
||||
allowHeadlessExecution:true];
|
||||
ASSERT_TRUE([engine runWithEntrypoint:@"main"]);
|
||||
ASSERT_TRUE(engine.running);
|
||||
[engine shutDownEngine];
|
||||
}
|
||||
|
||||
} // flutter::testing
|
||||
@ -0,0 +1,7 @@
|
||||
// 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.
|
||||
|
||||
void main() {
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user